/core/classes/core.class.php
PHP | 2418 lines | 1663 code | 276 blank | 479 comment | 229 complexity | ebf3aecb88d40dc69b15c4ee00a5d398 MD5 | raw file
Possible License(s): LGPL-3.0, BSD-3-Clause
Large files files are truncated, but you can click here to view the full file
- <?php
-
- /**
- * 返回一个静态资源的URL路径. Core::url_assets() 的别名
- *
- * echo url_assets('js/global.js');
- *
- * @param string $uri
- */
- function url_assets($uri='')
- {
- return Core::url_assets($uri);
- }
-
- /**
- * 返回一个URL. Core::url() 的别名
- *
- * echo url(); //返回首页地址
- *
- * @param string $uri
- * @return string
- */
- function url($uri='')
- {
- return Core::url($uri);
- }
-
- /**
- * 读取配置数据. Core::config() 的别名
- *
- * echo config('core'); //返回核心配置
- *
- * @param string $key
- * @return string
- */
- function config($key=null)
- {
- return Core::config($key);
- }
-
-
- /**
- * MyQEE 核心类
- *
- * @author 呼吸二氧化碳 <jonwang@myqee.com>
- * @category MyQEE
- * @package System
- * @subpackage Core
- * @copyright Copyright (c) 2008-2013 myqee.com
- * @license http://www.myqee.com/license.html
- */
- abstract class Core_Core extends Bootstrap
- {
- /**
- * MyQEE版本号
- *
- * @var string
- */
- const VERSION = '3.0';
-
- /**
- * 版本发布状态
- *
- * stable, rc1, rc2, beta1, beta2, ...
- *
- * @var string
- */
- const RELEASE = 'rc2';
-
- /**
- * 项目开发者
- *
- * @var string
- */
- const CODER = '呼吸二氧化碳 <jonwang@myqee.com>';
-
- /**
- * 页面编码
- *
- * @var string
- */
- public static $charset = 'utf-8';
-
- /**
- * 页面传入的PATHINFO参数
- *
- * @var array
- */
- public static $arguments = array();
-
- /**
- * 页面输出内容
- *
- * @var string
- */
- public static $output = '';
-
- /**
- * 自动加载时各个文件夹后缀
- *
- * 例如,classes目录为.class,则文件实际后缀为.class.php
- * 注意,只有对EXT常理设置的后缀文件有效,默认情况下EXT=.php
- *
- * @var array
- */
- public static $autoload_dir_ext = array
- (
- 'config' => '.config',
- 'classes' => '.class',
- 'controllers' => '.controller',
- 'models' => '.model',
- 'orm' => '.orm',
- 'views' => '.view',
- );
-
- /**
- * 缓冲区包含数
- * @var int
- */
- protected static $buffer_level = 0;
-
- /**
- * 页面在关闭前需要执行的方法列队
- * 通过Core::register_shutdown_function()设置
- * @var array
- */
- protected static $shutdown_function = array();
-
- /**
- * getFactory获取的对象寄存器
- * @var array
- */
- protected static $instances = array();
-
- /**
- * 执行Core::close_all_connect()方法时会关闭链接的类和方法名的列队
- *
- * 可通过Core::add_close_connect_class()方法进行设置增加
- *
- * array
- * (
- * 'Database' => 'close_all_connect',
- * );
- *
- * @var array
- */
- protected static $close_connect_class_list = array();
-
- /**
- * import_library回调函数列表
- *
- * @var array
- */
- protected static $import_library_callback = array();
-
- /**
- * change_project回调函数列表
- *
- * @var array
- */
- protected static $change_project_callback = array();
-
- /**
- * 使用 Core::url() 会附带的参数列表
- *
- * @var array
- */
- protected static $_url_auto_args = array();
-
- /**
- * 系统启动
- *
- * @param boolean $auto_execute 是否直接运行
- */
- public static function setup($auto_execute = true)
- {
- static $run = null;
-
- if (null===$run)
- {
- $run = true;
-
- Core::$charset = Core::$config['charset'];
-
- if (!IS_CLI)
- {
- # 输出powered by信息
- $x_powered_by = (isset(Core::$config['hide_x_powered_by_header']) && Core::$config['hide_x_powered_by_header']) ? Core::$config['hide_x_powered_by_header'] : false;
-
- if (is_string($x_powered_by))
- {
- $str = 'X-Powered-By: ' . trim(str_replace(array("\r", "\n"), '', $x_powered_by));
- }
- else if (!$x_powered_by)
- {
- $str = 'X-Powered-By: PHP/' . PHP_VERSION . ' MyQEE/' . Core::VERSION .'('. Core::RELEASE .')';
- }
- else
- {
- $str = null;
- }
-
- if ($str)
- {
- header($str);
- }
- }
-
- if (IS_DEBUG)
- {
- Core::debug()->info('SERVER IP:' . $_SERVER["SERVER_ADDR"] . (function_exists('php_uname')?'. SERVER NAME:' . php_uname('a') : ''));
-
- if (Core::$project)
- {
- Core::debug()->info('project: ' . Core::$project);
- }
-
- if (IS_ADMIN_MODE)
- {
- Core::debug()->info('admin mode');
- }
-
- if (IS_REST_MODE)
- {
- Core::debug()->info('RESTFul mode');
- }
-
- Core::debug()->group('include path');
- foreach ( Core::include_path() as $value )
- {
- Core::debug()->log(Core::debug_path($value));
- }
- Core::debug()->groupEnd();
- }
-
- if ((IS_CLI || IS_DEBUG) && class_exists('ErrException', true))
- {
- # 注册脚本
- register_shutdown_function(array('ErrException', 'shutdown_handler'));
- # 捕获错误
- set_exception_handler(array('ErrException', 'exception_handler'));
- set_error_handler(array('ErrException', 'error_handler'), error_reporting());
- }
- else
- {
- # 注册脚本
- register_shutdown_function(array('Core', 'shutdown_handler'));
- # 捕获错误
- set_exception_handler(array('Core', 'exception_handler'));
- set_error_handler(array('Core', 'error_handler'), error_reporting());
- }
-
- if (!IS_CLI)
- {
- # 初始化 HttpIO 对象
- HttpIO::setup();
- }
-
- # 注册输出函数
- register_shutdown_function(array('Core', '_output_body'));
-
- if (true===IS_SYSTEM_MODE)
- {
- if (false===Core::check_system_request_allow())
- {
- # 内部请求验证不通过
- Core::show_500('system request hash error');
- }
- }
-
- if (IS_DEBUG && isset($_REQUEST['debug']) && class_exists('Profiler', true))
- {
- Profiler::setup();
- }
-
- if (!defined('URL_ASSETS'))
- {
- /**
- * 静态文件URL地址前缀
- *
- * @var string
- */
- define('URL_ASSETS', rtrim(Core::config('url.assets', Core::url('/assets/')), '/') . '/');
- }
- }
-
- if ($auto_execute)
- {
- Core::run();
- }
- }
-
- protected static function run()
- {
- if (IS_CLI || IS_SYSTEM_MODE)
- {
- Core::execute(Core::$path_info);
- }
- else
- {
- ob_start();
-
- try
- {
- Core::execute(Core::$path_info);
- }
- catch (Exception $e)
- {
- $code = $e->getCode();
-
- if (404===$code || E_PAGE_NOT_FOUND===$code)
- {
- Core::show_404($e->getMessage());
- }
- elseif (500===$code)
- {
- Core::show_500($e->getMessage());
- }
- else
- {
- Core::show_500($e);
- }
- }
-
- Core::$output = ob_get_clean();
- }
- }
-
- /**
- * 获取指定key的配置
- *
- * 若不传key,则返回Core_Config对象,可获取动态配置,例如Core::config()->get();
- *
- * @param string $key
- * @param mixed $default 默认值
- * @return Config
- * @return array
- */
- public static function config($key = null, $default = null)
- {
- if (null===$key)
- {
- return Core::factory('Config');
- }
-
- $c = explode('.', $key);
- $cname = array_shift($c);
-
- if (strtolower($cname)=='core')
- {
- $v = Core::$core_config;
- }
- elseif (isset(Core::$config[$cname]))
- {
- $v = Core::$config[$cname];
- }
- else
- {
- return $default;
- }
-
- if ($c)foreach ($c as $i)
- {
- if (!isset($v[$i]))return $default;
- $v = $v[$i];
- }
-
- return $v;
- }
-
- /**
- * Cookie
- * @return Core_Cookie
- */
- public static function cookie()
- {
- return Core::factory('Cookie');
- }
-
- /**
- * 路由处理
- *
- * @return Core_Route
- */
- public static function route()
- {
- return Core::factory('Route');
- }
-
- /**
- * 返回URL路径
- *
- * 自3.0起可用 url() 直接快速调用此方法
- *
- * Core::url('test/');
- * url('test/');
- *
- * @param string $url URL
- * @param true|string $isfullurl_or_project 若传true,则返回当前项目的完整url(http(s)://开头),若传项目名,比如default,则返回指定项目的完整URL
- * @return string
- */
- public static function url($uri = '' , $isfullurl_or_project = false)
- {
- list($url, $query) = explode('?', $uri , 2);
-
- $url = Core::$base_url. ltrim($url, '/') . ($url!='' && substr($url,-1)!='/' && false===strpos($url, '.') && Core::$config['url_suffix']?Core::$config['url_suffix']:'') . ($query?'?'.$query:'');
-
- # 返回完整URL
- if (true===$isfullurl_or_project && !preg_match('#^http(s)?://#i', $url))
- {
- $url = HttpIO::PROTOCOL . $_SERVER["HTTP_HOST"] . $url;
- }
-
- # 添加自动追加的参数
- if (Core::$_url_auto_args)
- {
- list($url, $hash) = explode('#', $url, 2);
- list($u, $q) = explode('?', $url, 2);
- if (!$q)
- {
- $q = '';
- parse_str($q, $q);
- $q += Core::$_url_auto_args;
- }
- else
- {
- $q = Core::$_url_auto_args;
- }
-
- $url = $u .'?'. http_build_query($q, '', '&') . ($hash?'#'.$hash:'');
- }
-
- return $url;
- }
-
- /**
- * 返回静态资源URL路径
- *
- * @param string $uri
- */
- public static function url_assets($uri = '')
- {
- $url = ltrim($uri, './ ');
-
- if (IS_DEBUG & 1)
- {
- # 本地调试环境
- $url_asstes = Core::url('/assets-dev/');
- }
- else
- {
- $url_asstes = URL_ASSETS . Core::$project . '/' . (IS_ADMIN_MODE?'~admin/':'');
-
- list($file, $query) = explode('?', $uri.'?', 2);
-
- $uri = $file . '?' . (strlen($query)>0?$query.'&':'') . Core::assets_hash($file);
- }
-
- return $url_asstes . $url;
- }
-
- /**
- * 增加URL默认参数
- *
- * 比如用在URL跟踪访客统计上,不支持Session的时候通过URL传送的SessionID等
- *
- * 增加的参数在所有使用 `Core::url()` 返回的内容里都会附带这个参数
- *
- * Core::add_url_args('debug', 'test');
- *
- * Core::add_url_args(array('debug'=>'test', 't2'=>'v'2));
- *
- * @param $key 参数名称
- * @param $value 参数值
- * @since v3.0
- */
- public static function add_url_args($key, $value)
- {
- if (is_array($key))
- {
- Core::$_url_auto_args += $key;
- }
- else
- {
- Core::$_url_auto_args[$key] = $value;
- }
- }
-
- /**
- * Include一个指定URI的控制器
- *
- * @param string $uri
- * @return class_name | false
- */
- public static function load_controller($uri)
- {
- $found = Core::find_controller($uri);
-
- if ($found)
- {
- # 返回类的名称
- return $found['class'];
- }
- else
- {
- return false;
- }
- }
-
- /**
- * 是否系统设置禁用文件写入功能
- *
- * 可在 `config.php` 中设置 `$config['file_write_mode'] = 'disable';` 如果disable则返回true,否则返回false
- *
- * @return boolean
- */
- public static function is_file_write_disabled()
- {
- if (Core::config('core.file_write_mode')=='disable')
- {
- return true;
- }
- else
- {
- return false;
- }
- }
-
- /**
- * 记录日志
- *
- * @param string $msg 日志内容
- * @param string $type 类型,例如:log,error,debug 等
- * @param stirng $file 指定文件名,不指定则默认
- * @return boolean
- */
- public static function log($msg, $type = 'log', $file = null)
- {
- if (Core::is_file_write_disabled())return true;
-
- # log配置
- $log_config = Core::config('log');
-
- # 不记录日志
- if (isset($log_config['use']) && !$log_config['use'])
- {
- return true;
- }
-
- # 内容格式化
- if ($log_config['format'])
- {
- $format = $log_config['format'];
- }
- else
- {
- # 默认格式
- $format = ':time - :host::port - :url - :msg';
- }
-
- # 获取日志内容
- $data = Core::log_format($msg, $type, $format);
-
- if (IS_DEBUG)
- {
- # 如果有开启debug模式,输出到浏览器
- Core::debug()->log($data, $type);
- }
-
- # 保存日志
- return Core::write_log($data, $type, $file);
- }
-
- /**
- * 执行指定URI的控制器
- *
- * @param string $uri
- */
- public static function execute($uri)
- {
- $found = Core::find_controller($uri);
-
- if ($found)
- {
- if (isset($found['route']))
- {
- $class_name = $found['class'];
- $class_exists = class_exists($class_name, true);
- $arguments = array();
- if (isset($found['route']['action']) && $found['route']['action'])
- {
- $arguments[] = $found['route']['action'];
- }
- }
- else
- {
- require $found['file'];
-
- if ($found['ns']=='team-library' || $found['ns']=='project')
- {
- $class_name = $found['class'];
- }
- else
- {
- $class_name = str_replace('.', '_', $found['ns']) . '_' . $found['class'];
- }
-
- $class_exists = class_exists($class_name, false);
- }
-
- if ($class_exists)
- {
-
- $controller = new $class_name();
-
- Controller::$controllers[] = $controller;
-
- # 是否有必要将action从$arguments中移出
- $need_shift_action = false;
- $arguments = $found['args'];
- if ($arguments)
- {
- $action = current($arguments);
- if (0===strlen($action))
- {
- $action = 'default';
- }
- else
- {
- $need_shift_action = true;
- }
- }
- else
- {
- $action = 'index';
- }
-
- $action_name = 'action_' . $action;
-
- if (!method_exists($controller, $action_name))
- {
- if ($action_name!='action_default' && method_exists($controller, 'action_default'))
- {
- $action_name = 'action_default';
- }
- elseif ($action_name!='' && (!$arguments || $arguments===array('')) && method_exists($controller, 'action_index'))
- {
- $action_name = 'action_index';
- }
- elseif (method_exists($controller, '__call'))
- {
- $controller->__call($action_name, $arguments);
-
- Core::rm_controoler($controller);
- return;
- }
- else
- {
- Core::rm_controoler($controller);
-
- throw new Exception(__('Page Not Found'), 404);
- }
- }
- elseif ($need_shift_action)
- {
- array_shift($arguments);
- }
-
- $ispublicmethod = new ReflectionMethod($controller, $action_name);
-
- if (!$ispublicmethod->isPublic())
- {
- Core::rm_controoler($controller);
-
- throw new Exception(__('Request Method Not Allowed.'), 405);
- }
- unset($ispublicmethod);
-
- # POST 方式,自动CSRF判断
- if (HttpIO::METHOD=='POST')
- {
- $auto_check_post_method_referer = isset($controller->auto_check_post_method_referer)?$controller->auto_check_post_method_referer:Core::config('auto_check_post_method_referer', true);
-
- if ($auto_check_post_method_referer && !HttpIO::csrf_check())
- {
- throw new Exception(__('Not Acceptable.'), 406);
- }
- }
-
- if (isset($found['route']))
- {
- # 设置Route参数
- foreach ($found['route'] as $k => $v)
- {
- $controller->$k = $v;
- }
- }
- else
- {
- $controller->ids = $found['ids'];
- }
-
- # 将参数传递给控制器
- $controller->action = $action_name;
- $controller->controller = $found['class'];
- $controller->uri = $uri;
- $controller->directory = $found['dir'];
-
-
- if (IS_SYSTEM_MODE)
- {
- # 系统内部调用参数
- $controller->arguments = @unserialize(HttpIO::POST('data', HttpIO::PARAM_TYPE_OLDDATA));
- }
- else
- {
- $controller->arguments = $arguments;
- }
-
- # 设置 HttpIO 参数
- HttpIO::set_params_controller($controller);
-
- # 前置方法
- if (method_exists($controller, 'before'))
- {
- $controller->before();
- }
-
- # 执行方法
- $count_arguments = count($arguments);
- switch ($count_arguments)
- {
- case 0:
- $controller->$action_name();
- break;
- case 1:
- $controller->$action_name($arguments[0]);
- break;
- case 2:
- $controller->$action_name($arguments[0], $arguments[1]);
- break;
- case 3:
- $controller->$action_name($arguments[0], $arguments[1], $arguments[2]);
- break;
- case 4:
- $controller->$action_name($arguments[0], $arguments[1], $arguments[2], $arguments[3]);
- break;
- default:
- call_user_func_array(array($controller, $action_name), $arguments);
- break;
- }
-
- # 后置方法
- if (method_exists($controller, 'after'))
- {
- $controller->after();
- }
-
- # 移除控制器
- Core::rm_controoler($controller);
-
- unset($controller);
- }
- else
- {
- throw new Exception(__('Page Not Found'), 404);
- }
- }
- else
- {
- throw new Exception(__('Page Not Found'), 404);
- }
- }
-
- protected static function rm_controoler($controller)
- {
- foreach (Controller::$controllers as $k=>$c)
- {
- if ($c===$controller)unset(Controller::$controllers[$k]);
- }
-
- Controller::$controllers = array_values(Controller::$controllers);
- }
-
- /**
- * 寻找控制器
- *
- * @return array
- */
- protected static function find_controller($uri)
- {
- $uri = ltrim($uri, '/');
-
- if (Core::$config['url_suffix'] && substr(strtolower($uri), -strlen(Core::$config['url_suffix']))==Core::$config['url_suffix'])
- {
- $uri = substr($uri, 0, -strlen(Core::$config['url_suffix']));
- }
-
- if (!IS_SYSTEM_MODE && isset(Core::$config['route']) && Core::$config['route'])
- {
- # 有路由配置,首先根据路由配置查询控制器
- $found_route = Route::get($uri);
-
- if ($found_route)
- {
- if (!isset($found_route['controller']) || !$found_route['controller'])
- {
- if (IS_DEBUG)Core::debug()->error('The route not match controller');
- Core::show_404();
- }
-
- return array
- (
- 'class' => 'Controller_' . preg_replace('#[^a-zA-Z0-9_]#', '_', trim($found_route['controller'])),
- 'route' => $found_route,
- );
- }
- else
- {
- unset($found_route);
- }
- }
-
- if ($uri!='')
- {
- $uri_arr = explode('/', strtolower($uri));
- }
- else
- {
- $uri_arr = array();
- }
-
- if (IS_DEBUG)
- {
- Core::debug()->log('/'. $uri, 'find controller uri');
- }
-
- $include_path = Core::$include_path;
-
- # log
- $find_log = $find_path_log = array();
-
- # 控制器目录
- $controller_dir = Core::$dir_setting['controller'][0];
-
- if (IS_SYSTEM_MODE)
- {
- $controller_dir .= '-system';
- }
- elseif (IS_ADMIN_MODE)
- {
- $controller_dir .= '-admin';
- }
- elseif (IS_REST_MODE)
- {
- $controller_dir .= '-rest';
- }
- elseif (IS_CLI)
- {
- $controller_dir .= '-shell';
- }
-
- # 首先找到存在的目录
- $found_path = array();
- foreach ($include_path as $ns => $ipath)
- {
- if($ipath)foreach ($ipath as $lib_ns => $path)
- {
- if ($ns==='library')
- {
- $tmp_ns = 'library_' . str_replace('.', '_', $lib_ns);
- }
- else
- {
- $tmp_ns = $ns;
- }
-
- $tmp_str = $real_path = $real_class = '';
- $tmp_path = $path . $controller_dir . DS;
- $ids = array();
-
- foreach ($uri_arr as $uri_path)
- {
- $ds = DS;
- if ($uri_path==='')
- {
- if (count($uri_arr)>1)
- {
- break;
- }
- $real_uri_path = '';
- $ds = '';
- }
- elseif (is_numeric($uri_path))
- {
- $real_uri_path = '_id';
- $ids[] = $uri_path;
- }
- elseif ($uri_path == '_id')
- {
- # 不允许直接在URL中使用_id
- break;
- }
- elseif (preg_match('#[^a-z0-9_]#i', $uri_path))
- {
- # 不允许非a-z0-9_的字符在控制中
- break;
- }
- else
- {
- $real_uri_path = $uri_path;
- }
-
- $tmpdir = $tmp_path . $real_path . $real_uri_path . $ds;
- if (IS_DEBUG)
- {
- $find_path_log[] = Core::debug_path($tmpdir);
- }
- $real_path .= $real_uri_path . DS;
- $real_class .= $real_uri_path . '_';
- $tmp_str .= $uri_path . DS;
-
- if (is_dir($tmpdir))
- {
- $found_path[$tmp_str][] = array
- (
- $tmp_ns,
- $tmpdir,
- ltrim($real_class, '_'),
- $ids,
- );
- }
- else
- {
- break;
- }
- }
-
- // 根目录的
- if (is_dir($tmp_path))
- {
- $found_path[''][] = array
- (
- $tmp_ns,
- $tmp_path,
- '',
- array(),
- );
-
- if (IS_DEBUG)
- {
- $find_path_log[] = Core::debug_path($tmp_path);
- }
- }
- }
- }
-
- unset($ids);
- $found = null;
-
- # 寻找可能的文件
- if ($found_path)
- {
- # 调整优先级
- krsort($found_path);
-
- foreach ($found_path as $path => $all_path)
- {
- $path_len = strlen($path);
- $tmp_p = substr($uri, $path_len);
-
- if (strlen($tmp_p)>0)
- {
- $args = explode('/', substr($uri, $path_len));
- }
- else
- {
- $args = array();
- }
-
- $the_id = array();
- $tmp_class = array_shift($args);
- $tmp_arg = $tmp_class;
- $directory = rtrim('/'. substr($uri, 0, $path_len) . $tmp_class, '/');
-
- if (0===strlen($tmp_class))
- {
- $tmp_class = 'index';
- }
- elseif (is_numeric($tmp_class))
- {
- $the_id = array
- (
- $tmp_class
- );
- $tmp_class = '_id';
- }
- elseif ($tmp_class == '_id')
- {
- continue;
- }
-
- $real_class = $tmp_class;
- $tmp_class = strtolower($tmp_class);
-
- // 记录找到的index.controller.php
- $found_index_class = null;
-
- if (IS_DEBUG)
- {
- $find_log2 = array();
- }
-
- foreach ($all_path as $tmp_arr)
- {
- list($ns, $tmp_path, $real_path, $ids) = $tmp_arr;
- $tmpfile = $tmp_path . $tmp_class . Core::$dir_setting['controller'][1] . EXT;
-
- if (IS_DEBUG)
- {
- $find_log[] = Core::debug_path($tmpfile);
- }
-
- if (is_file($tmpfile))
- {
- if ($the_id)
- {
- $ids = array_merge($ids, $the_id);
- }
-
- if ($directory && substr($directory, -1-strlen($tmp_class))=='/'.$tmp_class)
- {
- $directory = substr($directory, 0, -1-strlen($tmp_class));
- }
-
- $found = array
- (
- 'file' => $tmpfile,
- 'dir' => $directory,
- 'ns' => $ns,
- 'class' => 'Controller_' . $real_path . $real_class,
- 'args' => $args,
- 'ids' => $ids,
- );
-
- break 2;
- }
- elseif (!$found_index_class && $tmp_class!='default')
- {
- // 记录 index.controller.php 控制器
- $tmpfile = $tmp_path . 'default' . Core::$dir_setting['controller'][1] . EXT;
- if (IS_DEBUG)
- {
- $find_log2[] = Core::debug_path($tmpfile);
- }
-
- if (is_file($tmpfile))
- {
- if (null!==$tmp_arg)
- {
- array_unshift($args, $tmp_arg);
-
- if (strlen($tmp_arg)>0)
- {
- $directory = substr($directory, 0, -strlen($tmp_arg) - 1);
- }
- }
-
- $found_index_class = array
- (
- 'file' => $tmpfile,
- 'dir' => $directory,
- 'ns' => $ns,
- 'class' => 'Controller_' . $real_path . 'Default',
- 'args' => $args,
- 'ids' => $ids,
- );
- }
- }
- }
-
- if (IS_DEBUG && $find_log2)
- {
- $find_log = array_merge($find_log, $find_log2);
- }
-
- // index.controller.php 文件
- if (!$found && $found_index_class)
- {
- $found = $found_index_class;
- break;
- }
- }
- }
-
- if (IS_DEBUG)
- {
- Core::debug()->group('find controller path');
- foreach ($find_path_log as $value)
- {
- Core::debug()->log($value);
- }
- Core::debug()->groupEnd();
-
- Core::debug()->group('find controller files');
- foreach ($find_log as $value)
- {
- Core::debug()->log($value);
- }
- Core::debug()->groupEnd();
-
- if ($found)
- {
- $found2 = $found;
- $found2['file'] = Core::debug_path($found2['file']);
- Core::debug()->log($found2, 'found contoller');
- }
- else
- {
- Core::debug()->log('/'. $uri, 'not found contoller');
- }
- }
-
- if (is_array($found) && isset($found['class']))
- {
- $found['class'] = preg_replace('#[^a-zA-Z0-9_]#', '_', trim($found['class']));
- }
-
- return $found;
- }
-
-
- /**
- * 写入日志
- *
- * 若有特殊写入需求,可以扩展本方法(比如调用数据库类克写到数据库里)
- *
- * @param string $data
- * @param string $type 日志类型
- * @param stirng $file 指定文件名,不指定则默认
- * @return boolean
- */
- protected static function write_log($data, $type = 'log', $file = null)
- {
- static $pro = null;
-
- if (!$type)$type = 'log';
-
- if (null===$pro)
- {
- if (preg_match('#^(db|cache)://([a-z0-9_]+)/([a-z0-9_]+)$#i', DIR_LOG , $m))
- {
- $pro = $m;
- }
- else
- {
- $pro = false;
- }
- }
-
- # Log目录采用文件目录
- if (false===$pro)
- {
- $write_mode = Core::config('core.file_write_mode');
-
- # 禁用写入
- if ($write_mode=='disable')return true;
-
- # 再判断是否有转换储存处理
- if (preg_match('#^(db|cache)://([a-z0-9_]+)/([a-z0-9_]+)$#i', $write_mode , $m))
- {
- $pro = $m;
- }
- }
-
- if (false===$pro)
- {
- # 以文件的形式保存
-
- $log_config = Core::config('log');
-
- if (!$file)
- {
- if ($log_config['file'])
- {
- $file = date($log_config['file']);
- }
- else
- {
- $file = date('Y/m/d/');
- }
- $file .= $type . '.log';
- }
-
- $dir = trim(dirname($file), '/');
-
- # 如果目录不存在,则创建
- if (!is_dir(DIR_LOG.$dir))
- {
- $temp = explode('/', str_replace('\\', '/', $dir) );
- $cur_dir = '';
- for($i=0; $i<count($temp); $i++)
- {
- $cur_dir .= $temp[$i] . "/";
- if (!is_dir(DIR_LOG.$cur_dir))
- {
- @mkdir(DIR_LOG.$cur_dir, 0755);
- }
- }
- }
-
- return false===@file_put_contents(DIR_LOG . $file, $data . CRLF , FILE_APPEND)?false:true;
- }
- else
- {
- # 以db或cache方式保存
-
- if ($pro[1]=='db')
- {
- $db_data = array
- (
- 'key' => md5($file),
- 'key_str'=> substr($file, 0, 255),
- 'type' => $type,
- 'day' => date('Ymd'),
- 'time' => TIME,
- 'value' => $data,
- );
-
- $obj = new Database($pro[2]);
- $status = $obj->insert($pro[3], $db_data) ? true:false;
- }
- else
- {
- if ($pro[3])
- {
- $pro[1]['prefix'] = trim($pro[3]) . '_';
- }
-
- $pro[1]['prefix'] .= $type.'_';
-
- $obj = new Cache($pro[2]);
-
- $status = $obj->set(date('Ymd').'_'.md5($file), $data, 86400*30); // 存1月
- }
-
- return $status;
- }
- }
-
- /**
- * 用于保存日志时格式化内容,如需要特殊格式可以自行扩展
- *
- * @param string $msg
- * @param string $format
- * @return string
- */
- protected static function log_format($msg,$type,$format)
- {
- $value = array
- (
- ':time' => date('Y-m-d H:i:s'), //当前时间
- ':url' => $_SERVER['SCRIPT_URI'], //请求的URL
- ':msg' => $msg, //日志信息
- ':type' => $type, //日志类型
- ':host' => $_SERVER["SERVER_ADDR"], //服务器
- ':port' => $_SERVER["SERVER_PORT"], //端口
- ':ip' => HttpIO::IP, //请求的IP
- ':agent' => $_SERVER["HTTP_USER_AGENT"], //客户端信息
- ':referer' => $_SERVER["HTTP_REFERER"], //来源页面
- );
-
- return strtr($format, $value);
- }
-
- /**
- * 获取debug对象
- * 可安全用于生产环境,在生产环境下将忽略所有debug信息
- * @return Debug
- */
- public static function debug()
- {
- static $debug = null;
- if (null === $debug)
- {
- if (!IS_CLI && ( IS_DEBUG || false!==strpos($_SERVER["HTTP_USER_AGENT"],'FirePHP') || isset($_SERVER["HTTP_X_FIREPHP_VERSION"]) ) && class_exists('Debug', true))
- {
- $debug = Debug::instance();
- }
- else
- {
- $debug = new __NoDebug();
- }
- }
- return $debug;
- }
-
- /**
- * 将真实路径地址输出为调试地址
- *
- * 显示结果类似 ./system/libraries/Database.class.php
- *
- * @param string path to debug
- * @param boolean $highlight 是否返回高亮前缀,可以传字符颜色,比如#f00
- * @return string
- */
- public static function debug_path($file, $highlight=false)
- {
- if ($highlight)
- {
- if (IS_CLI)
- {
- # 命令行下输出带色彩的前缀
- $l = "\x1b[36m";
- $r = "\x1b[39m";
- }
- else
- {
- $l = '<span style="color:'.(is_string($highlight) && preg_match('/^[a-z0-9#\(\)\.,]+$/i',$highlight) ?$highlight:'#a00').'">';
- $r = '</span>';
- }
- }
- else
- {
- $l = $r = '';
- }
-
- $file = str_replace('\\', DS, $file);
-
- if (strpos($file, DIR_CORE) === 0)
- {
- $file = $l . './core/' . $r . substr($file, strlen(DIR_CORE));
- }
- elseif (strpos($file, DIR_TEAM_LIBRARY) === 0)
- {
- $file = $l . './team-library/' . $r . substr($file, strlen(DIR_TEAM_LIBRARY));
- }
- elseif (strpos($file, DIR_LIBRARY) === 0)
- {
- $file = $l . './libraries/' . $r . substr($file, strlen(DIR_LIBRARY));
- }
- elseif (strpos($file, DIR_MODULE) === 0)
- {
- $file = $l . './modules/' . $r . substr($file, strlen(DIR_MODULE));
- }
- elseif (strpos($file, DIR_DRIVER) === 0)
- {
- $file = $l . './drivers/' . $r . substr($file, strlen(DIR_DRIVER));
- }
- elseif (strpos($file, DIR_PROJECT) === 0)
- {
- $file = $l . './projects/' . $r . substr($file, strlen(DIR_PROJECT));
- }
- elseif (strpos($file, DIR_TEMP) === 0)
- {
- $file = $l . './data/temp/' . $r . substr($file, strlen(DIR_TEMP));
- }
- elseif (strpos($file, DIR_LOG) === 0)
- {
- $file = $l . './data/log/' . $r . substr($file, strlen(DIR_LOG));
- }
- elseif (strpos($file, DIR_CACHE) === 0)
- {
- $file = $l . './data/cache/' . $r . substr($file, strlen(DIR_CACHE));
- }
- elseif (strpos($file, DIR_DATA) === 0)
- {
- $file = $l . './data/' . $r . substr($file, strlen(DIR_DATA));
- }
- elseif (strpos($file, DIR_ASSETS) === 0)
- {
- $file = $l . './wwwroot/assets/' . $r . substr($file, strlen(DIR_ASSETS));
- }
- elseif (strpos($file, DIR_UPLOAD) === 0)
- {
- $file = $l . './wwwroot/upload/' . $r . substr($file, strlen(DIR_UPLOAD));
- }
- elseif (strpos($file, DIR_WWWROOT) === 0)
- {
- $file = $l . './wwwroot/' . $r . substr($file, strlen(DIR_WWWROOT));
- }
- elseif (strpos($file, DIR_SYSTEM) === 0)
- {
- $file = $l . './' . $r . substr($file, strlen(DIR_SYSTEM));
- }
-
- $file = str_replace('\\', '/', $file);
-
- return $file;
- }
-
- /**
- * 关闭缓冲区
- *
- * @param boolean 是否输出缓冲数据
- * @return void
- */
- public static function close_buffers($flush = true)
- {
- if (ob_get_level() > Core::$buffer_level)
- {
- $close = ($flush === true) ? 'ob_end_flush' : 'ob_end_clean';
- while (ob_get_level() > Core::$buffer_level)
- {
- $close();
- }
- Core::$buffer_level = ob_get_level();
- }
- }
-
- /**
- * 404,可直接将Exception对象传给$msg
- *
- * @param string/Exception $msg
- */
- public static function show_404($msg = null)
- {
- Core::close_buffers(false);
-
- # 避免输出的CSS头试抛出页面无法显示
- @header('Content-Type: text/html;charset=' . Core::config('core.charset'), true);
-
- HttpIO::$status = 404;
- HttpIO::send_headers();
-
- if (null === $msg)
- {
- $msg = __('Page Not Found');
- }
-
- if (IS_DEBUG && class_exists('ErrException', false))
- {
- if ($msg instanceof Exception)
- {
- throw $msg;
- }
- else
- {
- throw new Exception($msg, 43);
- }
- }
-
- if (IS_CLI)
- {
- echo $msg . CRLF;
- exit();
- }
-
- try
- {
- $view = new View('error/404');
- $view->message = $msg;
- $view->render(true);
- }
- catch ( Exception $e )
- {
- list ( $REQUEST_URI ) = explode('?', $_SERVER['REQUEST_URI'], 2);
- $REQUEST_URI = htmlspecialchars(rawurldecode($REQUEST_URI));
- echo '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">' .
- CRLF . '<html>' .
- CRLF . '<head>' .
- CRLF . '<title>404 Not Found</title>' .
- CRLF . '</head>'.
- CRLF . '<body>' .
- CRLF . '<h1>Not Found</h1>' .
- CRLF . '<p>The requested URL ' . $REQUEST_URI . ' was not found on this server.</p>' .
- CRLF . '<hr />' .
- CRLF . $_SERVER['SERVER_SIGNATURE'] .
- CRLF . '</body>' .
- CRLF . '</html>';
- }
-
- exit();
- }
-
- /**
- * 系统错误,可直接将Exception对象传给$msg
- * @param string/Exception $msg
- */
- public static function show_500($msg = null)
- {
- Core::close_buffers(false);
-
- # 避免输出的CSS头试抛出页面无法显示
- @header('Content-Type: text/html;charset=' . Core::config('core.charset'), true);
-
- HttpIO::$status = 500;
- HttpIO::send_headers();
-
- if (null === $msg)
- {
- $msg = __('Internal Server Error');
- }
-
- if (IS_DEBUG && class_exists('ErrException', false))
- {
- if ($msg instanceof Exception)
- {
- throw $msg;
- }
- else
- {
- throw new Exception($msg, 0);
- }
- }
-
- if (IS_CLI)
- {
- echo "\x1b[36m";
- if ($msg instanceof Exception)
- {
- echo $msg->getMessage() . CRLF;
- }
- else
- {
- echo $msg . CRLF;
- }
-
- echo "\x1b[39m";
- echo CRLF;
- exit();
- }
-
- try
- {
- if ($msg instanceof Exception)
- {
- print_r($msg);exit;
- $error = $msg->getMessage();
- $trace_obj = $msg;
- }
- else
- {
- $error = $msg;
- $trace_obj = new Exception($msg);
- }
-
- $error_config = Core::config('core.error500');
-
- $view = new View('error/500');
- if ($error_config && isset($error_config['close']) && $error_config['close']==true)
- {
- # 不记录
- $view->error_saved = false;
- }
- else
- {
- $trace_array = array
- (
- 'project' => Core::$project,
- 'uri' => HttpIO::$uri,
- 'url' => HttpIO::PROTOCOL . $_SERVER['HTTP_HOST'] . $_SERVER["REQUEST_URI"],
- 'post' => HttpIO::POST(null, HttpIO::PARAM_TYPE_OLDDATA),
- 'get' => $_SERVER['QUERY_STRING'],
- 'cookie' => HttpIO::COOKIE(null, HttpIO::PARAM_TYPE_OLDDATA),
- 'client_ip' => HttpIO::IP,
- 'user_agent' => HttpIO::USER_AGENT,
- 'referrer' => HttpIO::REFERRER,
- 'server_ip' => $_SERVER["SERVER_ADDR"],
- 'trace' => $trace_obj->__toString(),
- );
-
- $date = @date('Y-m-d');
- $no = strtoupper(substr(md5(serialize($trace_array)), 10, 10));
- $error_no = $date.'-'.$no;
-
- # 其它数据
- $trace_array['server_name'] = (function_exists('php_uname')? php_uname('a') : 'unknown');
- $trace_array['time'] = TIME;
- $trace_array['use_time'] = microtime(1) - START_TIME;
- $trace_array['trace'] = $trace_obj;
-
- $trace_data = base64_encode(gzcompress(serialize($trace_array), 9));
- unset($trace_array);
-
- $view->error_saved = true;
-
- # 记录错误日志
- try
- {
- if (isset($error_config['save_type']) && $error_config['save_type'])
- {
- $save_type = $error_config['save_type'];
- }
- else
- {
- $save_type = 'file';
- }
-
- if ($save_type=='file')
- {
- # 文件模式
- $write_mode = Core::config('core.file_write_mode');
-
- if (preg_match('#^(db|cache)://([a-z0-9_]+)/([a-z0-9_]+)$#i', $write_mode , $m))
- {
- $save_type = $m[1];
- $error_config['type_config'] = $m[2];
- }
- }
-
- switch ($save_type)
- {
- case 'database':
- $obj = $error_config['type_config']?new Database($error_config['type_config']) : new Database();
- $data = array
- (
- 'time' => strtotime($date.' 00:00:00'),
- 'no' => $no,
- 'log' => $trace_data,
- 'expire_time' => TIME + 7*86400,
- );
- $obj->insert('error500_log', $data);
- break;
- case 'cache':
- $obj = $error_config['type_config']?new Cache($error_config['type_config']) : new Cache();
- if (!$obj->get($error_no))
- {
- $obj->set($error_no, $trace_data, 7*86400);
- }
- break;
- default:
- $file = DIR_LOG .'error500'. DS . str_replace('-', DS, $date) . DS . $no . '.log';
- if (!is_file($file))
- {
- File::create_file($file, $trace_data, null, null, $error_config['type_config']?$error_config['type_config']:'default');
- }
- break;
- }
- }
- catch (Exception $e)
- {
-
- }
- }
-
- $view->error_no = $error_no;
- $view->error = $error;
- $view->render(true);
- }
- catch (Exception $e)
- {
- list ($REQUEST_URI) = explode('?', $_SERVER['REQUEST_URI'], 2);
- $REQUEST_URI = htmlspecialchars(rawurldecode($REQUEST_URI));
- echo '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">' .
- CRLF . '<html>' .
- CRLF . '<head>' .
- CRLF . '<…
Large files files are truncated, but you can click here to view the full file