App.class.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2009 http://thinkphp.cn All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: liu21st <liu21st@gmail.com>
  10. // +----------------------------------------------------------------------
  11. // $Id$
  12. /**
  13. +------------------------------------------------------------------------------
  14. * ThinkPHP 应用程序类 执行应用过程管理
  15. +------------------------------------------------------------------------------
  16. * @category Think
  17. * @package Think
  18. * @subpackage Core
  19. * @author liu21st <liu21st@gmail.com>
  20. * @version $Id$
  21. +------------------------------------------------------------------------------
  22. */
  23. class App
  24. {//类定义开始
  25. /**
  26. +----------------------------------------------------------
  27. * 应用程序初始化
  28. +----------------------------------------------------------
  29. * @access public
  30. +----------------------------------------------------------
  31. * @return void
  32. +----------------------------------------------------------
  33. */
  34. static public function init()
  35. {
  36. // 设定错误和异常处理
  37. set_error_handler(array('App','appError'));
  38. set_exception_handler(array('App','appException'));
  39. //[RUNTIME]
  40. // 检查项目是否编译过
  41. // 在部署模式下会自动在第一次执行的时候编译项目
  42. if(defined('RUNTIME_MODEL')){
  43. // 运行模式无需载入项目编译缓存
  44. }elseif(is_file(RUNTIME_PATH.'~app.php') && (!is_file(CONFIG_PATH.'config.php') || filemtime(RUNTIME_PATH.'~app.php')>filemtime(CONFIG_PATH.'config.php'))) {
  45. // 直接读取编译后的项目文件
  46. C(include RUNTIME_PATH.'~app.php');
  47. }else{
  48. // 预编译项目
  49. App::build();
  50. }
  51. //[/RUNTIME]
  52. // 项目开始标签
  53. if(C('APP_PLUGIN_ON')) tag('app_begin');
  54. // 设置系统时区 PHP5支持
  55. if(function_exists('date_default_timezone_set'))
  56. date_default_timezone_set(C('DEFAULT_TIMEZONE'));
  57. // 允许注册AUTOLOAD方法
  58. if(C('APP_AUTOLOAD_REG') && function_exists('spl_autoload_register'))
  59. spl_autoload_register(array('Think', 'autoload'));
  60. if(C('SESSION_AUTO_START')) session_start(); // Session初始化
  61. // 应用调度过滤器
  62. // 如果没有加载任何URL调度器
  63. // 默认只支持 QUERY_STRING 方式
  64. if(C('URL_DISPATCH_ON')) Dispatcher::dispatch();
  65. if(!defined('PHP_FILE'))
  66. // PHP_FILE 由内置的Dispacher定义
  67. // 如果不使用该插件,需要重新定义
  68. define('PHP_FILE',_PHP_FILE_);
  69. // 取得模块和操作名称
  70. // 可以在Dispatcher中定义获取规则
  71. // 加载项目分组公共文件
  72. if(C('APP_GROUP_LIST')) {
  73. if(!defined('GROUP_NAME')) define('GROUP_NAME', App::getGroup()); // Group名称
  74. // 分组配置文件
  75. if(is_file(CONFIG_PATH.GROUP_NAME.'/config.php'))
  76. C(include CONFIG_PATH.GROUP_NAME.'/config.php');
  77. // 分组函数文件
  78. if(is_file(COMMON_PATH.GROUP_NAME.'/function.php'))
  79. include COMMON_PATH.GROUP_NAME.'/function.php';
  80. }
  81. if(!defined('MODULE_NAME')) define('MODULE_NAME', App::getModule()); // Module名称
  82. if(!defined('ACTION_NAME')) define('ACTION_NAME', App::getAction()); // Action操作
  83. // 加载模块配置文件
  84. if(is_file(CONFIG_PATH.strtolower(MODULE_NAME).'_config.php'))
  85. C(include CONFIG_PATH.strtolower(MODULE_NAME).'_config.php');
  86. // 系统检查
  87. App::checkLanguage(); //语言检查
  88. App::checkTemplate(); //模板检查
  89. if(C('HTML_CACHE_ON')) // 开启静态缓存
  90. HtmlCache::readHTMLCache();
  91. // 项目初始化标签
  92. if(C('APP_PLUGIN_ON')) tag('app_init');
  93. return ;
  94. }
  95. //[RUNTIME]
  96. /**
  97. +----------------------------------------------------------
  98. * 读取配置信息 编译项目
  99. +----------------------------------------------------------
  100. * @access private
  101. +----------------------------------------------------------
  102. * @return string
  103. +----------------------------------------------------------
  104. */
  105. static private function build()
  106. {
  107. // 加载惯例配置文件
  108. C(include THINK_PATH.'/Common/convention.php');
  109. // 加载项目配置文件
  110. if(is_file(CONFIG_PATH.'config.php'))
  111. C(include CONFIG_PATH.'config.php');
  112. $runtime = defined('RUNTIME_ALLINONE');
  113. $common = '';
  114. //是否调试模式 ALL_IN_ONE模式下面调试模式无效
  115. $debug = C('APP_DEBUG') && !$runtime;
  116. // 加载项目公共文件
  117. if(is_file(COMMON_PATH.'common.php')) {
  118. include COMMON_PATH.'common.php';
  119. if(!$debug) // 编译文件
  120. $common .= compile(COMMON_PATH.'common.php',$runtime);
  121. }
  122. // 加载项目编译文件列表
  123. if(is_file(CONFIG_PATH.'app.php')) {
  124. $list = include CONFIG_PATH.'app.php';
  125. foreach ($list as $file){
  126. // 加载并编译文件
  127. require $file;
  128. if(!$debug) $common .= compile($file,$runtime);
  129. }
  130. }
  131. // 读取扩展配置文件
  132. $list = C('APP_CONFIG_LIST');
  133. foreach ($list as $val){
  134. if(is_file(CONFIG_PATH.$val.'.php'))
  135. C('_'.$val.'_',array_change_key_case(include CONFIG_PATH.$val.'.php'));
  136. }
  137. // 如果是调试模式加载调试模式配置文件
  138. if($debug) {
  139. // 加载系统默认的开发模式配置文件
  140. C(include THINK_PATH.'/Common/debug.php');
  141. if(is_file(CONFIG_PATH.'debug.php'))
  142. // 允许项目增加开发模式配置定义
  143. C(include CONFIG_PATH.'debug.php');
  144. }else{
  145. // 部署模式下面生成编译文件
  146. // 下次直接加载项目编译文件
  147. if(defined('RUNTIME_ALLINONE')) {
  148. // 获取用户自定义变量
  149. $defs = get_defined_constants(TRUE);
  150. $content = array_define($defs['user']);
  151. $content .= substr(file_get_contents(RUNTIME_PATH.'~runtime.php'),5);
  152. $content .= $common."\nreturn ".var_export(C(),true).';';
  153. file_put_contents(RUNTIME_PATH.'~allinone.php',strip_whitespace('<?php '.$content));
  154. }else{
  155. $content = "<?php ".$common."\nreturn ".var_export(C(),true).";\n?>";
  156. file_put_contents(RUNTIME_PATH.'~app.php',strip_whitespace($content));
  157. }
  158. }
  159. return ;
  160. }
  161. //[/RUNTIME]
  162. /**
  163. +----------------------------------------------------------
  164. * 获得实际的模块名称
  165. +----------------------------------------------------------
  166. * @access private
  167. +----------------------------------------------------------
  168. * @return string
  169. +----------------------------------------------------------
  170. */
  171. static private function getModule()
  172. {
  173. $var = C('VAR_MODULE');
  174. $module = !empty($_POST[$var]) ?
  175. $_POST[$var] :
  176. (!empty($_GET[$var])? $_GET[$var]:C('DEFAULT_MODULE'));
  177. if(C('URL_CASE_INSENSITIVE')) {
  178. // URL地址不区分大小写
  179. define('P_MODULE_NAME',strtolower($module));
  180. // 智能识别方式 index.php/user_type/index/ 识别到 UserTypeAction 模块
  181. $module = ucfirst(parse_name(P_MODULE_NAME,1));
  182. }
  183. unset($_POST[$var],$_GET[$var]);
  184. return $module;
  185. }
  186. /**
  187. +----------------------------------------------------------
  188. * 获得实际的操作名称
  189. +----------------------------------------------------------
  190. * @access private
  191. +----------------------------------------------------------
  192. * @return string
  193. +----------------------------------------------------------
  194. */
  195. static private function getAction()
  196. {
  197. $var = C('VAR_ACTION');
  198. $action = !empty($_POST[$var]) ?
  199. $_POST[$var] :
  200. (!empty($_GET[$var])?$_GET[$var]:C('DEFAULT_ACTION'));
  201. unset($_POST[$var],$_GET[$var]);
  202. return $action;
  203. }
  204. /**
  205. +----------------------------------------------------------
  206. * 获得实际的分组名称
  207. +----------------------------------------------------------
  208. * @access private
  209. +----------------------------------------------------------
  210. * @return string
  211. +----------------------------------------------------------
  212. */
  213. static private function getGroup()
  214. {
  215. $var = C('VAR_GROUP');
  216. $group = !empty($_POST[$var]) ?
  217. $_POST[$var] :
  218. (!empty($_GET[$var])?$_GET[$var]:C('DEFAULT_GROUP'));
  219. unset($_POST[$var],$_GET[$var]);
  220. return ucfirst(strtolower($group));
  221. }
  222. /**
  223. +----------------------------------------------------------
  224. * 语言检查
  225. * 检查浏览器支持语言,并自动加载语言包
  226. +----------------------------------------------------------
  227. * @access private
  228. +----------------------------------------------------------
  229. * @return void
  230. +----------------------------------------------------------
  231. */
  232. static private function checkLanguage()
  233. {
  234. $langSet = C('DEFAULT_LANG');
  235. // 不开启语言包功能,仅仅加载框架语言文件直接返回
  236. if (!C('LANG_SWITCH_ON')){
  237. L(include THINK_PATH.'/Lang/'.$langSet.'.php');
  238. return;
  239. }
  240. // 启用了语言包功能
  241. // 根据是否启用自动侦测设置获取语言选择
  242. if (C('LANG_AUTO_DETECT')){
  243. if(isset($_GET[C('VAR_LANGUAGE')])){// 检测浏览器支持语言
  244. $langSet = $_GET[C('VAR_LANGUAGE')];// url中设置了语言变量
  245. cookie('think_language',$langSet,3600);
  246. }elseif(cookie('think_language'))// 获取上次用户的选择
  247. $langSet = cookie('think_language');
  248. elseif(isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])){// 自动侦测浏览器语言
  249. preg_match('/^([a-z\-]+)/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches);
  250. $langSet = $matches[1];
  251. cookie('think_language',$langSet,3600);
  252. }
  253. }
  254. // 定义当前语言
  255. define('LANG_SET',strtolower($langSet));
  256. // 加载框架语言包
  257. if(is_file(THINK_PATH.'/Lang/'.$langSet.'.php'))
  258. L(include THINK_PATH.'/Lang/'.$langSet.'.php');
  259. // 读取项目公共语言包
  260. if (is_file(LANG_PATH.$langSet.'/common.php'))
  261. L(include LANG_PATH.$langSet.'/common.php');
  262. $group = '';
  263. // 读取当前分组公共语言包
  264. if (defined('GROUP_NAME')){
  265. $group = GROUP_NAME.C('TMPL_FILE_DEPR');
  266. if (is_file(LANG_PATH.$langSet.'/'.$group.'lang.php'))
  267. L(include LANG_PATH.$langSet.'/'.$group.'lang.php');
  268. }
  269. // 读取当前模块语言包
  270. if (is_file(LANG_PATH.$langSet.'/'.$group.strtolower(MODULE_NAME).'.php'))
  271. L(include LANG_PATH.$langSet.'/'.$group.strtolower(MODULE_NAME).'.php');
  272. }
  273. /**
  274. +----------------------------------------------------------
  275. * 模板检查,如果不存在使用默认
  276. +----------------------------------------------------------
  277. * @access private
  278. +----------------------------------------------------------
  279. * @return void
  280. +----------------------------------------------------------
  281. */
  282. static private function checkTemplate()
  283. {
  284. if(C('TMPL_DETECT_THEME')) {// 自动侦测模板主题
  285. $t = C('VAR_TEMPLATE');
  286. if (isset($_GET[$t])){
  287. $templateSet = $_GET[$t];
  288. cookie('think_template',$templateSet,3600);
  289. }else{
  290. if(cookie('think_template')){
  291. $templateSet = cookie('think_template');
  292. }else{
  293. $templateSet = C('DEFAULT_THEME');
  294. cookie('think_template',$templateSet,3600);
  295. }
  296. }
  297. if(!is_dir(TMPL_PATH.$templateSet))
  298. //模版不存在的话,使用默认模版
  299. $templateSet = C('DEFAULT_THEME');
  300. }else{
  301. $templateSet = C('DEFAULT_THEME');
  302. }
  303. //模版名称
  304. define('TEMPLATE_NAME',$templateSet);
  305. // 当前模版路径
  306. define('TEMPLATE_PATH',TMPL_PATH.TEMPLATE_NAME);
  307. $tmplDir = TMPL_DIR.'/'.TEMPLATE_NAME.'/';
  308. //当前项目地址
  309. define('__APP__',PHP_FILE);
  310. //当前页面地址
  311. define('__SELF__',$_SERVER['PHP_SELF']);
  312. // 应用URL根目录
  313. if(C('APP_DOMAIN_DEPLOY')) {
  314. // 独立域名部署需要指定模板从根目录开始
  315. $appRoot = '/';
  316. }else{
  317. $appRoot = __ROOT__.'/'.APP_NAME.'/';
  318. }
  319. $depr = C('URL_PATHINFO_MODEL')==2?C('URL_PATHINFO_DEPR'):'/';
  320. $module = defined('P_MODULE_NAME')?P_MODULE_NAME:MODULE_NAME;
  321. if(defined('GROUP_NAME')) {
  322. $group = C('URL_CASE_INSENSITIVE') ?strtolower(GROUP_NAME):GROUP_NAME;
  323. define('__URL__',PHP_FILE.'/'.((GROUP_NAME != C('DEFAULT_GROUP'))?$group.$depr:'').$module);
  324. C('TMPL_FILE_NAME',TEMPLATE_PATH.'/'.GROUP_NAME.'/'.MODULE_NAME.C('TMPL_FILE_DEPR').ACTION_NAME.C('TMPL_TEMPLATE_SUFFIX'));
  325. C('CACHE_PATH',CACHE_PATH.GROUP_NAME.'/');
  326. }else{
  327. define('__URL__',PHP_FILE.'/'.$module);
  328. C('TMPL_FILE_NAME',TEMPLATE_PATH.'/'.str_replace(C('APP_GROUP_DEPR'),'/',MODULE_NAME).'/'.ACTION_NAME.C('TMPL_TEMPLATE_SUFFIX'));
  329. C('CACHE_PATH',CACHE_PATH);
  330. }
  331. //当前操作地址
  332. define('__ACTION__',__URL__.C('URL_PATHINFO_DEPR').ACTION_NAME);
  333. define('__CURRENT__', __ROOT__.'/'.APP_NAME.'/'.$tmplDir.MODULE_NAME);
  334. //项目模板目录
  335. define('APP_TMPL_PATH', $appRoot.$tmplDir);
  336. //网站公共文件目录
  337. define('WEB_PUBLIC_PATH', __ROOT__.'/Public');
  338. //项目公共文件目录
  339. define('APP_PUBLIC_PATH', APP_TMPL_PATH.'Public');
  340. return ;
  341. }
  342. /**
  343. +----------------------------------------------------------
  344. * 执行应用程序
  345. +----------------------------------------------------------
  346. * @access public
  347. +----------------------------------------------------------
  348. * @return void
  349. +----------------------------------------------------------
  350. * @throws ThinkExecption
  351. +----------------------------------------------------------
  352. */
  353. static public function exec()
  354. {
  355. // 是否开启标签扩展
  356. $tagOn = C('APP_PLUGIN_ON');
  357. // 项目运行标签
  358. if($tagOn) tag('app_run');
  359. //创建Action控制器实例
  360. $group = defined('GROUP_NAME') ? GROUP_NAME.C('APP_GROUP_DEPR') : '';
  361. $module = A($group.MODULE_NAME);
  362. if(!$module) {
  363. // 是否存在扩展模块
  364. $_module = C('_modules_.'.MODULE_NAME);
  365. if($_module) {
  366. // 'module'=>array('classImportPath'[,'className'])
  367. import($_module[0]);
  368. $class = isset($_module[1])?$_module[1]:MODULE_NAME.'Action';
  369. $module = new $class;
  370. }else{
  371. // 是否定义Empty模块
  372. $module = A("Empty");
  373. }
  374. if(!$module)
  375. // 模块不存在 抛出异常
  376. throw_exception(L('_MODULE_NOT_EXIST_').MODULE_NAME);
  377. }
  378. //获取当前操作名
  379. $action = ACTION_NAME;
  380. if(strpos($action,':')) {
  381. // 执行操作链 最多只能有一个输出
  382. $actionList = explode(':',$action);
  383. foreach ($actionList as $action){
  384. $module->$action();
  385. }
  386. }else{
  387. if (method_exists($module,'_before_'.$action)) {
  388. // 执行前置操作
  389. call_user_func(array(&$module,'_before_'.$action));
  390. }
  391. //执行当前操作
  392. call_user_func(array(&$module,$action));
  393. if (method_exists($module,'_after_'.$action)) {
  394. // 执行后缀操作
  395. call_user_func(array(&$module,'_after_'.$action));
  396. }
  397. }
  398. // 项目结束标签
  399. if($tagOn) tag('app_end');
  400. return ;
  401. }
  402. /**
  403. +----------------------------------------------------------
  404. * 运行应用实例 入口文件使用的快捷方法
  405. +----------------------------------------------------------
  406. * @access public
  407. +----------------------------------------------------------
  408. * @return void
  409. +----------------------------------------------------------
  410. */
  411. static public function run() {
  412. App::init();
  413. // 记录应用初始化时间
  414. if(C('SHOW_RUN_TIME')) $GLOBALS['_initTime'] = microtime(TRUE);
  415. App::exec();
  416. // 保存日志记录
  417. if(C('LOG_RECORD')) Log::save();
  418. return ;
  419. }
  420. /**
  421. +----------------------------------------------------------
  422. * 自定义异常处理
  423. +----------------------------------------------------------
  424. * @access public
  425. +----------------------------------------------------------
  426. * @param mixed $e 异常对象
  427. +----------------------------------------------------------
  428. */
  429. static public function appException($e)
  430. {
  431. halt($e->__toString());
  432. }
  433. /**
  434. +----------------------------------------------------------
  435. * 自定义错误处理
  436. +----------------------------------------------------------
  437. * @access public
  438. +----------------------------------------------------------
  439. * @param int $errno 错误类型
  440. * @param string $errstr 错误信息
  441. * @param string $errfile 错误文件
  442. * @param int $errline 错误行数
  443. +----------------------------------------------------------
  444. * @return void
  445. +----------------------------------------------------------
  446. */
  447. static public function appError($errno, $errstr, $errfile, $errline)
  448. {
  449. switch ($errno) {
  450. case E_ERROR:
  451. case E_USER_ERROR:
  452. $errorStr = "[$errno] $errstr ".basename($errfile)." 第 $errline 行.";
  453. if(C('LOG_RECORD')) Log::write($errorStr,Log::ERR);
  454. halt($errorStr);
  455. break;
  456. case E_STRICT:
  457. case E_USER_WARNING:
  458. case E_USER_NOTICE:
  459. default:
  460. $errorStr = "[$errno] $errstr ".basename($errfile)." 第 $errline 行.";
  461. Log::record($errorStr,Log::NOTICE);
  462. break;
  463. }
  464. }
  465. };//类定义结束
  466. ?>