admin 发表于 2025-5-25 18:24:55

communication备份

代码:

<?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 = substr($data, 0, $pos);
            $split1 = substr($data, $pos + 4, strlen($data));
   
            $split2 = explode("\r\n", $split1, 2);
            preg_match('/^(\S+) (\S+) (.*)$/', $split2, $matches);
            $rlt['code'] = !empty($matches) ? $matches : 200;
            $rlt['status'] = !empty($matches) ? $matches : 'OK';
            $rlt['responseline'] = !empty($split2) ? $split2 : '';
            $header = !empty($split2) ? explode("\r\n", $split2) : 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);
            } else {
                    $rlt['content'] = $split1;
            }
            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;
            }
   
            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;
    }
}

页: [1]
查看完整版本: communication备份