/** * 输出数据 * */ public function display() { header('Content-Type: application/json;charset=' . Config::get('default_charset')); if ($GLOBALS['debug']) { $sqls = Debug::getSqls(); if (isset($sqls[0])) { $this->args['sql'] = implode($sqls, ', '); } } Plugin::hook('cml.before_cml_stop'); exit(json_encode($this->args, PHP_VERSION >= '5.4.0' ? JSON_UNESCAPED_UNICODE : 0)); }
/** * 执行预处理语句 * * @param object $stmt PDOStatement * @param bool $clearBindParams * * @return bool */ public function execute($stmt, $clearBindParams = true) { //empty($param) && $param = $this->bindParams; $this->conf['log_slow_sql'] && ($startQueryTimeStamp = microtime(true)); if (!$stmt->execute()) { $error = $stmt->errorInfo(); throw new \InvalidArgumentException('Pdo execute Sql error!,【Sql : ' . $this->buildDebugSql() . '】,【Error:' . $error[2] . '】'); } $slow = 0; if ($this->conf['log_slow_sql']) { $queryTime = microtime(true) - $startQueryTimeStamp; if ($queryTime > $this->conf['log_slow_sql']) { if (Plugin::hook('cml.mysql_query_slow', ['sql' => $this->buildDebugSql(), 'query_time' => $queryTime]) !== false) { Log::notice('slow_sql', ['sql' => $this->buildDebugSql(), 'query_time' => $queryTime]); } $slow = $queryTime; } } if (Cml::$debug) { $this->debugLogSql($slow > 0 ? Debug::SQL_TYPE_SLOW : Debug::SQL_TYPE_NORMAL, $slow); } $this->currentSql = ''; $clearBindParams && $this->clearBindParams(); return true; }
/** * 根据key获取redis实例 * 这边还是用取模的方式,一致性hash用php实现性能开销过大。取模的方式对只有几台机器的情况足够用了 * 如果有集群需要,直接使用redis3.0+自带的集群功能就好了。不管是可用性还是性能都比用php自己实现好 * * @param $key * * @return \Redis */ private function hash($key) { $serverNum = count($this->conf['server']); $success = sprintf('%u', crc32($key)) % $serverNum; if (!isset($this->redis[$success]) || !is_object($this->redis[$success])) { $instance = new \Redis(); $connectToRedisFunction = function ($host, $port, $isPersistentConnect) use($instance) { if ($isPersistentConnect) { return $instance->pconnect($host, $port, 1.5); } else { return $instance->connect($host, $port, 1.5); } }; $isPersistentConnect = !(isset($this->conf['server'][$success]['pconnect']) && $this->conf['server'][$success]['pconnect'] === false); $connectResult = $connectToRedisFunction($this->conf['server'][$success]['host'], $this->conf['server'][$success]['port'], $isPersistentConnect); $failOver = null; if (!$connectResult && !empty($this->conf['back'])) { $failOver = $this->conf['back']; $isPersistentConnect = !(isset($failOver['pconnect']) && $failOver['pconnect'] === false); $connectResult = $connectToRedisFunction($failOver['host'], $failOver['port'], $isPersistentConnect); } if (!$connectResult && $serverNum > 1) { $failOver = $success + 1; $failOver >= $serverNum && ($failOver = $success - 1); $failOver = $this->conf['server'][$failOver]; $isPersistentConnect = !(isset($failOver['pconnect']) && $failOver['pconnect'] === false); $connectResult = $connectToRedisFunction($failOver['host'], $failOver['port'], $isPersistentConnect); } if (!$connectResult) { Plugin::hook('cml.cache_server_down', [$this->conf['server'][$success]]); throw new CacheConnectFailException(Lang::get('_CACHE_CONNECT_FAIL_', 'Redis', $this->conf['server'][$success]['host'] . ':' . $this->conf['server'][$success]['port'])); } $password = false; if (is_null($failOver)) { if (isset($this->conf['server'][$success]['password']) && !empty($this->conf['server'][$success]['password'])) { $password = $this->conf['server'][$success]['password']; } isset($this->conf['server'][$success]['db']) && $instance->select($this->conf['server'][$success]['db']); } else { if (isset($failOver['password']) && !empty($failOver['password'])) { $password = $failOver['password']; } isset($failOver['db']) && $instance->select($failOver['db']); Log::emergency('redis server down', ['downServer' => $this->conf['server'][$success], 'failOverTo' => $failOver]); Plugin::hook('cml.redis_server_down_fail_over', ['downServer' => $this->conf['server'][$success], 'failOverTo' => $failOver]); } if ($password && !$instance->auth($password)) { throw new \RuntimeException('redis password error!'); } $instance->setOption(\Redis::OPT_PREFIX, $this->conf['prefix']); $this->redis[$success] = $instance; } return $this->redis[$success]; }
/** * 未找到控制器的时候设置勾子 * */ public static function montFor404Page() { Plugin::mount('cml.before_show_404_page', [function () { $cmdLists = Config::get('cmlframework_system_command'); $cmd = strtolower(trim(Cml::getContainer()->make('cml_route')->getAppName(), '/')); if (isset($cmdLists[$cmd])) { call_user_func($cmdLists[$cmd]); } }]); Plugin::hook('cml.before_show_404_page'); }
/** * 使用的缓存配置 默认为使用default_cache配置的参数 * * @param bool|array $conf * * @throws CacheConnectFailException | PhpExtendNotInstall */ public function __construct($conf = false) { $this->conf = $conf ? $conf : Config::get('default_cache'); if (extension_loaded('Memcached')) { $this->memcache = new \Memcached('cml_memcache_pool'); $this->type = 1; } elseif (extension_loaded('Memcache')) { $this->memcache = new \Memcache(); $this->type = 2; } else { throw new PhpExtendNotInstall(Lang::get('_CACHE_EXTEND_NOT_INSTALL_', 'Memcached/Memcache')); } if (!$this->memcache) { throw new PhpExtendNotInstall(Lang::get('_CACHE_NEW_INSTANCE_ERROR_', 'Memcache')); } $singleNodeDownFunction = function ($host, $port) { //这边挂掉调用此回调在几s内只会调用一次。其它情况使用memcache方法均返回flase不报错 Plugin::hook('cml.cache_server_down', ['host' => $host, 'port' => $port]); Log::emergency('memcache server down', ['downServer' => ['host' => $host, 'port' => $port]]); }; $allNodeDownFunction = function ($serverList) { Plugin::hook('cml.cache_server_down', $this->conf['server'], $serverList); //全挂 throw new CacheConnectFailException(Lang::get('_CACHE_CONNECT_FAIL_', 'Memcache', json_encode($serverList))); }; $downServer = 0; if ($this->type == 2) { //memcache foreach ($this->conf['server'] as $val) { if (!$this->memcache->addServer($val['host'], $val['port'])) { Log::emergency('memcache server down', ['downServer' => $val]); } } $this->memcache->setFailureCallback($singleNodeDownFunction); $serverList = $this->memcache->getextendedstats(); foreach ($serverList as $server => $status) { $status || $downServer++; } if (count($serverList) <= $downServer) { $allNodeDownFunction($serverList); } return; } if (md5(json_encode($this->conf['server'])) !== md5(json_encode($this->memcache->getServerList()))) { $this->memcache->quit(); $this->memcache->resetServerList(); $this->memcache->addServers(array_values($this->conf['server'])); $this->memcache->setOptions([\Memcached::OPT_PREFIX_KEY => $this->conf['prefix'], \Memcached::OPT_DISTRIBUTION => \Memcached::DISTRIBUTION_CONSISTENT, \Memcached::OPT_LIBKETAMA_COMPATIBLE => true, \Memcached::OPT_SERVER_FAILURE_LIMIT => 1, \Memcached::OPT_RETRY_TIMEOUT => 30, \Memcached::OPT_AUTO_EJECT_HOSTS => true, \Memcached::OPT_REMOVE_FAILED_SERVERS => true]); \Memcached::HAVE_JSON && $this->memcache->setOption(\Memcached::OPT_SERIALIZER, \Memcached::SERIALIZER_JSON_ARRAY); } $serverStatus = $this->memcache->getStats(); foreach ($serverStatus as $server => $status) { if ($status['pid'] < 1) { $downServer++; $server = explode(':', $server); $singleNodeDownFunction($server[0], $server[1]); } } if (count($serverStatus) <= $downServer) { $allNodeDownFunction($serverStatus); } }
/** * 生成Excel文件 * * @param string $filename * * @return void */ public function display($filename = '') { $filename == '' && ($filename = 'excel'); $this->config('utf-8', false, 'default', $filename); header("Content-Type: application/vnd.ms-excel; charset=" . $this->coding); header("Content-Disposition: inline; filename=\"" . $this->filename . ".xls\""); /*打印*/ echo stripslashes(sprintf($this->header, $this->coding)); echo "\n<Worksheet ss:Name=\"" . $this->tWorksheetTitle . "\">\n<Table>\n"; foreach ($this->args as $val) { $rows = $this->addRow($val); echo "<Row>\n" . $rows . "</Row>\n"; } echo "</Table>\n</Worksheet>\n"; echo "</Workbook>"; Plugin::hook('cml.before_cml_stop'); exit; }
/** * 程序中并输出调试信息 * */ public static function cmlStop() { Plugin::hook('cml.before_cml_stop'); //输出Debug模式的信息 if ($GLOBALS['debug']) { header('Content-Type:text/html; charset=' . Config::get('default_charset')); Debug::stop(); } else { $deBugLogData = dump('', 1); if (!empty($deBugLogData)) { require CML_PATH . DIRECTORY_SEPARATOR . 'Cml' . DIRECTORY_SEPARATOR . 'ConsoleLog.php'; } CML_OB_START && ob_end_flush(); exit; } }
/** * 输出数据 * */ public function display() { header('Content-Type: application/xml;charset=' . Config::get('default_charset')); Plugin::hook('cml.before_cml_stop'); exit($this->array2xml($this->args)); }
/** * 挂载插件钩子 * */ public function __destruct() { Plugin::hook('cml.run_controller_end'); }
/** * 未找到控制器的时候设置勾子 * */ public static function montFor404Page() { Plugin::mount('cml.before_show_404_page', array(function () { $cmdLists = Config::get('cmlframework_system_command'); $cmd = strtolower(trim(Route::$urlParams['path'], DIRECTORY_SEPARATOR)); if (isset($cmdLists[$cmd])) { call_user_func($cmdLists[$cmd]); } })); Plugin::hook('cml.before_show_404_page'); }