gpt4 book ai didi

php使用curl下载指定大小的文件实例代码

转载 作者:qq735679552 更新时间:2022-09-28 22:32:09 25 4
gpt4 key购买 nike

CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.

这篇CFSDN的博客文章php使用curl下载指定大小的文件实例代码由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.

php中使用基于libcurl的curl函数,可以对目标url发起http请求并获取返回的响应内容。通常的请求方式类似如下的代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public function callFunction( $url , $postData , $method , header= '' )
{
   $maxRetryTimes = 3;
   $curl = curl_init();
   /******初始化请求参数start******/
   if ( strtoupper ( $method ) !== 'GET' && $postData ){
     curl_setopt( $curl , CURLOPT_POSTFIELDS, json_encode( $postData ));
   } elseif ( strtoupper ( $method ) === 'GET' && $postData ){
     $url .= '?' . http_build_query( $postData );
   }
   /******初始化请求参数end******/
   curl_setopt_array( $curl , array (
     CURLOPT_URL => $url ,
     CURLOPT_TIMEOUT => 10,
     CURLOPT_NOBODY => 0,
     CURLOPT_RETURNTRANSFER => 1
   ));
   if (method == 'POST' ){
     curl_setopt( $curl , CURLOPT_POST, true);
   }
   if (false == empty ()){
     curl_setopt( $curl , CURLOPT_HTTPHEADER, $header );
   }
   $response = false;
   while (( $response === false) && (-- $maxRetryTimes > 0)){
     $response = trim(curl_exec( $curl ));
   }
   return $response ;
}

上面代码中的这个$response是curl发起的这次http请求从$url获取到的数据,如果没有在$header中通过range来指定要下载的大小,无论这个资源多大,那么都要请求完整的并返回的是这个URI的完整内容。通常只用curl来请求求一些接口或者远程调用一个函数获取数据,,所以这个场景下CURLOPT_TIMEOUT这个参数很重要.

对于curl的使用场景不止访问数据接口,还要对任意的url资源进行检测是否能提供正确的http服务。当用户填入的url是一个资源文件时,例如一个pdf或者ppt之类的,这时候如果网络状况较差的情况下用curl请求较大的资源,将不可避免的出现超时或者耗费更多的网络资源。之前的策略是完全下载(curl会下载存储在内存中),请求完后检查内容大小,当超过目标值就把这个监控的任务暂停。这样事发后限制其实治标不治本,终于客户提出了新的需求,不能停止任务只下载指定大小的文件并返回md5值由客户去校验正确性.

经过了一些尝试,解决了这个问题,记录过程如下文.

1、尝试使用 CURLOPT_MAXFILESIZE.

对php和libcurl的版本有版本要求,完全的事前处理,当发现目标大于设置时,直接返回了超过大小限制的错误而不去下载目标了,不符合要求.

2、使用curl下载过程的回调函数.

参考 http://php.net/manual/en/function.curl-setopt-array.php ,最终使用了CURLOPT_WRITEFUNCTION参数设置了on_curl_write,该函数将会1s中被回调1次.

?
1
2
3
4
5
6
$ch = curl_init();
$options = array (CURLOPT_URL    => 'http://www.php.net/' ,
CURLOPT_HEADER    => false,
CURLOPT_HEADERFUNCTION  => 'on_curl_header' ,
CURLOPT_WRITEFUNCTION  => 'on_curl_write'
);

最终我的实现片段:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function on_curl_write( $ch , $data )
{
   $pid = getmypid ();
   $downloadSizeRecorder = DownloadSizeRecorder::getInstance( $pid );
   $bytes = strlen ( $data );
   $downloadSizeRecorder ->downloadData .= $data ;
   $downloadSizeRecorder ->downloadedFileSize += $bytes ;
//  error_log(' on_curl_write '.$downloadSizeRecorder->downloadedFileSize." > {$downloadSizeRecorder->maxSize} \n", 3, '/tmp/hyb.log');
   //确保已经下载的内容略大于最大限制
   if (( $downloadSizeRecorder ->downloadedFileSize - $bytes ) > $downloadSizeRecorder ->maxSize) {
     return false;
   }
   return $bytes ; //这个不正确的返回,将会报错,中断下载 "errno":23,"errmsg":"Failed writing body (0 != 16384)"
}

DownloadSizeRecorder是一个单例模式的类,curl下载时记录大小,实现返回下载内容的md5等.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
class DownloadSizeRecorder
{
   const ERROR_FAILED_WRITING = 23; //Failed writing body
   public $downloadedFileSize ;
   public $maxSize ;
   public $pid ;
   public $hasOverMaxSize ;
   public $fileFullName ;
   public $downloadData ;
   private static $selfInstanceList = array ();
   public static function getInstance( $pid )
   {
     if (!isset(self:: $selfInstanceList [ $pid ])){
       self:: $selfInstanceList [ $pid ] = new self( $pid );
     }
     return self:: $selfInstanceList [ $pid ];
   }
   private function __construct( $pid )
   {
     $this ->pid = $pid ;
     $this ->downloadedFileSize = 0;
     $this ->fileFullName = '' ;
     $this ->hasOverMaxSize = false;
     $this ->downloadData = '' ;
   }
   /**
    * 保存文件
    */
   public function saveMaxSizeData2File(){
     if ( empty ( $resp_data )){
       $resp_data = $this ->downloadData;
     }
     $fileFullName = '/tmp/http_' . $this ->pid. '_' .time(). "_{$this->maxSize}.download" ;
     if ( $resp_data && strlen ( $resp_data )>0)
     {
       list( $headerOnly , $bodyOnly ) = explode ( "\r\n\r\n" , $resp_data , 2);
       $saveDataLenth = ( $this ->downloadedFileSize < $this ->maxSize) ? $this ->downloadedFileSize : $this ->maxSize;
       $needSaveData = substr ( $bodyOnly , 0, $saveDataLenth );
       if ( empty ( $needSaveData )){
         return ;
       }
       file_put_contents ( $fileFullName , $needSaveData );
       if ( file_exists ( $fileFullName )){
         $this ->fileFullName = $fileFullName ;
       }
     }
   }
   /**
    * 返回文件的md5
    * @return string
    */
   public function returnFileMd5(){
     $md5 = '' ;
     if ( file_exists ( $this ->fileFullName)){
       $md5 = md5_file( $this ->fileFullName);
     }
     return $md5 ;
   }
   /**
    * 返回已下载的size
    * @return int
    */
   public function returnSize(){
     return ( $this ->downloadedFileSize < $this ->maxSize) ? $this ->downloadedFileSize : $this ->maxSize;
   }
   /**
    * 删除下载的文件
    */
   public function deleteFile(){
     if ( file_exists ( $this ->fileFullName)){
       unlink( $this ->fileFullName);
     }
   }
}

curl请求的代码实例中,实现限制下载大小 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
……
curl_setopt( $ch , CURLOPT_WRITEFUNCTION, 'on_curl_write' ); //设置回调函数
……
$pid = getmypid ();
$downloadSizeRecorder = DownloadSizeRecorder::getInstance( $pid );
$downloadSizeRecorder ->maxSize = $size_limit ;
……
//发起curl请求
$response = curl_exec( $ch );
……
//保存文件,返回md5
$downloadSizeRecorder ->saveMaxSizeData2File(); //保存
$downloadFileMd5 = $downloadSizeRecorder ->returnFileMd5();
$downloadedfile_size = $downloadSizeRecorder ->returnSize();
$downloadSizeRecorder ->deleteFile();

到这里,踩了一个坑。增加了on_curl_write后,$response会返回true,导致后面取返回内容的时候异常。好在已经实时限制了下载的大小,用downloadData来记录了已经下载的内容,直接可以使用.

?
1
2
3
if ( $response === true){
   $response = $downloadSizeRecorder ->downloadData;
}

总结 。

以上所述是小编给大家介绍的php使用curl下载指定大小的文件,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我网站的支持! 。

原文链接:http://www.tuicool.com/articles/imQniaN 。

最后此篇关于php使用curl下载指定大小的文件实例代码的文章就讲到这里了,如果你想了解更多关于php使用curl下载指定大小的文件实例代码的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com