PHP cURL使用jquery下载进度

d3n*_*m4k 5 javascript php jquery curl

每次使用php更新时,我无法弄清楚如何推进进度.为了清楚起见,我将写一个例子.

jQuery的:

function uploadMovieDownload(link){
    $.post("php/downloadmovie.php", { source:link }, function(json){ console.log(json); });
}

uploadMovieDownload(url);
Run Code Online (Sandbox Code Playgroud)

PHP(php/downloadmovie.php):

session_start();
ob_start();
date_default_timezone_set("Europe/Bucharest");
ini_set('display_errors',true);

require_once(dirname(__FILE__)."/functions.php");


$url = $_POST['source'];
$headers = getHeaders($url);
$url = $headers['url'];
$path = dirname(__FILE__)."/temp/test.mp4";

$fp = fopen ($path, 'w+');
$ch = curl_init();
curl_setopt( $ch, CURLOPT_URL, $url );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, false );
curl_setopt( $ch, CURLOPT_PROGRESSFUNCTION, 'progress' );
curl_setopt( $ch, CURLOPT_NOPROGRESS, false );
curl_setopt( $ch, CURLOPT_BINARYTRANSFER, true );
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false );
curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, 100 );
curl_setopt( $ch, CURLOPT_FILE, $fp );
curl_exec( $ch );
curl_close( $ch );
fclose( $fp );


function progress($resource,$download_size, $downloaded, $upload_size, $uploaded){
    if($download_size > 0) echo $downloaded / $download_size  * 100;
    ob_flush();
    flush();
}

echo "Done";
ob_flush();
flush();
Run Code Online (Sandbox Code Playgroud)

我遇到的问题是它在完成后返回进度,而不是在下载时推送它.如果您有任何吸烟,请提前感谢.

han*_*rik 8

使用那种方法,你会遇到各种缓存问题,是php输出缓冲吗?你会遇到问题.你是一个Web服务器,ala nginx/apache/lighthttp/anything?你会遇到问题.是浏览器缓存输出?(所有主流浏览器都这样做),你会遇到问题.

我建议一个没有这些问题的替代方案:使用$ _SESSION存储下载百分比,并使用XMLHttpRequests查询百分比(实际上查询WebSockets上的百分比将是最佳的,无滞后的,使用更少的bw等,但更难实现)

downloadmovie.php

<?php 
require_once(dirname(__FILE__)."/functions.php");


$url = $_POST['source'];
$headers = getHeaders($url);
$url = $headers['url'];
//after validation of input
session_start();
$_SESSION['download_percentage']=0.0;//initialize it
session_write_close();
fastcgi_finish_request();//or if you're not using fcgi, some equivalent..

$path = dirname(__FILE__)."/temp/test.mp4";

$fp = fopen ($path, 'w+');
$ch = curl_init();
curl_setopt( $ch, CURLOPT_URL, $url );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, false );
curl_setopt( $ch, CURLOPT_PROGRESSFUNCTION, 'progress' );
curl_setopt( $ch, CURLOPT_NOPROGRESS, false );
curl_setopt( $ch, CURLOPT_BINARYTRANSFER, true );
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false );
curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, 100 );
curl_setopt( $ch, CURLOPT_FILE, $fp );
curl_exec( $ch );
curl_close( $ch );
fclose( $fp );


function progress($resource,$download_size, $downloaded, $upload_size, $uploaded){
    $percentage=$download_size==0? 0.0 : (($downloaded/$download_size)*100);
    session_start();
    $_SESSION['download_percentage']=$percentage;
    session_write_close();
}
Run Code Online (Sandbox Code Playgroud)

getProgress.xhr.php

<?php 
if(""===session_id()){
session_start();
}
echo $_SESSION['download_percentage']??'?';
Run Code Online (Sandbox Code Playgroud)

然后在浏览器中监控进度:

(function checkProgress() {
    "use strict";
    var xhr = new XMLHttpRequest();
    xhr.open("GET", "getProgress.xhr.php");
    xhr.addEventListener("readystatechange", function(ev) {
        var xhr = ev.target;
        if (xhr.readyState !== 4) {
            return;
        }
        console.log(xhr.responseText + " percent downloaded!");
        if (xhr.responseText === "100") {
            return; /*stop checking for progress when its finished*/
        }
        setTimeout(checkProgress, 1000); //<<check for progress every 1 second

    });
    xhr.send();
})();
Run Code Online (Sandbox Code Playgroud)

重要编辑:正如@ drew010指出的那样,没有session_write_close(); session_start(); 每次curl更新值,修复它.

  • 我认为这是最好的解决方案,但不要忘记每次更新后都需要使用“session_write_close”,然后再次使用“session_start”,否则 Ajax 请求将被卡住,直到会话关闭,因为它将被锁定并阻止使用同一会话的后续请求。 (2认同)

小智 0

不要使用ob_flush(),只使用flush()。(删除所有 ob_ 函数)。另外,考虑修改缓冲区大小:

curl_setopt($ch, CURLOPT_BUFFERSIZE, 16000);
Run Code Online (Sandbox Code Playgroud)

尝试一下尺寸。