我有一个PHP脚本,它通过cURL下载一个大文件,并通过输出缓冲向客户端报告中间下载进度。
ob_start();
ob_flush();
flush();
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://example.com/big-video-file.mp4");
curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, 'progress');
curl_setopt($ch, CURLOPT_NOPROGRESS, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);
curl_close($ch);
echo 100;
ob_flush();
flush();
function progress($resource,$download_size, $downloaded, $upload_size, $uploaded) {
if ($download_size > 0) echo round(($downloaded / $download_size) * 100).',';
ob_flush();
flush();
}
然后我可以通过onreadystatechange
收听readyState
== 3来获取客户端的最新动态。
let req = new XMLHttpRequest(), ta = document.querySelector('textarea');
req.open('GET', 'curl_progress.php?ajax=1');
req.addEventListener('readystatechange', function() {
if (req.readyState == 3) { //we get here repeatedly - yay!
let spl = req.responseText.split(',');
ta.value += spl[spl.length-2]+'\n';
} else if (req.readyState == 4 && req.status == 200)
ta.value += 100;
}, false);
req.send();
这很有效。不要担心我对最新进展的字符串处理;这里的重点是readyState
== 3重复发生。
现在,我的问题是:为什么这不适合上传?
我改编了脚本来代替上传。再次,PHP端工作正常。我可以看到它通过输出缓冲吐出跟踪信息。这是适应的cURL上传请求而不是下载:
$ch = curl_init($_SESSION['vimeo_upload_url']);
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_POST => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_INFILE => fopen($_FILES['file']['tmp_name'], 'r'),
CURLOPT_INFILESIZE => $_FILES['file']['size'],
CURLOPT_UPLOAD => true,
CURLOPT_PROGRESSFUNCTION => 'curl_progress',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_NOPROGRESS => false,
CURLOPT_SSL_VERIFYPEER => false
]);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Tus-Resumable: 1.0.0',
'Upload-Offset: 0',
'Content-Type: application/offset+octet-stream'
]);
function curl_progress($resource, $download_size, $downloaded, $upload_size, $uploaded) {
if ($upload_size > 0) echo round(($uploaded / $upload_size) * 100).',';
ob_flush();
flush();
}
上传本身效果很好 - 没问题。
但是在客户端readyState
== 3只触发一次 - 就在整个事情完成之前。
let req = new XMLHttpRequest(), fd = new FormData();
fd.append('file', input.files[0]);
req.open('POST', '../vimeo_upload.php?action=transfer_file');
req.addEventListener('readystatechange', function() {
if (this.readyState == 3) { //we get here only once!
let spl = this.responseText.split(',');
console.log(spl[spl.length-2]);
} else if (this.readyState == 4 && this.status == 200)
console.log(100);
}, false);
有没有人知道为什么会这样,也就是说为什么我不能像下载一样多次点击它?