/** * {@inheritdoc} */ public function get($name) { if (!isset($_FILES[$name])) { return false; } return new Entity(['name' => Arr::get($_FILES[$name], 'name'), 'type' => Arr::get($_FILES[$name], 'type'), 'path' => Arr::get($_FILES[$name], 'tmp_name'), 'error' => Arr::get($_FILES[$name], 'error', 0), 'size' => Arr::get($_FILES[$name], 'size', 0)]); }
/** * 获取主请求的uri字符串,默认按照PATH_INFO、REQUEST_URI、PHP_SELF、REDIRECT_URL这样的顺序读取 * * $uri = Uri::detectUri(); * * @return string URI * @throws HelperException */ public static function detectUri() { // 如果PATH_INFO读不到,那么就从其他途径读 if (!($uri = Arr::get($_SERVER, 'PATH_INFO'))) { // REQUEST_URI和PHP_SELF会包含当前脚本路径 if (isset($_SERVER['REQUEST_URI'])) { $uri = $_SERVER['REQUEST_URI']; if ($requestUri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)) { $uri = $requestUri; } $uri = rawurldecode($uri); } elseif (isset($_SERVER['PHP_SELF'])) { $uri = $_SERVER['PHP_SELF']; } elseif (isset($_SERVER['REDIRECT_URL'])) { $uri = $_SERVER['REDIRECT_URL']; } else { throw new HelperException('Unable to detect the URI using PATH_INFO, REQUEST_URI, PHP_SELF or REDIRECT_URL'); } $baseUrl = parse_url(Base::$baseUrl, PHP_URL_PATH); if (strpos($uri, $baseUrl) === 0) { $uri = (string) substr($uri, strlen($baseUrl)); } if (Base::$indexFile && strpos($uri, Base::$indexFile) === 0) { $uri = (string) substr($uri, strlen(Base::$indexFile)); } } return $uri; }
/** * 实现register_shutdown_function */ public static function applyShutdownFunction() { Base::getLog()->debug(__METHOD__ . ' apply shutdown functions'); foreach (self::$shutdownFunctions as $pair) { call_user_func_array(Arr::get($pair, 'callback'), Arr::get($pair, 'params')); } }
/** * 下面要修改成workerman的逻辑 * * @inheritdoc */ public function sessionID($id = null) { $current = Arr::get($_COOKIE, HttpCache::$sessionName, ''); if ($id === null) { return $current; } $this->setCookie(HttpCache::$sessionName, $id, ini_get('session.cookie_lifetime'), ini_get('session.cookie_path'), ini_get('session.cookie_domain'), ini_get('session.cookie_secure'), ini_get('session.cookie_httponly')); $_COOKIE[HttpCache::$sessionName] = $id; return $current; }
/** * {@inheritdoc} */ public function init() { parent::init(); foreach ($this->config as $routeName => $routeConfig) { if (is_numeric($routeName)) { $routeName = Arr::get($routeConfig, 'name', uniqid()); } $this->set($routeName, Arr::get($routeConfig, 'uri'), Arr::get($routeConfig, 'regex'), Arr::get($routeConfig, 'force', false), Arr::get($routeConfig, 'defaults', [])); } }
/** * 获取指定的配置组信息,并返回实例 * * @param string $key * @return \tourze\NoSQL\Redis\Client * @throws \tourze\NoSQL\Exception\NoSQLException */ public static function instance($key = 'default') { $instanceKey = self::instanceKey($key); if (!isset(self::$_instances[$instanceKey])) { $config = Config::load('redis')->get($key); if (!$config) { throw new NoSQLException('The requested config group not found.'); } self::$_instances[$instanceKey] = new Client(Arr::get($config, 'parameters'), Arr::get($config, 'options')); } return self::$_instances[$instanceKey]; }
/** * @param array $options * @return ArrayLoader|FileLoader * @throws \tourze\Twig\Exception\TwigException */ public static function createLoader(array $options) { $type = Arr::get($options, 'type', 'Array'); $args = Arr::get($options, 'args', []); switch ($type) { case self::ARRAY_LOADER: $instance = new ArrayLoader($args); break; case self::FILE_LOADER: $instance = new FileLoader($args); break; default: throw new TwigException('The requested twig loader not found.'); } return $instance; }
/** * {@inheritdoc} */ public function get($name, $default = null) { Base::getLog()->debug(__METHOD__ . ' get cache', ['name' => $name, 'default' => $default]); if (!isset($this->_cache[$name])) { Base::getLog()->debug(__METHOD__ . ' cache not found, return default value', ['name' => $name, 'default' => $default]); return $default; } $data = Arr::get($this->_cache, $name); // 判断过期时间,过期的话,直接删除 $current = time(); $expired = Arr::get($data, 'expired'); if ($current > $expired) { Base::getLog()->debug(__METHOD__ . ' cache is expired', ['name' => $name, 'current' => $current, 'expired' => $expired]); $this->remove($name); return $default; } $value = Arr::get($data, 'value'); $this->saveHitTime($name); return $value; }
/** * 上报统计数据 * * @param string $module * @param string $interface * @param bool $success * @param int $code * @param string $msg * @param string $reportAddress * @return boolean */ public static function report($module, $interface, $success, $code, $msg, $reportAddress = '') { // 如果msg是个数组,那么要额外处理转换成字符串 if (is_array($msg)) { // $msg格式为[':message', [':message' => 'TEST']] if (count($msg) == 2 && !Arr::isAssoc($msg) && is_array($msg[1])) { $msg = __($msg[0], $msg[1]); } } if (strpos($msg, '[ip]') !== false) { $msg = str_replace('[ip]', Arr::get($_SERVER, 'REMOTE_ADDR'), $msg); } if (strpos($msg, '[ua]') !== false) { $msg = str_replace('[ua]', Arr::get($_SERVER, 'HTTP_USER_AGENT'), $msg); } $reportAddress = $reportAddress ? $reportAddress : Config::load('statClient')->get('ip'); if (isset(self::$timeMap[$module][$interface]) && self::$timeMap[$module][$interface] > 0) { $startTime = self::$timeMap[$module][$interface]; self::$timeMap[$module][$interface] = 0; } else { if (isset(self::$timeMap['']['']) && self::$timeMap[''][''] > 0) { $startTime = self::$timeMap['']['']; self::$timeMap[''][''] = 0; } else { $startTime = microtime(true); } } //echo "\n"; //echo $startTime . "\n"; $endTime = microtime(true); //echo $endTime . "\n"; $costTime = $endTime - $startTime; //echo $costTime . "\n"; $binData = Protocol::encode($module, $interface, $costTime, $success, $code, $msg); Base::getLog()->debug(__METHOD__ . ' prepare bin data', ['bin' => $binData]); return self::sendData($reportAddress, $binData); }
/** * 解析参数字符串为数组 * * params('depth=2,something=test') * * 转换为 * * array(2) ( * "depth" => int 2 * "something" => string(4) "test" * ) * * @param string $var 要解析的字符串 * @return array */ public static function params($var) { $var = explode(',', $var); $new = []; foreach ($var as $i) { $i = explode('=', trim($i)); $new[$i[0]] = Arr::get($i, 1, null); if (ctype_digit($new[$i[0]])) { $new[$i[0]] = (int) $new[$i[0]]; } } return $new; }
/** * 返回处理后的错误信息 * * // 从message/forms/authorize.php读取错误信息 * $errors = $validation->errors('forms/login'); * * @param string $file 要读取的消息文本 * @param mixed $translate 是否翻译 * @return array */ public function errors($file = null, $translate = true) { if (null === $file) { if (!$this->getErrorFileName()) { return $this->_errors; } $file = $this->getErrorFileName(); } $messages = []; foreach ($this->_errors as $field => $set) { $error = array_shift($set); $params = array_shift($set); $label = $this->_labels[$field]; if ($translate) { $label = is_string($translate) ? __($label, null, $translate) : __($label); } $values = [':field' => $label, ':value' => Arr::get((array) $this, $field)]; if (is_array($values[':value'])) { $values[':value'] = implode(', ', Arr::flatten($values[':value'])); } if ($params) { foreach ($params as $key => $value) { if (is_array($value)) { $value = implode(', ', Arr::flatten($value)); } elseif (is_object($value)) { // 消息文件中不能使用对象 continue; } if (isset($this->_labels[$value])) { // 使用标签值作为值 $value = $this->_labels[$value]; if ($translate) { $value = is_string($translate) ? __($value, null, $translate) : __($value); } } // 绑定参数,从1开始 $values[':param' . ($key + 1)] = $value; } } // 直接读消息文本 $message = Message::load($file, "{$field}.{$error}"); // 尝试读取字段的默认说明 if (!$message) { $message = Message::load($file, "{$field}.default"); } // 尝试读取这个错误的通用提示 if (!$message) { $message = Message::load($file, $error); } // 从默认的校验错误列表中读取信息 if (!$message) { $message = Message::load('validation', $error); } // 最后都还是不行,那就直接返回 if (!$message) { $message = "{$file}.{$field}.{$error}"; } if ($translate) { $message = is_string($translate) ? __($message, $values, $translate) : __($message, $values); } else { $message = strtr($message, $values); } $messages[$field] = $message; } return $messages; }
/** * {@inheritdoc} */ public function code($code) { Base::getLog()->debug(__METHOD__ . ' response status code', ['code' => $code]); $text = Arr::get(self::$text, $code, false); if (!$text) { return; } $this->header($this->protocol . ' ' . $code . ' ' . $text); }
/** * 是否是外部链接 * * @return boolean */ public function isExternal() { return !in_array(Arr::get($this->_defaults, 'host', false), Route::$localHosts); }
/** * 解包 * * @param string $receiveBuffer * @return array */ public static function decode($receiveBuffer) { // 解包 $data = self::unpack($receiveBuffer); $module = substr($receiveBuffer, self::PACKAGE_FIXED_LENGTH, Arr::get($data, 'module_name_len')); $interface = substr($receiveBuffer, self::PACKAGE_FIXED_LENGTH + $data['module_name_len'], $data['interface_name_len']); $msg = substr($receiveBuffer, self::PACKAGE_FIXED_LENGTH + $data['module_name_len'] + $data['interface_name_len']); return ['module' => $module, 'interface' => $interface, 'cost_time' => $data['cost_time'], 'success' => $data['success'], 'time' => $data['time'], 'code' => $data['code'], 'msg' => $msg]; }
/** * {@inheritdoc} */ public function getReasonPhrase() { return Arr::get(Http::$text, $this->status, ''); }
/** * 覆盖原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); } }
/** * 测试[Arr::unshift]的功能 * * @dataProvider dataUnshift * @param mixed $key * @param mixed $val */ public function testUnshift($key, $val) { $arr = [uniqid(time()) => uniqid(), uniqid() => uniqid()]; Arr::unshift($arr, $key, $val); $this->assertEquals(true, Arr::get($arr, $key) === $val && array_search($key, $arr) == 0); }
/** * 加载指定的配置 * * @param string $name * @return bool * @throws \tourze\Server\Exception\BaseException */ public static function load($name) { if (!($config = Config::load('main')->get('server.' . $name))) { throw new BaseException('The requested config not found.'); } if (!($socketName = Arr::get($config, 'socketName'))) { throw new BaseException('The socket name should not be empty.'); } $config['name'] = $name; // 如果有自定义初始化的class名 if (isset($config['initClass'])) { $class = $config['initClass']; unset($config['initClass']); new $class($config); } else { // 根据socketName来判断,如果是http的话,有单独的处理 if (substr($socketName, 0, 4) == 'http') { new Web($config); } else { new Worker($config); } } return true; }
/** * 更新当前对象 * * @param Validation $validation Validation object * @throws ModelException * @return Model */ public function update(Validation $validation = null) { if (!$this->_loaded) { throw new ModelException('Cannot update :model model because it is not loaded.', [':model' => $this->_objectName]); } Base::getLog()->debug(__METHOD__ . ' update record'); // Run validation if the model isn't valid or we have additional validation rules. if (!$this->_valid || $validation) { $this->check($validation); } if (empty($this->_changed)) { // Nothing to update return $this; } $data = []; foreach ($this->_changed as $column) { // Compile changed data $data[$column] = $this->_object[$column]; } // 更新时,自动更新该字段 if (is_array($updatedColumn = $this->updatedColumn())) { $column = Arr::get($updatedColumn, 'column'); $format = Arr::get($updatedColumn, 'format'); $data[$column] = $this->_object[$column] = true === $format ? time() : date($format); } $id = $this->pk(); $query = $this->_db->createQueryBuilder()->update($this->_tableName)->where($this->_primaryKey . ' = :id')->setParameter(':id', $id); foreach ($data as $k => $v) { $query->set($k, ":{$k}"); $query->setParameter($k, $v); } $query->execute(); if (isset($data[$this->_primaryKey])) { // Primary key was changed, reflect it $this->_primaryKeyValue = $data[$this->_primaryKey]; } // Object has been saved $this->_saved = true; // All changes have been saved $this->_changed = []; $this->_originalValues = $this->_object; return $this; }
/** * 检测输入密码的强壮程度,并返回检测结果,结果越大,密码就越健壮 * * @param $password * @return int */ public static function strength($password) { $zxcvbn = new Zxcvbn(); $result = $zxcvbn->passwordStrength($password); return (int) Arr::get($result, 'score'); }
/** * 读取全局变量 * * @param string $key 键名 * @param mixed $default 默认值 * @return mixed */ public static function getGlobal($key, $default = null) { return Arr::get(self::$_globalData, $key, $default); }
/** * 格式化日志记录 * * @param string $str * @param string $date * @param array $codeMap * @return array */ public static function formatStatLog($str, $date, &$codeMap) { Base::getLog()->info(__METHOD__ . ' format stat log', ['str' => $str, 'date' => $date]); // time:[success_count:xx,success_cost_time:xx,fail_count:xx,fail_cost_time:xx] $stData = $codeMap = []; $lines = explode("\n", $str); // 汇总计算 foreach ($lines as $line) { // line = IP time success_count success_cost_time fail_count fail_cost_time code_json $lineData = explode("\t", $line); if (!isset($lineData[5])) { continue; } $timeLine = Arr::get($lineData, 1); $timeLine = intval(ceil($timeLine / 300) * 300); $successCount = Arr::get($lineData, 2); $successCostTime = Arr::get($lineData, 3); $failCount = Arr::get($lineData, 4); $failCostTime = Arr::get($lineData, 5); $codeMapList = json_decode($lineData[6], true); if (!isset($stData[$timeLine])) { $stData[$timeLine] = ['success_count' => 0, 'success_cost_time' => 0, 'fail_count' => 0, 'fail_cost_time' => 0]; } $stData[$timeLine]['success_count'] += $successCount; $stData[$timeLine]['success_cost_time'] += $successCostTime; $stData[$timeLine]['fail_count'] += $failCount; $stData[$timeLine]['fail_cost_time'] += $failCostTime; if (is_array($codeMapList)) { foreach ($codeMapList as $code => $count) { if (!isset($codeMap[$code])) { $codeMap[$code] = 0; } $codeMap[$code] += $count; } } } // 按照时间排序 ksort($stData); // time => [total_count:xx,success_count:xx,suc_avg_time:xx,fail_count:xx,fail_avg_time:xx,percent:xx] $data = []; // 计算成功率 耗时 foreach ($stData as $timeLine => $item) { $data[$timeLine] = ['time' => date('Y-m-d H:i:s', $timeLine), 'total_count' => $item['success_count'] + $item['fail_count'], 'total_avg_time' => $item['success_count'] + $item['fail_count'] == 0 ? 0 : round(($item['success_cost_time'] + $item['fail_cost_time']) / ($item['success_count'] + $item['fail_count']), 6), 'success_count' => $item['success_count'], 'suc_avg_time' => $item['success_count'] == 0 ? $item['success_count'] : round($item['success_cost_time'] / $item['success_count'], 6), 'fail_count' => $item['fail_count'], 'fail_avg_time' => $item['fail_count'] == 0 ? 0 : round($item['fail_cost_time'] / $item['fail_count'], 6), 'percent' => $item['success_count'] + $item['fail_count'] == 0 ? 0 : round($item['success_count'] * 100 / ($item['success_count'] + $item['fail_count']), 4)]; } $timePoint = strtotime($date); for ($i = 0; $i < 288; $i++) { $data[$timePoint] = isset($data[$timePoint]) ? $data[$timePoint] : ['time' => date('Y-m-d H:i:s', $timePoint), 'total_count' => 0, 'total_avg_time' => 0, 'success_count' => 0, 'suc_avg_time' => 0, 'fail_count' => 0, 'fail_avg_time' => 0, 'percent' => 100]; $timePoint += 300; } ksort($data); return $data; }
/** * 跟 [array_map](http://php.net/array_map) 类似的函数,差异在于这个函数只能处理单个数组 * * // 数组中的每个元素都执行一次strip_tags * $array = Arr::map($array, 'strip_tags'); * * // 数组中的每个元素都$this->filter过滤一次 * $array = Arr::map($array, [[$this,'filter']]); * * // 数组中的每个元素都执行strip_tags和$this->filter * $array = Arr::map($array, ['strip_tags', [$this,'filter'])]; * * @param array $array 要映射的数组 * @param callable $callbacks 包含了callback的数组,或者一个函数 * @param array $keys 只过滤这部分key * @return array */ public static function map($array, $callbacks, $keys = null) { foreach ($array as $key => $val) { if (is_array($val)) { $array[$key] = self::map($array[$key], $callbacks); } elseif (!is_array($keys) || in_array($key, $keys)) { if (is_array($callbacks)) { // 如果callbacks变量的第一个参数是object,那么久按照另外的逻辑处理 if (is_object(Arr::get($callbacks, 0))) { $callbacks = [[Arr::get($callbacks, 0), Arr::get($callbacks, 1)]]; // 后面的参数暂时忽略了 } // 继续正常逻辑走 foreach ($callbacks as $cb) { $array[$key] = call_user_func($cb, $array[$key]); } } else { $array[$key] = call_user_func($callbacks, $array[$key]); } } } return $array; }
/** * 从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; }
</td> <td><?php echo Arr::get($item, 'success_count'); ?> </td> <td><?php echo Arr::get($item, 'suc_avg_time'); ?> </td> <td><?php echo Arr::get($item, 'fail_count') > 0 ? new A(['href' => '/logger?' . $query . '&' . http_build_query(['start_time' => strtotime(Arr::get($item, 'time')) - 300, 'end_time' => strtotime(Arr::get($item, 'time'))])], Arr::get($item, 'fail_count')) : Arr::get($item, 'fail_count'); ?> </td> <td><?php echo Arr::get($item, 'fail_avg_time'); ?> </td> <td><?php echo Arr::get($item, 'percent'); ?> %</td> </tr> <?php } ?> </tbody> </table> </div> </div> </div>
/** * {@inheritdoc} */ public function get($name, $default = null) { Base::getLog()->debug(__METHOD__ . ' get session', ['name' => $name, 'default' => $default]); return Arr::get($_SESSION, $name, $default); }
/** * 单例模式,获取一个指定的实例 * * // 加载默认实例 * $db = Database::instance(); * * // 指定实例名称和配置 * $db = Database::instance('custom', $config); * * @param string $name 实例名 * @param array $config 配置参数 * @return Connection */ public static function instance($name = null, array $config = null) { if (null === $name) { $name = Db::$default; } if (!isset(Db::$instances[$name])) { // 读取配置 if (null === $config) { $config = (array) Config::load(self::$configFile)->get($name); Base::getLog()->debug(__METHOD__ . ' get default config', ['name' => $name]); } // 合并默认配置 if (isset(self::$defaultConfig[Arr::get($config, 'driver')])) { $config = Arr::merge(self::$defaultConfig[Arr::get($config, 'driver')], $config); Base::getLog()->debug(__METHOD__ . ' merge config', ['name' => $name]); } $conn = DriverManager::getConnection($config); Base::getLog()->debug(__METHOD__ . ' create dbal connection', ['name' => $name]); // 额外注册字段类型 if (isset(self::$mappingType[Arr::get($config, 'driver')])) { $platform = $conn->getDatabasePlatform(); foreach (self::$mappingType[Arr::get($config, 'driver')] as $dbType => $doctrineType) { if (!$platform->hasDoctrineTypeMappingFor($dbType)) { Base::getLog()->debug(__METHOD__ . ' add dbal mapping type', ['raw' => $dbType, 'dbal' => $doctrineType]); $platform->registerDoctrineTypeMapping($dbType, $doctrineType); } } } Db::$instances[$name] = $conn; Base::getLog()->debug(__METHOD__ . ' save db instance', ['name' => $name]); } return Db::$instances[$name]; }
/** * 保存(或替换)一个组件 * * @param string $name * @param array $config * @throws \tourze\Base\Exception\ComponentClassNotFoundException * @throws \tourze\Base\Exception\ComponentNotFoundException */ public static function set($name, array $config) { // 还是没有,那么抛出异常 if (!$config) { throw new ComponentNotFoundException('The requested component [:component] missing config.', [':component' => $name]); } $class = Arr::get($config, 'class'); if (!$class || !class_exists($class)) { throw new ComponentClassNotFoundException('The requested component class [:class] not found.', [':class' => $class]); } /** @var Component $instance */ $instance = new $class(Arr::get($config, 'params', [])); foreach (Arr::get($config, 'call', []) as $method => $args) { call_user_func_array([$instance, $method], $args); } self::$components[$name] = $instance; }
/** * 当前模型有改动过的数据信息 * * @param string $field field to check for changes * * @return bool Whether or not the field has changed */ public function changed($field = null) { return null === $field ? $this->_changed : Arr::get($this->_changed, $field); }
/** * 获得指定模块的统计数据 * * @param string $module * @param string $interface * @param int $date * @return bool/string */ protected function getStatistic($date, $module, $interface) { if (empty($module) || empty($interface)) { return ''; } // log文件 $logFile = Config::load('statServer')->get('dataPath') . $this->statDir . "{$module}/{$interface}.{$date}"; $handle = @fopen($logFile, 'r'); if (!$handle) { return ''; } // 预处理统计数据,每5分钟一行 // [time=>[ip=>['success_count'=>xx, 'success_cost_time'=>xx, 'fail_count'=>xx, 'fail_cost_time'=>xx, 'code_map'=>[code=>count, ..], ..], ..] $statData = []; while (!feof($handle)) { $line = fgets($handle, 4096); if ($line) { $columns = explode("\t", $line); if (count($columns) < 7) { continue; } list($ip, $time, $successCount, $successCostTime, $failCount, $failCostTime, $codeMap) = $columns; $time = intval(ceil($time / 300) * 300); if (!isset($statData[$time])) { $statData[$time] = []; } if (!isset($statData[$time][$ip])) { $statData[$time][$ip] = ['success_count' => 0, 'success_cost_time' => 0, 'fail_count' => 0, 'fail_cost_time' => 0, 'code_map' => []]; } $statData[$time][$ip]['success_count'] += $successCount; $statData[$time][$ip]['success_cost_time'] += round($successCostTime, 5); $statData[$time][$ip]['fail_count'] += $failCount; $statData[$time][$ip]['fail_cost_time'] += round($failCostTime, 5); $codeMap = json_decode(trim($codeMap), true); if ($codeMap && is_array($codeMap)) { foreach ($codeMap as $code => $count) { if (!isset($statData[$time][$ip]['code_map'][$code])) { $statData[$time][$ip]['code_map'][$code] = 0; } $statData[$time][$ip]['code_map'][$code] += $count; } } } // end if } // end while fclose($handle); ksort($statData); // 整理数据 $result = ''; foreach ($statData as $time => $items) { foreach ($items as $ip => $item) { $line = [$ip, $time, Arr::get($item, 'success_count'), Arr::get($item, 'success_cost_time'), Arr::get($item, 'fail_count'), Arr::get($item, 'fail_cost_time'), json_encode(Arr::get($item, 'code_map'))]; $result .= implode("\t", $line) . "\n"; } } return $result; }