套接字打开{}

在本文中

fsockopen HTTP传输

方法

姓名描述
Fsockopen::接受编码检索我们可以接受的编码
Fsockopen::connect_error_handlerstream_socket_client()的错误处理程序
Fsockopen::format_get设置给定GET数据的URL格式
Fsockopen::请求执行请求
Fsockopen::request_multiple同时发送多个请求
Fsockopen::测试自检运输工具是否可用。
Fsockopen::验证证书from_context根据通用名称和使用者替代名称验证证书

来源

最终类Fsockopen实现传输{/***秒到微秒的转换**@var整数*/const SECOND_IN_MICOSECONDS=1000000;/***原始HTTP数据**@var字符串*/public$headers=“”;/***流元数据**@var数组属性的关联数组,请参见https://www.php.net/stream_get_meta_data网址*/公共$info;/***我们应该保留的最大字节数是多少?**@var int | bool Byte count,如果没有限制则为false。*/私有$max_bytes=false;/***缓存接收到的连接错误。**@var字符串*/私有$connect_error=“”;/***执行请求**@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连接套接字失败(`fsockopenerror`)*@throws\WpOrg\Requests\Exception关于套接字超时(`timeout`)*/公共函数请求($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));}$options['hooks']->dispatch('sockopen.before_request');$url_parts=解析url($url);if(空($urlparts)){throw new Exception(“无效URL”,“invalidurl”,$URL);}$host=$url_parts['host'];$context=流context_create();$verifyname=false;$case_insitive_headers=新的CaseInsitiveDictionary($headers);//HTTPS支持if(isset($urlparts['scheme'])&&strtolower($urlbarts['scheme''])==='https'){$remote_socket=“ssl://”$宿主;if(!isset($urlparts['port']){$url_parts['port']=端口::HTTPS;}$context_options=[“verify_peer”=>true,“capture_peer_cert”=>true,];$verifyname=true;//SNI,如果启用(OpenSSL>=0.9.8j)//phpcs:忽略PHPCompatibility。常量。找到新常量.openssl_tlsext_server_nameif(已定义('OPENSSL_TLSEXT_SERVER_NAME')和&OPENSSL-TLSEXT_SERVER_NAME){$context_options['SNI_enabled']=真;if(isset($options['verifyname'])&&$options['verifyname']==false){$context_options['SNI_enabled']=false;}}if(isset($options['verify'])){if($options['verify']===false){$context_options['verify_peer']=false;$context_options['verify_peer_name']=假;$verifyname=false;}elseif(is_string($options[“验证”])){$context_options['cafile']=$options['verify'];}}if(isset($options['verifyname'])&&$options['verifyname']==false){$context_options['verify_peer_name']=假;$verifyname=false;}stream_context_set_option($context,['ssl'=>$context_options]);}其他{$remote_socket=“tcp://”$宿主;}$this->max_bytes=$options['max_bytes'];if(!isset($urlparts['port']){$url_parts['port']=端口::HTTP;}$remote_socket.=“:”$url_parts[“端口”];//phpcs:忽略WordPress。菲律宾比索。开发功能.error_log_set_error_handlerset_error_handler([$this,'connect_error_chandler'],E_WARNING|E_NOTICE);$options['hooks']->dispatch('sockopen.remote_socket',[&$remote_soccket]);$socket=stream_socket_client($remote_socket,$errno,$errstr,ceil($options['connect_timeout']),stream_client_connect,$context);restore_error_handler();if($verifyname&&!$this->verifycertificate_from_context($host,$context)){throw new Exception(“SSL证书与请求的域名不匹配”,“SSL.no_match”);}if(!$socket){if($errno===0){//连接问题抛出新的异常(rtrim($this->connect_error),'fsockopen.connecte_error');}抛出新异常($errstr,'fsockopenerror',null,$errno);}$data_format=$options['data_format'];if($data_format===“查询”){$path=self::format_get($url_parts,$data);$data=“”;}其他{$path=自身::format_get($url_parts,[]);}$options['hooks']->dispatch('sockopen.remote_host_path',[&$path,$url]);$request_body=“”;$out=sprintf(“%s%s HTTP/%.1F\r\n”,$options['type'],$path,$option['protocol_version']);if($options['type']!==请求::TRACE){if(is_array($data)){$request_body=http_build_query($data,“”,“&”);}其他{$request_body=$data;}//始终在POST请求中包含内容长度以防止//当正文为空时,来自某些服务器的411个错误。if(!empty($data)||$options['type']===请求::POST){if(!isset($case_insitive_headers['Content-Length'])){$headers['Content-Length']=strlen($request_body);}if(!isset($case_insitive_headers['Content-Type'])){$headers['Content-Type']='application/x-www-form-urlencoded;字符集=UTF-8';}}}if(!isset($case_insitive_headers[“主机”]){$out.=美元sprintf(“主机:%s”,$url_parts['Host']);$scheme_lower=strtolower($url_parts['scheme']);if(($scheme_lower==='http'&&$url_parts['port']!==端口::http)||{$out.=“:”$url_parts[“端口”];}$out.=美元“\r\n”;}if(!isset($case_insitive_headers[“用户代理”]){$out.=美元sprintf(“用户代理:%s\r\n”,$options['useragent']);}$accept_encoding=$this->accept_encoding();if(!isset($case_insensitive_headers[接受编码])&&!空($accept_encoding){$out.=美元sprintf(“接受编码:%s\r\n”,$Accept_Encoding);}$headers=请求::扁平化($header);if(!空($headers)){$out.=美元内爆(“\r\n”,$headers)。“\r\n”;}$options['hooks']->dispatch('sockopen.after_headers',[&$out]);if(substr($out,-2)!==“\r\n”){$out.=美元“\r\n”;}if(!isset($case_insitive_headers[“连接”]){$out.=美元“连接:关闭\r\n”;}$out.=美元“\r\n”$请求体;$options['hooks']->dispatch('sockopen.before_send',[&$out]);fwrite($socket,$out);$options['hooks']->dispatch('sockopen.after_send',[$out]);if(!$options['block']){fclose($socket);$fake_headers=“”;$options['hooks']->dispatch('sockopen.after_request',[&$fake_headers]);返回“”;}$timeout_sec=(int)floor($options['timeout']);if($timeout_sec===$options['timeout']){$timeout_msec=0;}其他{$timeout_msec=self::SECOND_IN_MICROSECONDS*$options['timeout']%self:;}stream_set_timeout($socket、$timeout_sec、$timeout_msec);$response=“”;$body=“”;$headers=“”;$this->info=stream_get_meta_data($socket);$大小=0;$doingbody=false;$download=false;if($options['filename']){//phpcs:忽略WordPress。菲律宾比索。NoSilencedErrors——关闭PHP本机警告,支持抛出异常。$download=@fopen($options['filename'],'wb');if($download===false){$error=错误_get_last();抛出新异常($error['message'],'fopen');}}while(!feof($socket)){$this->info=stream_get_meta_data($socket);if($this->info['time_out']){throw new Exception(“套接字超时”,“超时”);}$block=fread($socket,请求::BUFFER_SIZE);if(!$doingbody){$响应。=$区块;if(strpos($response,“\r\n\r\n”){list($headers,$block)=爆炸(“\r\n\r\n”,$response,2);$doingbody=true;}}//我们现在处于身体模式吗?if($doingbody){$options['hooks']->dispatch('request.progress',[$block,$size,$this->max_bytes]);$data_length=字符串($block);if($this->max_bytes){//我们已经达到极限了吗?if($size===$this->max_bytes){继续;}if(($size+$data_length)>$this->max_bytes){//限制长度$limited_length=($this->max_bytes-$size);$block=子项($block,0,$limited_length);}}$size+=字符串($block);if($download){fwrite($download,$block);}其他{$主体。=$区块;}}}$this->headers=$headers;如果($download){fclose($download);}其他{$this->标题。=“\r\n\r\n”$身体;}fclose($socket);$options['hooks']->dispatch('sockopen.after_request',[&$this->headers,&$this->info]);返回$this->标题;}/***同时发送多个请求**@param array$requests根据请求数据(“url”、“headers”、“data”、“options”数组)\WpOrg\Requests\Transport::request()*@param array$options全局选项,请参阅\WpOrg\Requests\Requests::response()用于文档*@return数组\WpOrg\Requests\Response对象的数组(可以包含\WpOrg\Requests\Exception或字符串响应)**@throws\WpOrg\Requests\Exception\InvalidArgument当传递的$Requests参数不是数组或具有数组访问权限的可迭代对象时。*@throws\WpOrg\Requests\Exception\InvalidArgument当传递的$options参数不是数组时。*/公共函数request_multile($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));}$responses=[];$class=获取类($this);foreach($requests作为$id=>$request){尝试{$handler=新的$class();$responses[$id]=$handler->request($request['url'],$request['headers'],$request['data'],美元request['options']);$request['options']['hooks']->调度('transport.internal.parse_response',[&$responses[$id],$request]);}catch(异常$e){$responses[$id]=$e;}if(!is_string($responses[$id])){$request['options']['hooks']->调度('multiple.request.complete',[&$response[$id],$id]);}}返回$responses;}/***检索我们可以接受的编码**@return string Accept-Encoding头值*/私有静态函数accept_encoding(){$类型=[];if(函数_exists('zinflate')){$type[]='放气;q=1.0’;}if(function_exists('gzunpress')){$type[]='压缩;q=0.5’;}$type[]='gzip;q=0.5’;返回内爆(',',$type);}/***设置给定GET数据的URL格式**@param array$url_parts从接收到的url部件数组https://www.php.net/parse_url*@param array | object$data要使用的生成查询的数据,请参见https://www.php.net/http_build_query网站*@return带数据的字符串URL*/私有静态函数format_get($urlparts,$data){if(!空($data)){if(空($urlparts['query']){$url_parts['query']='';}$url_parts['query'].='&'。http_build_query($data,“”,“&”);$url_parts['query']=修剪($url_parts['query'],'&');}if(isset($urlparts[“路径”]){if(isset($urlparts['query'])){$get=$url_parts['path'].'?'$url_parts[“查询”];}其他{$get=$url_parts['path'];}}其他{$get=“/”;}返回$get;}/***stream_socket_client()的错误处理程序**@param int$errno错误号(例如e_WARNING)*@param string$errstr错误消息*/公共函数connect_error_handler($errno,$errstr){//我们可以处理它if(($errno&E_WARNING)===0&&($errno&E_NOTICE)===0){//返回false以指示应启用默认错误处理程序返回false;}$this->connect_error.=$错误。“\n”;返回true;}/***根据通用名称和使用者替代名称验证证书**不幸的是,PHP没有根据替代项检查证书*名字,比如“https://www.github.com/'无效。*相反**@链接https://tools.ietf.org/html/rfc2818#部分-RFC2818第3.1节**@param string$host要验证的主机名*@param resource$context流上下文*@return布尔**@throws\WpOrg\Requests\Exception通过TLS连接失败(`fsockopen.ssl.connect_error`)*@throws\WpOrg\Requests\Exception未获取主机匹配项(`fsockopen.ssl.no_match`)*/公共函数verify_certificate_from_context($host,$context){$meta=stream_context_get_options($context);//如果我们没有SSL选项,则无法在进行连接//全部if(空($meta)||empty($meta['ssl'])||空($meta['ssel']['peer_certificate']){抛出新异常(rtrim($this->connect_error),'ssl.connecte_error');}$cert=openssl_x509_parse($meta['sl']['peer_certificate']);return Ssl::verify_certificate($host,$cert);}/***自检运输工具是否可用。**可以在中找到可用的测试功能\WpOrg\请求\能力**@codeCoverage忽略*@param array<string,bool>$capabilities可选。要测试的功能的关联数组,即“[”<功能>“=>true]”。*@return bool是否可以使用传输。*/公共静态功能测试($capabilities=[]){if(!function_exists('sockopen')){返回false;}//如果需要,请检查流是否支持SSLif(isset($capabilities[功能::SSL])&&$capablities[能力::SSL]){if(!extension_loaded('openssl')|!函数存在('openssl_x509_parse'){返回false;}}返回true;}}

用户贡献的笔记

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