Think.class.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. <?php
  2. /**
  3. * 洛阳赤炎鹰网络科技有限公司
  4. * https://www.cyyvip.com
  5. * Copyright (c) 2022 赤店商城 All rights reserved.
  6. */
  7. // +----------------------------------------------------------------------
  8. // | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  9. // +----------------------------------------------------------------------
  10. // | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
  11. // +----------------------------------------------------------------------
  12. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  13. // +----------------------------------------------------------------------
  14. // | Author: liu21st <liu21st@gmail.com>
  15. // +----------------------------------------------------------------------
  16. namespace Think;
  17. /**
  18. * ThinkPHP 引导类
  19. */
  20. class Think {
  21. // 类映射
  22. private static $_map = array();
  23. // 实例化对象
  24. private static $_instance = array();
  25. /**
  26. * 应用程序初始化
  27. * @access public
  28. * @return void
  29. */
  30. static public function start() {
  31. // 注册AUTOLOAD方法
  32. spl_autoload_register('Think\Think::autoload');
  33. // 设定错误和异常处理
  34. register_shutdown_function('Think\Think::fatalError');
  35. set_error_handler('Think\Think::appError');
  36. set_exception_handler('Think\Think::appException');
  37. // 初始化文件存储方式
  38. Storage::connect(STORAGE_TYPE);
  39. $runtimefile = RUNTIME_PATH.APP_MODE.'~runtime.php';
  40. if(!APP_DEBUG && Storage::has($runtimefile)){
  41. Storage::load($runtimefile);
  42. }else{
  43. if(Storage::has($runtimefile))
  44. Storage::unlink($runtimefile);
  45. $content = '';
  46. // 读取应用模式
  47. $mode = include is_file(CONF_PATH.'core.php')?CONF_PATH.'core.php':MODE_PATH.APP_MODE.'.php';
  48. // 加载核心文件
  49. foreach ($mode['core'] as $file){
  50. if(is_file($file)) {
  51. include $file;
  52. if(!APP_DEBUG) $content .= compile($file);
  53. }
  54. }
  55. // 加载应用模式配置文件
  56. foreach ($mode['config'] as $key=>$file){
  57. is_numeric($key)?C(load_config($file)):C($key,load_config($file));
  58. }
  59. // 读取当前应用模式对应的配置文件
  60. if('common' != APP_MODE && is_file(CONF_PATH.'config_'.APP_MODE.CONF_EXT))
  61. C(load_config(CONF_PATH.'config_'.APP_MODE.CONF_EXT));
  62. // 加载模式别名定义
  63. if(isset($mode['alias'])){
  64. self::addMap(is_array($mode['alias'])?$mode['alias']:include $mode['alias']);
  65. }
  66. // 加载应用别名定义文件
  67. if(is_file(CONF_PATH.'alias.php'))
  68. self::addMap(include CONF_PATH.'alias.php');
  69. // 加载模式行为定义
  70. if(isset($mode['tags'])) {
  71. Hook::import(is_array($mode['tags'])?$mode['tags']:include $mode['tags']);
  72. }
  73. // 加载应用行为定义
  74. if(is_file(CONF_PATH.'tags.php'))
  75. // 允许应用增加开发模式配置定义
  76. Hook::import(include CONF_PATH.'tags.php');
  77. // 加载框架底层语言包
  78. L(include THINK_PATH.'Lang/'.strtolower(C('DEFAULT_LANG')).'.php');
  79. if(!APP_DEBUG){
  80. $content .= "\nnamespace { Think\\Think::addMap(".var_export(self::$_map,true).");";
  81. $content .= "\nL(".var_export(L(),true).");\nC(".var_export(C(),true).');Think\Hook::import('.var_export(Hook::get(),true).');}';
  82. Storage::put($runtimefile,strip_whitespace('<?php
  83. /**
  84. * 洛阳赤炎鹰网络科技有限公司
  85. * https://www.cyyvip.com
  86. * Copyright (c) 2022 赤店商城 All rights reserved.
  87. */
  88. '.$content));
  89. }else{
  90. // 调试模式加载系统默认的配置文件
  91. C(include THINK_PATH.'Conf/debug.php');
  92. // 读取应用调试配置文件
  93. if(is_file(CONF_PATH.'debug'.CONF_EXT))
  94. C(include CONF_PATH.'debug'.CONF_EXT);
  95. }
  96. }
  97. // 读取当前应用状态对应的配置文件
  98. if(APP_STATUS && is_file(CONF_PATH.APP_STATUS.CONF_EXT))
  99. C(include CONF_PATH.APP_STATUS.CONF_EXT);
  100. // 设置系统时区
  101. date_default_timezone_set(C('DEFAULT_TIMEZONE'));
  102. // 检查应用目录结构 如果不存在则自动创建
  103. if(C('CHECK_APP_DIR')) {
  104. $module = defined('BIND_MODULE') ? BIND_MODULE : C('DEFAULT_MODULE');
  105. if(!is_dir(APP_PATH.$module) || !is_dir(LOG_PATH)){
  106. // 检测应用目录结构
  107. Build::checkDir($module);
  108. }
  109. }
  110. // 记录加载文件时间
  111. G('loadTime');
  112. // 运行应用
  113. App::run();
  114. }
  115. // 注册classmap
  116. static public function addMap($class, $map=''){
  117. if(is_array($class)){
  118. self::$_map = array_merge(self::$_map, $class);
  119. }else{
  120. self::$_map[$class] = $map;
  121. }
  122. }
  123. // 获取classmap
  124. static public function getMap($class=''){
  125. if(''===$class){
  126. return self::$_map;
  127. }elseif(isset(self::$_map[$class])){
  128. return self::$_map[$class];
  129. }else{
  130. return null;
  131. }
  132. }
  133. /**
  134. * 类库自动加载
  135. * @param string $class 对象类名
  136. * @return void
  137. */
  138. public static function autoload($class) {
  139. // 检查是否存在映射
  140. if(isset(self::$_map[$class])) {
  141. include self::$_map[$class];
  142. }elseif(false !== strpos($class,'\\')){
  143. $name = strstr($class, '\\', true);
  144. if(in_array($name,array('Think','Org','Behavior','Com','Vendor')) || is_dir(LIB_PATH.$name)){
  145. // Library目录下面的命名空间自动定位
  146. $path = LIB_PATH;
  147. }else{
  148. // 检测自定义命名空间 否则就以模块为命名空间
  149. $namespace = C('AUTOLOAD_NAMESPACE');
  150. $path = isset($namespace[$name])? dirname($namespace[$name]).'/' : APP_PATH;
  151. }
  152. $filename = $path . str_replace('\\', '/', $class) . EXT;
  153. if(is_file($filename)) {
  154. // Win环境下面严格区分大小写
  155. if (IS_WIN && false === strpos(str_replace('/', '\\', realpath($filename)), $class . EXT)){
  156. return ;
  157. }
  158. include $filename;
  159. }
  160. }elseif (!C('APP_USE_NAMESPACE')) {
  161. // 自动加载的类库层
  162. foreach(explode(',',C('APP_AUTOLOAD_LAYER')) as $layer){
  163. if(substr($class,-strlen($layer))==$layer){
  164. if(require_cache(MODULE_PATH.$layer.'/'.$class.EXT)) {
  165. return ;
  166. }
  167. }
  168. }
  169. // 根据自动加载路径设置进行尝试搜索
  170. foreach (explode(',',C('APP_AUTOLOAD_PATH')) as $path){
  171. if(import($path.'.'.$class))
  172. // 如果加载类成功则返回
  173. return ;
  174. }
  175. }
  176. }
  177. /**
  178. * 取得对象实例 支持调用类的静态方法
  179. * @param string $class 对象类名
  180. * @param string $method 类的静态方法名
  181. * @return object
  182. */
  183. static public function instance($class,$method='') {
  184. $identify = $class.$method;
  185. if(!isset(self::$_instance[$identify])) {
  186. if(class_exists($class)){
  187. $o = new $class();
  188. if(!empty($method) && method_exists($o,$method))
  189. self::$_instance[$identify] = call_user_func(array(&$o, $method));
  190. else
  191. self::$_instance[$identify] = $o;
  192. }
  193. else
  194. self::halt(L('_CLASS_NOT_EXIST_').':'.$class);
  195. }
  196. return self::$_instance[$identify];
  197. }
  198. /**
  199. * 自定义异常处理
  200. * @access public
  201. * @param mixed $e 异常对象
  202. */
  203. static public function appException($e) {
  204. $error = array();
  205. $error['message'] = $e->getMessage();
  206. $trace = $e->getTrace();
  207. if('E'==$trace[0]['function']) {
  208. $error['file'] = $trace[0]['file'];
  209. $error['line'] = $trace[0]['line'];
  210. }else{
  211. $error['file'] = $e->getFile();
  212. $error['line'] = $e->getLine();
  213. }
  214. $error['trace'] = $e->getTraceAsString();
  215. Log::record($error['message'],Log::ERR);
  216. // 发送404信息
  217. header('HTTP/1.1 404 Not Found');
  218. header('Status:404 Not Found');
  219. self::halt($error);
  220. }
  221. /**
  222. * 自定义错误处理
  223. * @access public
  224. * @param int $errno 错误类型
  225. * @param string $errstr 错误信息
  226. * @param string $errfile 错误文件
  227. * @param int $errline 错误行数
  228. * @return void
  229. */
  230. static public function appError($errno, $errstr, $errfile, $errline) {
  231. switch ($errno) {
  232. case E_ERROR:
  233. case E_PARSE:
  234. case E_CORE_ERROR:
  235. case E_COMPILE_ERROR:
  236. case E_USER_ERROR:
  237. ob_end_clean();
  238. $errorStr = "$errstr ".$errfile." 第 $errline 行.";
  239. if(C('LOG_RECORD')) Log::write("[$errno] ".$errorStr,Log::ERR);
  240. self::halt($errorStr);
  241. break;
  242. default:
  243. $errorStr = "[$errno] $errstr ".$errfile." 第 $errline 行.";
  244. self::trace($errorStr,'','NOTIC');
  245. break;
  246. }
  247. }
  248. // 致命错误捕获
  249. static public function fatalError() {
  250. Log::save();
  251. if ($e = error_get_last()) {
  252. switch($e['type']){
  253. case E_ERROR:
  254. case E_PARSE:
  255. case E_CORE_ERROR:
  256. case E_COMPILE_ERROR:
  257. case E_USER_ERROR:
  258. ob_end_clean();
  259. self::halt($e);
  260. break;
  261. }
  262. }
  263. }
  264. /**
  265. * 错误输出
  266. * @param mixed $error 错误
  267. * @return void
  268. */
  269. static public function halt($error) {
  270. $e = array();
  271. if (APP_DEBUG || IS_CLI) {
  272. //调试模式下输出错误信息
  273. if (!is_array($error)) {
  274. $trace = debug_backtrace();
  275. $e['message'] = $error;
  276. $e['file'] = $trace[0]['file'];
  277. $e['line'] = $trace[0]['line'];
  278. ob_start();
  279. debug_print_backtrace();
  280. $e['trace'] = ob_get_clean();
  281. } else {
  282. $e = $error;
  283. }
  284. if(IS_CLI){
  285. exit(iconv('UTF-8','gbk',$e['message']).PHP_EOL.'FILE: '.$e['file'].'('.$e['line'].')'.PHP_EOL.$e['trace']);
  286. }
  287. } else {
  288. //否则定向到错误页面
  289. $error_page = C('ERROR_PAGE');
  290. if (!empty($error_page)) {
  291. redirect($error_page);
  292. } else {
  293. $message = is_array($error) ? $error['message'] : $error;
  294. $e['message'] = C('SHOW_ERROR_MSG')? $message : C('ERROR_MESSAGE');
  295. }
  296. }
  297. // 包含异常页面模板
  298. $exceptionFile = C('TMPL_EXCEPTION_FILE',null,THINK_PATH.'Tpl/think_exception.tpl');
  299. include $exceptionFile;
  300. exit;
  301. }
  302. /**
  303. * 添加和获取页面Trace记录
  304. * @param string $value 变量
  305. * @param string $label 标签
  306. * @param string $level 日志级别(或者页面Trace的选项卡)
  307. * @param boolean $record 是否记录日志
  308. * @return void|array
  309. */
  310. static public function trace($value='[think]',$label='',$level='DEBUG',$record=false) {
  311. static $_trace = array();
  312. if('[think]' === $value){ // 获取trace信息
  313. return $_trace;
  314. }else{
  315. $info = ($label?$label.':':'').print_r($value,true);
  316. $level = strtoupper($level);
  317. if((defined('IS_AJAX') && IS_AJAX) || !C('SHOW_PAGE_TRACE') || $record) {
  318. Log::record($info,$level,$record);
  319. }else{
  320. if(!isset($_trace[$level]) || count($_trace[$level])>C('TRACE_MAX_RECORD')) {
  321. $_trace[$level] = array();
  322. }
  323. $_trace[$level][] = $info;
  324. }
  325. }
  326. }
  327. }