php如何实现下载进度
使用 cURL 获取下载进度
在 PHP 中,可以通过 cURL 的 CURLOPT_PROGRESSFUNCTION 和 CURLOPT_NOPROGRESS 选项来实现下载进度跟踪。需要启用进度回调函数并关闭默认的进度显示。
$url = 'https://example.com/largefile.zip';
$file = fopen('downloaded.zip', 'w');
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_FILE, $file);
curl_setopt($ch, CURLOPT_NOPROGRESS, false);
curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, function(
$resource, $download_size, $downloaded, $upload_size, $uploaded
) {
if ($download_size > 0) {
$progress = round(($downloaded / $download_size) * 100, 2);
echo "Progress: {$progress}%\n";
}
});
curl_exec($ch);
curl_close($ch);
fclose($file);
使用输出缓冲实时显示进度
对于需要网页实时显示进度的情况,可以结合输出缓冲和 flush 函数。这种方法适用于浏览器端的进度显示。
ob_start();
$url = 'https://example.com/largefile.zip';
$file = fopen('downloaded.zip', 'w');
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_FILE => $file,
CURLOPT_NOPROGRESS => false,
CURLOPT_PROGRESSFUNCTION => function(
$resource, $download_size, $downloaded, $upload_size, $uploaded
) {
if ($download_size > 0) {
$progress = round(($downloaded / $download_size) * 100, 2);
echo "<script>updateProgress({$progress})</script>";
ob_flush();
flush();
}
}
]);
curl_exec($ch);
curl_close($ch);
fclose($file);
ob_end_clean();
分段下载与进度存储
对于大文件下载,可以考虑分段下载并将进度信息存储到数据库或文件中,以便中断后恢复下载。

$url = 'https://example.com/largefile.zip';
$file_path = 'downloaded.zip';
$progress_file = 'progress.json';
// 读取之前的进度
$progress = file_exists($progress_file) ? json_decode(file_get_contents($progress_file), true) : [
'downloaded' => 0,
'total_size' => 0
];
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RANGE => $progress['downloaded'] . '-',
CURLOPT_WRITEFUNCTION => function($ch, $data) use ($file_path, $progress_file, &$progress) {
$length = fwrite(fopen($file_path, 'a'), $data);
$progress['downloaded'] += $length;
if ($progress['total_size'] == 0) {
$progress['total_size'] = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
}
file_put_contents($progress_file, json_encode($progress));
return $length;
}
]);
curl_exec($ch);
curl_close($ch);
使用 PHP 内置流包装器
PHP 的流包装器也可以用于实现简单的下载进度跟踪,虽然功能不如 cURL 全面。
$url = 'https://example.com/largefile.zip';
$context = stream_context_create([], [
'notification' => function($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) {
if ($notification_code == STREAM_NOTIFY_PROGRESS && $bytes_max > 0) {
$progress = round(($bytes_transferred / $bytes_max) * 100, 2);
echo "Progress: {$progress}%\n";
}
}
]);
file_put_contents('downloaded.zip', fopen($url, 'r', false, $context));
结合 AJAX 实现网页进度显示
对于网页应用,可以结合前端 AJAX 和后端会话来实现实时进度显示。

后端 PHP (download.php):
session_start();
$url = 'https://example.com/largefile.zip';
$_SESSION['download_progress'] = ['total' => 0, 'current' => 0];
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_FILE => fopen('downloaded.zip', 'w'),
CURLOPT_NOPROGRESS => false,
CURLOPT_PROGRESSFUNCTION => function($ch, $download_size, $downloaded, $upload_size, $uploaded) {
$_SESSION['download_progress'] = [
'total' => $download_size,
'current' => $downloaded
];
}
]);
curl_exec($ch);
curl_close($ch);
前端 JavaScript:
function checkProgress() {
fetch('progress.php')
.then(response => response.json())
.then(data => {
if (data.total > 0) {
const progress = Math.round((data.current / data.total) * 100);
document.getElementById('progress').innerText = `${progress}%`;
}
if (data.current < data.total) {
setTimeout(checkProgress, 500);
}
});
}
// 开始下载
fetch('download.php').then(() => checkProgress());
进度检查接口 (progress.php):
session_start();
header('Content-Type: application/json');
echo json_encode($_SESSION['download_progress'] ?? ['total' => 0, 'current' => 0]);






