如何将 curl 上传进度发送到要显示的 ajax

Posted

技术标签:

【中文标题】如何将 curl 上传进度发送到要显示的 ajax【英文标题】:How to send curl upload progress to ajax to be displayed 【发布时间】:2016-03-22 16:47:47 【问题描述】:

我要做的是使用 ajax 将文件/文件信息上传到 upload.php,然后通过 curl 将相同的信息再次上传到远程服务器到 remoteUpload.php。最后在remoteUpload.php 文件中,我执行文件的实际上传。

在执行第一步时 -> 将文件/文件信息上传到upload.php 我使用 ajax 显示此步骤的进度条。

但是当做第二步时 -> 再次使用 curl 将相同的信息上传到远程服务器到remoteUpload.php 进度条没有显示,这是我的问题。

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:(上传.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";

【问题讨论】:

【参考方案1】:

您可以将progressCallback() 保存到$_SESSION 您的$progress 并在“第一步”完成后从js 端运行setIntevral(/*ajax*/) 向服务器发出ajax 请求获取$_SESSION['progress] 并显示第二个进度条(或在表单中加载第一个进度条直到 50% 并继续加载第二个 50%),当它完成调用 clearInterval()


详细解答

说明:我们将按照以下逻辑计算进度。如果我们一次上传了 5 个文件(在您的情况下似乎上传的是多个文件),那么我们将 100% 除以 5 并在一个文件 curl 提交期间增加 25% 进度,为此您需要以下 5修改

1)如果未完成,请在您的upload.php 中的session_start() 上方的某处调用

2)保存到会话总文件数和当前处理文件索引

// 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)0-100格式保存progressCallback函数当前进度号

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

4) 创建新的getUploadProgress.php 并从会话中返回 json 编码的进度信息

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)添加你的ajax.onreadystatechangesetInteval函数调用,并在你的js全局变量中定义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);
        
;

注意:在使用这个示例代码的过程中,当然需要额外的roundsJS/PHP functions添加,变量调整或者一些逻辑调整以获得更有效,但基本上这是逻辑您可以使用的一个选项

【讨论】:

谢谢,但是如何在我的代码上应用你的话? 好的,我已经尝试尽可能匹配,在基本示例中解释它,在详细答案之后检查代码 很遗憾,没有出现进度,而是等到完成,然后直接100%打印。 实际上从这一点上我帮不了你,你也不应该用新代码更新你的问题或创建 php fiddle,你也不应该调试它在 php 和 js 的不同位置进行转储以查看什么在会话中你在 js 中得到了什么进度计算 js 等等......或者你可以把日志记录在 php 文件中(为了不中断上传流转储和退出)例如你可以输入progressCallback这个日志file_put_content("PATH/progress.log", json_encode($progress)."\n", FILE_APPEND);

以上是关于如何将 curl 上传进度发送到要显示的 ajax的主要内容,如果未能解决你的问题,请参考以下文章

在javascript-ajax中提交表单时如何显示进度条

显示多文件上传 Jquery/Ajax 的进度

JavaWeb项目实现文件上传动态显示进度

ajax上传文件及进度显示

Ajax技术——带进度条的文件上传

Ajax技术——带进度条的文件上传