/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
- <?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 . '<title>Internal Server Error</title>' .
- CRLF . '</head>' .
- CRLF . '<body>' .
- CRLF . '<h1>Internal Server Error</h1>' .
- CRLF . '<p>The requested URL ' . $REQUEST_URI . ' was error on this server.</p>' .
- CRLF . '<hr />' .
- CRLF . $_SERVER['SERVER_SIGNATURE'] .
- CRLF . '</body>' .
- CRLF . '</html>';
- }
-
- exit();
- }
-
- /**
- * 返回一个用.表示的字符串的key对应数组的内容
- *
- * 例如
- *
- * $arr = array
- * (
- * 'a' => array
- * (
- * 'b' => 123,
- * 'c' => array
- * (
- * 456,
- * ),
- * ),
- * );
- * Core::key_string($arr,'a.b'); //返回123
- *
- * Core::key_string($arr,'a');
- * // 返回
- * array
- * (
- * 'b' => 123,
- * 'c' => array
- * (
- * 456,
- * ),
- * );
- *
- * Core::key_string($arr,'a.c.0'); //返回456
- *
- * Core::key_string($arr,'a.d'); //返回null
- *
- * @param array $arr
- * @param string $key
- * @return fixed
- */
- public static function key_string($arr, $key, $default = null)
- {
- if (!is_array($arr)) return $default;
- $keyArr = explode('.', $key);
- foreach ( $keyArr as $key )
- {
- if ( isset($arr[$key]) )
- {
- $arr = $arr[$key];
- }
- else
- {
- return $default;
- }
- }
- return $arr;
- }
-
- /**
- * 添加页面在关闭前执行的列队
- * 将利用call_user_func或call_user_func_array回调
- * 类似 register_shutdown_function
- * @param array $function 方法名,可以是数组
- * @param array $param_arr 参数,可空
- */
- public static function register_shutdown_function($function, $param_arr = null)
- {
- Core::$shutdown_function[] = array($function, $param_arr);
- }
-
- public static function shutdown_handler()
- {
- $error = error_get_last();
- if ( $error )
- {
- static $run = null;
- if ( $run === true ) return;
- $run = true;
- if ( ((E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR) & $error['type']) !== 0 )
- {
- $error['file'] = Core::debug_path($error['file']);
- Core::show_500(var_export($error, true));
- exit();
- }
- }
- }
-
- public static function exception_handler(Exception $e)
- {
- $code = $e->getCode();
- if ( $code !== 8 )
- {
- Core::show_500($e);
- exit();
- }
- }
-
- public static function error_handler($code, $error, $file = null, $line = null)
- {
- if ( (error_reporting() & $code) !== 0 )
- {
- throw new ErrorException( $error, $code, 0, $file, $line );
- }
- return true;
- }
-
- /**
- * 根据$objName返回一个实例化并静态存储的对象
- *
- * @param string $obj_name
- * @param string $key
- */
- public static function factory($obj_name, $key = '')
- {
- if (!isset(Core::$instances[$obj_name][$key]))
- {
- Core::$instances[$obj_name][$key] = new $obj_name($key);
- }
-
- return Core::$instances[$obj_name][$key];
- }
-
- /**
- * 释放对象以释放内存
- *
- * 通常在批处理后操作,可有效的释放getFactory静态缓存的对象
- *
- * @param string $obj_name 对象名称 不传的话则清除全部
- * @param string $key 对象关键字 不传的话则清除$objName里的所有对象
- */
- public static function factory_release($obj_name = null, $key = null)
- {
- if (IS_CLI || IS_DEBUG)
- {
- $old_memory = memory_get_usage();
- }
-
- if (null===$obj_name)
- {
- Core::$instances = array();
- }
- elseif (isset(Core::$instances[$obj_name]))
- {
- if (null===$key)
- {
- unset(Core::$instances[$obj_name]);
- }
- else
- {
- unset(Core::$instances[$obj_name][$key]);
- }
- }
-
- if (IS_CLI)
- {
- echo __('The release memory:') . ( memory_get_usage() - $old_memory ) . "\n";
- }
- else if (IS_DEBUG)
- {
- Core::debug()->info(__('The release memory:') . ( memory_get_usage() - $old_memory) );
- }
- }
-
- /**
- * 将项目切换回初始项目
- *
- * 当使用Core::change_project()设置切换过项目后,可使用此方法返回初始化时的项目
- */
- public static function reset_project()
- {
- if (defined('INITIAL_PROJECT_NAME') && INITIAL_PROJECT_NAME != Core::$project)
- {
- Core::change_project(INITIAL_PROJECT_NAME);
- }
- }
-
- /**
- * 切换到另外一个项目
- *
- * 切换其它项目后,相关的config,include_path等都将加载为设定项目的,但是已经加载的class等是不可能销毁的,所以需谨慎使用
- *
- * @param string $project
- * @return boolean
- * @throws Exception 失败则抛出异常(比如不存在指定的项目)
- */
- public static function change_project($project)
- {
- if (Core::$project==$project)
- {
- return true;
- }
-
- if ( !isset(Core::$core_config['projects'][$project] ) )
- {
- Core::show_500( __('not found the project: :project.', array(':project'=>$project) ) );
- }
-
- if ( !Core::$core_config['projects'][$project]['isuse'] )
- {
- Core::show_500( __('the project: :project is not open.', array(':project'=>$project) ) );
- }
-
- # 记录所有项目设置,当切换回项目时,使用此设置还原
- static $all_prjects_setting = array();
-
- if (Core::$project)
- {
- // 记录上一个项目设置
- $all_prjects_setting[Core::$project] = array
- (
- 'config' => Core::$config,
- 'include_path' => Core::$include_path,
- 'file_list' => Core::$file_list,
- 'project_dir' => Core::$project_dir,
- 'base_url' => Core::$base_url,
- );
- }
-
- # 原来的项目
- $old_project = Core::$project;
-
- if (isset($all_prjects_setting[$project]))
- {
- # 设为当前项目
- Core::$project = $project;
-
- # 还原配置
- Core::$config = $all_prjects_setting[$project]['config'];
- Core::$include_path = $all_prjects_setting[$project]['include_path'];
- Core::$file_list = $all_prjects_setting[$project]['file_list'];
- Core::$project_dir = $all_prjects_setting[$project]['project_dir'];
- Core::$base_url = $all_prjects_setting[$project]['base_url'];
-
- # 清除缓存数据
- unset($all_prjects_setting[$project]);
- }
- else
- {
- $p_config = Core::$core_config['projects'][$project];
-
- if (!isset($p_config['dir']) || !$p_config['dir'])
- {
- Core::show_500(__('the project ":project" dir is not defined.', array(':project'=>$project)));
- }
-
- # 设置include path
- $project_dir = DIR_PROJECT . $project . DS;
- if (!is_dir($project_dir))
- {
- Core::show_500(__('not found the project: :project.', array(':project' => $project)));
- }
-
- # 项目路径
- $project_dir = realpath(DIR_PROJECT . $p_config['dir']);
-
- if (!$project_dir || !is_dir($project_dir))
- {
- Core::show_500(__('the project dir :dir is not exist.', array(':dir'=>$p_config['dir'])));
- }
-
- # 设为当前项目
- Core::$project = $project;
-
- $project_dir .= DS;
-
- Core::$project_dir = $project_dir;
-
- # 处理base_url
- if (isset($p_config['url']) && $p_config['url'])
- {
- $url = rtrim(current((array)$p_config['url']),'/');
- }
- else
- {
- $url = '/';
- }
-
- if (IS_ADMIN_MODE)
- {
- if (isset($p_config['url_admin']) && $p_config['url_admin'])
- {
- $current_url = current((array)$p_config['url_admin']);
- if (false===strpos($current_url[0],'://'))
- {
- $url .= trim($current_url, '/');
- $url = trim($url, '/') .'/';
- }
- }
- }
-
- if (IS_REST_MODE)
- {
- if (isset($p_config['url_rest']) && $p_config['url_rest'])
- {
- $current_url = current((array)$p_config['url_rest']);
- if (false===strpos($current_url[0], '://'))
- {
- $url .= trim($current_url, '/');
- $url = trim($url,'/') .'/';
- }
- }
- }
-
- Core::$base_url = $url;
-
- # 重置$include_path
- Core::$include_path['project'] = array
- (
- Core::$project => $project_dir
- );
-
- # 重新加载类库配置
- Core::reload_all_libraries();
- }
-
- # 记录debug信息
- if (IS_DEBUG)
- {
- Core::debug()->info($project, '程序已切换到了新项目');
- }
-
- # 回调callback
- if (Core::$change_project_callback)
- {
- foreach (Core::$change_project_callback as $fun)
- {
- call_user_func($fun, $old_project, $project);
- }
- }
-
- return true;
- }
-
- /**
- * 增加change_project回调事件
- *
- * //将在每次执行 Core::change_project($new_project) 成功后执行 MyClass::myfun($old_project, $new_project) 方法,其中$old_project是原来的项目名
- * Core::change_project_add_callback('MyClass::myfun');
- *
- * @param string|array $fun
- */
- public static function change_project_add_callback($fun)
- {
- Core::$change_project_callback[] = $fun;
-
- if (count(Core::$change_project_callback)>1)
- {
- # 移除重复的项目
- Core::$change_project_callback = array_unique(Core::$change_project_callback);
- }
- }
-
- /**
- * 移除import_library回调事件
- *
- * @param string|array $fun
- */
- public static function change_project_remove_callback($fun)
- {
- if (Core::$change_project_callback)
- {
- $new_arr = array();
- foreach (Core::$change_project_callback as $item)
- {
- if ($item!==$fun)
- {
- $new_arr = $item;
- }
- }
-
- Core::$change_project_callback = $new_arr;
- }
- }
-
- /**
- * 导入指定类库
- *
- * 支持多个,当一次导入多个时,从数组最后一个开始导入
- *
- * 导入的格式必须是类似 com.a.b 的形式,否则会抛出异常,例如: com.myqee.test
- *
- * Bootstrap::import_library('com.myqee.test');
- * Bootstrap::import_library(array('com.myqee.test','com.myqee.cms'));
- *
- * @param string|array $library_name 指定类库 支持多个
- * @return boolean
- */
- public static function import_library($library_name)
- {
- $library_name = (array)$library_name;
-
- $status = parent::import_library($library_name);
-
- # 回调callback
- if ($status>0 && Core::$import_library_callback)
- {
- foreach (Core::$import_library_callback as $fun)
- {
- call_user_func($fun, $library_name);
- }
- }
-
- return $status;
- }
-
- /**
- * 增加import_library回调事件
- *
- * //将在每次执行 Core::import_library($library_name) 成功后执行 MyClass::myfun((array)$library_name) 方法
- * Core::add_import_library_callback('MyClass::myfun');
- *
- * @param string|array $fun
- */
- public static function import_library_add_callback($fun)
- {
- Core::$import_library_callback[] = $fun;
-
- if (count(Core::$import_library_callback)>1)
- {
- # 移除重复的项目
- Core::$import_library_callback = array_unique(Core::$import_library_callback);
- }
- }
-
- /**
- * 移除import_library回调事件
- *
- * @param string|array $fun
- */
- public static function import_library_remove_callback($fun)
- {
- if (Core::$import_library_callback)
- {
- $new_arr = array();
- foreach (Core::$import_library_callback as $item)
- {
- if ($item!==$fun)
- {
- $new_arr = $item;
- }
- }
-
- Core::$import_library_callback = $new_arr;
- }
- }
-
- /**
- * 执行注册的关闭方法
- */
- protected static function run_shutdown_function()
- {
- static $run = null;
- if ( null!==$run )
- {
- return true;
- }
- $run = true;
-
- if (Core::$shutdown_function)
- {
- foreach (Core::$shutdown_function as $item)
- {
- try
- {
- call_user_func_array($item[0], (array)$item[1]);
- }
- catch ( Exception $e )
- {
-
- }
- }
- }
- }
-
- /**
- * 特殊的合并项目配置
- *
- * 相当于一维数组之间相加,这里支持多维
- *
- * @param array $c1
- * @param array $c2
- * @return array
- */
- protected static function _merge_project_config($c1, $c2)
- {
- foreach ($c2 as $k=>$v)
- {
- if (!isset($c1[$k]))
- {
- $c1[$k] = $v;
- }
- elseif ( is_array($c1[$k]) && is_array($v) )
- {
- $c1[$k] = Core::_merge_project_config($c1[$k] , $v );
- }
- elseif (is_numeric($k) && is_array($c1[$k]))
- {
- $c1[$k][] = $v;
- }
- }
- return $c1;
- }
-
- /**
- * 关闭所有可能的外部链接,比如Database,Memcache等连接
- */
- public static function close_all_connect()
- {
- foreach ( Core::$close_connect_class_list as $class_name=>$fun )
- {
- try
- {
- call_user_func_array( array($class_name,$fun), array() );
- }
- catch (Exception $e)
- {
- Core::debug()->error('close_all_connect error:'.$e->getMessage());
- }
- }
- }
-
- /**
- * 增加执行Core::close_all_connect()时会去关闭的类
- *
- * Core::add_close_connect_class('Database','close_all_connect');
- * Core::add_close_connect_class('Cache_Driver_Memcache');
- * Core::add_close_connect_class('TestClass','close');
- * //当执行 Core::close_all_connect() 时会调用 Database::close_all_connect() 和 Cache_Driver_Memcache::close_all_connect() 和 TestClass::close() 方法
- *
- * @param string $class_name
- * @param string $fun
- */
- public static function add_close_connect_class($class_name, $fun='close_all_connect')
- {
- Core::$close_connect_class_list[$class_name] = $fun;
- }
-
- /**
- * 检查内部调用HASH是否有效
- *
- * @return boolean
- */
- protected static function check_system_request_allow()
- {
- $hash = $_SERVER['HTTP_X_MYQEE_SYSTEM_HASH']; // 请求验证HASH
- $time = $_SERVER['HTTP_X_MYQEE_SYSTEM_TIME']; // 请求验证时间
- $rstr = $_SERVER['HTTP_X_MYQEE_SYSTEM_RSTR']; // 请求随机字符串
- $project = $_SERVER['HTTP_X_MYQEE_SYSTEM_PROJECT']; // 请求的项目
- $path_info = $_SERVER['HTTP_X_MYQEE_SYSTEM_PATHINFO']; // 请求的path_info
- $isadmin = $_SERVER['HTTP_X_MYQEE_SYSTEM_ISADMIN']; // 是否ADMIN
- $isrest = $_SERVER['HTTP_X_MYQEE_SYSTEM_ISREST']; // 是否RESTFul请求
- if (!$hash || !$time || !$rstr || !$project || !$path_info) return false;
-
- // 请求时效检查
- if (microtime(1) - $time > 600)
- {
- Core::log('system request timeout', 'system-request');
- return false;
- }
-
- // 验证IP
- if ('127.0.0.1'!=HttpIO::IP && HttpIO::IP != $_SERVER["SERVER_ADDR"])
- {
- $allow_ip = Core::config('core.system_exec_allow_ip');
-
- if (is_array($allow_ip) && $allow_ip)
- {
- $allow = false;
- foreach ($allow_ip as $ip)
- {
- if (HttpIO::IP == $ip)
- {
- $allow = true;
- break;
- }
-
- if (strpos($allow_ip, '*'))
- {
- // 对IP进行匹配
- if (preg_match('#^' . str_replace('\\*', '[^\.]+', preg_quote($allow_ip, '#')) . '$#', HttpIO::IP))
- {
- $allow = true;
- break;
- }
- }
- }
-
- if (!$allow)
- {
- Core::log('system request not allow ip:' . HttpIO::IP, 'system-request');
- return false;
- }
- }
- }
-
- $body = http_build_query(HttpIO::POST(null, HttpIO::PARAM_TYPE_OLDDATA));
-
- // 系统调用密钥
- $system_exec_pass = Core::config('system_exec_key');
-
- $key = Core::config()->get('system_exec_key', 'system', true);
-
- if (!$key || abs(TIME-$key['time'])>86400*10)
- {
- return false;
- }
-
- $other = $path_info .'_'. ($isadmin?1:0) .'_'. ($isrest?1:0) . $key['str'];
-
- if ($system_exec_pass && strlen($system_exec_pass) >= 10)
- {
- // 如果有则使用系统调用密钥
- $newhash = sha1($body . $time . $system_exec_pass . $rstr .'_'. $other);
- }
- else
- {
- // 没有,则用系统配置和数据库加密
- $newhash = sha1($body . $time . serialize(Core::config('core')) . serialize(Core::config('database')) . $rstr .'_'. $other);
- }
-
- if ($newhash==$hash)
- {
- return true;
- }
- else
- {
- Core::log('system request hash error', 'system-request');
- return false;
- }
- }
-
- /**
- * 获取asset文件MD5号
- *
- * @param string $file
- * @return md5
- */
- public static function assets_hash($file)
- {
- //TODO 须加入文件版本号
- return '';
- }
-
-
- /**
- * 返回客户端IP数组列表
- *
- * 也可直接用 `HttpIO::IP` 来获取到当前单个IP
- *
- * @return array
- */
- public static function ip()
- {
- $ip = array();
-
- if (isset($_SERVER['HTTP_X_FORWARDED_FOR']))
- {
- $ip = explode(',', str_replace(' ', '', $_SERVER['HTTP_X_FORWARDED_FOR']));
- }
-
- if(isset($_SERVER['HTTP_CLIENT_IP']))
- {
- $ip = array_merge($ip, explode(',', str_replace(' ', '', $_SERVER['HTTP_CLIENT_IP'])));
- }
-
- if (isset($_SERVER['REMOTE_ADDR']))
- {
- $ip = array_merge($ip, explode(',', str_replace(' ', '', $_SERVER['REMOTE_ADDR'])));
- }
-
- return $ip;
- }
-
-
- /**
- * 系统调用内容输出函数(请勿自行执行)
- */
- public static function _output_body()
- {
- # 发送header数据
- HttpIO::send_headers();
-
- if (IS_DEBUG && isset($_REQUEST['debug']) && class_exists('Profiler', true))
- {
- # 调试打开时不缓存页面
- HttpIO::set_cache_header(0);
- }
-
- # 执行注册的关闭方法
- ob_start();
- Core::run_shutdown_function();
- $output = ob_get_clean();
-
- # 在页面输出前关闭所有的连接
- Core::close_all_connect();
-
- # 输出内容
- echo Core::$output , $output;
- }
- }
-
-
- /**
- * 无调试对象
- *
- * @author 呼吸二氧化碳 <jonwang@myqee.com>
- * @category Core
- * @package Classes
- * @subpackage Core
- * @copyright Copyright (c) 2008-2013 myqee.com
- * @license http://www.myqee.com/license.html
- */
- class __NoDebug
- {
- public function __call($m, $v)
- {
- return $this;
- }
-
- public function log($i = null)
- {
- return $this;
- }
-
- public function info($i = null)
- {
- return $this;
- }
-
- public function error($i = null)
- {
- return $this;
- }
-
- public function group($i = null)
- {
- return $this;
- }
-
- public function groupEnd($i = null)
- {
- return $this;
- }
-
- public function table($Label = null, $Table = null)
- {
- return $this;
- }
-
- public function profiler($i = null)
- {
- return $this;
- }
-
- public function is_open()
- {
- return false;
- }
- }
-