卷曲{}

在本文中

cURL HTTP传输

方法

姓名描述
卷曲::__construct施工单位
卷曲::__destrust析构函数
卷曲::format_get设置给定GET数据的URL格式
卷曲::get_expect_header获取给定请求数据的正确“Expect”头。
卷曲::get_subrequest_handle获取用于多请求的cURL句柄
卷曲::process_response处理响应
卷曲::请求执行请求
卷曲::request_multiple同时发送多个请求
卷曲::setup_handle为给定数据设置cURL句柄
卷曲::stream_body收集收到的数据
卷曲::stream_headers收到邮件时收集邮件头
卷曲::测试自检运输工具是否可用。

来源

最后一个类Curl实现了Transport{常数CURL_7_10_5=0x070A05;const CURL_7_16_2=0x071002;/***原始HTTP数据**@var字符串*/public$headers=“”;/***原始车身数据**@var字符串*/public$response_data=“”;/***关于当前请求的信息**@var数组cURL信息数组,请参见https://www.php.net/curl_getinfo*/公共$info;/***cURL版本号**@var整数*/公共$version;/***cURL句柄**@var resource | \ PHP中的CurlHandle resource<8.0,PHP中的CurlHandle实例>=8.0。*/私有$handle;/***挂钩调度程序实例**@var\WpOrg\Requests\Hooks*/私有$hooks;/***我们完成头球了吗?**@var布尔值*/private$done_headers=false;/***如果流式传输到文件,请保留文件指针**@var资源*/私有$stream_handle;/***响应正文中有多少字节?**@var整数*/私有$response_bytes;/***我们应该保留的最大字节数是多少?**@var int | bool Byte count,如果没有限制则为false。*/私有$response_byte_limit;/***施工单位*/公共函数__construct(){$curl=curl_version();$this->version=$curl['version_number'];$this->句柄=curl_init();curl_setopt($this->句柄,CURLOPT_HEADER,false);curl_setopt($this->句柄,CURLOPT_RETURNTRANSFER,1);if($this->版本>=自身::CURL_7_10_5){curl_setopt($this->句柄,CURLOPT_ENCODING,'');}if(已定义(“CURLOPT_PROTOCOLS”){//phpcs:忽略PHPCompatibility。常量。找到新常量.curlopt_protocolscurl_setopt($this->句柄,CURLOPT_PROTOCOLS,CURLPROTO_HTTP|CURLPROPO_HTTPS);}if(已定义('CURLOPT_REDIR_PROTOCOLS')){//phpcs:忽略PHPCompatibility。常量。找到新常量.curlopt_redir_protocolscurl_setopt($this->句柄,CURLOPT_REDIR_PROTOCOLS,CURLPROTO_HTTP|CURLPROPO_HTTPS);}}/***析构函数*/公共函数__destrust(){if(isresource($this->句柄){curl_close($this->句柄);}}/***执行请求**@param string |要请求的Stringable$url url*@param array$headers请求头的关联数组*@param string | array$data要作为POST正文或GET/HEAD URL中的参数发送的数据*@param array$options请求选项,请参阅\WpOrg\Requests\Requests::response()用于文档*@return string原始HTTP结果**@throws\WpOrg\Requests\Exception\InvalidArgument当传递的$url参数不是字符串或Stringable时。*@throws\WpOrg\Requests\Exception\InvalidArgument当传递的$headers参数不是数组时。*@throws\WpOrg\Requests\Exception\InvalidArgument当传递的$data参数不是数组或字符串时。*@throws\WpOrg\Requests\Exception\InvalidArgument当传递的$options参数不是数组时。*@throws\WpOrg\Requests\Exception关于cURL错误(`curlerror`)*/公共函数请求($url、$headers=[]、$data=[],$options=[[]){if(InputValidator::is_string_or_stringable($url)===false){throw InvalidArgument::create(1,'$url','string|Stringable',gettype($url));}if(is_array($headers)===false){throw InvalidArgument::create(2,'$headers','array',gettype($headers));}if(!is_array($data)&&!is_string($data){if($data===null){$data=“”;}其他{throw InvalidArgument::create(3,'$data','array|string',gettype($data));}}if(is_array($options)===false){throw InvalidArgument::create(4,'$options','array',gettype($options));}$this->hook=$options[‘books’];$this->setup_handle($url、$headers、$data、$options);$options['hooks']->dispatch('curl.before_send',[&$this->handle]);if($options['filename']!==false){//phpcs:忽略WordPress。菲律宾比索。NoSilencedErrors——为了引发异常,使PHP本机警告静音。$this->stream_handle=@fopen($options['filename'],'wb');if($this->stream_handle===false){$error=错误_get_last();抛出新异常($error['message'],'fopen');}}$this->response_data='';$this->response_bytes=0;$this->response_byte_limit=false;if($options['max_bytes']!==false){$this->response_byt_limit=$options['max_bytes'];}if(isset($options['verify'])){if($options['verify']===false){curl_setopt($this->句柄,CURLOPT_SSL_VERIFYHOST,0);curl_setopt($this->句柄,CURLOPT_SSL_VERIFYPEER,0);}elseif(is_string($options['verify'])){curl_setopt($this->句柄,CURLOPT_CAINFO,$options['verify']);}}if(isset($options['verifyname'])&&$options['verifyname']==false){curl_setopt($this->句柄,CURLOPT_SSL_VERIFYHOST,0);}curl_exec($this->句柄);$response=$this->response_data;$options['hooks']->dispatch('curl.after_send',[]);if(curl_errno($this->句柄)===CURLE_WRITE_ERROR||curl_errno($this->句柄)===CURRE_BAD_CONTENT_ENCODING){//重置编码并重试curl_setopt($this->句柄,CURLOPT_ENCODING,'none');$this->response_data='';$this->response_bytes=0;curl_exec($this->句柄);$response=$this->response_data;}$this->进程响应($response,$options);//需要从卷曲手柄中删除$this引用。//否则,将不会对\WpOrg\Requests\Transport\Curl进行垃圾收集,并且不会调用Curl_close()。curl_setopt($this->句柄,CURLOPT_HEADERFUNCTION,null);curl_setopt($this->句柄,CURLOPT_WRITEFUNCTION,null);返回$this->标题;}/***同时发送多个请求**@param array$请求请求数据*@param array$options全局选项*@return数组\WpOrg\Requests\Response对象的数组(可以包含\WpOrg\Requests\Exception或字符串响应)**@throws\WpOrg\Requests\Exception\InvalidArgument当传递的$Requests参数不是数组或具有数组访问权限的可迭代对象时。*@throws\WpOrg\Requests\Exception\InvalidArgument当传递的$options参数不是数组时。*/公共函数request_multiple($requests,$options){//如果你没有要求,我们无法得到任何回应if(空($requests)){返回[];}if(InputValidator::has_array_access($requests)===false||InputValidator::is_iterable($requists)===false){throw InvalidArgument::create(1,'$requests','array|ArrayAccess&Traversable',gettype($request));}if(is_array($options)===false){throw InvalidArgument::create(2,'$options','array',gettype($options));}$multihandle=curl_multi_init();$子请求=[];$subhandles=[];$class=获取类($this);foreach($requests作为$id=>$request){$subrequests[$id]=新的$class();$subhandles[$id]=$subrequests[$id=]->get_subrequest_handle($request['url'],$request['headers'],$request['data'],$请求['options']);$request['options']['hooks']->调度('curl.before_mlti_add',[&$subhandles[$id]]);curl_multi_add_handle($multihandle,$subhandles[$id]);}$已完成=0;$responses=[];$subrequestcount=计数($subrequests);$request['options']['hooks']->调度('curl.before_multi_exec',[&$multihandle]);做{$活动=0;做{$status=curl_multi_exec($multihandle,$active);}而($状态===CURLM_CALL_MULTI_PERFORM);$to_process=[];//根据需要阅读信息while($done=curl_multi_info_read($multihandle)){$key=array_search($done['handle'],$subhandles,true);if(!isset($to_process[$key]){$to_process[$key]=$done;}}//在开始获取新请求之前,分析完成的请求foreach($to_process as$key=>$done){$options=$requests[$key]['options'];if($done['result']!==CURLE_OK){//获取句柄的错误字符串。$reason=curl_error($done['handle']);$exception=新的CurlException($原因,卷曲异常::容易,$done[“处理”],$done[结果]);$responses[$key]=$exception;$options['hooks']->dispatch('transport.internal.parse_error',[&$response[$key],$requests[$key]]);}其他{$response[$key]=$subrequests[$key]->process_response($subrequests[$key]->response_data,$options);$options['hooks']->dispatch('transport.internal.parse_response',[&$responses[$key],$requests[$key]]);}curl_multi_remove_handle($multihandle,$done['handle']);curl_close($done['handle']);if(!is_string($responses[$key])){$options['hooks']->dispatch('multiple.request.complete',[&$response[$key],$key]);}$已完成++;}}while($active||$已完成<$subrequestcount);$request['options']['hooks']->调度('curl.after_multi_exec',[&$multihandle]);curl_multi_close($multihandle);返回$responses;}/***获取用于多请求的cURL句柄**要请求的@param string$url url*@param array$headers请求头的关联数组*@param string | array$data要作为POST正文或GET/HEAD URL中的参数发送的数据*@param array$options请求选项,请参阅\WpOrg\Requests\Requests::response()用于文档*@return resource|\CurlHandle Subrequest的cURL句柄*/公共函数&get_subrequest_handle($url、$headers、$data、$options){$this->setup_handle($url、$headers、$data、$options);if($options['filename']!==false){$this->stream_handle=fopen($options['filename'],'wb');}$this->response_data='';$this->response_bytes=0;$this->response_byte_limit=false;if($options['max_bytes']!==false){$this->response_byt_limit=$options['max_bytes'];}$this->hooks=$options['hooks'];返回$this->句柄;}/***为给定数据设置cURL句柄**@param string$url要请求的url*@param array$headers请求头的关联数组*@param string | array$data要作为POST正文或GET/HEAD URL中的参数发送的数据*@param array$options请求选项,请参阅\WpOrg\Requests\Requests::response()用于文档*/私有函数setup_handle($url、$headers、$data、$options){$options['hooks']->dispatch('curl.before_request',[&$this->handle]);//强制关闭旧版本cURL(<7.22)的连接。if(!isset($headers〔'连接'〕)){$headers['Connection']='close';}/***添加“Expect”标头。**默认情况下,cURL会将“Expect:100-Continue”添加到大多数请求中。此收割台可以*将cURL执行请求所需的时间增加一秒钟。收件人*为了防止出现这种情况,我们需要设置一个空的“Expect”头。匹配的行为*古斯,我们将向小于1MB的请求添加空标头,并使用*HTTP/1.1。** https://curl.se/mail/lib-2017-07/0013.html*/if(!isset($headers['Expect'])&&$options['protocol_version']===1.1){$headers['Expect']=$this->get_Expect_header($data);}$headers=请求::扁平化($header);if(!空($data)){$data_format=$options['data_format'];if($data_format===“查询”){$url=自我::format_get($url,$data);$data=“”;}elseif(!is_string($data)){$data=http_build_query($data,“”,“&”);}}开关($options['type']){案例请求::POST:curl_setopt($this->句柄,CURLOPT_POST,true);curl_setopt($this->句柄,CURLOPT_POSTFIELDS,$data);断裂;案例请求::头部:curl_setopt($this->句柄,CURLOPT_CUSTOMREQUEST,$options['type']);curl_setopt($this->句柄,CURLOPT_NOBODY,true);断裂;case请求::TRACE:curl_setopt($this->句柄,CURLOPT_CUSTOMREQUEST,$options['type']);断裂;案例请求::补丁:case请求::PUT:案例请求::删除:案例请求::选项:违约:curl_setopt($this->句柄,CURLOPT_CUSTOMREQUEST,$options['type']);if(!空($data)){curl_setopt($this->句柄,CURLOPT_POSTFIELDS,$data);}}//使用系统时,cURL需要至少1秒的超时//DNS解析器,因为它使用“alarm()”,这只是第二个解析。//无法检测我们的//结束,所以不管提供的超时时间如何,我们都需要进行舍入。//// https://github.com/curl/curl/blob/4f45240bc84a9aa648c8f7243be7b79e9f9323a5/lib/hostip.c#L606-L609型$timeout=最大值($options['timeout'],1);if(is_int($timeout)||$this->版本<self::CURL_7_16_2){curl_setopt($this->句柄,CURLOPT_TIMEOUT,ceil($TIMEOUT));}其他{//phpcs:忽略PHPCompatibility。常量。找到新常量.curlopt_timeout_mscurl_setopt($this->句柄,CURLOPT_TIMEOUT_MS,round($TIMEOUT*1000));}if(is_int($options['connect_timeout'])||$this->版本<self::CURL_7_16_2){curl_setopt($this->句柄,CURLOPT_CONNECTTIMEOUT,ceil($options['connect_timeout']);}其他{//phpcs:忽略PHPCompatibility。常量。找到新常量.curlopt_connecttimeout_mscurl_setopt($this->句柄,CURLOPT_CONNECTTIMEOUT_MS,round($options['connect_timeout']*1000);}curl_setopt($this->句柄,CURLOPT_URL,$URL);curl_setopt($this->句柄,CURLOPT_USERAGENT,$options['USERAGENT']);if(!空($headers)){curl_setopt($this->句柄,CURLOPT_HTTPHEADER,$headers);}if($options['protocol_version']===1.1){curl_setopt($this->句柄,CURLOPT_HTTP_VERSION,curl_HTTP_VERSION_1_1);}其他{curl_setopt($this->句柄,CURLOPT_HTTP_VERSION,curl_HTTP_ERSION_1_0);}if($options['block']===true){curl_setopt($this->句柄,CURLOPT_HEADERFUNCTION,[$this,'stream_headers']);curl_setopt($this->句柄,CURLOPT_WRITEFUNCTION,[$this,'stream_body']);curl_setopt($this->句柄,CURLOPT_BUFFERSIZE,请求::BUFFER_SIZE);}}/***处理响应**@param string$response来自正文的响应数据*@param array$options请求选项*@return string|false HTTP响应数据,包括标头。如果非阻塞,则为False。*@throws\WpOrg\Requests\Exception如果请求导致cURL错误。*/公共函数process_response($响应,$选项){if($options['blocking']===false){$fake_headers=“”;$options['hooks']->调度('curl.after_request',[&$fake_headers]);返回false;}if($options['filename']!==false&&$this->streamhandle){fclose($this->stream_handle);$this->headers=修剪($this->headers);}其他{$this->标题。=$响应;}if(curl_errno($this->句柄){$error=冲刺(“cURL错误%s:%s”,curl_errno($this->句柄),curl_error($this->句柄));抛出新的异常($error,'curlerror',$this->句柄);}$this->info=curl_getinfo($this->句柄);$options['hooks']->dispatch('curl.after_request',[&$this->headers,&$this->info]);返回$this->标题;}/***收到邮件时收集邮件头**@param resource|\CurlHandle$handle cURL句柄*@param string$headers标题字符串*@return integer提供的头的长度*/公共函数stream_headers($handle,$headers){//我们为什么要这样做?cURL将发送最终响应和任何//临时响应,例如100 Continue。我们不需要这样。//(我们可能想把这个放在某处以防万一)如果($this->done_headers){$this->headers=“”;$this->done_headers=false;}$this->标题。=$标题;if($headers===“\r\n”){$this->done_headers=true;}return strlen($headers);}/***收集收到的数据**@自1.6.1起**@param resource|\CurlHandle$handle cURL句柄*@param string$data正文数据*@return integer提供数据的长度*/公共函数stream_body($handle,$data){$this->hook->dispatch(“请求进度”,[$data,$this->response_bytes,$this->response_byt_limit]);$data_length=字符串($data);//我们是否限制了响应大小?if($this->response_byte_limit){if($this->response_bytes===$this->response_byte_limit){//已经达到最大值,继续返回$data_length;}if(($this->response_bytes+$data_length)>$this->response_byte_limit){//限制长度$limited_length=($this->response_byte_limit-$this->response_bytes);$data=子项($data,0,$limited_length);}}if($this->stream_handle){fwrite($this->stream_handle,$data);}其他{$this->response_data.=$数据;}$this->response_bytes+=strlen($data);返回$data_length;}/***设置给定GET数据的URL格式**@param string$url原始url。*@param array | object$data要使用的生成查询的数据,请参见https://www.php.net/http_build_query网站*@return带数据的字符串URL*/私有静态函数format_get($url,$data){if(!空($data)){$query=“”;$url_parts=解析url($url);if(空($url_parts['query']){$url_parts['query']='';}其他{$query=$url_parts['query'];}$query.=“&”。http_build_query($data,“”,“&”);$query=修剪($query,'&');if(空($urlparts['query']){$url.=“?”$查询;}其他{$url=str_replace($url_parts['query'],$query,$url);}}返回$url;}/***自检运输工具是否可用。**可以在中找到可用的测试功能\工作组织\请求\能力**@codeCoverage忽略*@param array<string,bool>$capabilities可选。要测试的功能的关联数组,即“[”<功能>“=>true]”。*@return bool是否可以使用传输。*/公共静态功能测试($capabilities=[]){如果(!function_exists('curl_init')|!函数存在('curl_exec'){返回false;}//如果需要,请检查我们安装的curl版本是否支持SSLif(isset($capabilities[功能::SSL])&&$capablities[能力::SSL]){$curl_version=curl_版本();if(!(CURL_VERSION_SSL&$CURL_VERSION[“功能”]){返回false;}}返回true;}/***获取给定请求数据的正确“Expect”头。**@param string | array$data要作为POST正文或GET/HEAD URL中的参数发送的数据。*@return string“Expect”头。*/私有函数get_expect_header($data){if(!is_array($data)){return strlen((string)$data)>=1048576?'100-继续“:”;}$bytesize=0;$iterator=new RecursiveIteratorIterator(新RecursieArrayIterator,$data);foreach($iterator作为$datum){$bytesize+=strlen((字符串)$datum);if($bytesize>=1048576){return“100-Continue”;}}返回“”;}}

用户贡献的笔记

你必须登录在能够发表注释或反馈之前。