从PHP下载安全的图像


Safe image download from PHP

我想让我的用户通过提供图像的URL来上传文件。

很像imgur,你进入http://something.com/image.png脚本下载文件,然后将其保存在服务器上并发布。

我尝试使用file_get_contents()getimagesize()。但我认为会有问题:

  1. 如何保护脚本不受100个用户向大型图像提供100个URL的影响
  2. 如何确定下载过程是否需要或已经需要太长时间

这其实很有趣。

看起来您实际上可以跟踪和控制cURL传输的进度。参见CURLOPT_NOPROGRESSCURLOPT_PROGRESSFUNCTIONCURLOPT_WRITEFUNCTION 文档

我发现了这个例子,并将其更改为:

<?php
file_put_contents('progress.txt', '');
$target_file_name = 'targetfile.zip';
$target_file = fopen($target_file_name, 'w');
$ch = curl_init('http://localhost/so/testfile2.zip');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_NOPROGRESS, FALSE);
curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, 'progress_callback');
curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'write_callback');
curl_exec($ch);
if ($target_file) {
    fclose($target_file);
}
$_download_size = 0;
function progress_callback($download_size, $downloaded_size, $upload_size, $uploaded_size) {
    global $_download_size;
    $_download_size = $download_size;
    static $previous_progress = 0;
    if ($download_size == 0) {
        $progress = 0;
    }
    else {
        $progress = round($downloaded_size * 100 / $download_size);
    }
    if ($progress > $previous_progress) {
        $previous_progress = $progress;
        $fp = fopen('progress.txt', 'a');
        fputs($fp, $progress .'% ('. $downloaded_size .'/'. $download_size .")'n");
        fclose($fp);
    }
}
function write_callback($ch, $data) {
    global $target_file_name;
    global $target_file;
    global $_download_size;
    if ($_download_size > 1000000) {
        return '';
    }
    return fwrite($target_file, $data);
}

write_callback检查数据的大小是否大于指定的限制。如果是,则返回一个空字符串,中止传输。我在两个分别为80K和33M的文件上测试了这一点,限制为1M。在您的情况下,progress_callback在第二行之外是毫无意义的,但我将所有内容都保留在其中用于调试目的。

获取数据大小的另一种方法是执行HEAD请求,但我认为不需要服务器发送Content-length头。

要回答第一个问题,只需在代码中添加适当的限制即可。定义在给定的时间内要接受的请求数量,在数据库中跟踪您的请求,然后从那里开始。同时对文件大小设置上限。

对于问题2,如果使用cURL,可以设置适当的超时。