/** * 自定义异常处理 * * @param mixed $e 异常对象 */ public function appException(&$e) { if (Cml::$debug) { $run = new Run(); $run->pushHandler(Request::isCli() ? new PlainTextHandler() : new PrettyPageHandler()); $run->handleException($e); } else { $error = []; $error['message'] = $e->getMessage(); $trace = $e->getTrace(); $error['files'][0] = $trace[0]; if (substr($e->getFile(), -20) !== '\\Tools\\functions.php' || $e->getLine() !== 90) { array_unshift($error['files'], ['file' => $e->getFile(), 'line' => $e->getLine(), 'type' => 'throw']); } //正式环境 只显示‘系统错误’并将错误信息记录到日志 Log::emergency($error['message'], [$error['files'][0]]); $error = []; $error['message'] = Lang::get('_CML_ERROR_'); if (Request::isCli()) { \Cml\pd($error); } else { header('HTTP/1.1 500 Internal Server Error'); View::getEngine('html')->reset()->assign('error', $error); Cml::showSystemTemplate(Config::get('html_exception')); } } exit; }
public static function createSymbolicLink($rootDir = null) { CML_IS_MULTI_MODULES || exit('please set is_multi_modules => true'); $deper = Request::isCli() ? PHP_EOL : '<br />'; echo "{$deper}**************************=create link start!*********************{$deper}"; echo '|' . str_pad('', 64, ' ', STR_PAD_BOTH) . '|'; is_null($rootDir) && ($rootDir = CML_PROJECT_PATH . DIRECTORY_SEPARATOR . 'public'); is_dir($rootDir) || mkdir($rootDir, true, 0700); //modules_static_path_name // 递归遍历目录 $dirIterator = new \DirectoryIterator(CML_APP_MODULES_PATH); foreach ($dirIterator as $file) { if (!$file->isDot() && $file->isDir()) { $resourceDir = $file->getPathName() . DIRECTORY_SEPARATOR . Config::get('modules_static_path_name'); if (is_dir($resourceDir)) { $distDir = CML_PROJECT_PATH . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR . $file->getFilename(); $cmd = Request::operatingSystem() ? "mklink /d {$distDir} {$resourceDir}" : "ln -s {$resourceDir} {$distDir}"; exec($cmd, $result); $tip = "create link Application [{$file->getFilename()}] result : [" . (is_dir($distDir) ? 'true' : 'false') . "]"; $tip = str_pad($tip, 64, ' ', STR_PAD_BOTH); print_r($deper . '|' . $tip . '|'); } } } echo $deper . '|' . str_pad('', 64, ' ', STR_PAD_BOTH) . '|'; echo "{$deper}****************************create link end!**********************{$deper}"; }
/** * 生成软链接 * * @param null $rootDir 站点静态文件根目录默认为项目目录下的public目录 */ public static function createSymbolicLink($rootDir = null) { $isCli = Request::isCli(); if ($isCli) { Output::writeln(Colour::colour('create link start!', [Colour::GREEN, Colour::HIGHLIGHT])); } else { echo "<br />**************************create link start!*********************<br />"; } is_null($rootDir) && ($rootDir = CML_PROJECT_PATH . DIRECTORY_SEPARATOR . 'public'); is_dir($rootDir) || mkdir($rootDir, true, 0700); //modules_static_path_name // 递归遍历目录 $dirIterator = new \DirectoryIterator(Cml::getApplicationDir('apps_path')); foreach ($dirIterator as $file) { if (!$file->isDot() && $file->isDir()) { $resourceDir = $file->getPathname() . DIRECTORY_SEPARATOR . Cml::getApplicationDir('app_static_path_name'); if (is_dir($resourceDir)) { $distDir = $rootDir . DIRECTORY_SEPARATOR . $file->getFilename(); $cmd = Request::operatingSystem() ? "mklink /d {$distDir} {$resourceDir}" : "ln -s {$resourceDir} {$distDir}"; is_dir($distDir) || exec($cmd, $result); $tip = " create link Application [{$file->getFilename()}] result : [" . (is_dir($distDir) ? 'true' : 'false') . "]"; if ($isCli) { Output::writeln(Colour::colour($tip, [Colour::WHITE, Colour::HIGHLIGHT])); } else { print_r('|<span style="color:blue">' . str_pad($tip, 64, ' ', STR_PAD_BOTH) . '</span>|'); } } } } if ($isCli) { Output::writeln(Colour::colour('create link end!', [Colour::GREEN, Colour::HIGHLIGHT])); } else { echo "<br />****************************create link end!**********************<br />"; } }
/** * 自定义异常处理 * * @param mixed $e 异常对象 */ public function appException(&$e) { $error = []; $exceptionClass = new \ReflectionClass($e); $error['exception'] = '\\' . $exceptionClass->name; $error['message'] = $e->getMessage(); $trace = $e->getTrace(); foreach ($trace as $key => $val) { $error['files'][$key] = $val; } if (substr($e->getFile(), -20) !== '\\Tools\\functions.php' || $e->getLine() !== 90) { array_unshift($error['files'], ['file' => $e->getFile(), 'line' => $e->getLine(), 'type' => 'throw']); } if (!Cml::$debug) { //正式环境 只显示‘系统错误’并将错误信息记录到日志 Log::emergency($error['message'], [$error['files'][0]]); $error = []; $error['message'] = Lang::get('_CML_ERROR_'); } if (Request::isCli()) { pd($error); } else { header('HTTP/1.1 500 Internal Server Error'); View::getEngine('html')->reset()->assign('error', $error); Cml::showSystemTemplate(Config::get('html_exception')); } }
/** * 判断从命令行执行的系统命令 * */ public static function runCliCommand() { Request::isCli() || exit('please run on cli!'); if ($_SERVER['argv'][1] != 'cml.cmd') { return; } $deper = Request::isCli() ? PHP_EOL : '<br />'; echo $deper . $deper . "//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^{$deper}"; echo "//^^^^^^^^^^^^^^^^^^^^^^^^^ cml.cmd start! ^^^^^^^^^^^^^^^^^^^{$deper}"; call_user_func('\\Cml\\Tools\\' . $_SERVER['argv'][2]); echo $deper . $deper . "//^^^^^^^^^^^^^^^^^^^^^^^^^ cml.cmd end! ^^^^^^^^^^^^^^^^^^^^^^^^^{$deper}"; echo "//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^{$deper}"; exit; }
/** * 解析url获取pathinfo * * @return void */ public static function parsePathInfo() { $urlModel = Config::get('url_model'); $pathInfo = self::$pathInfo; if (empty($pathInfo)) { $isCli = Request::isCli(); //是否为命令行访问 if ($isCli) { isset($_SERVER['argv'][1]) && ($pathInfo = explode('/', $_SERVER['argv'][1])); } else { if ($urlModel === 1 || $urlModel === 2) { //pathInfo模式(含显示、隐藏index.php两种)SCRIPT_NAME if (isset($_GET[Config::get('var_pathinfo')])) { $param = $_GET[Config::get('var_pathinfo')]; } else { $param = preg_replace('/(.*)\\/(.*)\\.php(.*)/i', '\\1\\3', $_SERVER['REQUEST_URI']); $scriptName = preg_replace('/(.*)\\/(.*)\\.php(.*)/i', '\\1', $_SERVER['SCRIPT_NAME']); if (!empty($scriptName)) { $param = substr($param, strpos($param, $scriptName) + strlen($scriptName)); } } $param = ltrim($param, '/'); if (!empty($param)) { //无参数时直接跳过取默认操作 //获取参数 $pathInfo = explode(Config::get('url_pathinfo_depr'), trim(preg_replace(['/\\' . Config::get('url_html_suffix') . '/', '/\\&.*/', '/\\?.*/'], '', $param), Config::get('url_pathinfo_depr'))); } } elseif ($urlModel === 3 && isset($_GET[Config::get('var_pathinfo')])) { //兼容模式 $urlString = $_GET[Config::get('var_pathinfo')]; unset($_GET[Config::get('var_pathinfo')]); $pathInfo = explode(Config::get('url_pathinfo_depr'), trim(str_replace(Config::get('url_html_suffix'), '', ltrim($urlString, '/')), Config::get('url_pathinfo_depr'))); } } } isset($pathInfo[0]) && empty($pathInfo[0]) && ($pathInfo = []); //参数不完整获取默认配置 if (empty($pathInfo)) { $pathInfo = explode('/', trim(Config::get('url_default_action'), '/')); } self::$pathInfo = $pathInfo; }
public static function init() { if (Request::isCli()) { self::$isLocal = 'cli'; return true; } switch ($_SERVER['HTTP_HOST']) { case $_SERVER['SERVER_ADDR']: // no break // no break case '127.0.0.1': //no break //no break case 'localhost': self::$isLocal = 'development'; return true; } if (isset($_SERVER['SERVER_NAME'])) { $host = $_SERVER['SERVER_NAME']; } else { $host = $_SERVER['HTTP_HOST']; if ($_SERVER['SERVER_PORT'] != 80) { $host = explode(':', $host); $host = $host[0]; } } $domain = substr($host, strrpos($host, '.') + 1); if ($domain == 'dev' || $domain == 'loc') { self::$isLocal = 'development'; return true; } if (substr($_SERVER['HTTP_HOST'], 0, strpos($_SERVER['HTTP_HOST'], '.')) == '192') { self::$isLocal = 'development'; } return true; }
/** * 输出调试消息 * * @return void */ private static function showCmlPHPConsole() { if (Request::isAjax()) { $debugInfo = json_encode(array('sql' => self::$sqls, 'tipInfo' => self::$tipInfo), PHP_VERSION >= '5.4.0' ? JSON_UNESCAPED_UNICODE : 0); echo <<<str <script> console.log({$debugInfo}); </script> str; } else { echo '<div id="cmlphp_console_info" style="letter-spacing: -.0em;position: fixed;bottom:0;right:0;font-size:14px;width:100%;z-index: 999999;color: #000;text-align:left;font-family:\'微软雅黑\';"> <div id="cmlphp_console_info_switch" style="height: 26px; bottom: 0px; color: rgb(0, 0, 0); line-height: 26px; cursor: pointer; display: block; width: 100%; border-bottom: 3px rgb(255, 102, 0) solid;"> <div style="background:#232323;color:#FFF;padding:0 6px;height:27px; line-height:27px;font-size:14px;width: 110px;margin:0 auto;">CmlPHP控制台</div> </div> <div id="cmlphp_console_info_content" style="display: none;background:white;margin:0;height: 390px;"> <div style="height:30px;padding: 6px 12px 0;border-bottom:1px solid #ececec;border-top:1px solid #ececec;font-size:16px"> <span style="color:#000;padding-right:12px;height:30px;line-height: 30px;display:inline-block;margin-right:3px;cursor: pointer;font-weight:700">CmlPHP运行信息</span> </div> <div style="overflow:auto;height:352px;padding: 0; line-height: 24px"> <ul style="padding: 0; margin:0"> <li style="border-bottom:1px solid #EEE;font-size:14px;padding:0 12px"> <b>运行信息</b>( 消耗时间<font color="red">' . self::useTime() . ' </font>秒)(消耗内存<font color="red">' . self::useMemory() . ' </font>)</span> </li>'; if (count(self::$includefile) > 0) { echo '<li style="border-bottom:1px solid #EEE;font-size:14px;padding:0 12px;font-weight:bold;"><b>包含类库</b></li><li style="font-size:14px;padding:0 0px 0 50px;">'; foreach (self::$includefile as $file) { echo "<span style='padding-left:10px;'>【{$file}】</span>"; } echo '</li>'; } if (count(self::$tipInfo) > 0) { echo '<li style="border-bottom:1px solid #EEE;font-size:14px;padding:0 12px;font-weight:bold;"><b>系统信息</b></li>'; foreach (self::$tipInfo as $info) { echo "<li style='font-size:14px;padding:0 0px 0 60px;'>{$info}</li>"; } } if (count(self::$sqls) > 0) { echo '<li style="border-bottom:1px solid #EEE;font-size:14px;padding:0 12px;font-weight:bold;"><b>SQL语句</b></li>'; foreach (self::$sqls as $sql) { echo "<li style='font-size:14px;padding:0 0px 0 60px;'>{$sql}</li>"; } } echo '</ul> </div> </div> </div> <script type="text/javascript"> (function(){ var show = false; var switchShow = document.getElementById(\'cmlphp_console_info_switch\'); var trace = document.getElementById(\'cmlphp_console_info_content\'); switchShow.onclick = function(){ trace.style.display = show ? \'none\' : \'block\'; show = show ? false : true; } })(); </script>'; } }
/** * 打印一行 * * @param string $msg * * @return void */ private static function printMessage($msg) { $deper = Request::isCli() ? PHP_EOL : '<br />'; echo $deper . $msg . $deper; }
/** * 类加载-设置全局TOKEN,防止CSRF攻击 * * @return void */ public static function setToken() { if (!isset($_COOKIE['CML_TOKEN']) || empty($_COOKIE['CML_TOKEN'])) { $str = substr(md5(Cml::$nowTime . Request::getService('HTTP_USER_AGENT')), 5, 8); setcookie('CML_TOKEN', $str, null, '/'); $_COOKIE['CML_TOKEN'] = $str; } }
/** * 初始化运行环境 * * @param callable $initDi 注入依赖 */ private static function init($initDi) { define('CML_PATH', dirname(__DIR__)); //框架的路径 define('CML_CORE_PATH', CML_PATH . DIRECTORY_SEPARATOR . 'Cml'); // 系统核心类库目录 define('CML_EXTEND_PATH', CML_PATH . DIRECTORY_SEPARATOR . 'Vendor'); // 系统扩展类库目录 self::handleConfigLang(); //后面自动载入的类都会自动收集到Debug类下 spl_autoload_register('Cml\\Cml::autoloadComposerAdditional', true, true); //初始化依赖 $initDi(); //包含框架中的框架函数库文件 Cml::requireFile(CML_CORE_PATH . DIRECTORY_SEPARATOR . 'Tools' . DIRECTORY_SEPARATOR . 'functions.php'); //设置自定义捕获致命异常函数 //普通错误由Cml\Debug::catcher捕获 php默认在display_errors为On时致命错误直接输出 为off时 直接显示服务器错误或空白页,体验不好 register_shutdown_function(function () { if ($error = error_get_last()) { //获取最后一个发生的错误的信息。 包括提醒、警告、致命错误 if (in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING])) { //当捕获到的错误为致命错误时 报告 if (Plugin::hook('cml.before_fatal_error', $error) == 'jump') { return; } Cml::getContainer()->make('cml_error_or_exception')->fatalError($error); Plugin::hook('cml.after_fatal_error', $error); } } Plugin::hook('cml.before_cml_stop'); }); //捕获致命异常 //设置自定义的异常处理函数。 set_exception_handler(function ($e) { if (Plugin::hook('cml.before_throw_exception', $e) === 'resume') { return; } Cml::getContainer()->make('cml_error_or_exception')->appException($e); }); //手动抛出的异常由此函数捕获 ini_set('display_errors', 'off'); //屏蔽系统自带的错误输出 //载入插件配置文件 $pluginConfig = Cml::getApplicationDir('global_config_path') . DIRECTORY_SEPARATOR . 'plugin.php'; is_file($pluginConfig) && Cml::requireFile($pluginConfig); Plugin::hook('cml.before_set_time_zone'); //用于动态设置时区等。 date_default_timezone_set(Config::get('time_zone')); //设置时区 self::$nowTime = time(); self::$nowMicroTime = microtime(true); //全局的自定义语言包 $globalLang = Cml::getApplicationDir('global_lang_path') . DIRECTORY_SEPARATOR . Config::get('lang') . '.php'; is_file($globalLang) && Lang::set(Cml::requireFile($globalLang)); //设置调试模式 if (Cml::$debug) { Debug::start(); //记录开始运行时间\内存初始使用 //设置捕获系统异常 使用set_error_handler()后,error_reporting将会失效。所有的错误都会交给set_error_handler。 set_error_handler('\\Cml\\Debug::catcher'); Debug::addTipInfo(Lang::get('_CML_DEBUG_ADD_CLASS_TIP_', 'Cml\\Cml'), Debug::TIP_INFO_TYPE_INCLUDE_LIB); Debug::addTipInfo(Lang::get('_CML_DEBUG_ADD_CLASS_TIP_', 'Cml\\Config'), Debug::TIP_INFO_TYPE_INCLUDE_LIB); Debug::addTipInfo(Lang::get('_CML_DEBUG_ADD_CLASS_TIP_', 'Cml\\Lang'), Debug::TIP_INFO_TYPE_INCLUDE_LIB); Debug::addTipInfo(Lang::get('_CML_DEBUG_ADD_CLASS_TIP_', 'Cml\\Http\\Request'), Debug::TIP_INFO_TYPE_INCLUDE_LIB); Debug::addTipInfo(Lang::get('_CML_DEBUG_ADD_CLASS_TIP_', 'Cml\\Debug'), Debug::TIP_INFO_TYPE_INCLUDE_LIB); $runTimeClassList = null; } else { $GLOBALS['debug'] = false; //关闭debug //ini_set('error_reporting', E_ALL & ~E_NOTICE);//记录除了notice之外的错误 ini_set('log_errors', 'off'); //关闭php自带错误日志 //严重错误已经通过fatalError记录。为了防止日志过多,默认不记录致命错误以外的日志。有需要可以修改配置开启 if (Config::get('log_warn_log')) { set_error_handler('\\Cml\\Log::catcherPhpError'); } //线上模式包含runtime.php $runTimeFile = Cml::getApplicationDir('global_store_path') . DIRECTORY_SEPARATOR . '_runtime_.php'; if (!is_file($runTimeFile)) { //程序运行必须的类 $runTimeClassList = [CML_CORE_PATH . DIRECTORY_SEPARATOR . 'Controller.php', CML_CORE_PATH . DIRECTORY_SEPARATOR . 'Http' . DIRECTORY_SEPARATOR . 'Response.php', CML_CORE_PATH . DIRECTORY_SEPARATOR . 'Route.php', CML_CORE_PATH . DIRECTORY_SEPARATOR . 'Secure.php']; Config::get('session_user') && ($runTimeClassList[] = CML_CORE_PATH . DIRECTORY_SEPARATOR . 'Session.php'); $runTimeContent = '<?php'; foreach ($runTimeClassList as $file) { $runTimeContent .= str_replace(['<?php', '?>'], '', php_strip_whitespace($file)); } file_put_contents($runTimeFile, $runTimeContent, LOCK_EX); $runTimeContent = null; } Cml::requireFile($runTimeFile); } if (Request::isCli()) { RunCliCommand::runCliCommand(); } else { header('X-Powered-By:CmlPHP'); // 页面压缩输出支持 if (Config::get('output_encode')) { $zlib = ini_get('zlib.output_compression'); if (empty($zlib)) { ///@ob_end_clean () ; //防止在启动ob_start()之前程序已经有输出(比如配置文件尾多敲了换行)会导致服务器303错误 ob_start('ob_gzhandler') || ob_start(); define('CML_OB_START', true); } else { define('CML_OB_START', false); } } } Plugin::hook('cml.before_parse_url'); //载入路由 $routeConfigFile = Cml::getApplicationDir('global_config_path') . DIRECTORY_SEPARATOR . 'route.php'; is_file($routeConfigFile) && Cml::requireFile($routeConfigFile); Cml::getContainer()->make('cml_route')->parseUrl(); //解析处理URL Plugin::hook('cml.after_parse_url'); //载入模块配置 $modulesConfig = Cml::getApplicationDir('apps_path') . '/' . Cml::getContainer()->make('cml_route')->getAppName() . '/' . Cml::getApplicationDir('app_config_path_name') . '/' . 'normal.php'; is_file($modulesConfig) && Config::set(Cml::requireFile($modulesConfig)); //载入模块语言包 $appLang = Cml::getApplicationDir('apps_path') . '/' . Cml::getContainer()->make('cml_route')->getAppName() . '/' . Cml::getApplicationDir('app_lang_path_name') . '/' . Config::get('lang') . '.php'; is_file($appLang) && Lang::set(Cml::requireFile($appLang)); }
/** * 输出调试消息 * * @return void */ private static function showCmlPHPConsole() { if (Request::isAjax()) { if (Config::get('dump_use_php_console')) { self::$sqls && \Cml\dumpUsePHPConsole(self::$sqls, 'sql'); \Cml\dumpUsePHPConsole(self::$tipInfo, 'tipInfo'); \Cml\dumpUsePHPConsole(self::$includefile, 'includeFile'); } else { $deBugLogData = array('tipInfo' => self::$tipInfo); self::$sqls && ($deBugLogData['sql'] = self::$sqls); if (!empty($deBugLogData)) { require CML_PATH . DIRECTORY_SEPARATOR . 'Cml' . DIRECTORY_SEPARATOR . 'ConsoleLog.php'; } } } else { echo '<div id="cmlphp_console_info" style="letter-spacing: -.0em;position: fixed;bottom:0;right:0;font-size:14px;width:100%;z-index: 999999;color: #000;text-align:left;font-family:\'微软雅黑\';"> <div id="cmlphp_console_info_switch" style="height: 28px; bottom: 0px; color: rgb(0, 0, 0); cursor: pointer; display: block; width: 100%; border-top: 3px rgb(255, 102, 0) solid;"> <div style="background:#232323;color:#FFF;padding:2px 6px;height:28px;font-size:14px;"> <span id="cmlphp_console_info_simpleinfo">消耗时间<i>' . self::useTime() . 's</i> 消耗内存<i>' . self::useMemory() . ' </i></span> <div style="float:right;margin:0 auto;width:110px;text-align:center;"> <svg id="cmlphp_console_info_logo" width="85" height="25" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <g> <rect fill="none" id="canvas_background" height="27" width="87" y="-1" x="-1"/> <g display="none" overflow="visible" y="0" x="0" height="100%" width="100%" id="canvasGrid"> <rect fill="url(#gridpattern)" stroke-width="0" y="0" x="0" height="100%" width="100%"/> </g> </g> <g> <image xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFUAAAAZCAYAAABAb2JNAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyFpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDowRjZFRTU5QUQ2MjAxMUU1QkFBREQ3NzMwM0IxOTZCRCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDowRjZFRTU5QkQ2MjAxMUU1QkFBREQ3NzMwM0IxOTZCRCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjBGNkVFNTk4RDYyMDExRTVCQUFERDc3MzAzQjE5NkJEIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjBGNkVFNTk5RDYyMDExRTVCQUFERDc3MzAzQjE5NkJEIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+IZdrVgAAAzVJREFUeNrsmEtuFDEQhsvt7k4mbJgcYTgCOUGU7JEQWXEFFigSuQLMErGBNTv2KBKIEyRHGI5ALyHpdpv6bVfbE/LohozEwpbc73GVv/qr7ERZaym3+21FRpChZqgZam4Zaoaaoeb2r6288c3+8oSPr0kBPR+U9Gu/3iVLDfU9Eba92PvKeXpbsJ0zNyauC7VyT2H3Zh8a7ods85xtLrif8fXuYD91I/VJqR983PPyGmUn2jo9Pp8GdX85d0C/vVJ3Injylqi33lnDwjcMFnDxDF5NBesnM3fnQjof4Iku/HsKgY6QnjG493y95+57Ox98wmsJNp6p4JMfZx5tcD89HjNfb0uCMUGpc9JqHIStyjtt2NGi99HtMNn+75QqmQGA6JUGVHL+6GIdfoTKCqXHgz3AM30Mdtf7exX8lKaVH7sMdsa07crbmpz+xZUJ3Aq1lEksqDWrIX3we8CODelymzNH3D+5SYoqax671hFwqYP6gtL64RpAYzqCW2f8e/SLlqhNgu0EkACFMLbLcfOd1eu2RkOVSY2LnFcBuk8j5RQrk4+qWrlaRPT1mlEO+FtOX4YKuxJUjD2rcL1iJS0cZBtUKGksgJCOLr0D1MvOeqj87U/twUKxgN0ar0wECedZTbTD/cXHL3x/4OyI2iUbROEPd5owj6lKLcZD/dXS4LwNAOGouqJ8LDpE34dFIIWO5z0WGArpHmocJvtgC2M9cs+rMkJJJyrZIcHAdck3UlNlPi1LtU3KSqWtAwgb6Mujw82t/lOUetGlhT9OLAUrKU1paQhQhwUlAKhCuiuKCiJaHzP9Ldn1GitKV0lAbVAwUl13cSxXXkpvA1A3uqUqimZw8k6orZ+XOIoz6uysThaeBKrUR1lA1gBRrKE2lBb0PqQ4xpcyY5JAplslG3YdoljnT3hXSn3uIlCMKXY2CvXzy4aevntDzz9YF0UAQupcGtQqr07ATPepTqGqcWoQ52VrZd2uoBmUg94FkJ0RlTbD4lGXjXvm6h4H2Fj6c7+cAqWodl9qvC0XZBVXdm1iqai1tyOKrXRzX1BV/id1/jM1Q81Qc8tQM9QMNbcM9T9svwUYANvRWSdKGhh9AAAAAElFTkSuQmCC" id="svg_1" height="25" width="85" y="0" x="0"/> </g> </svg><svg version="1.1" width=25 xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" height="24" viewBox="0 0 24 24" style="display:inline-block" enable-background="new 0 0 24 24" xml:space="preserve" id="cmlphp_console_info_minisize"> <path fill="#AAAAAA" d="M21.1,18.3c0.8,0.8,0.8,2,0,2.8c-0.4,0.4-0.9,0.6-1.4,0.6s-1-0.2-1.4-0.6L12,14.8l-6.3,6.3 c-0.4,0.4-0.9,0.6-1.4,0.6s-1-0.2-1.4-0.6c-0.8-0.8-0.8-2,0-2.8L9.2,12L2.9,5.7c-0.8-0.8-0.8-2,0-2.8c0.8-0.8,2-0.8,2.8,0L12,9.2 l6.3-6.3c0.8-0.8,2-0.8,2.8,0c0.8,0.8,0.8,2,0,2.8L14.8,12L21.1,18.3z"></path> </svg> </div> </div> </div> <div id="cmlphp_console_info_content" style="display: none;background:white;margin:0;height: 390px;"> <div style="height:30px;padding: 6px 12px 0;border-bottom:1px solid #ececec;border-top:1px solid #ececec;font-size:16px"> <span>运行信息</span> </div> <div style="overflow:auto;height:352px;padding: 0; line-height: 24px"> <ul style="padding: 0; margin:0"> '; if (count(self::$includefile) > 0) { echo '<li style="border-bottom:1px solid #EEE;font-size:14px;padding:0 12px;font-weight:bold;"><b>包含类库</b></li><li style="font-size:14px;padding:0 0px 0 50px;">'; foreach (self::$includefile as $file) { echo "<span style='padding-left:10px;'>【{$file}】</span>"; } echo '</li>'; } if (count(self::$tipInfo) > 0) { echo '<li style="border-bottom:1px solid #EEE;font-size:14px;padding:0 12px;font-weight:bold;"><b>系统信息</b></li>'; foreach (self::$tipInfo as $info) { echo "<li style='font-size:14px;padding:0 0px 0 60px;'>{$info}</li>"; } } if (count(self::$sqls) > 0) { echo '<li style="border-bottom:1px solid #EEE;font-size:14px;padding:0 12px;font-weight:bold;"><b>SQL语句</b></li>'; foreach (self::$sqls as $sql) { echo "<li style='font-size:14px;padding:0 0px 0 60px;'>{$sql}</li>"; } } echo '</ul> </div> </div> </div> <script type="text/javascript"> (function(){ var show = false; var switchShow = document.getElementById(\'cmlphp_console_info_switch\'); var trace = document.getElementById(\'cmlphp_console_info_content\'); var cmlphp_console_info_minisize = document.getElementById(\'cmlphp_console_info_minisize\'); var cmlphp_console_info = document.getElementById("cmlphp_console_info"); var cmlphp_console_info_simpleinfo = document.getElementById("cmlphp_console_info_simpleinfo"); var cmlphp_console_info_logo = document.getElementById("cmlphp_console_info_logo"); cmlphp_console_info_minisize.onclick = function() { cmlphp_console_info_minisize.style.display = "none"; show = true; trace.style.display = "none"; cmlphp_console_info.style.width = "110px"; cmlphp_console_info_simpleinfo.style.display="none" }; cmlphp_console_info_logo.onclick = function() { cmlphp_console_info_minisize.style.display = "inline-block"; cmlphp_console_info_simpleinfo.style.display="inline-block" cmlphp_console_info.style.width = "100%"; }; switchShow.onclick = function(){ trace.style.display = show ? \'none\' : \'block\'; show = show ? false : true; }; })(); </script>'; } }
/** * 解析url * * @return void */ public static function parseUrl() { $path = DIRECTORY_SEPARATOR; $urlModel = Config::get('url_model'); $pathinfo = array(); $isCli = Request::isCli(); //是否为命令行访问 if ($isCli) { isset($_SERVER['argv'][1]) && ($pathinfo = explode('/', $_SERVER['argv'][1])); } else { if ($urlModel === 1 || $urlModel === 2) { //pathinfo模式(含显示、隐藏index.php两种)SCRIPT_NAME if (isset($_GET[Config::get('var_pathinfo')])) { $param = $_GET[Config::get('var_pathinfo')]; } else { $param = preg_replace('/(.*)\\/(.*)\\.php(.*)/i', '\\1\\3', $_SERVER['REQUEST_URI']); $scriptName = preg_replace('/(.*)\\/(.*)\\.php(.*)/i', '\\1', $_SERVER['SCRIPT_NAME']); if (!empty($scriptName)) { $param = substr($param, strpos($param, $scriptName) + strlen($scriptName)); } } $param = ltrim($param, '/'); if (!empty($param)) { //无参数时直接跳过取默认操作 //获取参数 $pathinfo = explode(Config::get('url_pathinfo_depr'), trim(preg_replace(array('/\\' . Config::get('url_html_suffix') . '/', '/\\&.*/', '/\\?.*/'), '', $param), Config::get('url_pathinfo_depr'))); } } elseif ($urlModel === 3 && isset($_GET[Config::get('var_pathinfo')])) { //兼容模式 $urlString = $_GET[Config::get('var_pathinfo')]; unset($_GET[Config::get('var_pathinfo')]); $pathinfo = explode(Config::get('url_pathinfo_depr'), trim(str_replace(Config::get('url_html_suffix'), '', ltrim($urlString, '/')), Config::get('url_pathinfo_depr'))); } } isset($pathinfo[0]) && empty($pathinfo[0]) && ($pathinfo = array()); //参数不完整获取默认配置 if (empty($pathinfo)) { $pathinfo = explode('/', trim(Config::get('url_default_action'), '/')); } self::$pathinfo = $pathinfo; //检测路由 if (self::$rules) { //配置了路由,所有请求通过路由处理 $isRoute = self::isRoute($pathinfo); if ($isRoute[0]) { //匹配路由成功 $routeArr = explode('/', $isRoute['route']); $isRoute = null; self::$urlParams['action'] = array_pop($routeArr); self::$urlParams['controller'] = ucfirst(array_pop($routeArr)); while ($tmp = array_shift($routeArr)) { $path .= $tmp . DIRECTORY_SEPARATOR; } unset($routeArr); } else { self::findAction($pathinfo, $path); //未匹配到路由 按文件名映射查找 } } else { self::findAction($pathinfo, $path); //未匹配到路由 按文件名映射查找 } for ($i = 0; $i < count($pathinfo); $i += 2) { $_GET[$pathinfo[$i]] = $pathinfo[$i + 1]; } unset($pathinfo); if (self::$urlParams['controller'] == '') { //控制器没取到,这时程序会 中止/404,取$path最后1位当做控制器用于异常提醒 $tmp = explode(DIRECTORY_SEPARATOR, trim($path, DIRECTORY_SEPARATOR)); self::$urlParams['controller'] = ucfirst(array_pop($tmp)); $path = empty($tmp) ? '' : DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, $tmp) . DIRECTORY_SEPARATOR; } self::$urlParams['path'] = $path ? $path : DIRECTORY_SEPARATOR; unset($path); //定义URL常量 $spath = dirname($_SERVER['SCRIPT_NAME']); if ($spath == '/' || $spath == '\\') { $spath = ''; } //定义项目根目录地址 self::$urlParams['root'] = $spath . '/'; $_REQUEST = array_merge($_REQUEST, $_GET); }
/** * 初始化运行环境 * */ private static function init() { header('X-Powered-By:CmlPHP'); define('CML_PATH', dirname(__DIR__)); //框架的路径 //设置框架所有需要的路径 define('CML_APP_FULL_PATH', CML_PROJECT_PATH . DIRECTORY_SEPARATOR . CML_APP_PATH); define('CML_RUNTIME_PATH', CML_APP_FULL_PATH . DIRECTORY_SEPARATOR . 'Runtime'); define('CML_EXTEND_PATH', CML_PATH . DIRECTORY_SEPARATOR . 'Vendor'); // 系统扩展类库目录 //设置运行时文件路径 define('CML_RUNTIME_CACHE_PATH', CML_RUNTIME_PATH . DIRECTORY_SEPARATOR . 'Cache'); //系统缓存目录 define('CML_RUNTIME_LOGS_PATH', CML_RUNTIME_PATH . DIRECTORY_SEPARATOR . 'Logs'); //系统日志目录 define('CML_RUNTIME_DATA_PATH', CML_RUNTIME_PATH . DIRECTORY_SEPARATOR . 'Data'); //数据表的结构文件 self::handleConfigLang(); date_default_timezone_set(Config::get('time_zone')); //设置时区 self::$nowTime = time(); self::$nowMicroTime = microtime(true); //包含框架中的框架函数库文件 require CML_PATH . DIRECTORY_SEPARATOR . 'Cml' . DIRECTORY_SEPARATOR . 'Function' . DIRECTORY_SEPARATOR . 'function.php'; // 注册AUTOLOAD方法 //spl_autoload_register('Cml\Cml::autoload'); //设置自定义捕获致命异常函数 //普通错误由Cml\Debug::catcher捕获 php默认在display_errors为On时致命错误直接输出 为off时 直接显示服务器错误或空白页,体验不好 register_shutdown_function('Cml\\Cml::fatalError'); //捕获致命异常 //设置自定义的异常处理函数。 set_exception_handler('Cml\\Cml::appException'); //手动抛出的异常由此函数捕获 ini_set('display_errors', 'off'); //屏蔽系统自带的错误输出 //程序运行必须的类 $runTimeClassList = array(CML_PATH . DIRECTORY_SEPARATOR . 'Cml' . DIRECTORY_SEPARATOR . 'Controller.php', CML_PATH . DIRECTORY_SEPARATOR . 'Cml' . DIRECTORY_SEPARATOR . 'Http' . DIRECTORY_SEPARATOR . 'Response.php', CML_PATH . DIRECTORY_SEPARATOR . 'Cml' . DIRECTORY_SEPARATOR . 'Route.php', CML_PATH . DIRECTORY_SEPARATOR . 'Cml' . DIRECTORY_SEPARATOR . 'Secure.php'); Config::get('session_user') && ($runTimeClassList[] = CML_PATH . DIRECTORY_SEPARATOR . 'Cml' . DIRECTORY_SEPARATOR . 'Session.php'); //设置调试模式 if (Config::get('debug')) { $GLOBALS['debug'] = true; //开启debug Debug::start(); //记录开始运行时间\内存初始使用 //设置捕获系统异常 使用set_error_handler()后,error_reporting将会失效。所有的错误都会交给set_error_handler。 set_error_handler('\\Cml\\Debug::catcher'); spl_autoload_register('Cml\\Cml::autoloadComposerAdditional', true, true); //包含程序运行必须的类 foreach ($runTimeClassList as $file) { require $file; Debug::addTipInfo(Lang::get('_CML_DEBUG_ADD_CLASS_TIP_', 'Cml\\' . basename($file)), 1); } Debug::addTipInfo(Lang::get('_CML_DEBUG_ADD_CLASS_TIP_', 'Cml\\Debug'), 1); $runTimeClassList = null; Debug::addTipInfo(Lang::get('_CML_DEBUG_ADD_CLASS_TIP_', 'Cml\\Cml'), 1); Debug::addTipInfo(Lang::get('_CML_DEBUG_ADD_CLASS_TIP_', 'Cml\\Config'), 1); Debug::addTipInfo(Lang::get('_CML_DEBUG_ADD_CLASS_TIP_', 'Cml\\Lang'), 1); Debug::addTipInfo(Lang::get('_CML_DEBUG_ADD_CLASS_TIP_', 'Cml\\Http\\Request'), 1); } else { $GLOBALS['debug'] = false; //关闭debug //ini_set('error_reporting', E_ALL & ~E_NOTICE);//记录除了notice之外的错误 ini_set('log_errors', 'off'); //关闭php自带错误日志 //严重错误已经通过fatalError记录。为了防止日志过多,默认不记录致命错误以外的日志。有需要可以修改配置开启 if (Config::get('log_warn_log')) { set_error_handler('\\Cml\\Log::catcherPhpError'); } //线上模式包含runtime.php $runTimeFile = CML_RUNTIME_PATH . DIRECTORY_SEPARATOR . '_runtime_.php'; if (!is_file($runTimeFile)) { $runTimeContent = '<?php'; foreach ($runTimeClassList as $file) { $runTimeContent .= str_replace(array('<?php', '?>'), '', php_strip_whitespace($file)); } file_put_contents($runTimeFile, $runTimeContent, LOCK_EX); $runTimeContent = null; } require $runTimeFile; } // 页面压缩输出支持 if (Config::get('output_encode')) { $zlib = ini_get('zlib.output_compression'); if (empty($zlib)) { ///@ob_end_clean () ; //防止在启动ob_start()之前程序已经有输出(比如配置文件尾多敲了换行)会导致服务器303错误 ob_start('ob_gzhandler') || ob_start(); define('CML_OB_START', true); } else { define('CML_OB_START', false); } } //包含应用函数库文件 都使用composer去管理 //$projectFuns = CML_APP_FULL_PATH.DIRECTORY_SEPARATOR.'Function'.DIRECTORY_SEPARATOR.'function.php'; //is_file($projectFuns) && require $projectFuns; //载入插件配置文件 $pluginConfig = CML_APP_FULL_PATH . DIRECTORY_SEPARATOR . 'Config' . DIRECTORY_SEPARATOR . 'plugin.php'; is_file($pluginConfig) && (require $pluginConfig); Request::isCli() && RunCliCommand::runCliCommand(); Plugin::hook('cml.before_parse_url'); //载入路由 $routeConfigFile = CML_APP_FULL_PATH . DIRECTORY_SEPARATOR . 'Config' . DIRECTORY_SEPARATOR . 'route.php'; is_file($routeConfigFile) && (require $routeConfigFile); Route::parseUrl(); //解析处理URL Plugin::hook('cml.after_parse_url'); //载入模块配置 if (CML_IS_MULTI_MODULES) { $modulesConfig = CML_APP_MODULES_PATH . Route::$urlParams['path'] . 'Config' . DIRECTORY_SEPARATOR . 'normal.php'; is_file($modulesConfig) && Config::set(require $modulesConfig); //载入模块语言包 $appLang = CML_APP_MODULES_PATH . Route::$urlParams['path'] . 'Lang' . DIRECTORY_SEPARATOR . Config::get('lang') . '.php'; is_file($appLang) && Lang::set(require $appLang); } //设置应用路径 define('CML_APP_CONTROLLER_PATH', CML_APP_MODULES_PATH . (CML_IS_MULTI_MODULES ? Route::$urlParams['path'] . 'Controller' . DIRECTORY_SEPARATOR : DIRECTORY_SEPARATOR . 'Controller' . Route::$urlParams['path'])); }
/** * 输出调试消息 * * @return void */ public function stopAndShowDebugInfo() { if (Request::isAjax()) { if (Config::get('dump_use_php_console')) { self::$sql && \Cml\dumpUsePHPConsole(self::$sql, 'sql'); \Cml\dumpUsePHPConsole(self::$tipInfo, 'tipInfo'); \Cml\dumpUsePHPConsole(self::$includeFile, 'includeFile'); } else { $deBugLogData = ['tipInfo' => self::$tipInfo]; self::$sql && ($deBugLogData['sql'] = self::$sql); if (!empty($deBugLogData)) { Cml::requireFile(CML_CORE_PATH . DIRECTORY_SEPARATOR . 'ConsoleLog.php', ['deBugLogData' => $deBugLogData]); } } } else { View::getEngine('html')->assign('includeLib', Debug::getIncludeLib())->assign('includeFile', Debug::getIncludeFiles())->assign('tipInfo', Debug::getTipInfo())->assign('sqls', Debug::getSqls())->assign('usetime', Debug::getUseTime())->assign('usememory', Debug::getUseMemory()); Cml::showSystemTemplate(Config::get('debug_page')); } }