common.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2006-2012 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. /**
  12. * Think 基础函数库
  13. * @category Think
  14. * @package Common
  15. * @author liu21st <liu21st@gmail.com>
  16. */
  17. /**
  18. * 获取模版文件 格式 项目://分组@主题/模块/操作
  19. * @param string $name 模版资源地址
  20. * @param string $layer 视图层(目录)名称
  21. * @return string
  22. */
  23. function T($template='',$layer=''){
  24. if(is_file($template)) {
  25. return $template;
  26. }
  27. // 解析模版资源地址
  28. if(false === strpos($template,'://')){
  29. $template = APP_NAME.'://'.str_replace(':', '/',$template);
  30. }
  31. $info = parse_url($template);
  32. $file = $info['host'].(isset($info['path'])?$info['path']:'');
  33. $group = isset($info['user'])?$info['user'].'/':(defined('GROUP_NAME')?GROUP_NAME.'/':'');
  34. $app = $info['scheme'];
  35. $layer = $layer?$layer:C('DEFAULT_V_LAYER');
  36. // 获取当前主题的模版路径
  37. if(($list = C('EXTEND_GROUP_LIST')) && isset($list[$app])){ // 扩展分组
  38. $baseUrl = $list[$app].'/'.$group.$layer.'/';
  39. }elseif(1==C('APP_GROUP_MODE')){ // 独立分组模式
  40. $baseUrl = dirname(BASE_LIB_PATH).'/'.$group.$layer.'/';
  41. }else{
  42. $baseUrl = TMPL_PATH.$group;
  43. }
  44. // 分析模板文件规则
  45. if('' == $file) {
  46. // 如果模板文件名为空 按照默认规则定位
  47. $file = MODULE_NAME . C('TMPL_FILE_DEPR') . ACTION_NAME;
  48. }elseif(false === strpos($file, '/')){
  49. $file = MODULE_NAME . C('TMPL_FILE_DEPR') . $file;
  50. }
  51. return $baseUrl.$file.C('TMPL_TEMPLATE_SUFFIX');
  52. }
  53. /**
  54. * 获取输入参数 支持过滤和默认值
  55. * 使用方法:
  56. * <code>
  57. * I('id',0); 获取id参数 自动判断get或者post
  58. * I('post.name','','htmlspecialchars'); 获取$_POST['name']
  59. * I('get.'); 获取$_GET
  60. * </code>
  61. * @param string $name 变量的名称 支持指定类型
  62. * @param mixed $default 不存在的时候默认值
  63. * @param mixed $filter 参数过滤方法
  64. * @return mixed
  65. */
  66. function I($name,$default='',$filter=null) {
  67. if(strpos($name,'.')) { // 指定参数来源
  68. list($method,$name) = explode('.',$name,2);
  69. }else{ // 默认为自动判断
  70. $method = 'param';
  71. }
  72. switch(strtolower($method)) {
  73. case 'get' : $input =& $_GET;break;
  74. case 'post' : $input =& $_POST;break;
  75. case 'put' : parse_str(file_get_contents('php://input'), $input);break;
  76. case 'param' :
  77. switch($_SERVER['REQUEST_METHOD']) {
  78. case 'POST':
  79. $input = $_POST;
  80. break;
  81. case 'PUT':
  82. parse_str(file_get_contents('php://input'), $input);
  83. break;
  84. default:
  85. $input = $_GET;
  86. }
  87. if(C('VAR_URL_PARAMS') && isset($_GET[C('VAR_URL_PARAMS')])){
  88. $input = array_merge($input,$_GET[C('VAR_URL_PARAMS')]);
  89. }
  90. break;
  91. case 'request' : $input =& $_REQUEST; break;
  92. case 'session' : $input =& $_SESSION; break;
  93. case 'cookie' : $input =& $_COOKIE; break;
  94. case 'server' : $input =& $_SERVER; break;
  95. case 'globals' : $input =& $GLOBALS; break;
  96. default:
  97. return NULL;
  98. }
  99. // 全局过滤
  100. if(C('VAR_FILTERS')) {
  101. $_filters = explode(',',C('VAR_FILTERS'));
  102. foreach($_filters as $_filter){
  103. // 全局参数过滤
  104. array_walk_recursive($input,$_filter);
  105. }
  106. }
  107. if(empty($name)) { // 获取全部变量
  108. $data = $input;
  109. $filters = isset($filter)?$filter:C('DEFAULT_FILTER');
  110. if($filters) {
  111. $filters = explode(',',$filters);
  112. foreach($filters as $filter){
  113. $data = array_map($filter,$data); // 参数过滤
  114. }
  115. }
  116. }elseif(isset($input[$name])) { // 取值操作
  117. $data = $input[$name];
  118. $filters = isset($filter)?$filter:C('DEFAULT_FILTER');
  119. if($filters) {
  120. $filters = explode(',',$filters);
  121. foreach($filters as $filter){
  122. if(function_exists($filter)) {
  123. $data = is_array($data)?array_map($filter,$data):$filter($data); // 参数过滤
  124. }else{
  125. $data = filter_var($data,is_int($filter)?$filter:filter_id($filter));
  126. if(false === $data) {
  127. return isset($default)?$default:NULL;
  128. }
  129. }
  130. }
  131. }
  132. }else{ // 变量默认值
  133. $data = isset($default)?$default:NULL;
  134. }
  135. is_array($data) && array_walk_recursive($data,'think_filter');
  136. return $data;
  137. }
  138. /**
  139. * 记录和统计时间(微秒)和内存使用情况
  140. * 使用方法:
  141. * <code>
  142. * G('begin'); // 记录开始标记位
  143. * // ... 区间运行代码
  144. * G('end'); // 记录结束标签位
  145. * echo G('begin','end',6); // 统计区间运行时间 精确到小数后6位
  146. * echo G('begin','end','m'); // 统计区间内存使用情况
  147. * 如果end标记位没有定义,则会自动以当前作为标记位
  148. * 其中统计内存使用需要 MEMORY_LIMIT_ON 常量为true才有效
  149. * </code>
  150. * @param string $start 开始标签
  151. * @param string $end 结束标签
  152. * @param integer|string $dec 小数位或者m
  153. * @return mixed
  154. */
  155. function G($start,$end='',$dec=4) {
  156. static $_info = array();
  157. static $_mem = array();
  158. if(is_float($end)) { // 记录时间
  159. $_info[$start] = $end;
  160. }elseif(!empty($end)){ // 统计时间和内存使用
  161. if(!isset($_info[$end])) $_info[$end] = microtime(TRUE);
  162. if(MEMORY_LIMIT_ON && $dec=='m'){
  163. if(!isset($_mem[$end])) $_mem[$end] = memory_get_usage();
  164. return number_format(($_mem[$end]-$_mem[$start])/1024);
  165. }else{
  166. return number_format(($_info[$end]-$_info[$start]),$dec);
  167. }
  168. }else{ // 记录时间和内存使用
  169. $_info[$start] = microtime(TRUE);
  170. if(MEMORY_LIMIT_ON) $_mem[$start] = memory_get_usage();
  171. }
  172. }
  173. /**
  174. * 设置和获取统计数据
  175. * 使用方法:
  176. * <code>
  177. * N('db',1); // 记录数据库操作次数
  178. * N('read',1); // 记录读取次数
  179. * echo N('db'); // 获取当前页面数据库的所有操作次数
  180. * echo N('read'); // 获取当前页面读取次数
  181. * </code>
  182. * @param string $key 标识位置
  183. * @param integer $step 步进值
  184. * @return mixed
  185. */
  186. function N($key, $step=0,$save=false) {
  187. static $_num = array();
  188. if (!isset($_num[$key])) {
  189. $_num[$key] = (false !== $save)? S('N_'.$key) : 0;
  190. }
  191. if (empty($step))
  192. return $_num[$key];
  193. else
  194. $_num[$key] = $_num[$key] + (int) $step;
  195. if(false !== $save){ // 保存结果
  196. S('N_'.$key,$_num[$key],$save);
  197. }
  198. }
  199. /**
  200. * 字符串命名风格转换
  201. * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格
  202. * @param string $name 字符串
  203. * @param integer $type 转换类型
  204. * @return string
  205. */
  206. function parse_name($name, $type=0) {
  207. if ($type) {
  208. return ucfirst(preg_replace("/_([a-zA-Z])/e", "strtoupper('\\1')", $name));
  209. } else {
  210. return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_"));
  211. }
  212. }
  213. /**
  214. * 优化的require_once
  215. * @param string $filename 文件地址
  216. * @return boolean
  217. */
  218. function require_cache($filename) {
  219. static $_importFiles = array();
  220. if (!isset($_importFiles[$filename])) {
  221. if (file_exists_case($filename)) {
  222. require $filename;
  223. $_importFiles[$filename] = true;
  224. } else {
  225. $_importFiles[$filename] = false;
  226. }
  227. }
  228. return $_importFiles[$filename];
  229. }
  230. /**
  231. * 批量导入文件 成功则返回
  232. * @param array $array 文件数组
  233. * @param boolean $return 加载成功后是否返回
  234. * @return boolean
  235. */
  236. function require_array($array,$return=false){
  237. foreach ($array as $file){
  238. if (require_cache($file) && $return) return true;
  239. }
  240. if($return) return false;
  241. }
  242. /**
  243. * 区分大小写的文件存在判断
  244. * @param string $filename 文件地址
  245. * @return boolean
  246. */
  247. function file_exists_case($filename) {
  248. if (is_file($filename)) {
  249. if (IS_WIN && C('APP_FILE_CASE')) {
  250. if (basename(realpath($filename)) != basename($filename))
  251. return false;
  252. }
  253. return true;
  254. }
  255. return false;
  256. }
  257. /**
  258. * 导入所需的类库 同java的Import 本函数有缓存功能
  259. * @param string $class 类库命名空间字符串
  260. * @param string $baseUrl 起始路径
  261. * @param string $ext 导入的文件扩展名
  262. * @return boolean
  263. */
  264. function import($class, $baseUrl = '', $ext='.class.php') {
  265. static $_file = array();
  266. $class = str_replace(array('.', '#'), array('/', '.'), $class);
  267. if ('' === $baseUrl && false === strpos($class, '/')) {
  268. // 检查别名导入
  269. return alias_import($class);
  270. }
  271. if (isset($_file[$class . $baseUrl]))
  272. return true;
  273. else
  274. $_file[$class . $baseUrl] = true;
  275. $class_strut = explode('/', $class);
  276. if (empty($baseUrl)) {
  277. $libPath = defined('BASE_LIB_PATH')?BASE_LIB_PATH:LIB_PATH;
  278. if ('@' == $class_strut[0] || APP_NAME == $class_strut[0]) {
  279. //加载当前项目应用类库
  280. $baseUrl = dirname($libPath);
  281. $class = substr_replace($class, basename($libPath).'/', 0, strlen($class_strut[0]) + 1);
  282. }elseif ('think' == strtolower($class_strut[0])){ // think 官方基类库
  283. $baseUrl = CORE_PATH;
  284. $class = substr($class,6);
  285. }elseif (in_array(strtolower($class_strut[0]), array('org', 'com'))) {
  286. // org 第三方公共类库 com 企业公共类库
  287. $baseUrl = LIBRARY_PATH;
  288. }else { // 加载其他项目应用类库
  289. $class = substr_replace($class, '', 0, strlen($class_strut[0]) + 1);
  290. $baseUrl = APP_PATH . '../' . $class_strut[0] . '/'.basename($libPath).'/';
  291. }
  292. }
  293. if (substr($baseUrl, -1) != '/')
  294. $baseUrl .= '/';
  295. $classfile = $baseUrl . $class . $ext;
  296. if (!class_exists(basename($class),false)) {
  297. // 如果类不存在 则导入类库文件
  298. return require_cache($classfile);
  299. }
  300. }
  301. /**
  302. * 基于命名空间方式导入函数库
  303. * load('@.Util.Array')
  304. * @param string $name 函数库命名空间字符串
  305. * @param string $baseUrl 起始路径
  306. * @param string $ext 导入的文件扩展名
  307. * @return void
  308. */
  309. function load($name, $baseUrl='', $ext='.php') {
  310. $name = str_replace(array('.', '#'), array('/', '.'), $name);
  311. if (empty($baseUrl)) {
  312. if (0 === strpos($name, '@/')) {
  313. //加载当前项目函数库
  314. $baseUrl = COMMON_PATH;
  315. $name = substr($name, 2);
  316. } else {
  317. //加载ThinkPHP 系统函数库
  318. $baseUrl = EXTEND_PATH . 'Function/';
  319. }
  320. }
  321. if (substr($baseUrl, -1) != '/')
  322. $baseUrl .= '/';
  323. require_cache($baseUrl . $name . $ext);
  324. }
  325. /**
  326. * 快速导入第三方框架类库 所有第三方框架的类库文件统一放到 系统的Vendor目录下面
  327. * @param string $class 类库
  328. * @param string $baseUrl 基础目录
  329. * @param string $ext 类库后缀
  330. * @return boolean
  331. */
  332. function vendor($class, $baseUrl = '', $ext='.php') {
  333. if (empty($baseUrl))
  334. $baseUrl = VENDOR_PATH;
  335. return import($class, $baseUrl, $ext);
  336. }
  337. /**
  338. * 快速定义和导入别名 支持批量定义
  339. * @param string|array $alias 类库别名
  340. * @param string $classfile 对应类库
  341. * @return boolean
  342. */
  343. function alias_import($alias, $classfile='') {
  344. static $_alias = array();
  345. if (is_string($alias)) {
  346. if(isset($_alias[$alias])) {
  347. return require_cache($_alias[$alias]);
  348. }elseif ('' !== $classfile) {
  349. // 定义别名导入
  350. $_alias[$alias] = $classfile;
  351. return;
  352. }
  353. }elseif (is_array($alias)) {
  354. $_alias = array_merge($_alias,$alias);
  355. return;
  356. }
  357. return false;
  358. }
  359. /**
  360. * D函数用于实例化Model 格式 项目://分组/模块
  361. * @param string $name Model资源地址
  362. * @param string $layer 业务层名称
  363. * @return Model
  364. */
  365. function D($name='',$layer='') {
  366. if(empty($name)) return new Model;
  367. static $_model = array();
  368. $layer = $layer?$layer:C('DEFAULT_M_LAYER');
  369. if(strpos($name,'://')) {// 指定项目
  370. list($app) = explode('://',$name);
  371. $name = str_replace('://','/'.$layer.'/',$name);
  372. }else{
  373. $app = C('DEFAULT_APP');
  374. $name = $app.'/'.$layer.'/'.$name;
  375. }
  376. if(isset($_model[$name])) return $_model[$name];
  377. $path = explode('/',$name);
  378. if($list = C('EXTEND_GROUP_LIST') && isset($list[$app])){ // 扩展分组
  379. $baseUrl = $list[$app];
  380. import($path[2].'/'.$path[1].'/'.$path[3].$layer,$baseUrl);
  381. }elseif(count($path)>3 && 1 == C('APP_GROUP_MODE')) { // 独立分组
  382. $baseUrl = $path[0]== '@' ? dirname(BASE_LIB_PATH) : APP_PATH.'../'.$path[0].'/'.C('APP_GROUP_PATH').'/';
  383. import($path[2].'/'.$path[1].'/'.$path[3].$layer,$baseUrl);
  384. }else{
  385. import($name.$layer);
  386. }
  387. $class = basename($name.$layer);
  388. if(class_exists($class)) {
  389. $model = new $class(basename($name));
  390. }else {
  391. $model = new Model(basename($name));
  392. }
  393. $_model[$name] = $model;
  394. return $model;
  395. }
  396. /**
  397. * M函数用于实例化一个没有模型文件的Model
  398. * @param string $name Model名称 支持指定基础模型 例如 MongoModel:User
  399. * @param string $tablePrefix 表前缀
  400. * @param mixed $connection 数据库连接信息
  401. * @return Model
  402. */
  403. function M($name='', $tablePrefix='',$connection='') {
  404. static $_model = array();
  405. if(strpos($name,':')) {
  406. list($class,$name) = explode(':',$name);
  407. }else{
  408. $class = 'Model';
  409. }
  410. $guid = $tablePrefix . $name . '_' . $class;
  411. if (!isset($_model[$guid]))
  412. $_model[$guid] = new $class($name,$tablePrefix,$connection);
  413. return $_model[$guid];
  414. }
  415. /**
  416. * A函数用于实例化Action 格式:[项目://][分组/]模块
  417. * @param string $name Action资源地址
  418. * @param string $layer 控制层名称
  419. * @param boolean $common 是否公共目录
  420. * @return Action|false
  421. */
  422. function A($name,$layer='',$common=false) {
  423. static $_action = array();
  424. $layer = $layer?$layer:C('DEFAULT_C_LAYER');
  425. if(strpos($name,'://')) {// 指定项目
  426. list($app) = explode('://',$name);
  427. $name = str_replace('://','/'.$layer.'/',$name);
  428. }else{
  429. $app = '@';
  430. $name = '@/'.$layer.'/'.$name;
  431. }
  432. if(isset($_action[$name])) return $_action[$name];
  433. $path = explode('/',$name);
  434. if($list = C('EXTEND_GROUP_LIST') && isset($list[$app])){ // 扩展分组
  435. $baseUrl = $list[$app];
  436. import($path[2].'/'.$path[1].'/'.$path[3].$layer,$baseUrl);
  437. }elseif(count($path)>3 && 1 == C('APP_GROUP_MODE')) { // 独立分组
  438. $baseUrl = $path[0]== '@' ? dirname(BASE_LIB_PATH) : APP_PATH.'../'.$path[0].'/'.C('APP_GROUP_PATH').'/';
  439. import($path[2].'/'.$path[1].'/'.$path[3].$layer,$baseUrl);
  440. }elseif($common) { // 加载公共类库目录
  441. import(str_replace('@/','',$name).$layer,LIB_PATH);
  442. }else{
  443. import($name.$layer);
  444. }
  445. $class = basename($name.$layer);
  446. if(class_exists($class,false)) {
  447. $action = new $class();
  448. $_action[$name] = $action;
  449. return $action;
  450. }else {
  451. return false;
  452. }
  453. }
  454. /**
  455. * 远程调用模块的操作方法 URL 参数格式 [项目://][分组/]模块/操作
  456. * @param string $url 调用地址
  457. * @param string|array $vars 调用参数 支持字符串和数组
  458. * @param string $layer 要调用的控制层名称
  459. * @return mixed
  460. */
  461. function R($url,$vars=array(),$layer='') {
  462. $info = pathinfo($url);
  463. $action = $info['basename'];
  464. $module = $info['dirname'];
  465. $class = A($module,$layer);
  466. if($class){
  467. if(is_string($vars)) {
  468. parse_str($vars,$vars);
  469. }
  470. return call_user_func_array(array(&$class,$action.C('ACTION_SUFFIX')),$vars);
  471. }else{
  472. return false;
  473. }
  474. }
  475. /**
  476. * 获取和设置语言定义(不区分大小写)
  477. * @param string|array $name 语言变量
  478. * @param string $value 语言值
  479. * @return mixed
  480. */
  481. function L($name=null, $value=null) {
  482. static $_lang = array();
  483. // 空参数返回所有定义
  484. if (empty($name))
  485. return $_lang;
  486. // 判断语言获取(或设置)
  487. // 若不存在,直接返回全大写$name
  488. if (is_string($name)) {
  489. $name = strtoupper($name);
  490. if (is_null($value))
  491. return isset($_lang[$name]) ? $_lang[$name] : $name;
  492. $_lang[$name] = $value; // 语言定义
  493. return;
  494. }
  495. // 批量定义
  496. if (is_array($name))
  497. $_lang = array_merge($_lang, array_change_key_case($name, CASE_UPPER));
  498. return;
  499. }
  500. /**
  501. * 获取和设置配置参数 支持批量定义
  502. * @param string|array $name 配置变量
  503. * @param mixed $value 配置值
  504. * @return mixed
  505. */
  506. function C($name=null, $value=null) {
  507. static $_config = array();
  508. // 无参数时获取所有
  509. if (empty($name)) {
  510. if(!empty($value) && $array = S('c_'.$value)) {
  511. $_config = array_merge($_config, array_change_key_case($array));
  512. }
  513. return $_config;
  514. }
  515. // 优先执行设置获取或赋值
  516. if (is_string($name)) {
  517. if (!strpos($name, '.')) {
  518. $name = strtolower($name);
  519. if (is_null($value))
  520. return isset($_config[$name]) ? $_config[$name] : null;
  521. $_config[$name] = $value;
  522. return;
  523. }
  524. // 二维数组设置和获取支持
  525. $name = explode('.', $name);
  526. $name[0] = strtolower($name[0]);
  527. if (is_null($value))
  528. return isset($_config[$name[0]][$name[1]]) ? $_config[$name[0]][$name[1]] : null;
  529. $_config[$name[0]][$name[1]] = $value;
  530. return;
  531. }
  532. // 批量设置
  533. if (is_array($name)){
  534. $_config = array_merge($_config, array_change_key_case($name));
  535. if(!empty($value)) {// 保存配置值
  536. S('c_'.$value,$_config);
  537. }
  538. return;
  539. }
  540. return null; // 避免非法参数
  541. }
  542. /**
  543. * 处理标签扩展
  544. * @param string $tag 标签名称
  545. * @param mixed $params 传入参数
  546. * @return mixed
  547. */
  548. function tag($tag, &$params=NULL) {
  549. // 系统标签扩展
  550. $extends = C('extends.' . $tag);
  551. // 应用标签扩展
  552. $tags = C('tags.' . $tag);
  553. if (!empty($tags)) {
  554. if(empty($tags['_overlay']) && !empty($extends)) { // 合并扩展
  555. $tags = array_unique(array_merge($extends,$tags));
  556. }elseif(isset($tags['_overlay'])){ // 通过设置 '_overlay'=>1 覆盖系统标签
  557. unset($tags['_overlay']);
  558. }
  559. }elseif(!empty($extends)) {
  560. $tags = $extends;
  561. }
  562. if($tags) {
  563. if(APP_DEBUG) {
  564. G($tag.'Start');
  565. trace('[ '.$tag.' ] --START--','','INFO');
  566. }
  567. // 执行扩展
  568. foreach ($tags as $key=>$name) {
  569. if(!is_int($key)) { // 指定行为类的完整路径 用于模式扩展
  570. $name = $key;
  571. }
  572. B($name, $params);
  573. }
  574. if(APP_DEBUG) { // 记录行为的执行日志
  575. trace('[ '.$tag.' ] --END-- [ RunTime:'.G($tag.'Start',$tag.'End',6).'s ]','','INFO');
  576. }
  577. }else{ // 未执行任何行为 返回false
  578. return false;
  579. }
  580. }
  581. /**
  582. * 动态添加行为扩展到某个标签
  583. * @param string $tag 标签名称
  584. * @param string $behavior 行为名称
  585. * @param string $path 行为路径
  586. * @return void
  587. */
  588. function add_tag_behavior($tag,$behavior,$path='') {
  589. $array = C('tags.'.$tag);
  590. if(!$array) {
  591. $array = array();
  592. }
  593. if($path) {
  594. $array[$behavior] = $path;
  595. }else{
  596. $array[] = $behavior;
  597. }
  598. C('tags.'.$tag,$array);
  599. }
  600. /**
  601. * 执行某个行为
  602. * @param string $name 行为名称
  603. * @param Mixed $params 传入的参数
  604. * @return void
  605. */
  606. function B($name, &$params=NULL) {
  607. if(strpos($name,'/')){
  608. list($name,$method) = explode('/',$name);
  609. }else{
  610. $method = 'run';
  611. }
  612. $class = $name.'Behavior';
  613. if(APP_DEBUG) {
  614. G('behaviorStart');
  615. }
  616. $behavior = new $class();
  617. $behavior->$method($params);
  618. if(APP_DEBUG) { // 记录行为的执行日志
  619. G('behaviorEnd');
  620. trace($name.' Behavior ::'.$method.' [ RunTime:'.G('behaviorStart','behaviorEnd',6).'s ]','','INFO');
  621. }
  622. }
  623. /**
  624. * 去除代码中的空白和注释
  625. * @param string $content 代码内容
  626. * @return string
  627. */
  628. function strip_whitespace($content) {
  629. $stripStr = '';
  630. //分析php源码
  631. $tokens = token_get_all($content);
  632. $last_space = false;
  633. for ($i = 0, $j = count($tokens); $i < $j; $i++) {
  634. if (is_string($tokens[$i])) {
  635. $last_space = false;
  636. $stripStr .= $tokens[$i];
  637. } else {
  638. switch ($tokens[$i][0]) {
  639. //过滤各种PHP注释
  640. case T_COMMENT:
  641. case T_DOC_COMMENT:
  642. break;
  643. //过滤空格
  644. case T_WHITESPACE:
  645. if (!$last_space) {
  646. $stripStr .= ' ';
  647. $last_space = true;
  648. }
  649. break;
  650. case T_START_HEREDOC:
  651. $stripStr .= "<<<THINK\n";
  652. break;
  653. case T_END_HEREDOC:
  654. $stripStr .= "THINK;\n";
  655. for($k = $i+1; $k < $j; $k++) {
  656. if(is_string($tokens[$k]) && $tokens[$k] == ';') {
  657. $i = $k;
  658. break;
  659. } else if($tokens[$k][0] == T_CLOSE_TAG) {
  660. break;
  661. }
  662. }
  663. break;
  664. default:
  665. $last_space = false;
  666. $stripStr .= $tokens[$i][1];
  667. }
  668. }
  669. }
  670. return $stripStr;
  671. }
  672. //[RUNTIME]
  673. // 编译文件
  674. function compile($filename) {
  675. $content = file_get_contents($filename);
  676. // 替换预编译指令
  677. $content = preg_replace('/\/\/\[RUNTIME\](.*?)\/\/\[\/RUNTIME\]/s', '', $content);
  678. $content = substr(trim($content), 5);
  679. if ('?>' == substr($content, -2))
  680. $content = substr($content, 0, -2);
  681. return $content;
  682. }
  683. // 根据数组生成常量定义
  684. function array_define($array,$check=true) {
  685. $content = "\n";
  686. foreach ($array as $key => $val) {
  687. $key = strtoupper($key);
  688. if($check) $content .= 'defined(\'' . $key . '\') or ';
  689. if (is_int($val) || is_float($val)) {
  690. $content .= "define('" . $key . "'," . $val . ');';
  691. } elseif (is_bool($val)) {
  692. $val = ($val) ? 'true' : 'false';
  693. $content .= "define('" . $key . "'," . $val . ');';
  694. } elseif (is_string($val)) {
  695. $content .= "define('" . $key . "','" . addslashes($val) . "');";
  696. }
  697. $content .= "\n";
  698. }
  699. return $content;
  700. }
  701. //[/RUNTIME]
  702. /**
  703. * 添加和获取页面Trace记录
  704. * @param string $value 变量
  705. * @param string $label 标签
  706. * @param string $level 日志级别
  707. * @param boolean $record 是否记录日志
  708. * @return void
  709. */
  710. function trace($value='[think]',$label='',$level='DEBUG',$record=false) {
  711. static $_trace = array();
  712. if('[think]' === $value){ // 获取trace信息
  713. return $_trace;
  714. }else{
  715. $info = ($label?$label.':':'').print_r($value,true);
  716. if('ERR' == $level && C('TRACE_EXCEPTION')) {// 抛出异常
  717. throw_exception($info);
  718. }
  719. $level = strtoupper($level);
  720. if(!isset($_trace[$level])) {
  721. $_trace[$level] = array();
  722. }
  723. $_trace[$level][] = $info;
  724. if((defined('IS_AJAX') && IS_AJAX) || !C('SHOW_PAGE_TRACE') || $record) {
  725. Log::record($info,$level,$record);
  726. }
  727. }
  728. }