I'm having an issue retrieving a file using php curl over ftps with implicit ssl (as discussed here: ftp_ssl_connect with implicit ftp over tls). The problem is that sometimes - probably 5% of the time, I end up with a partial download.
My class is more or less adapted from adapted from Nico Westerdale's answer and here are the relevant methods:
class ftps {
private $server;
private $username;
private $password;
private $curlhandle;
public $dir = '/';
public function __construct($server, $username, $password) {
$this->server = $server;
$this->username = $username;
$this->password = $password;
$this->curlhandle = curl_init();
}
private function common($remote) {
curl_reset($this->curlhandle);
curl_setopt($this->curlhandle, CURLOPT_URL, 'ftps://' . $this->server . '/' . $remote);
curl_setopt($this->curlhandle, CURLOPT_USERPWD, $this->username . ':' . $this->password);
curl_setopt($this->curlhandle, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($this->curlhandle, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($this->curlhandle, CURLOPT_FTP_SSL, CURLFTPSSL_TRY);
curl_setopt($this->curlhandle, CURLOPT_FTPSSLAUTH, CURLFTPAUTH_TLS);
return $this->curlhandle;
}
public function download($filepath, $local = false) {
$filename = basename($filepath);
$remote = dirname($filepath);
if ($remote == '.') {
$remote = $this->dir;
}
if ($local === false) {
$local = $filename;
}
if ($fp = fopen($local, 'w')) {
$this->curlhandle = self::common($remote . $filename);
curl_setopt($this->curlhandle, CURLOPT_UPLOAD, 0);
curl_setopt($this->curlhandle, CURLOPT_FILE, $fp);
curl_exec($this->curlhandle);
if (curl_error($this->curlhandle)) {
return false;
} else {
return $local;
}
}
return false;
}
}
I'm using it like this:
$ftps = new ftps('example.com','john_doe','123456');
$ftps->download('remote_filename','local_filename');
As I mentioned above, this works almost flawlessly except about 5% of the time the result is a partially downloaded file. I then check the remote server and am able to verify that the file is indeed there in it's entirety - try the script again and it invariably gets the whole file on a second attempt.
What would cause an intermittent issue using curl like this? My next move would be to implement some kind of checksum and continue download attempts until everything hashes but this feels more like a sloppy workaround than a true solution and it would be nice to know the actual root of the problem.