i'm buidling a php script to upload larges files from a local php server to a distant ftp server with log of progress in a mysql base. Evrything work fine, but i get problem with the resume function and i can't find any clear information of the process to follow to resume an ftp upload with curl. my code bellow :
$fp = fopen($localfile, 'r');
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_NOPROGRESS, false);
curl_setopt($curl, CURLOPT_PROGRESSFUNCTION, 'curlProgressCallback'); // lof progress to base
curl_setopt($curl, CURLOPT_READFUNCTION, 'curlAbortCallback'); // check if user request abort
curl_setopt($curl, CURLOPT_URL, $ftp);
curl_setopt($curl, CURLOPT_PORT, FTPPort);
curl_setopt($curl, CURLOPT_LOW_SPEED_LIMIT, 1000);
curl_setopt($curl, CURLOPT_LOW_SPEED_TIME, 20);
curl_setopt($curl, CURLOPT_USERPWD, FTPLog . ":" . FTPPass);
curl_setopt($curl, CURLOPT_FTP_CREATE_MISSING_DIRS, true);
curl_setopt($curl, CURLOPT_UPLOAD, 1);
if($resume){
$startFrom=ftpFileSize($dest); // return the actual file size on the ftp server
}else{
$startFrom=false;
}
if($startFrom){
curl_setopt ($curl, CURLOPT_FTPAPPEND, 1);
curl_setopt($curl, CURLOPT_RESUME_FROM, $startFrom);
fseek($fp, $startFrom, SEEK_SET);
$sizeToUp=filesize($localfile);//-$startFrom;
}else{
$sizeToUp=filesize($localfile);
}
curl_setopt($curl, CURLOPT_INFILE, $fp);
curl_setopt($curl, CURLOPT_INFILESIZE, $sizeToUp);
curl_exec($curl);
If someone call help me on this or redirect me on a valid example it will be very helfull and appreciate.
Tks for your feedback
Mr
So i've abort my research to make resume with curl, not enought help or documentation on it, And it's really more easy to do it with ftp_nb_put. So i f its can help someone, you can find a exemple of my final code bellow :
define("FTPAdd","your serveur ftp address");
define("FTPPort",21);
define("FTPTimeout",120);
define("FTPLog","your login");
define("FTPPass","your password");
function ftpUp_checkForAndMakeDirs($ftpThread, $file) {
$parts = explode("/", dirname($file));
foreach ($parts as $curDir) {
if (@ftp_chdir($ftpThread, $curDir) === false) { // Attempt to change directory, suppress errors
ftp_mkdir($ftpThread, $curDir); //directory doesn't exist - so make it
ftp_chdir($ftpThread, $curDir); //go into the new directory
}
}
}
function ftpUp_progressCallBack($uploadedData){
global $abortRequested;
//you can do any action you want while file upload progress, personaly, il log progress in to data base
//and i request DB to know if user request a file transfert abort and set the var $abortRequested to true or false
}
function ftpUp($src,$file,$dest,$resume){
global $abortRequested;
$conn_id = ftp_connect(FTPAdd,FTPPort,FTPTimeout);
if ($conn_id==false){
echo "FTP Connection problem";return false;
}else{
$login_res = ftp_login($conn_id, FTPLog, FTPPass);
if ($login_res){
$ftpThread=$conn_id;
}else{
echo "FTP Authentification error";return false;
}
}
$fp = fopen($src, 'r');
ftpUp_checkForAndMakeDirs($ftpThread, $dest); //verif et creation de l'arborescence sur le serveur ftp
ftp_set_option ($ftpThread, FTP_AUTOSEEK, TRUE); // indispensable pour pouvoir faire du resume
if($resume){
$upload = ftp_nb_fput ($ftpThread, $file, $fp ,FTPUpMode, FTP_AUTORESUME);
}else{
$upload = ftp_nb_fput ($ftpThread, $file, $fp ,FTPUpMode);
}
///////////////////////////////////////////////////////////////////////////////////
//uploading process
while ($upload == FTP_MOREDATA) {
//progress of upload
ftpUp_progressCallBack(ftell ($fp));
//continue or abort
if(!$abortRequested){
$upload = ftp_nb_continue($ftpThread);
}else{
$upload = "userAbort";
}
}
///////////////////////////////////////////////////////////////////////////////////
//end and result
ftpUp_progressCallBack(ftell ($fp));
if ($upload != FTP_FINISHED) {
@fclose($fp);
@ftp_close ($ftpThread);
if ($abortRequested){
echo "FTP Abort by user : resume needed";
}else{
echo "FTP upload error : ".$upload." (try resume)";
}
}else{
@fclose($fp);
@ftp_close ($ftpThread);
echo "upload sucess";
}
}
$file="test.zip";
$src = "FilesToUp/" . $file;
$destDir = "www/data/upFiles/";
$dest = $destDir . $file;
$abortRequested=false;
ftpUp($src,$file,$dest,true);
I do not think cURL & PHP can do this.
Are you using Linux? If so look at aria2. It supports resumable connections and supports FTP. I am not sure if it will do exactly what you want.
I was searching for a viable answer using CURL + PHP to resume a transfer that was broken and could not find clear, viable solution on the internet. This is an OLD question but I figured it did need a proper answer. This is the result of a day or two of research. See functions below and quick usage example.
Connect function:
function ftp_getconnect($uName, $pWord, $uHost)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_USERPWD, "$uName:$pWord");
curl_setopt($ch, CURLOPT_URL, $uHost);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$return = curl_exec($ch);
if($return === false)
{
print_r(curl_getinfo($ch));
echo curl_error($ch);
curl_close($ch);
die('Could not connect');
}
else
{
return $ch;
}
}
Disconnect function:
function ftp_disconnect($ch)
{
$return = curl_close($ch);
if($return === false)
{
return "Error: Could not close connection".PHP_EOL;
}
else
{
return $return;
}
}
Function to get the remote file size (in bytes):
function get_rem_file_size($ch, $rem_file)
{
curl_setopt($ch, CURLOPT_INFILE, STDIN);
curl_setopt($ch, CURLOPT_URL, $rem_file);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_FTP_CREATE_MISSING_DIRS, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FTPLISTONLY, false);
$return = curl_exec($ch);
if($return === false)
{
print_r(curl_getinfo($ch));
echo curl_error($ch);
curl_close($ch);
die('Could not connect');
}
else
{
$file_header = curl_getinfo($ch);
return $file_header['download_content_length'];
}
}
Upload file function:
function upload_file($ch,$local_file,$remote_file,$resume)
{
echo "attempting to upload $local_file to $remote_file".PHP_EOL;
$file = fopen($local_file, 'rb');
if($resume)
{
curl_setopt($ch, CURLOPT_RESUME_FROM, get_rem_file_size($ch, $remote_file));
}
curl_setopt($ch, CURLOPT_URL, $remote_file);
curl_setopt($ch, CURLOPT_UPLOAD, true);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_FTP_CREATE_MISSING_DIRS, true);
curl_setopt($ch, CURLOPT_INFILE, $file);
curl_setopt($ch, CURLOPT_INFILESIZE, filesize($local_file));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$return = curl_exec($ch);
if($return === false)
{
fclose($file);
return curl_error($ch).PHP_EOL;
}
else
{
fclose($file);
echo $local_file.' uploaded'.PHP_EOL;
return true;
}
}
Quick usage example:
$ftp = ftp_getconnect($uName, $pWord, 'ftp://'.$uHost);
$rem_file = 'ftp://'.$uHost.'/path/to/remote/file.ext';
$loc_file = 'path/to/local/file.ext';
$resume = 'true';
$success = upload_file($ftp, $loc_file, $rem_file, $resume);
if($success !== true)
{
//failure
echo $success;
curl_close($ch);
}
print_r(ftp_disconnect($ftp));
Quick note, if there is a large set of files, you can loop through them and upload_file
without connecting/disconnecting each time.