我无法弄清楚每次使用php更新时如何推进进度。为了清楚起见,我将写一个例子。
jQuery的:
function uploadMovieDownload(link){
$.post("php/downloadmovie.php", { source:link }, function(json){ console.log(json); });
}
uploadMovieDownload(url);
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();
我遇到的问题是它在完成后返回进度,而不是在下载时推送它。如果您有任何吸烟,请提前致谢。
答案 0 :(得分: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();
}
getProgress.xhr.php
<?php
if(""===session_id()){
session_start();
}
echo $_SESSION['download_percentage']??'?';
然后在浏览器中监控进度:
(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();
})();
重要编辑:正如@ drew010指出的那样,没有session_write_close(); session_start();每次curl更新该值,修复该值。
答案 1 :(得分:1)
来自cURL download progress in PHP的引用
echo "<pre>";
echo "Loading ...";
ob_flush();
flush();
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://stackoverflow.com");
//curl_setopt($ch, CURLOPT_BUFFERSIZE,128);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, 'progress');
curl_setopt($ch, CURLOPT_NOPROGRESS, false); // needed to make progress function work
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
$html = curl_exec($ch);
curl_close($ch);
function progress($resource,$download_size, $downloaded, $upload_size, $uploaded)
{
if($download_size > 0)
echo $downloaded / $download_size * 100;
ob_flush();
flush();
sleep(1); // just to see effect
}
echo "Done";
ob_flush();
flush();
?>
答案 2 :(得分:0)
不要使用ob_flush(),只需使用flush()。 (删除所有ob_函数)。 另外,请考虑修改buffersize:
curl_setopt($ch, CURLOPT_BUFFERSIZE, 16000);
试验尺寸。
答案 3 :(得分:0)
PHP将在完成所有脚本后显示结果。这就是你完成进度的原因。
您可以在后台执行curl下载,并将进度写入会话,数据库,会话或内存,如redis,memchche。然后在客户端每隔很短的时间阅读一次该过程。
您也可以使用Iframe执行此操作。