【问题标题】:How to check whether file completely downloaded using php CURL如何使用php CURL检查文件是否完全下载
【发布时间】:2020-07-27 06:55:31
【问题描述】:

我正在从外部 url 下载录音并使用 CURL 保存,如下所示:

$ch = curl_init($Recording); 
$fp = fopen($recording_file_loc, 'wb'); 
curl_setopt($ch, CURLOPT_FILE, $fp); 
curl_setopt($ch, CURLOPT_HEADER, 0); 
curl_exec($ch);  
curl_close($ch); 
fclose($fp); 

文件完全下载后,我需要更改文件权限,如下所示。

chmod($recording_file_loc , 0640);

在执行 chmod 之前,我如何检查并确保文件完全下载??

更新: 我更新了我的代码如下:

$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if($statusCode == 200){
chmod($recording_file_loc , 0640);
}
else{
echo $statusCode;
}

【问题讨论】:

  • 你试过if (fclose($fp) ) chmod.. - 因为 fclose 在完成时返回 true。并且 php 是同步语言,我认为如果创建火会等待 curl
  • 你可以检查 curl 是否报错 - stackoverflow.com/questions/3987006/…

标签: php curl


【解决方案1】:

在 curl 检测到任何错误的传输中,curl_errno($ch) 不应再返回 0,因此 if(curl_errno($ch)!==0),您的下载可能发生了一些不好的事情。

另一件事,正如@Pamela 在评论中指出的那样,如果响应代码不是 2XX(如 HTTP 200 OK 或 HTTP 204 No Content),那是另一个可能出错的迹象,可以通过执行 @ 来检测987654322@

所以..

if(curl_errno($ch)!==0 || ((string)curl_getinfo($ch,CURLINFO_RESPONSE_CODE))[0]!=='2'){
    // the download probably failed. 
}

一般来说,这可能无法在未实现“Content-Length”标头的服务器上检测到,如果您从不支持 Content-Length 的服务器下载,则可能没有标准化的方法完全检测损坏的下载..(您可能必须检查您下载的内容以确保它是您所期望的或其他东西,idk)

例如,在正文长度与“Content-Length”标头不匹配的传输中,curl_errno($ch) 返回 int(56)(而不是通常的 int(0))和 curl_exec($ch ) 返回 bool(false) (PS!如果你使用了 CURLOPT_RETURNTRANSFER,那么它可能包含一个字符串而不是 bool)

这是一个小型 HTTP 服务器发送“Content-Length: 3”,然后在仅发送 2 个(据称是 3 个)字节的正文后切断连接:

<?php

$port=1234;
$srv=socket_create_listen($port);
while(($conn=socket_accept($srv))){
        $headers=implode("\r\n",array(
                "HTTP/1.1 200 OK",
                "Content-Type: text/plain",
                "Content-Length: 3",
                "Connection: close",
                "","",
        ));
        // i lied! i said 3 bytes body, but only send 2 bytes body
        $body="ab";
        $response=$headers.$body;
        var_dump(strlen($response),socket_write($conn,$response));
        socket_close($conn);
}

以及随附的测试脚本:

<?php

$ch=curl_init("http://127.0.0.1:1234");
var_dump(curl_exec($ch));
var_dump(curl_errno($ch),curl_error($ch));

印刷:

abbool(false)
int(56)
string(38) "Recv failure: Connection reset by peer"

【讨论】:

    【解决方案2】:

    您需要检查下载过程是否完成。

    curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, 'progress'); // call progress function
    curl_setopt($ch, CURLOPT_NOPROGRESS, false);
    

    然后你需要定义一个检查下载进度的函数

    // progress function definition
    function progress($resource,$download_size, $downloaded, $upload_size, $uploaded)
    {
        // Progress
        if($download_size > 0)
             echo $downloaded / $download_size  * 100;
    
        if($downloaded / $download_size == 1){
    
            // chmod code here
        }
    
    }
    

    查看此链接cURL download progress in PHP

    【讨论】:

    • 我认为最好检查http状态码如下: $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);并执行: if($statusCode == 200){ chmod($recording_file_loc , 0640); } else{ echo "状态码:" . $状态码; }
    • 是的,这是可能的。是的
    • 不足。如果一个页面响应HTTP 200 OK\r\nContent-Length: 3,但随后只发送了2个字节的正文并关闭连接,它仍然是200 OK,但你的下载将不完整。
    【解决方案3】:

    获取这样的信息:

    $ch = curl_init($Recording); 
    $fp = fopen($recording_file_loc, 'wb'); 
    curl_setopt($ch, CURLOPT_FILE, $fp); 
    curl_setopt($ch, CURLOPT_HEADER, 0); 
    curl_exec($ch);
    $info = curl_getinfo($ch);
    curl_close($ch); 
    fclose($fp);
    

    然后像这样检查“download_content_length”和“size_download”:

    if($info["download_content_length"]==$info["size_download"])
    {
        //Download complete!
    }
    else
    {
        //Error
    }
    

    请注意,只有在服务器提前发送 Content-Length 标头时才有效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-09-26
      • 1970-01-01
      • 2020-06-26
      • 2013-05-18
      • 2021-05-23
      • 2021-04-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多