|
|
 代码:
- <?php
- namespace addons\carplate\library;
- class Communication
- {
- /**
- * 模拟 http 请求
- *
- * @param string $url 请求URL地址
- * @param string $post 请求数据
- * @param array $extra header 参数
- * @param int $timeout 超时时间
- *
- * @return array http响应封装信息或错误信息
- */
- public function ihttp_request($url, $post = '', $extra = array(), $timeout = 60) {
- //timeout为0时,相当于是非阻塞异步请求
- //curl不支持timeout为0的情况,需要使用fsockopen来处理
- if (function_exists('curl_init') && function_exists('curl_exec') && $timeout > 0) {
- $ch = $this->ihttp_build_curl($url, $post, $extra, $timeout);
- if ($this->is_error($ch)) {
- return $ch;
- }
- $data = curl_exec($ch);
- $status = curl_getinfo($ch);
- $errno = curl_errno($ch);
- $error = curl_error($ch);
- curl_close($ch);
- if ($errno || empty($data)) {
- return $this->error($errno, $error);
- } else {
- return $this->ihttp_response_parse($data);
- }
- }
- $urlset = $this->ihttp_parse_url($url, true);
- if (!empty($urlset['ip'])) {
- $urlset['host'] = $urlset['ip'];
- }
-
- $body = $this->ihttp_build_httpbody($url, $post, $extra);
-
- if ('https' == $urlset['scheme']) {
- $fp = $this->ihttp_socketopen('ssl://' . $urlset['host'], $urlset['port'], $errno, $error);
- } else {
- $fp = $this->ihttp_socketopen($urlset['host'], $urlset['port'], $errno, $error);
- }
- stream_set_blocking($fp, $timeout > 0 ? true : false);
- stream_set_timeout($fp, ini_get('default_socket_timeout'));
- if (!$fp) {
- return $this->error(1, $error);
- } else {
- fwrite($fp, $body);
- $content = '';
- if ($timeout > 0) {
- while (!feof($fp)) {
- $content .= fgets($fp, 512);
- }
- }
- fclose($fp);
-
- return $this->ihttp_response_parse($content, true);
- }
- }
-
- /**
- * 封装的 GET 请求方法.
- *
- * @param string $url 请求URL地址
- *
- * @return array
- */
- public function ihttp_get($url) {
- return $this->ihttp_request($url);
- }
-
- /**
- * 封装的POST请求方法.
- *
- * @param string $url 请求URL地址
- * @param array $data 请求数据
- *
- * @return array
- */
- public function ihttp_post($url, $data) {
- $headers = array('Content-Type' => 'application/x-www-form-urlencoded');
-
- return $this->ihttp_request($url, $data, $headers);
- }
-
- /**
- * 非阻塞并发请求多个URL地址
- *
- * @param array $urls 请求多个地址数组
- * @param array $posts 请求多个地址对应的POST数据
- * 二维数据组时,需要与URL键值一一对应,每个请求不同的POST数据
- * 一维数组时,每个请求使用此数据
- * @param array $extra 同 ihttp_request
- * @param int $timeout 同 ihttp_request
- *
- * @return array 返回结果与url键值对应结果数组
- */
- public function ihttp_multi_request($urls, $posts = array(), $extra = array(), $timeout = 60) {
- if (!is_array($urls)) {
- return $this->error(1, '请使用ihttp_request函数');
- }
- $curl_multi = curl_multi_init();
- $curl_client = $response = array();
-
- foreach ($urls as $i => $url) {
- if (isset($posts[$i]) && is_array($posts[$i])) {
- $post = $posts[$i];
- } else {
- $post = $posts;
- }
- if (!empty($url)) {
- $curl = $this->ihttp_build_curl($url, $post, $extra, $timeout);
- if ($this->is_error($curl)) {
- continue;
- }
- if (CURLM_OK === curl_multi_add_handle($curl_multi, $curl)) {
- //存到数据组中,方便之后获取结果
- $curl_client[] = $curl;
- }
- }
- }
- if (!empty($curl_client)) {
- $active = null;
- do {
- $mrc = curl_multi_exec($curl_multi, $active);
- } while (CURLM_CALL_MULTI_PERFORM == $mrc);
-
- while ($active && CURLM_OK == $mrc) {
- do {
- $mrc = curl_multi_exec($curl_multi, $active);
- } while (CURLM_CALL_MULTI_PERFORM == $mrc);
- }
- }
-
- foreach ($curl_client as $i => $curl) {
- $response[$i] = curl_multi_getcontent($curl);
- curl_multi_remove_handle($curl_multi, $curl);
- }
- curl_multi_close($curl_multi);
-
- return $response;
- }
-
- public function ihttp_socketopen($hostname, $port, &$errno, &$errstr, $timeout = 15) {
- $fp = '';
- $port = !empty($port) ? $port : 80;
- if (function_exists('fsockopen')) {
- $fp = @fsockopen($hostname, $port, $errno, $errstr, $timeout);
- } elseif (function_exists('pfsockopen')) {
- $fp = @pfsockopen($hostname, $port, $errno, $errstr, $timeout);
- } elseif (function_exists('stream_socket_client')) {
- $fp = @stream_socket_client($hostname . ':' . $port, $errno, $errstr, $timeout);
- }
-
- return $fp;
- }
-
- /**
- * 对请求得到的数据的进行分析和封装.
- *
- * @param string $data
- * @param bool $chunked
- *
- * @return array error 或 $data 的封装
- */
- public function ihttp_response_parse($data, $chunked = false) {
- $rlt = array();
-
- $pos = strpos($data, "\r\n\r\n");
- $split1[0] = substr($data, 0, $pos);
- $split1[1] = substr($data, $pos + 4, strlen($data));
-
- $split2 = explode("\r\n", $split1[0], 2);
- preg_match('/^(\S+) (\S+) (.*)$/', $split2[0], $matches);
- $rlt['code'] = !empty($matches[2]) ? $matches[2] : 200;
- $rlt['status'] = !empty($matches[3]) ? $matches[3] : 'OK';
- $rlt['responseline'] = !empty($split2[0]) ? $split2[0] : '';
- $header = !empty($split2[1]) ? explode("\r\n", $split2[1]) : array();
- $isgzip = false;
- $ischunk = false;
- foreach ($header as $v) {
- $pos = strpos($v, ':');
- $key = substr($v, 0, $pos);
- $value = trim(substr($v, $pos + 1));
- if (isset($rlt['headers'][$key]) && is_array($rlt['headers'][$key])) {
- $rlt['headers'][$key][] = $value;
- } elseif (!empty($rlt['headers'][$key])) {
- $temp = $rlt['headers'][$key];
- unset($rlt['headers'][$key]);
- $rlt['headers'][$key][] = $temp;
- $rlt['headers'][$key][] = $value;
- } else {
- $rlt['headers'][$key] = $value;
- }
- if (!$isgzip && 'content-encoding' == strtolower($key) && 'gzip' == strtolower($value)) {
- $isgzip = true;
- }
- if (!$ischunk && 'transfer-encoding' == strtolower($key) && 'chunked' == strtolower($value)) {
- $ischunk = true;
- }
- }
- if ($chunked && $ischunk) {
- $rlt['content'] = $this->ihttp_response_parse_unchunk($split1[1]);
- } else {
- $rlt['content'] = $split1[1];
- }
- if ($isgzip && function_exists('gzdecode')) {
- $rlt['content'] = gzdecode($rlt['content']);
- }
-
- $rlt['meta'] = $data;
- if ('100' == $rlt['code']) {
- return $this->ihttp_response_parse($rlt['content']);
- }
-
- return $rlt;
- }
-
- public function ihttp_response_parse_unchunk($str = null) {
- if (!is_string($str) or strlen($str) < 1) {
- return false;
- }
- $eol = "\r\n";
- $add = strlen($eol);
- $tmp = $str;
- $str = '';
- do {
- $tmp = ltrim($tmp);
- $pos = strpos($tmp, $eol);
- if (false === $pos) {
- return false;
- }
- $len = hexdec(substr($tmp, 0, $pos));
- if (!is_numeric($len) or $len < 0) {
- return false;
- }
- $str .= substr($tmp, ($pos + $add), $len);
- $tmp = substr($tmp, ($len + $pos + $add));
- $check = trim($tmp);
- } while (!empty($check));
- unset($tmp);
-
- return $str;
- }
-
- /**
- * 格式化请求URL.
- *
- * @param string $url 要格式化检查的URL
- * @param bool $set_default_port 是否根据协议指定默认端口
- *
- * @return array
- */
- public function ihttp_parse_url($url, $set_default_port = false) {
- if (empty($url)) {
- return $this->error(1);
- }
- $urlset = parse_url($url);
- if (!empty($urlset['scheme']) && !in_array($urlset['scheme'], array('http', 'https'))) {
- return $this->error(1, '只能使用 http 及 https 协议');
- }
- if (empty($urlset['path'])) {
- $urlset['path'] = '/';
- }
- if (!empty($urlset['query'])) {
- $urlset['query'] = "?{$urlset['query']}";
- }
- if (strexists($url, 'https://') && !extension_loaded('openssl')) {
- if (!extension_loaded('openssl')) {
- return $this->error(1, '请开启您PHP环境的openssl', '');
- }
- }
- if (empty($urlset['host'])) {
- $current_url = parse_url($GLOBALS['_W']['siteroot']);
- $urlset['host'] = $current_url['host'];
- $urlset['scheme'] = $current_url['scheme'];
- $urlset['path'] = $current_url['path'] . 'web/' . str_replace('./', '', $urlset['path']);
- $urlset['ip'] = '127.0.0.1';
- } elseif (!$this->ihttp_allow_host($urlset['host'])) {
- return $this->error(1, 'host 非法');
- }
-
- if ($set_default_port && empty($urlset['port'])) {
- $urlset['port'] = 'https' == $urlset['scheme'] ? '443' : '80';
- }
-
- return $urlset;
- }
-
- /**
- * 是否允许指定host访问.
- *
- * @param $host
- *
- * @return bool
- */
- public function ihttp_allow_host($host) {
- global $_W;
- if (strexists($host, '@')) {
- return false;
- }
- $pattern = '/^(10|172|192|127)/';
- if (preg_match($pattern, $host) && isset($_W['setting']['ip_white_list'])) {
- $ip_white_list = $_W['setting']['ip_white_list'];
- if ($ip_white_list && isset($ip_white_list[$host]) && !$ip_white_list[$host]['status']) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * 创建一个curl请求对象
- * 参数同 ihttp_request.
- *
- * @return curl response
- */
- public function ihttp_build_curl($url, $post, $extra, $timeout) {
- if (!function_exists('curl_init') || !function_exists('curl_exec')) {
- return $this->error(1, 'curl扩展未开启');
- }
-
- $urlset = $this->ihttp_parse_url($url);
- if ($this->is_error($urlset)) {
- return $urlset;
- }
-
- if (!empty($urlset['ip'])) {
- $extra['ip'] = $urlset['ip'];
- }
-
- $ch = curl_init();
- if (!empty($extra['ip'])) {
- $extra['Host'] = $urlset['host'];
- $urlset['host'] = $extra['ip'];
- unset($extra['ip']);
- }
- curl_setopt($ch, CURLOPT_URL, $urlset['scheme'] . '://' . $urlset['host'] . (empty($urlset['port']) || '80' == $urlset['port'] ? '' : ':' . $urlset['port']) . $urlset['path'] . (!empty($urlset['query']) ? $urlset['query'] : ''));
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
- @curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
- curl_setopt($ch, CURLOPT_HEADER, 1);
- @curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
- if ($post) {
- if (is_array($post)) {
- $filepost = false;
- // 5.6版本后,'@'上传,使用CURLFile替代
- foreach ($post as $name => &$value) {
- if (version_compare(phpversion(), '5.5') >= 0 && is_string($value) && '@' == substr($value, 0, 1)) {
- $post[$name] = new CURLFile(ltrim($value, '@'));
- }
- if ((is_string($value) && '@' == substr($value, 0, 1)) || (class_exists('CURLFile') && $value instanceof CURLFile)) {
- $filepost = true;
- }
- }
- if (!$filepost) {
- $post = http_build_query($post);
- }
- }
- curl_setopt($ch, CURLOPT_POST, 1);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
- }
- if (!empty($GLOBALS['_W']['config']['setting']['proxy'])) {
- $urls = parse_url($GLOBALS['_W']['config']['setting']['proxy']['host']);
- if (!empty($urls['host'])) {
- curl_setopt($ch, CURLOPT_PROXY, "{$urls['host']}:{$urls['port']}");
- $proxytype = 'CURLPROXY_' . strtoupper($urls['scheme']);
- if (!empty($urls['scheme']) && defined($proxytype)) {
- curl_setopt($ch, CURLOPT_PROXYTYPE, constant($proxytype));
- } else {
- curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
- curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
- }
- if (!empty($GLOBALS['_W']['config']['setting']['proxy']['auth'])) {
- curl_setopt($ch, CURLOPT_PROXYUSERPWD, $GLOBALS['_W']['config']['setting']['proxy']['auth']);
- }
- }
- }
- curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
- curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
- curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
- curl_setopt($ch, CURLOPT_SSLVERSION, 1);
- if (defined('CURL_SSLVERSION_TLSv1')) {
- curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
- }
- curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:9.0.1) Gecko/20100101 Firefox/9.0.1');
- if (!empty($extra) && is_array($extra)) {
- $headers = array();
- foreach ($extra as $opt => $value) {
- if (strexists($opt, 'CURLOPT_')) {
- curl_setopt($ch, constant($opt), $value);
- } elseif (is_numeric($opt)) {
- curl_setopt($ch, $opt, $value);
- } else {
- $headers[] = "{$opt}: {$value}";
- }
- }
- if (!empty($headers)) {
- curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
- }
- }
-
- return $ch;
- }
-
- public function ihttp_build_httpbody($url, $post, $extra) {
- $urlset = $this->ihttp_parse_url($url, true);
- if ($this->is_error($urlset)) {
- return $urlset;
- }
-
- if (!empty($urlset['ip'])) {
- $extra['ip'] = $urlset['ip'];
- }
-
- $body = '';
- if (!empty($post) && is_array($post)) {
- $filepost = false;
- $boundary = $this->random(40);
- foreach ($post as $name => &$value) {
- if ((is_string($value) && '@' == substr($value, 0, 1)) && file_exists(ltrim($value, '@'))) {
- $filepost = true;
- $file = ltrim($value, '@');
-
- $body .= "--$boundary\r\n";
- $body .= 'Content-Disposition: form-data; name="' . $name . '"; filename="' . basename($file) . '"; Content-Type: application/octet-stream' . "\r\n\r\n";
- $body .= file_get_contents($file) . "\r\n";
- } else {
- $body .= "--$boundary\r\n";
- $body .= 'Content-Disposition: form-data; name="' . $name . '"' . "\r\n\r\n";
- $body .= $value . "\r\n";
- }
- }
- if (!$filepost) {
- $body = http_build_query($post, '', '&');
- } else {
- $body .= "--$boundary\r\n";
- }
- }
-
- $method = empty($post) ? 'GET' : 'POST';
- $fdata = "{$method} {$urlset['path']}{$urlset['query']} HTTP/1.1\r\n";
- $fdata .= "Accept: */*\r\n";
- $fdata .= "Accept-Language: zh-cn\r\n";
- if ('POST' == $method) {
- $fdata .= empty($filepost) ? "Content-Type: application/x-www-form-urlencoded\r\n" : "Content-Type: multipart/form-data; boundary=$boundary\r\n";
- }
- $fdata .= "Host: {$urlset['host']}\r\n";
- $fdata .= "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:9.0.1) Gecko/20100101 Firefox/9.0.1\r\n";
- if (function_exists('gzdecode')) {
- $fdata .= "Accept-Encoding: gzip, deflate\r\n";
- }
- $fdata .= "Connection: close\r\n";
- if (!empty($extra) && is_array($extra)) {
- foreach ($extra as $opt => $value) {
- if (!strexists($opt, 'CURLOPT_')) {
- $fdata .= "{$opt}: {$value}\r\n";
- }
- }
- }
- if ($body) {
- $fdata .= 'Content-Length: ' . strlen($body) . "\r\n\r\n{$body}";
- } else {
- $fdata .= "\r\n";
- }
-
- return $fdata;
- }
-
- /**
- * 检测数组是否产生错误.
- * @param mixed $data
- * @return boolean
- */
- public function is_error($data) {
- if (empty($data) || !is_array($data) || !array_key_exists('errno', $data) || (array_key_exists('errno', $data) && 0 == $data['errno'])) {
- return false;
- } else {
- return true;
- }
- }
-
- /**
- * 构造错误数组.
- * @param int $errno 错误码,0为无任何错误
- * @param string $message 错误信息
- * @return array
- */
- public function error($errno, $message = '') {
- return array(
- 'errno' => $errno,
- 'message' => $message,
- );
- }
-
- /**
- * 获取随机字符串.
- * @param number $length 字符串长度
- * @param bool $numeric 是否为纯数字
- * @return string
- */
- public function random($length, $numeric = false) {
- $seed = base_convert(md5(microtime() . $_SERVER['DOCUMENT_ROOT']), 16, $numeric ? 10 : 35);
- $seed = $numeric ? (str_replace('0', '', $seed) . '012340567890') : ($seed . 'zZ' . strtoupper($seed));
- if ($numeric) {
- $hash = '';
- } else {
- $hash = chr(rand(1, 26) + rand(0, 1) * 32 + 64);
- --$length;
- }
- $max = strlen($seed) - 1;
- for ($i = 0; $i < $length; ++$i) {
- $hash .= $seed[mt_rand(0, $max)];
- }
-
- return $hash;
- }
-
- /**
- * 记录运行日志.
- *
- * @param string|array $log 日志内容
- * @param string $type 日志类型
- * @param string $filename 日志文件名称
- * @param bool $includePost 是否记录POST信息
- *
- * @return array|boolean
- */
- public function logging_run($log, $type = 'trace', $filename = 'run') {
- global $_W;
- $filename = IA_ROOT . '/data/logs/' . $filename . '_' . date('Ymd') . '.php';
-
- load()->func('file');
- mkdirs(dirname($filename));
-
- $logFormat = '%date %type %user %url %context';
- if (!empty($GLOBALS['_POST'])) {
- $context[] = logging_implode($GLOBALS['_POST']);
- }
-
- if (is_array($log)) {
- $context[] = logging_implode($log);
- } else {
- $context[] = preg_replace('/[ \t\r\n]+/', ' ', $log);
- }
-
- $log = str_replace(explode(' ', $logFormat), array(
- '[' . date('Y-m-d H:i:s', $_W['timestamp']) . ']',
- $type,
- $_W['username'],
- $_SERVER['PHP_SELF'] . '?' . $_SERVER['QUERY_STRING'],
- implode("\n", $context),
- ), $logFormat);
- if (file_exists($filename)) {
- $log = $log . "\r\n";
- } else {
- $log = "<?php exit;?>\r\n" . $log . "\r\n";
- }
- file_put_contents($filename, $log, FILE_APPEND);
- return true;
- }
-
- public function logging_implode($array, $skip = array()) {
- $return = '';
- if (is_array($array) && !empty($array)) {
- foreach ($array as $key => $value) {
- if (empty($skip) || !in_array($key, $skip, true)) {
- if (is_array($value)) {
- $return .= $key . '={' . $this->logging_implode($value, $skip) . '}; ';
- } else {
- $return .= "$key=$value; ";
- }
- }
- }
- }
-
- return $return;
- }
- }
复制代码
|
|