如何使用cURL和PHP重定向大文件?

时间:2017-12-06 18:43:52

标签: php http curl

我需要使用cURL和PHP来访问云存储中的大文件。 存储URL根据请求而变化。 PHP脚本使用库来使用cURL授予访问权限并返回文件。

但是,HTTP请求正在抛出500状态,因为PHP失败并出现错误:

PHP Fatal error:  Allowed memory size of 134217728 bytes exhausted (tried to allocate 133700011 bytes)

那么,我该如何正确地重定向请求呢?字段Location:也不起作用,因为它错过了HTTP标头中的额外参数。

这是脚本:

function fetch($url, $cookie=null) {
    $ch =  curl_init();

    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_AUTOREFERER, true);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLINFO_HEADER_OUT, true);

    if ($cookie) {
        curl_setopt($ch, CURLOPT_COOKIE, $cookie);
    }

    $result = curl_exec($ch);

    curl_close($ch);

    return $result;
}

任何提示?

2 个答案:

答案 0 :(得分:0)

Sub Fill_from_above() For Each c In Selection.Cells If c.Value = "" Then c.Value = c.Offset(-1, 0).Value End If Next c End Sub

$ stream_resource是用fdopen()打开的,比如说。

答案 1 :(得分:0)

你的代码在将内容发送到客户端之前将其全部缓存在内存中,这既缓慢(因为在下载完成100%之前它不会开始发送到客户端)并且内存饥饿 (因为你将整个文件同时放在内存中),而是在下载时将文件批量发送到客户端,然后它更快,并且不会占用太多内存(因为你已经可以释放批量了发送给客户)。幸运的是,curl非常容易,甚至是默认模式,但是你在调用CURLOPT_RETURNTRANSFER时明确告诉curl不要这样做,所以停止这样做。现在curl_exec($ ch)返回一个bool而不是一个字符串,并且传输被批量发送到客户端,这应该可以解决你的内存问题并且速度更快。还要注意curl_setopt和curl_exec如果出现错误则返回bool(false),不应忽略这些错误,因此我建议你用这些错误捕获的包装器替换它们:

function ecurl_setopt ( /*resource*/$ch , int $option , /*mixed*/ $value ):bool{
    $ret=curl_setopt($ch,$option,$value);
    if($ret!==true){
        //option should be obvious by stack trace
        throw new RuntimeException ( 'curl_setopt() failed. curl_errno: ' . return_var_dump ( curl_errno ($ch) ).'. curl_error: '.curl_error($ch) );
    }
    return true;
}
function ecurl_exec ( /*resource*/$ch):bool{
    $ret=curl_exec($ch);
    if($ret!==true){
        throw new RuntimeException ( 'curl_exec() failed. curl_errno: ' . return_var_dump ( curl_errno ($ch) ).'. curl_error: '.curl_error($ch) );
    }
    return true;
}


function return_var_dump(/*...*/){
    $args = func_get_args ();
    ob_start ();
    call_user_func_array ( 'var_dump', $args );
    return ob_get_clean ();
}
  • 另外,如果您正在下载的文件是可压缩的,并且目标服务器支持它(绝大多数Web服务器都支持),那么执行curl_setopt($ch,CURLOPT_ENCODING,'');将允许下载所有已编译卷曲的压缩(通常为gzipdeflate),这应该会更快:)

  • 还要注意,如果您要以这种方式运行大量的大型,慢速并发下载,那么PHP只是语言性能的一个糟糕选择,每次下载都会占用整个php进程(或者在Apache mod_php的情况下,线程)直到下载完成,并且通常允许并发运行的PHP进程数量非常有限,这可能会阻止整个网站(我自己在Go中编写下载代理,Goroutines会在附近 - 完成此类工作)