/** * 从http数据包中解析$_POST、$_GET、$_COOKIE等 * @param string $recv_buffer * @param TcpConnection $connection * @return void */ public static function decode($recv_buffer, TcpConnection $connection) { // 初始化 $_POST = $_GET = $_COOKIE = $_REQUEST = $_SESSION = $_FILES = array(); $GLOBALS['HTTP_RAW_POST_DATA'] = ''; // 清空上次的数据 HttpCache::$header = array('Connection' => 'Connection: keep-alive'); HttpCache::$instance = new HttpCache(); // 需要设置的变量名 $_SERVER = array('QUERY_STRING' => '', 'REQUEST_METHOD' => '', 'REQUEST_URI' => '', 'SERVER_PROTOCOL' => '', 'SERVER_SOFTWARE' => 'workerman/3.0', 'SERVER_NAME' => '', 'HTTP_HOST' => '', 'HTTP_USER_AGENT' => '', 'HTTP_ACCEPT' => '', 'HTTP_ACCEPT_LANGUAGE' => '', 'HTTP_ACCEPT_ENCODING' => '', 'HTTP_COOKIE' => '', 'HTTP_CONNECTION' => '', 'REMOTE_ADDR' => '', 'REMOTE_PORT' => '0'); // 将header分割成数组 list($http_header, $http_body) = explode("\r\n\r\n", $recv_buffer, 2); $header_data = explode("\r\n", $http_header); list($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI'], $_SERVER['SERVER_PROTOCOL']) = explode(' ', $header_data[0]); unset($header_data[0]); foreach ($header_data as $content) { // \r\n\r\n if (empty($content)) { continue; } list($key, $value) = explode(':', $content, 2); $key = strtolower($key); $value = trim($value); switch ($key) { // HTTP_HOST case 'host': $_SERVER['HTTP_HOST'] = $value; $tmp = explode(':', $value); $_SERVER['SERVER_NAME'] = $tmp[0]; if (isset($tmp[1])) { $_SERVER['SERVER_PORT'] = $tmp[1]; } break; // cookie // cookie case 'cookie': $_SERVER['HTTP_COOKIE'] = $value; parse_str(str_replace('; ', '&', $_SERVER['HTTP_COOKIE']), $_COOKIE); break; // user-agent // user-agent case 'user-agent': $_SERVER['HTTP_USER_AGENT'] = $value; break; // accept // accept case 'accept': $_SERVER['HTTP_ACCEPT'] = $value; break; // accept-language // accept-language case 'accept-language': $_SERVER['HTTP_ACCEPT_LANGUAGE'] = $value; break; // accept-encoding // accept-encoding case 'accept-encoding': $_SERVER['HTTP_ACCEPT_ENCODING'] = $value; break; // connection // connection case 'connection': $_SERVER['HTTP_CONNECTION'] = $value; break; case 'referer': $_SERVER['HTTP_REFERER'] = $value; break; case 'if-modified-since': $_SERVER['HTTP_IF_MODIFIED_SINCE'] = $value; break; case 'if-none-match': $_SERVER['HTTP_IF_NONE_MATCH'] = $value; break; case 'content-type': if (!preg_match('/boundary="?(\\S+)"?/', $value, $match)) { $_SERVER['CONTENT_TYPE'] = $value; } else { $_SERVER['CONTENT_TYPE'] = 'multipart/form-data'; $http_post_boundary = '--' . $match[1]; } break; } } // 需要解析$_POST if ($_SERVER['REQUEST_METHOD'] === 'POST') { if (isset($_SERVER['CONTENT_TYPE']) && $_SERVER['CONTENT_TYPE'] === 'multipart/form-data') { self::parseUploadFiles($http_body, $http_post_boundary); } else { parse_str($http_body, $_POST); // $GLOBALS['HTTP_RAW_POST_DATA'] $GLOBALS['HTTP_RAW_POST_DATA'] = $http_body; } } // QUERY_STRING $_SERVER['QUERY_STRING'] = parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY); if ($_SERVER['QUERY_STRING']) { // $GET parse_str($_SERVER['QUERY_STRING'], $_GET); } else { $_SERVER['QUERY_STRING'] = ''; } // REQUEST $_REQUEST = array_merge($_GET, $_POST); // REMOTE_ADDR REMOTE_PORT $_SERVER['REMOTE_ADDR'] = $connection->getRemoteIp(); $_SERVER['REMOTE_PORT'] = $connection->getRemotePort(); return array('get' => $_GET, 'post' => $_POST, 'cookie' => $_COOKIE, 'server' => $_SERVER, 'files' => $_FILES); }
/** * Emit when http message coming. * * @param Connection\TcpConnection $connection * @return void */ public function onMessage($connection) { // REQUEST_URI. $workerman_url_info = parse_url($_SERVER['REQUEST_URI']); if (!$workerman_url_info) { Http::header('HTTP/1.1 400 Bad Request'); $connection->close('<h1>400 Bad Request</h1>'); return; } $workerman_path = isset($workerman_url_info['path']) ? $workerman_url_info['path'] : '/'; $workerman_path_info = pathinfo($workerman_path); $workerman_file_extension = isset($workerman_path_info['extension']) ? $workerman_path_info['extension'] : ''; if ($workerman_file_extension === '') { $workerman_path = ($len = strlen($workerman_path)) && $workerman_path[$len - 1] === '/' ? $workerman_path . 'index.php' : $workerman_path . '/index.php'; $workerman_file_extension = 'php'; } $workerman_root_dir = isset($this->serverRoot[$_SERVER['SERVER_NAME']]) ? $this->serverRoot[$_SERVER['SERVER_NAME']] : current($this->serverRoot); $workerman_file = "{$workerman_root_dir}/{$workerman_path}"; if ($workerman_file_extension === 'php' && !is_file($workerman_file)) { $workerman_file = "{$workerman_root_dir}/index.php"; if (!is_file($workerman_file)) { $workerman_file = "{$workerman_root_dir}/index.html"; $workerman_file_extension = 'html'; } } // File exsits. if (is_file($workerman_file)) { // Security check. if (!($workerman_request_realpath = realpath($workerman_file)) || !($workerman_root_dir_realpath = realpath($workerman_root_dir)) || 0 !== strpos($workerman_request_realpath, $workerman_root_dir_realpath)) { Http::header('HTTP/1.1 400 Bad Request'); $connection->close('<h1>400 Bad Request</h1>'); return; } $workerman_file = realpath($workerman_file); // Request php file. if ($workerman_file_extension === 'php') { $workerman_cwd = getcwd(); chdir($workerman_root_dir); ini_set('display_errors', 'off'); ob_start(); // Try to include php file. try { // $_SERVER. $_SERVER['REMOTE_ADDR'] = $connection->getRemoteIp(); $_SERVER['REMOTE_PORT'] = $connection->getRemotePort(); include $workerman_file; } catch (\Exception $e) { // Jump_exit? if ($e->getMessage() != 'jump_exit') { echo $e; } } $content = ob_get_clean(); ini_set('display_errors', 'on'); if (strtolower($_SERVER['HTTP_CONNECTION']) === "keep-alive") { $connection->send($content); } else { $connection->close($content); } chdir($workerman_cwd); return; } // Send file to client. return self::sendFile($connection, $workerman_file); } else { // 404 Http::header("HTTP/1.1 404 Not Found"); $connection->close('<html><head><title>404 File not found</title></head><body><center><h3>404 Not Found</h3></center></body></html>'); return; } }
/** * 当worker通过内部通讯端口连接到gateway时 * @param TcpConnection $connection */ public function onWorkerConnect($connection) { $connection->remoteAddress = $connection->getRemoteIp() . ':' . $connection->getRemotePort(); if (TcpConnection::$defaultMaxSendBufferSize == $connection->maxSendBufferSize) { $connection->maxSendBufferSize = 10 * 1024 * 1024; } $this->_workerConnections[$connection->remoteAddress] = $connection; }
/** * 覆盖原workerman流程,实现更多功能 * 当接收到完整的http请求后的处理逻辑 * * 1、如果请求的是以php为后缀的文件,则尝试加载 * 2、如果请求的url没有后缀,则尝试加载对应目录的index.php * 3、如果请求的是非php为后缀的文件,尝试读取原始数据并发送 * 4、如果请求的文件不存在,则返回404 * * @param TcpConnection $connection * @param mixed $data * @return mixed */ public function onMessage($connection, $data) { Base::getLog()->debug(__METHOD__ . ' receive http request', ['uri' => $_SERVER['REQUEST_URI'], 'ip' => $connection->getRemoteIp(), 'port' => $connection->getRemotePort(), 'data' => $data]); // 请求的文件 $urlInfo = parse_url($_SERVER['REQUEST_URI']); if (!$urlInfo) { Base::getHttp()->header('HTTP/1.1 400 Bad Request'); Base::getLog()->warning(__METHOD__ . ' receive bad request', ['uri' => $_SERVER['REQUEST_URI'], 'ip' => $connection->getRemoteIp(), 'port' => $connection->getRemotePort()]); return $connection->close($this->error400); } $path = $urlInfo['path']; $pathInfo = pathinfo($path); $extension = isset($pathInfo['extension']) ? $pathInfo['extension'] : ''; if ($extension === '') { $path = ($len = strlen($path)) && $path[$len - 1] === '/' ? $path . $this->indexFile : $path . '/' . $this->indexFile; $extension = 'php'; } $serverName = Arr::get($_SERVER, 'SERVER_NAME'); $rootDir = isset($this->serverRoot[$serverName]) ? $this->serverRoot[$serverName] : current($this->serverRoot); $file = "{$rootDir}/{$path}"; // 对应的php文件不存在,而且支持rewrite if (!is_file($file) && $this->rewrite) { $file = is_string($this->rewrite) ? $rootDir . '/' . $this->rewrite : $rootDir . '/' . $this->indexFile; $extension = 'php'; $_SERVER['PATH_INFO'] = $_SERVER['REQUEST_URI']; } // 请求的文件存在 if (is_file($file)) { Base::getLog()->debug(__METHOD__ . ' request file existed', ['file' => $file, 'extension' => $extension]); // 判断是否是站点目录里的文件 if (!($requestRealPath = realpath($file)) || !($rootDirRealPath = realpath($rootDir)) || 0 !== strpos($requestRealPath, $rootDirRealPath)) { Base::getHttp()->header('HTTP/1.1 400 Bad Request'); Base::getLog()->warning(__METHOD__ . ' receive bad request', ['uri' => $_SERVER['REQUEST_URI'], 'ip' => $connection->getRemoteIp(), 'port' => $connection->getRemotePort()]); return $connection->close('<h1>400 Bad Request</h1>'); } $file = realpath($file); // 如果请求的是php文件 // PHP文件需要include if ($extension === 'php') { Base::getLog()->debug(__METHOD__ . ' handle request', ['uri' => $_SERVER['REQUEST_URI'], 'ip' => $connection->getRemoteIp(), 'port' => $connection->getRemotePort(), 'file' => $file]); Base::getLog()->debug(__METHOD__ . ' clean components - start'); Base::cleanComponents(); Base::getLog()->debug(__METHOD__ . ' clean components - end'); $cwd = getcwd(); chdir($rootDir); ini_set('display_errors', 'off'); // 缓冲输出 ob_start(); // 载入php文件 try { // $_SERVER变量 $_SERVER['HOME'] = $_SERVER['DOCUMENT_ROOT'] = dirname($file); $_SERVER['SCRIPT_FILENAME'] = $file; Base::getLog()->debug(__METHOD__ . ' dispatch client info', ['ip' => $_SERVER['REMOTE_ADDR'], 'port' => $_SERVER['REMOTE_PORT']]); include $file; } catch (Exception $e) { Base::getLog()->error($e->getMessage(), ['code' => $e->getCode(), 'file' => $e->getFile(), 'line' => $e->getLine()]); // 如果不是exit if ($e->getMessage() != 'jump_exit') { echo $e; } } Patch::applyShutdownFunction(); $content = ob_get_clean(); ini_set('display_errors', 'on'); $result = $connection->close($content); chdir($cwd); return $result; } else { $contentType = Mime::getMimeFromExtension($extension, self::$defaultMimeType); Base::getLog()->debug(__METHOD__ . ' get static file content type', ['extension' => $extension, 'contentType' => $contentType]); Base::getHttp()->header('Content-Type: ' . $contentType); // 获取文件信息 $info = stat($file); $modifiedTime = $info ? date('D, d M Y H:i:s', Arr::get($info, 'mtime')) . ' GMT' : ''; // 如果有$_SERVER['HTTP_IF_MODIFIED_SINCE'] if (!empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $info) { // 文件没有更改则直接304 if ($modifiedTime === $_SERVER['HTTP_IF_MODIFIED_SINCE']) { Base::getLog()->debug(__METHOD__ . ' no modified, return 304'); // 304 Base::getHttp()->header('HTTP/1.1 304 Not Modified'); // 发送给客户端 return $connection->close(''); } } if ($modifiedTime) { Base::getLog()->debug(__METHOD__ . ' set last modified time', ['time' => $modifiedTime]); Base::getHttp()->header("Last-Modified: {$modifiedTime}"); } // 发送给客户端 return $connection->close(file_get_contents($file)); } } else { Base::getLog()->warning(__METHOD__ . ' requested file not found', ['file' => $file]); // 404 Base::getHttp()->header("HTTP/1.1 404 Not Found"); return $connection->close($this->error404); } }
/** * 当worker发来数据时 * @param TcpConnection $connection * @param mixed $data * @throws \Exception */ public function onWorkerMessage($connection, $data) { $cmd = $data['cmd']; switch ($cmd) { case GatewayProtocol::CMD_WORKER_CONNECT: $connection->remoteAddress = $connection->getRemoteIp() . ':' . $connection->getRemotePort(); $this->_workerConnections[$connection->remoteAddress] = $connection; return; // 向某客户端发送数据,Gateway::sendToClient($client_id, $message); // 向某客户端发送数据,Gateway::sendToClient($client_id, $message); case GatewayProtocol::CMD_SEND_TO_ONE: if (isset($this->_clientConnections[$data['connection_id']])) { $this->_clientConnections[$data['connection_id']]->send($data['body']); } return; // 关闭客户端连接,Gateway::closeClient($client_id); // 关闭客户端连接,Gateway::closeClient($client_id); case GatewayProtocol::CMD_KICK: if (isset($this->_clientConnections[$data['connection_id']])) { $this->_clientConnections[$data['connection_id']]->destroy(); } return; // 广播, Gateway::sendToAll($message, $client_id_array) // 广播, Gateway::sendToAll($message, $client_id_array) case GatewayProtocol::CMD_SEND_TO_ALL: // $client_id_array不为空时,只广播给$client_id_array指定的客户端 if ($data['ext_data']) { $connection_id_array = unpack('N*', $data['ext_data']); foreach ($connection_id_array as $connection_id) { if (isset($this->_clientConnections[$connection_id])) { $this->_clientConnections[$connection_id]->send($data['body']); } } } else { foreach ($this->_clientConnections as $client_connection) { $client_connection->send($data['body']); } } return; // 更新客户端session // 更新客户端session case GatewayProtocol::CMD_UPDATE_SESSION: if (isset($this->_clientConnections[$data['connection_id']])) { $this->_clientConnections[$data['connection_id']]->session = $data['ext_data']; } return; // 获得客户端在线状态 Gateway::getALLClientInfo() // 获得客户端在线状态 Gateway::getALLClientInfo() case GatewayProtocol::CMD_GET_ALL_CLIENT_INFO: $client_info_array = array(); foreach ($this->_clientConnections as $connection_id => $client_connection) { $client_info_array[$connection_id] = $client_connection->session; } $connection->send(json_encode($client_info_array) . "\n", true); return; // 判断某个client_id是否在线 Gateway::isOnline($client_id) // 判断某个client_id是否在线 Gateway::isOnline($client_id) case GatewayProtocol::CMD_IS_ONLINE: $connection->send((int) isset($this->_clientConnections[$data['connection_id']]) . "\n", true); return; // 将client_id与uid绑定 // 将client_id与uid绑定 case GatewayProtocol::CMD_BIND_UID: $uid = $data['ext_data']; if (empty($uid)) { echo "uid empty" . var_export($uid, true); return; } $connection_id = $data['connection_id']; if (!isset($this->_clientConnections[$connection_id])) { return; } $client_connection = $this->_clientConnections[$connection_id]; if (isset($client_connection->uid)) { $current_uid = $client_connection->uid; unset($this->_uidConnections[$current_uid][$connection_id]); if (empty($this->_uidConnections[$current_uid])) { unset($this->_uidConnections[$current_uid]); } } $client_connection->uid = $uid; $this->_uidConnections[$uid][$connection_id] = $client_connection; return; // client_id与uid解绑 Gateway::unbindUid($client_id, $uid); // client_id与uid解绑 Gateway::unbindUid($client_id, $uid); case GatewayProtocol::CMD_UNBIND_UID: $connection_id = $data['connection_id']; if (!isset($this->_clientConnections[$connection_id])) { return; } $client_connection = $this->_clientConnections[$connection_id]; if (isset($client_connection->uid)) { $current_uid = $client_connection->uid; unset($this->_uidConnections[$current_uid][$connection_id]); if (empty($this->_uidConnections[$current_uid])) { unset($this->_uidConnections[$current_uid]); } $client_connection->uid_info = ''; $client_connection->uid = null; } return; // 发送数据给uid Gateway::sendToUid($uid, $msg); // 发送数据给uid Gateway::sendToUid($uid, $msg); case GatewayProtocol::CMD_SEND_TO_UID: $uid_array = json_decode($data['ext_data'], true); foreach ($uid_array as $uid) { if (!empty($this->_uidConnections[$uid])) { foreach ($this->_uidConnections[$uid] as $connection) { $connection->send($data['body']); } } } return; // 将$client_id加入用户组 Gateway::joinGroup($client_id, $group); // 将$client_id加入用户组 Gateway::joinGroup($client_id, $group); case GatewayProtocol::CMD_JOIN_GROUP: $group = $data['ext_data']; if (empty($group)) { echo "group empty" . var_export($group, true); return; } $connection_id = $data['connection_id']; if (!isset($this->_clientConnections[$connection_id])) { return; } $client_connection = $this->_clientConnections[$connection_id]; if (!isset($client_connection->groups)) { $client_connection->groups = array(); } $client_connection->groups[$group] = $group; $this->_groupConnections[$group][$connection_id] = $client_connection; return; // 将$client_id从某个用户组中移除 Gateway::leaveGroup($client_id, $group); // 将$client_id从某个用户组中移除 Gateway::leaveGroup($client_id, $group); case GatewayProtocol::CMD_LEAVE_GROUP: $group = $data['ext_data']; if (empty($group)) { echo "leave group empty" . var_export($group, true); return; } $connection_id = $data['connection_id']; if (!isset($this->_clientConnections[$connection_id])) { return; } $client_connection = $this->_clientConnections[$connection_id]; if (!isset($client_connection->groups[$group])) { return; } unset($client_connection->groups[$group], $this->_groupConnections[$group][$connection_id]); return; // 向某个用户组发送消息 Gateway::sendToGroup($group, $msg); // 向某个用户组发送消息 Gateway::sendToGroup($group, $msg); case GatewayProtocol::CMD_SEND_TO_GROUP: $group_array = json_decode($data['ext_data'], true); foreach ($group_array as $group) { if (!empty($this->_groupConnections[$group])) { foreach ($this->_groupConnections[$group] as $connection) { $connection->send($data['body']); } } } return; // 获取某用户组成员信息 Gateway::getClientInfoByGroup($group); // 获取某用户组成员信息 Gateway::getClientInfoByGroup($group); case GatewayProtocol::CMD_GET_CLINET_INFO_BY_GROUP: $group = $data['ext_data']; if (!isset($this->_groupConnections[$group])) { $connection->send("[]\n", true); return; } $client_info_array = array(); foreach ($this->_groupConnections[$group] as $connection_id => $client_connection) { $client_info_array[$connection_id] = $client_connection->session; } $connection->send(json_encode($client_info_array) . "\n", true); return; // 获取用户组成员数 Gateway::getClientCountByGroup($group); // 获取用户组成员数 Gateway::getClientCountByGroup($group); case GatewayProtocol::CMD_GET_CLIENT_COUNT_BY_GROUP: $group = $data['ext_data']; if (!isset($this->_groupConnections[$group])) { $connection->send("0\n", true); return; } $connection->send(count($this->_groupConnections[$group]) . "\n", true); return; // 获取与某个uid绑定的所有client_id Gateway::getClientIdByUid($uid); // 获取与某个uid绑定的所有client_id Gateway::getClientIdByUid($uid); case GatewayProtocol::CMD_GET_CLIENT_ID_BY_UID: $uid = $data['ext_data']; if (empty($this->_uidConnections[$uid])) { $connection->send("[]\n", true); return; } $connection->send(json_encode(array_keys($this->_uidConnections[$uid])) . "\n", true); return; default: $err_msg = "gateway inner pack err cmd={$cmd}"; throw new \Exception($err_msg); } }
/** * Parse $_POST、$_GET、$_COOKIE. * * @param string $recv_buffer * @param TcpConnection $connection * @return array */ public static function decode($recv_buffer, TcpConnection $connection) { // Init. $_POST = $_GET = $_COOKIE = $_REQUEST = $_SESSION = $_FILES = array(); $GLOBALS['HTTP_RAW_POST_DATA'] = ''; // Clear cache. HttpCache::$header = array('Connection' => 'Connection: keep-alive'); HttpCache::$instance = new HttpCache(); // $_SERVER $_SERVER = array('QUERY_STRING' => '', 'REQUEST_METHOD' => '', 'REQUEST_URI' => '', 'SERVER_PROTOCOL' => '', 'SERVER_SOFTWARE' => 'workerman/' . Worker::VERSION, 'SERVER_NAME' => '', 'HTTP_HOST' => '', 'HTTP_USER_AGENT' => '', 'HTTP_ACCEPT' => '', 'HTTP_ACCEPT_LANGUAGE' => '', 'HTTP_ACCEPT_ENCODING' => '', 'HTTP_COOKIE' => '', 'HTTP_CONNECTION' => '', 'REMOTE_ADDR' => '', 'REMOTE_PORT' => '0'); // Parse headers. list($http_header, $http_body) = explode("\r\n\r\n", $recv_buffer, 2); $header_data = explode("\r\n", $http_header); list($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI'], $_SERVER['SERVER_PROTOCOL']) = explode(' ', $header_data[0]); $http_post_boundary = ''; unset($header_data[0]); foreach ($header_data as $content) { // \r\n\r\n if (empty($content)) { continue; } list($key, $value) = explode(':', $content, 2); $key = str_replace('-', '_', strtoupper($key)); $value = trim($value); $_SERVER['HTTP_' . $key] = $value; switch ($key) { // HTTP_HOST case 'HOST': $tmp = explode(':', $value); $_SERVER['SERVER_NAME'] = $tmp[0]; if (isset($tmp[1])) { $_SERVER['SERVER_PORT'] = $tmp[1]; } break; // cookie // cookie case 'COOKIE': parse_str(str_replace('; ', '&', $_SERVER['HTTP_COOKIE']), $_COOKIE); break; // content-type // content-type case 'CONTENT_TYPE': if (!preg_match('/boundary="?(\\S+)"?/', $value, $match)) { $_SERVER['CONTENT_TYPE'] = $value; } else { $_SERVER['CONTENT_TYPE'] = 'multipart/form-data'; $http_post_boundary = '--' . $match[1]; } break; case 'CONTENT_LENGTH': $_SERVER['CONTENT_LENGTH'] = $value; break; } } // Parse $_POST. if ($_SERVER['REQUEST_METHOD'] === 'POST') { if (isset($_SERVER['CONTENT_TYPE']) && $_SERVER['CONTENT_TYPE'] === 'multipart/form-data') { self::parseUploadFiles($http_body, $http_post_boundary); } else { parse_str($http_body, $_POST); // $GLOBALS['HTTP_RAW_POST_DATA'] $GLOBALS['HTTP_RAW_POST_DATA'] = $http_body; } } // QUERY_STRING $_SERVER['QUERY_STRING'] = parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY); if ($_SERVER['QUERY_STRING']) { // $GET parse_str($_SERVER['QUERY_STRING'], $_GET); } else { $_SERVER['QUERY_STRING'] = ''; } // REQUEST $_REQUEST = array_merge($_GET, $_POST); // REMOTE_ADDR REMOTE_PORT $_SERVER['REMOTE_ADDR'] = $connection->getRemoteIp(); $_SERVER['REMOTE_PORT'] = $connection->getRemotePort(); return array('get' => $_GET, 'post' => $_POST, 'cookie' => $_COOKIE, 'server' => $_SERVER, 'files' => $_FILES); }
/** * 从http数据包中解析$_POST、$_GET、$_COOKIE等 * * @param string $recv_buffer * @param TcpConnection $connection * @return array */ public static function decode($recv_buffer, TcpConnection $connection) { // 初始化 Base::getLog()->debug(__METHOD__ . ' clean global variables'); $_POST = $_GET = $_COOKIE = $_REQUEST = $_SESSION = $_FILES = []; $GLOBALS['HTTP_RAW_POST_DATA'] = ''; $userInfo = posix_getpwuid(posix_getuid()); $_SERVER = ['USER' => Arr::get($userInfo, 'name', ''), 'HOME' => '', 'QUERY_STRING' => '', 'REQUEST_METHOD' => '', 'REQUEST_URI' => '', 'SERVER_PROTOCOL' => '', 'SERVER_SOFTWARE' => 'tourze/' . Base::VERSION, 'SERVER_NAME' => '', 'SCRIPT_FILENAME' => '', 'HTTP_HOST' => '', 'HTTP_USER_AGENT' => '', 'HTTP_ACCEPT' => '', 'HTTP_ACCEPT_LANGUAGE' => '', 'HTTP_ACCEPT_ENCODING' => '', 'HTTP_COOKIE' => '', 'HTTP_CONNECTION' => '', 'REMOTE_ADDR' => '', 'REMOTE_PORT' => '0', 'REQUEST_TIME' => time()]; $_SERVER['REQUEST_TIME_FLOAT'] = $_SERVER['REQUEST_TIME'] . substr((string) microtime(), 1, 5); Base::getLog()->debug(__METHOD__ . ' clean previous headers'); // 清空上次的数据 HttpCache::$header = ['Connection: keep-alive']; HttpCache::$instance = new HttpCache(); // 将header分割成数组 list($httpHeader, $httpBody) = explode("\r\n\r\n", $recv_buffer, 2); $headerData = explode("\r\n", $httpHeader); // 第一行为比较重要的一行 $firstLine = array_shift($headerData); list($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI'], $_SERVER['SERVER_PROTOCOL']) = explode(' ', $firstLine); $_SERVER['PHP_SELF'] = $_SERVER['SCRIPT_NAME'] = $_SERVER['DOCUMENT_URI'] = $_SERVER['REQUEST_URI']; Base::getLog()->debug(__METHOD__ . ' receive http request', ['method' => $_SERVER['REQUEST_METHOD'], 'uri' => $_SERVER['REQUEST_URI'], 'protocol' => $_SERVER['SERVER_PROTOCOL']]); $httpPostBoundary = ''; foreach ($headerData as $content) { // \r\n\r\n if (empty($content)) { continue; } list($key, $value) = explode(':', $content, 2); $key = strtolower($key); $value = trim($value); switch ($key) { // HTTP_HOST case 'host': $_SERVER['HTTP_HOST'] = $value; $tmp = explode(':', $value); $_SERVER['SERVER_NAME'] = $tmp[0]; if (isset($tmp[1])) { $_SERVER['SERVER_PORT'] = $tmp[1]; } break; // cookie // cookie case 'cookie': $_SERVER['HTTP_COOKIE'] = $value; parse_str(str_replace('; ', '&', $_SERVER['HTTP_COOKIE']), $_COOKIE); break; // user-agent // user-agent case 'user-agent': $_SERVER['HTTP_USER_AGENT'] = $value; break; // accept // accept case 'accept': $_SERVER['HTTP_ACCEPT'] = $value; break; // accept-language // accept-language case 'accept-language': $_SERVER['HTTP_ACCEPT_LANGUAGE'] = $value; break; // accept-encoding // accept-encoding case 'accept-encoding': $_SERVER['HTTP_ACCEPT_ENCODING'] = $value; break; // connection // connection case 'connection': $_SERVER['HTTP_CONNECTION'] = $value; break; case 'referer': $_SERVER['HTTP_REFERER'] = $value; break; case 'if-modified-since': $_SERVER['HTTP_IF_MODIFIED_SINCE'] = $value; break; case 'if-none-match': $_SERVER['HTTP_IF_NONE_MATCH'] = $value; break; case 'content-type': if (!preg_match('/boundary="?(\\S+)"?/', $value, $match)) { $_SERVER['CONTENT_TYPE'] = $value; } else { $_SERVER['CONTENT_TYPE'] = 'multipart/form-data'; $httpPostBoundary = '--' . $match[1]; } break; } } // 需要解析$_POST if ($_SERVER['REQUEST_METHOD'] === 'POST') { if (isset($_SERVER['CONTENT_TYPE']) && $_SERVER['CONTENT_TYPE'] === 'multipart/form-data') { self::parseUploadFiles($httpBody, $httpPostBoundary); } else { parse_str($httpBody, $_POST); $GLOBALS['HTTP_RAW_POST_DATA'] = $httpBody; } } // QUERY_STRING $_SERVER['QUERY_STRING'] = parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY); if ($_SERVER['QUERY_STRING']) { // $GET parse_str($_SERVER['QUERY_STRING'], $_GET); } else { $_SERVER['QUERY_STRING'] = ''; } // REQUEST $_REQUEST = array_merge($_GET, $_POST); // REMOTE_ADDR REMOTE_PORT $_SERVER['REMOTE_ADDR'] = $connection->getRemoteIp(); $_SERVER['REMOTE_PORT'] = $connection->getRemotePort(); // 这两处要怎么读取呢? $_SERVER['SERVER_ADDR'] = null; $_SERVER['SERVER_PORT'] = null; $result = ['get' => $_GET, 'post' => $_POST, 'cookie' => $_COOKIE, 'server' => $_SERVER, 'files' => $_FILES]; Base::getLog()->debug(__METHOD__ . ' get request data', $result); return $result; }