当前位置:首页 > PHP

php如何实现下载进度

2026-02-14 04:47:33PHP

使用 cURL 获取下载进度

在 PHP 中,可以通过 cURL 的 CURLOPT_PROGRESSFUNCTIONCURLOPT_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();

分段下载与进度存储

对于大文件下载,可以考虑分段下载并将进度信息存储到数据库或文件中,以便中断后恢复下载。

php如何实现下载进度

$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如何实现下载进度

后端 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]);

分享给朋友:

相关文章

权限管理vue如何实现

权限管理vue如何实现

权限管理在 Vue 中的实现方法 基于路由的权限控制 通过 Vue Router 的全局前置守卫 beforeEach 实现路由拦截,结合用户角色或权限列表动态过滤可访问路由。示例代码: ro…

vue如何实现到期提醒

vue如何实现到期提醒

实现思路 在Vue中实现到期提醒功能,可以通过计算日期差、定时检查和通知用户三个核心步骤完成。需要结合Vue的响应式特性和JavaScript的日期处理能力。 计算日期差 使用JavaScr…

react如何实现插槽

react如何实现插槽

React 实现插槽的方法 React 本身没有直接提供类似 Vue 的插槽(slot)概念,但可以通过以下几种方式实现类似功能: 使用 props.children React 组件可以通过 p…

react如何实现混入

react如何实现混入

在React中实现混入(Mixin)功能可以通过以下几种方式实现,React官方已不推荐使用传统的React.createClass混入方式,但可通过高阶组件或自定义Hook替代。 高阶组件(HOC…

java如何实现多态

java如何实现多态

多态的概念 多态是面向对象编程的三大特性之一(封装、继承、多态),指同一操作作用于不同对象时,可以产生不同的行为。Java中主要通过方法重写(Override)和接口/抽象类实现多态。 实现多态的…

如何实现java序列化

如何实现java序列化

实现Java序列化的方法 1. 实现Serializable接口 要使一个类可序列化,需要让该类实现java.io.Serializable接口。这是一个标记接口,没有任何方法需要实现。 publ…