Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to send curl upload progress to ajax to be displayed

What I am trying to do is upload the file/files information to upload.php using ajax, then uploading the same information again to a remote server by curl to remoteUpload.php. Finally in remoteUpload.php file I perform the actual upload of the file/files.

When doing the first step -> upload the file/files information to upload.php I display a progress bar of this step using ajax.

But the when doing the second step -> upload the same information again to remote server using curl to remoteUpload.php the progress bar is not displayed, and this is my problem.

How to display the progress bar for second step by ajax ?

Javascript:

var upload_btn = document.getElementById('upload_file');
var result = document.getElementById('result');

upload_btn.onclick = function () {
    var uploadInput = document.getElementsByName('file[]')[0];
    if (uploadInput.files.length > 0) {
        console.clear();
        var ajax = new XMLHttpRequest();
        var inputFileData = formData(uploadInput);
        ajax.onreadystatechange = function () {
            if (ajax.readyState == 4 && ajax.status == 200) {
                var json = JSON.parse(ajax.responseText);
                result.innerHTML = json.text;
            }
        };
        ajax.upload.addEventListener('progress', function (e) {
            result.innerHTML = Math.round(e.loaded / e.total * 100) + "%";
        });
        ajax.open("post", "upload.php");
        ajax.send(inputFileData);
    }
};

function formData(inputFileObj) {
    var formData = new FormData;
    var inputFile = inputFileObj.files;
    if (inputFile.length > 0) {
        for (i = 0; i < inputFile.length; i++) {
            formData.append(inputFileObj.name, inputFile[i]);
        }
    }
    return formData;
}

PHP: (upload.php)

function progressCallback($dltotal, $dlnow, $ultotal, $ulnow) {
    static $last; 
    $progress = @round($ulnow / $ultotal * 100);
    if($last < $progress) echo json_encode(array('text' => $progress));
    flush();
    $last = $progress;
}

if (strtolower($_SERVER['REQUEST_METHOD']) == 'post' && !empty($_FILES)) {
    foreach ($_FILES['file']['tmp_name'] as $index => $tmpFileName) {
        if ($_FILES['file']['error'][$index] > 0) {
            $text = "A file did not uploaded correctly.";
            return false;
        }

        $ch = curl_init("http://serverfiles/remoteUpload.php");
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_NOPROGRESS, false);
        curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, 'progressCallback');
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, array('fileupload' => '@' . $tmpFileName));
        $text = curl_exec($ch);  
    }
}
echo json_encode(array('text' => $text));
exit;

PHP: (remoteUpload.php)

if (move_uploaded_file($_FILES['fileupload']['tmp_name'], "files/" . $_FILES['fileupload']['name']))
    echo "The file has been uploaded.";
else
    echo "error";
like image 639
Lion King Avatar asked Dec 16 '15 13:12

Lion King


1 Answers

You can save in progressCallback() to $_SESSION your $progress and from js side after "first step" upland complete run setIntevral(/*ajax*/) make ajax requests to server get $_SESSION['progress] and display second progress bar(or load first progress barr till 50% and continue load second 50%) in your form and when it complete call clearInterval()


DETAILED ANSWER

Explanation: we will count progress in following logic. If we have uploaded 5 files at once (as in your case seems uploaded was multi file) then we will divide 100% by 5 and will increase by 25% progress during one file curl submit, for this you need following 5 modifications

1) call somewhere above session_start() in your upload.php if it not done

2) save to session total files count and current processing file index

// Saveing total amount of uploaded files
$_SESSION['UP_total_count'] = count($_FILES['file']);    
foreach ($_FILES['file']['tmp_name'] as $index => $tmpFileName) {
    ...
    // Saving current index of uploaded file
    $_SESSION['UP_current_index'] = ($index+1);//+1 as it starts from 0
}

3) save in progressCallback function current progress number in 0-100 format

function progressCallback($dltotal, $dlnow, $ultotal, $ulnow) { 
    ...
    $_SESSION['UP_current_progress'] = $progress;
}

4) create new getUploadProgress.php and return json encoded progress infromation from session

session_start();
echo json_encode( array(
   'total_count' => $_SESSION['UP_total_count'],
   'current_index' => $_SESSION['UP_current_index'],
   'current_progress' => $_SESSION['UP_current_progress'],
) );

5) add in your ajax.onreadystatechange setInteval function call, and define in your js global variable progressSetInterval

....
var progressSetInterval = null;// Global

ajax.onreadystatechange = function () {
        if (ajax.readyState == 4 && ajax.status == 200) {
            ...
            progressSetInterval = setInterval(function(){ 
                $.ajax({
                   type: "POST",
                   url: "getUploadProgress.php",
                   success: function(data){

                       // Calculating progress based on 100 25 logic explained above
                       var progressPart = 100 / data['total_count'];
                       var currProgress = 
                           (data['total_count'] - data['current_index']) * progressPart;

                       currProgress += (progressPart/100) * data['current_progress'];

                       // You can display progress somehow, apped to div or show prgoress...
                       console.log( "Second progress: " + currProgress);

                       // if currProgress is 100% removing setinterval
                       if( currProgress >= 100 ){
                           clearInterval( progressSetInterval );
                       }
                   },
                   dataType: 'json'
               });
            }, 1000);
        }
};

NOTE: during usage of this example code of course there will be needed additional rounds, JS/PHP functions addition, variable adjustments or some logical adjustments for more effectiveness, but basically this is logic of one option which you can use

like image 168
Armen Avatar answered Nov 20 '22 06:11

Armen