functions.php 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2006-2014 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 API模式函数库
  13. */
  14. /**
  15. * 获取和设置配置参数 支持批量定义
  16. * @param string|array $name 配置变量
  17. * @param mixed $value 配置值
  18. * @param mixed $default 默认值
  19. * @return mixed
  20. */
  21. function C($name = null, $value = null, $default = null)
  22. {
  23. static $_config = array();
  24. // 无参数时获取所有
  25. if (empty($name)) {
  26. return $_config;
  27. }
  28. // 优先执行设置获取或赋值
  29. if (is_string($name)) {
  30. if (!strpos($name, '.')) {
  31. $name = strtolower($name);
  32. if (is_null($value)) {
  33. return isset($_config[$name]) ? $_config[$name] : $default;
  34. }
  35. $_config[$name] = $value;
  36. return;
  37. }
  38. // 二维数组设置和获取支持
  39. $name = explode('.', $name);
  40. $name[0] = strtolower($name[0]);
  41. if (is_null($value)) {
  42. return isset($_config[$name[0]][$name[1]]) ? $_config[$name[0]][$name[1]] : $default;
  43. }
  44. $_config[$name[0]][$name[1]] = $value;
  45. return;
  46. }
  47. // 批量设置
  48. if (is_array($name)) {
  49. $_config = array_merge($_config, array_change_key_case($name));
  50. return;
  51. }
  52. return null; // 避免非法参数
  53. }
  54. /**
  55. * 加载配置文件 支持格式转换 仅支持一级配置
  56. * @param string $file 配置文件名
  57. * @param string $parse 配置解析方法 有些格式需要用户自己解析
  58. * @return void
  59. */
  60. function load_config($file, $parse = CONF_PARSE)
  61. {
  62. $ext = pathinfo($file, PATHINFO_EXTENSION);
  63. switch ($ext) {
  64. case 'php':
  65. return include $file;
  66. case 'ini':
  67. return parse_ini_file($file);
  68. case 'yaml':
  69. return yaml_parse_file($file);
  70. case 'xml':
  71. return (array) simplexml_load_file($file);
  72. case 'json':
  73. return json_decode(file_get_contents($file), true);
  74. default:
  75. if (function_exists($parse)) {
  76. return $parse($file);
  77. } else {
  78. E(L('_NOT_SUPPORT_') . ':' . $ext);
  79. }
  80. }
  81. }
  82. /**
  83. * 抛出异常处理
  84. * @param string $msg 异常消息
  85. * @param integer $code 异常代码 默认为0
  86. * @return void
  87. */
  88. function E($msg, $code = 0)
  89. {
  90. throw new Think\Exception($msg, $code);
  91. }
  92. /**
  93. * 记录和统计时间(微秒)和内存使用情况
  94. * 使用方法:
  95. * <code>
  96. * G('begin'); // 记录开始标记位
  97. * // ... 区间运行代码
  98. * G('end'); // 记录结束标签位
  99. * echo G('begin','end',6); // 统计区间运行时间 精确到小数后6位
  100. * echo G('begin','end','m'); // 统计区间内存使用情况
  101. * 如果end标记位没有定义,则会自动以当前作为标记位
  102. * 其中统计内存使用需要 MEMORY_LIMIT_ON 常量为true才有效
  103. * </code>
  104. * @param string $start 开始标签
  105. * @param string $end 结束标签
  106. * @param integer|string $dec 小数位或者m
  107. * @return mixed
  108. */
  109. function G($start, $end = '', $dec = 4)
  110. {
  111. static $_info = array();
  112. static $_mem = array();
  113. if (is_float($end)) {
  114. // 记录时间
  115. $_info[$start] = $end;
  116. } elseif (!empty($end)) {
  117. // 统计时间和内存使用
  118. if (!isset($_info[$end])) {
  119. $_info[$end] = microtime(true);
  120. }
  121. if (MEMORY_LIMIT_ON && 'm' == $dec) {
  122. if (!isset($_mem[$end])) {
  123. $_mem[$end] = memory_get_usage();
  124. }
  125. return number_format(($_mem[$end] - $_mem[$start]) / 1024);
  126. } else {
  127. return number_format(($_info[$end] - $_info[$start]), $dec);
  128. }
  129. } else {
  130. // 记录时间和内存使用
  131. $_info[$start] = microtime(true);
  132. if (MEMORY_LIMIT_ON) {
  133. $_mem[$start] = memory_get_usage();
  134. }
  135. }
  136. }
  137. /**
  138. * 获取和设置语言定义(不区分大小写)
  139. * @param string|array $name 语言变量
  140. * @param string $value 语言值
  141. * @return mixed
  142. */
  143. function L($name = null, $value = null)
  144. {
  145. static $_lang = array();
  146. // 空参数返回所有定义
  147. if (empty($name)) {
  148. return $_lang;
  149. }
  150. // 判断语言获取(或设置)
  151. // 若不存在,直接返回全大写$name
  152. if (is_string($name)) {
  153. $name = strtoupper($name);
  154. if (is_null($value)) {
  155. return isset($_lang[$name]) ? $_lang[$name] : $name;
  156. }
  157. $_lang[$name] = $value; // 语言定义
  158. return;
  159. }
  160. // 批量定义
  161. if (is_array($name)) {
  162. $_lang = array_merge($_lang, array_change_key_case($name, CASE_UPPER));
  163. }
  164. return;
  165. }
  166. /**
  167. * 添加和获取页面Trace记录
  168. * @param string $value 变量
  169. * @param string $label 标签
  170. * @param string $level 日志级别
  171. * @param boolean $record 是否记录日志
  172. * @return void
  173. */
  174. function trace($value = '[think]', $label = '', $level = 'DEBUG', $record = false)
  175. {
  176. return Think\Think::trace($value, $label, $level, $record);
  177. }
  178. /**
  179. * 编译文件
  180. * @param string $filename 文件名
  181. * @return string
  182. */
  183. function compile($filename)
  184. {
  185. $content = php_strip_whitespace($filename);
  186. $content = trim(substr($content, 5));
  187. // 替换预编译指令
  188. $content = preg_replace('/\/\/\[RUNTIME\](.*?)\/\/\[\/RUNTIME\]/s', '', $content);
  189. if (0 === strpos($content, 'namespace')) {
  190. $content = preg_replace('/namespace\s(.*?);/', 'namespace \\1{', $content, 1);
  191. } else {
  192. $content = 'namespace {' . $content;
  193. }
  194. if ('?>' == substr($content, -2)) {
  195. $content = substr($content, 0, -2);
  196. }
  197. return $content . '}';
  198. }
  199. /**
  200. * 获取输入参数 支持过滤和默认值
  201. * 使用方法:
  202. * <code>
  203. * I('id',0); 获取id参数 自动判断get或者post
  204. * I('post.name','','htmlspecialchars'); 获取$_POST['name']
  205. * I('get.'); 获取$_GET
  206. * </code>
  207. * @param string $name 变量的名称 支持指定类型
  208. * @param mixed $default 不存在的时候默认值
  209. * @param mixed $filter 参数过滤方法
  210. * @param mixed $datas 要获取的额外数据源
  211. * @return mixed
  212. */
  213. function I($name, $default = '', $filter = null, $datas = null)
  214. {
  215. if (strpos($name, '/')) {
  216. // 指定修饰符
  217. list($name, $type) = explode('/', $name, 2);
  218. }
  219. if (strpos($name, '.')) {
  220. // 指定参数来源
  221. list($method, $name) = explode('.', $name, 2);
  222. } else {
  223. // 默认为自动判断
  224. $method = 'param';
  225. }
  226. switch (strtolower($method)) {
  227. case 'get':$input = &$_GET;
  228. break;
  229. case 'post':$input = &$_POST;
  230. break;
  231. case 'put':parse_str(file_get_contents('php://input'), $input);
  232. break;
  233. case 'param':
  234. switch ($_SERVER['REQUEST_METHOD']) {
  235. case 'POST':
  236. $input = $_POST;
  237. break;
  238. case 'PUT':
  239. parse_str(file_get_contents('php://input'), $input);
  240. break;
  241. default:
  242. $input = $_GET;
  243. }
  244. break;
  245. case 'path':
  246. $input = array();
  247. if (!empty($_SERVER['PATH_INFO'])) {
  248. $depr = C('URL_PATHINFO_DEPR');
  249. $input = explode($depr, trim($_SERVER['PATH_INFO'], $depr));
  250. }
  251. break;
  252. case 'request':$input = &$_REQUEST;
  253. break;
  254. case 'session':$input = &$_SESSION;
  255. break;
  256. case 'cookie':$input = &$_COOKIE;
  257. break;
  258. case 'server':$input = &$_SERVER;
  259. break;
  260. case 'globals':$input = &$GLOBALS;
  261. break;
  262. case 'data':$input = &$datas;
  263. break;
  264. default:
  265. return null;
  266. }
  267. if ('' == $name) {
  268. // 获取全部变量
  269. $data = $input;
  270. $filters = isset($filter) ? $filter : C('DEFAULT_FILTER');
  271. if ($filters) {
  272. if (is_string($filters)) {
  273. $filters = explode(',', $filters);
  274. }
  275. foreach ($filters as $filter) {
  276. $data = arrayMapRecursive($filter, $data); // 参数过滤
  277. }
  278. }
  279. } elseif (isset($input[$name])) {
  280. // 取值操作
  281. $data = $input[$name];
  282. $filters = isset($filter) ? $filter : C('DEFAULT_FILTER');
  283. if ($filters) {
  284. if (is_string($filters)) {
  285. $filters = explode(',', $filters);
  286. } elseif (is_int($filters)) {
  287. $filters = array($filters);
  288. }
  289. foreach ($filters as $filter) {
  290. if (function_exists($filter)) {
  291. $data = is_array($data) ? arrayMapRecursive($filter, $data) : $filter($data); // 参数过滤
  292. } elseif (0 === strpos($filter, '/')) {
  293. // 支持正则验证
  294. if (1 !== preg_match($filter, (string) $data)) {
  295. return isset($default) ? $default : null;
  296. }
  297. } else {
  298. $data = filter_var($data, is_int($filter) ? $filter : filter_id($filter));
  299. if (false === $data) {
  300. return isset($default) ? $default : null;
  301. }
  302. }
  303. }
  304. }
  305. if (!empty($type)) {
  306. switch (strtolower($type)) {
  307. case 's': // 字符串
  308. $data = (string) $data;
  309. break;
  310. case 'a': // 数组
  311. $data = (array) $data;
  312. break;
  313. case 'd': // 数字
  314. $data = (int) $data;
  315. break;
  316. case 'f': // 浮点
  317. $data = (float) $data;
  318. break;
  319. case 'b': // 布尔
  320. $data = (boolean) $data;
  321. break;
  322. }
  323. }
  324. } else {
  325. // 变量默认值
  326. $data = isset($default) ? $default : null;
  327. }
  328. is_array($data) && array_walk_recursive($data, 'think_filter');
  329. return $data;
  330. }
  331. function array_map_recursive($filter, $data)
  332. {
  333. $result = array();
  334. foreach ($data as $key => $val) {
  335. $result[$key] = is_array($val)
  336. ? array_map_recursive($filter, $val)
  337. : call_user_func($filter, $val);
  338. }
  339. return $result;
  340. }
  341. /**
  342. * 设置和获取统计数据
  343. * 使用方法:
  344. * <code>
  345. * N('db',1); // 记录数据库操作次数
  346. * N('read',1); // 记录读取次数
  347. * echo N('db'); // 获取当前页面数据库的所有操作次数
  348. * echo N('read'); // 获取当前页面读取次数
  349. * </code>
  350. * @param string $key 标识位置
  351. * @param integer $step 步进值
  352. * @return mixed
  353. */
  354. function N($key, $step = 0, $save = false)
  355. {
  356. static $_num = array();
  357. if (!isset($_num[$key])) {
  358. $_num[$key] = (false !== $save) ? S('N_' . $key) : 0;
  359. }
  360. if (empty($step)) {
  361. return $_num[$key];
  362. } else {
  363. $_num[$key] = $_num[$key] + (int) $step;
  364. }
  365. if (false !== $save) {
  366. // 保存结果
  367. S('N_' . $key, $_num[$key], $save);
  368. }
  369. }
  370. /**
  371. * 字符串命名风格转换
  372. * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格
  373. * @param string $name 字符串
  374. * @param integer $type 转换类型
  375. * @return string
  376. */
  377. function parse_name($name, $type = 0)
  378. {
  379. if ($type) {
  380. return ucfirst(preg_replace_callback('/_([a-zA-Z])/', function ($match) {return strtoupper($match[1]);}, $name));
  381. } else {
  382. return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_"));
  383. }
  384. }
  385. /**
  386. * 优化的require_once
  387. * @param string $filename 文件地址
  388. * @return boolean
  389. */
  390. function require_cache($filename)
  391. {
  392. static $_importFiles = array();
  393. if (!isset($_importFiles[$filename])) {
  394. if (file_exists_case($filename)) {
  395. require $filename;
  396. $_importFiles[$filename] = true;
  397. } else {
  398. $_importFiles[$filename] = false;
  399. }
  400. }
  401. return $_importFiles[$filename];
  402. }
  403. /**
  404. * 区分大小写的文件存在判断
  405. * @param string $filename 文件地址
  406. * @return boolean
  407. */
  408. function file_exists_case($filename)
  409. {
  410. if (is_file($filename)) {
  411. if (IS_WIN && APP_DEBUG) {
  412. if (basename(realpath($filename)) != basename($filename)) {
  413. return false;
  414. }
  415. }
  416. return true;
  417. }
  418. return false;
  419. }
  420. /**
  421. * 导入所需的类库 同java的Import 本函数有缓存功能
  422. * @param string $class 类库命名空间字符串
  423. * @param string $baseUrl 起始路径
  424. * @param string $ext 导入的文件扩展名
  425. * @return boolean
  426. */
  427. function import($class, $baseUrl = '', $ext = EXT)
  428. {
  429. static $_file = array();
  430. $class = str_replace(array('.', '#'), array('/', '.'), $class);
  431. if (isset($_file[$class . $baseUrl])) {
  432. return true;
  433. } else {
  434. $_file[$class . $baseUrl] = true;
  435. }
  436. $class_strut = explode('/', $class);
  437. if (empty($baseUrl)) {
  438. if ('@' == $class_strut[0] || MODULE_NAME == $class_strut[0]) {
  439. //加载当前模块的类库
  440. $baseUrl = MODULE_PATH;
  441. $class = substr_replace($class, '', 0, strlen($class_strut[0]) + 1);
  442. } elseif (in_array($class_strut[0], array('Think', 'Org', 'Behavior', 'Com', 'Vendor')) || is_dir(LIB_PATH . $class_strut[0])) {
  443. // 系统类库包和第三方类库包
  444. $baseUrl = LIB_PATH;
  445. } else {
  446. // 加载其他模块的类库
  447. $baseUrl = APP_PATH;
  448. }
  449. }
  450. if (substr($baseUrl, -1) != '/') {
  451. $baseUrl .= '/';
  452. }
  453. $classfile = $baseUrl . $class . $ext;
  454. if (!class_exists(basename($class), false)) {
  455. // 如果类不存在 则导入类库文件
  456. return require_cache($classfile);
  457. }
  458. }
  459. /**
  460. * 基于命名空间方式导入函数库
  461. * load('@.Util.Array')
  462. * @param string $name 函数库命名空间字符串
  463. * @param string $baseUrl 起始路径
  464. * @param string $ext 导入的文件扩展名
  465. * @return void
  466. */
  467. function load($name, $baseUrl = '', $ext = '.php')
  468. {
  469. $name = str_replace(array('.', '#'), array('/', '.'), $name);
  470. if (empty($baseUrl)) {
  471. if (0 === strpos($name, '@/')) {
  472. //加载当前模块函数库
  473. $baseUrl = MODULE_PATH . 'Common/';
  474. $name = substr($name, 2);
  475. } else {
  476. //加载其他模块函数库
  477. $array = explode('/', $name);
  478. $baseUrl = APP_PATH . array_shift($array) . '/Common/';
  479. $name = implode('/', $array);
  480. }
  481. }
  482. if (substr($baseUrl, -1) != '/') {
  483. $baseUrl .= '/';
  484. }
  485. require_cache($baseUrl . $name . $ext);
  486. }
  487. /**
  488. * 快速导入第三方框架类库 所有第三方框架的类库文件统一放到 系统的Vendor目录下面
  489. * @param string $class 类库
  490. * @param string $baseUrl 基础目录
  491. * @param string $ext 类库后缀
  492. * @return boolean
  493. */
  494. function vendor($class, $baseUrl = '', $ext = '.php')
  495. {
  496. if (empty($baseUrl)) {
  497. $baseUrl = VENDOR_PATH;
  498. }
  499. return import($class, $baseUrl, $ext);
  500. }
  501. /**
  502. * D函数用于实例化模型类 格式 [资源://][模块/]模型
  503. * @param string $name 资源地址
  504. * @param string $layer 模型层名称
  505. * @return Model
  506. */
  507. function D($name = '', $layer = '')
  508. {
  509. if (empty($name)) {
  510. return new Think\Model;
  511. }
  512. static $_model = array();
  513. $layer = $layer ?: C('DEFAULT_M_LAYER');
  514. if (isset($_model[$name . $layer])) {
  515. return $_model[$name . $layer];
  516. }
  517. $class = parse_res_name($name, $layer);
  518. if (class_exists($class)) {
  519. $model = new $class(basename($name));
  520. } elseif (false === strpos($name, '/')) {
  521. // 自动加载公共模块下面的模型
  522. $class = '\\Common\\' . $layer . '\\' . $name . $layer;
  523. $model = class_exists($class) ? new $class($name) : new Think\Model($name);
  524. } else {
  525. Think\Log::record('D方法实例化没找到模型类' . $class, Think\Log::NOTICE);
  526. $model = new Think\Model(basename($name));
  527. }
  528. $_model[$name . $layer] = $model;
  529. return $model;
  530. }
  531. /**
  532. * M函数用于实例化一个没有模型文件的Model
  533. * @param string $name Model名称 支持指定基础模型 例如 MongoModel:User
  534. * @param string $tablePrefix 表前缀
  535. * @param mixed $connection 数据库连接信息
  536. * @return Model
  537. */
  538. function M($name = '', $tablePrefix = '', $connection = '')
  539. {
  540. static $_model = array();
  541. if (strpos($name, ':')) {
  542. list($class, $name) = explode(':', $name);
  543. } else {
  544. $class = 'Think\\Model';
  545. }
  546. $guid = (is_array($connection) ? implode('', $connection) : $connection) . $tablePrefix . $name . '_' . $class;
  547. if (!isset($_model[$guid])) {
  548. $_model[$guid] = new $class($name, $tablePrefix, $connection);
  549. }
  550. return $_model[$guid];
  551. }
  552. /**
  553. * 解析资源地址并导入类库文件
  554. * 例如 module/controller addon://module/behavior
  555. * @param string $name 资源地址 格式:[扩展://][模块/]资源名
  556. * @param string $layer 分层名称
  557. * @return string
  558. */
  559. function parse_res_name($name, $layer, $level = 1)
  560. {
  561. if (strpos($name, '://')) {
  562. // 指定扩展资源
  563. list($extend, $name) = explode('://', $name);
  564. } else {
  565. $extend = '';
  566. }
  567. if (strpos($name, '/') && substr_count($name, '/') >= $level) {
  568. // 指定模块
  569. list($module, $name) = explode('/', $name, 2);
  570. } else {
  571. $module = MODULE_NAME;
  572. }
  573. $array = explode('/', $name);
  574. $class = $module . '\\' . $layer;
  575. foreach ($array as $name) {
  576. $class .= '\\' . parse_name($name, 1);
  577. }
  578. // 导入资源类库
  579. if ($extend) {
  580. // 扩展资源
  581. $class = $extend . '\\' . $class;
  582. }
  583. return $class . $layer;
  584. }
  585. /**
  586. * A函数用于实例化控制器 格式:[资源://][模块/]控制器
  587. * @param string $name 资源地址
  588. * @param string $layer 控制层名称
  589. * @param integer $level 控制器层次
  590. * @return Controller|false
  591. */
  592. function A($name, $layer = '', $level = '')
  593. {
  594. static $_action = array();
  595. $layer = $layer ?: C('DEFAULT_C_LAYER');
  596. $level = $level ?: (C('DEFAULT_C_LAYER') == $layer ? C('CONTROLLER_LEVEL') : 1);
  597. if (isset($_action[$name . $layer])) {
  598. return $_action[$name . $layer];
  599. }
  600. $class = parse_res_name($name, $layer, $level);
  601. if (class_exists($class)) {
  602. $action = new $class();
  603. $_action[$name . $layer] = $action;
  604. return $action;
  605. } else {
  606. return false;
  607. }
  608. }
  609. /**
  610. * 远程调用控制器的操作方法 URL 参数格式 [资源://][模块/]控制器/操作
  611. * @param string $url 调用地址
  612. * @param string|array $vars 调用参数 支持字符串和数组
  613. * @param string $layer 要调用的控制层名称
  614. * @return mixed
  615. */
  616. function R($url, $vars = array(), $layer = '')
  617. {
  618. $info = pathinfo($url);
  619. $action = $info['basename'];
  620. $module = $info['dirname'];
  621. $class = A($module, $layer);
  622. if ($class) {
  623. if (is_string($vars)) {
  624. parse_str($vars, $vars);
  625. }
  626. return call_user_func_array(array(&$class, $action . C('ACTION_SUFFIX')), $vars);
  627. } else {
  628. return false;
  629. }
  630. }
  631. /**
  632. * 执行某个行为
  633. * @param string $name 行为名称
  634. * @param Mixed $params 传入的参数
  635. * @return void
  636. */
  637. function B($name, &$params = null)
  638. {
  639. if (strpos($name, '/')) {
  640. list($name, $tag) = explode('/', $name);
  641. } else {
  642. $tag = 'run';
  643. }
  644. return \Think\Hook::exec($name, $tag, $params);
  645. }
  646. /**
  647. * 去除代码中的空白和注释
  648. * @param string $content 代码内容
  649. * @return string
  650. */
  651. function strip_whitespace($content)
  652. {
  653. $stripStr = '';
  654. //分析php源码
  655. $tokens = token_get_all($content);
  656. $last_space = false;
  657. for ($i = 0, $j = count($tokens); $i < $j; $i++) {
  658. if (is_string($tokens[$i])) {
  659. $last_space = false;
  660. $stripStr .= $tokens[$i];
  661. } else {
  662. switch ($tokens[$i][0]) {
  663. //过滤各种PHP注释
  664. case T_COMMENT:
  665. case T_DOC_COMMENT:
  666. break;
  667. //过滤空格
  668. case T_WHITESPACE:
  669. if (!$last_space) {
  670. $stripStr .= ' ';
  671. $last_space = true;
  672. }
  673. break;
  674. case T_START_HEREDOC:
  675. $stripStr .= "<<<THINK\n";
  676. break;
  677. case T_END_HEREDOC:
  678. $stripStr .= "THINK;\n";
  679. for ($k = $i + 1; $k < $j; $k++) {
  680. if (is_string($tokens[$k]) && ';' == $tokens[$k]) {
  681. $i = $k;
  682. break;
  683. } else if (T_CLOSE_TAG == $tokens[$k][0]) {
  684. break;
  685. }
  686. }
  687. break;
  688. default:
  689. $last_space = false;
  690. $stripStr .= $tokens[$i][1];
  691. }
  692. }
  693. }
  694. return $stripStr;
  695. }
  696. /**
  697. * 浏览器友好的变量输出
  698. * @param mixed $var 变量
  699. * @param boolean $echo 是否输出 默认为True 如果为false 则返回输出字符串
  700. * @param string $label 标签 默认为空
  701. * @param boolean $strict 是否严谨 默认为true
  702. * @return void|string
  703. */
  704. function dump($var, $echo = true, $label = null, $strict = true)
  705. {
  706. $label = (null === $label) ? '' : rtrim($label) . ' ';
  707. if (!$strict) {
  708. if (ini_get('html_errors')) {
  709. $output = print_r($var, true);
  710. $output = '<pre>' . $label . htmlspecialchars($output, ENT_QUOTES) . '</pre>';
  711. } else {
  712. $output = $label . print_r($var, true);
  713. }
  714. } else {
  715. ob_start();
  716. var_dump($var);
  717. $output = ob_get_clean();
  718. if (!extension_loaded('xdebug')) {
  719. $output = preg_replace('/\]\=\>\n(\s+)/m', '] => ', $output);
  720. $output = '<pre>' . $label . htmlspecialchars($output, ENT_QUOTES) . '</pre>';
  721. }
  722. }
  723. if ($echo) {
  724. echo ($output);
  725. return null;
  726. } else {
  727. return $output;
  728. }
  729. }
  730. /**
  731. * URL重定向
  732. * @param string $url 重定向的URL地址
  733. * @param integer $time 重定向的等待时间(秒)
  734. * @param string $msg 重定向前的提示信息
  735. * @return void
  736. */
  737. function redirect($url, $time = 0, $msg = '')
  738. {
  739. //多行URL地址支持
  740. $url = str_replace(array("\n", "\r"), '', $url);
  741. if (empty($msg)) {
  742. $msg = "系统将在{$time}秒之后自动跳转到{$url}!";
  743. }
  744. if (!headers_sent()) {
  745. // redirect
  746. if (0 === $time) {
  747. header('Location: ' . $url);
  748. } else {
  749. header("refresh:{$time};url={$url}");
  750. echo ($msg);
  751. }
  752. exit();
  753. } else {
  754. $str = "<meta http-equiv='Refresh' content='{$time};URL={$url}'>";
  755. if (0 != $time) {
  756. $str .= $msg;
  757. }
  758. exit($str);
  759. }
  760. }
  761. /**
  762. * 缓存管理
  763. * @param mixed $name 缓存名称,如果为数组表示进行缓存设置
  764. * @param mixed $value 缓存值
  765. * @param mixed $options 缓存参数
  766. * @return mixed
  767. */
  768. function S($name, $value = '', $options = null)
  769. {
  770. static $cache = '';
  771. if (is_array($options) && empty($cache)) {
  772. // 缓存操作的同时初始化
  773. $type = isset($options['type']) ? $options['type'] : '';
  774. $cache = Think\Cache::getInstance($type, $options);
  775. } elseif (is_array($name)) {
  776. // 缓存初始化
  777. $type = isset($name['type']) ? $name['type'] : '';
  778. $cache = Think\Cache::getInstance($type, $name);
  779. return $cache;
  780. } elseif (empty($cache)) {
  781. // 自动初始化
  782. $cache = Think\Cache::getInstance();
  783. }
  784. if ('' === $value) {
  785. // 获取缓存
  786. return $cache->get($name);
  787. } elseif (is_null($value)) {
  788. // 删除缓存
  789. return $cache->rm($name);
  790. } else {
  791. // 缓存数据
  792. if (is_array($options)) {
  793. $expire = isset($options['expire']) ? $options['expire'] : null;
  794. } else {
  795. $expire = is_numeric($options) ? $options : null;
  796. }
  797. return $cache->set($name, $value, $expire);
  798. }
  799. }
  800. /**
  801. * 快速文件数据读取和保存 针对简单类型数据 字符串、数组
  802. * @param string $name 缓存名称
  803. * @param mixed $value 缓存值
  804. * @param string $path 缓存路径
  805. * @return mixed
  806. */
  807. function F($name, $value = '', $path = DATA_PATH)
  808. {
  809. static $_cache = array();
  810. $filename = $path . $name . '.php';
  811. if ('' !== $value) {
  812. if (is_null($value)) {
  813. // 删除缓存
  814. if (false !== strpos($name, '*')) {
  815. return false; // TODO
  816. } else {
  817. unset($_cache[$name]);
  818. return Think\Storage::unlink($filename, 'F');
  819. }
  820. } else {
  821. Think\Storage::put($filename, serialize($value), 'F');
  822. // 缓存数据
  823. $_cache[$name] = $value;
  824. return;
  825. }
  826. }
  827. // 获取缓存数据
  828. if (isset($_cache[$name])) {
  829. return $_cache[$name];
  830. }
  831. if (Think\Storage::has($filename, 'F')) {
  832. $value = unserialize(Think\Storage::read($filename, 'F'));
  833. $_cache[$name] = $value;
  834. } else {
  835. $value = false;
  836. }
  837. return $value;
  838. }
  839. /**
  840. * 根据PHP各种类型变量生成唯一标识号
  841. * @param mixed $mix 变量
  842. * @return string
  843. */
  844. function to_guid_string($mix)
  845. {
  846. if (is_object($mix)) {
  847. return spl_object_hash($mix);
  848. } elseif (is_resource($mix)) {
  849. $mix = get_resource_type($mix) . strval($mix);
  850. } else {
  851. $mix = serialize($mix);
  852. }
  853. return md5($mix);
  854. }
  855. /**
  856. * XML编码
  857. * @param mixed $data 数据
  858. * @param string $root 根节点名
  859. * @param string $item 数字索引的子节点名
  860. * @param string $attr 根节点属性
  861. * @param string $id 数字索引子节点key转换的属性名
  862. * @param string $encoding 数据编码
  863. * @return string
  864. */
  865. function xml_encode($data, $root = 'think', $item = 'item', $attr = '', $id = 'id', $encoding = 'utf-8')
  866. {
  867. if (is_array($attr)) {
  868. $_attr = array();
  869. foreach ($attr as $key => $value) {
  870. $_attr[] = "{$key}=\"{$value}\"";
  871. }
  872. $attr = implode(' ', $_attr);
  873. }
  874. $attr = trim($attr);
  875. $attr = empty($attr) ? '' : " {$attr}";
  876. $xml = "<?xml version=\"1.0\" encoding=\"{$encoding}\"?>";
  877. $xml .= "<{$root}{$attr}>";
  878. $xml .= data_to_xml($data, $item, $id);
  879. $xml .= "</{$root}>";
  880. return $xml;
  881. }
  882. /**
  883. * 数据XML编码
  884. * @param mixed $data 数据
  885. * @param string $item 数字索引时的节点名称
  886. * @param string $id 数字索引key转换为的属性名
  887. * @return string
  888. */
  889. function data_to_xml($data, $item = 'item', $id = 'id')
  890. {
  891. $xml = $attr = '';
  892. foreach ($data as $key => $val) {
  893. if (is_numeric($key)) {
  894. $id && $attr = " {$id}=\"{$key}\"";
  895. $key = $item;
  896. }
  897. $xml .= "<{$key}{$attr}>";
  898. $xml .= (is_array($val) || is_object($val)) ? data_to_xml($val, $item, $id) : $val;
  899. $xml .= "</{$key}>";
  900. }
  901. return $xml;
  902. }
  903. /**
  904. * session管理函数
  905. * @param string|array $name session名称 如果为数组则表示进行session设置
  906. * @param mixed $value session值
  907. * @return mixed
  908. */
  909. function session($name, $value = '')
  910. {
  911. $prefix = C('SESSION_PREFIX');
  912. if (is_array($name)) {
  913. // session初始化 在session_start 之前调用
  914. if (isset($name['prefix'])) {
  915. C('SESSION_PREFIX', $name['prefix']);
  916. }
  917. if (C('VAR_SESSION_ID') && isset($_REQUEST[C('VAR_SESSION_ID')])) {
  918. session_id($_REQUEST[C('VAR_SESSION_ID')]);
  919. } elseif (isset($name['id'])) {
  920. session_id($name['id']);
  921. }
  922. if ('common' != APP_MODE) {
  923. // 其它模式可能不支持
  924. ini_set('session.auto_start', 0);
  925. }
  926. if (isset($name['name'])) {
  927. session_name($name['name']);
  928. }
  929. if (isset($name['path'])) {
  930. session_save_path($name['path']);
  931. }
  932. if (isset($name['domain'])) {
  933. ini_set('session.cookie_domain', $name['domain']);
  934. }
  935. if (isset($name['expire'])) {
  936. ini_set('session.gc_maxlifetime', $name['expire']);
  937. }
  938. if (isset($name['use_trans_sid'])) {
  939. ini_set('session.use_trans_sid', $name['use_trans_sid'] ? 1 : 0);
  940. }
  941. if (isset($name['use_cookies'])) {
  942. ini_set('session.use_cookies', $name['use_cookies'] ? 1 : 0);
  943. }
  944. if (isset($name['cache_limiter'])) {
  945. session_cache_limiter($name['cache_limiter']);
  946. }
  947. if (isset($name['cache_expire'])) {
  948. session_cache_expire($name['cache_expire']);
  949. }
  950. if (isset($name['type'])) {
  951. C('SESSION_TYPE', $name['type']);
  952. }
  953. if (C('SESSION_TYPE')) {
  954. // 读取session驱动
  955. $type = C('SESSION_TYPE');
  956. $class = strpos($type, '\\') ? $type : 'Think\\Session\\Driver\\' . ucwords(strtolower($type));
  957. $hander = new $class();
  958. session_set_save_handler(
  959. array(&$hander, "open"),
  960. array(&$hander, "close"),
  961. array(&$hander, "read"),
  962. array(&$hander, "write"),
  963. array(&$hander, "destroy"),
  964. array(&$hander, "gc"));
  965. }
  966. // 启动session
  967. if (C('SESSION_AUTO_START')) {
  968. session_start();
  969. }
  970. } elseif ('' === $value) {
  971. if (0 === strpos($name, '[')) {
  972. // session 操作
  973. if ('[pause]' == $name) {
  974. // 暂停session
  975. session_write_close();
  976. } elseif ('[start]' == $name) {
  977. // 启动session
  978. session_start();
  979. } elseif ('[destroy]' == $name) {
  980. // 销毁session
  981. $_SESSION = array();
  982. session_unset();
  983. session_destroy();
  984. } elseif ('[regenerate]' == $name) {
  985. // 重新生成id
  986. session_regenerate_id();
  987. }
  988. } elseif (0 === strpos($name, '?')) {
  989. // 检查session
  990. $name = substr($name, 1);
  991. if (strpos($name, '.')) {
  992. // 支持数组
  993. list($name1, $name2) = explode('.', $name);
  994. return $prefix ? isset($_SESSION[$prefix][$name1][$name2]) : isset($_SESSION[$name1][$name2]);
  995. } else {
  996. return $prefix ? isset($_SESSION[$prefix][$name]) : isset($_SESSION[$name]);
  997. }
  998. } elseif (is_null($name)) {
  999. // 清空session
  1000. if ($prefix) {
  1001. unset($_SESSION[$prefix]);
  1002. } else {
  1003. $_SESSION = array();
  1004. }
  1005. } elseif ($prefix) {
  1006. // 获取session
  1007. if (strpos($name, '.')) {
  1008. list($name1, $name2) = explode('.', $name);
  1009. return isset($_SESSION[$prefix][$name1][$name2]) ? $_SESSION[$prefix][$name1][$name2] : null;
  1010. } else {
  1011. return isset($_SESSION[$prefix][$name]) ? $_SESSION[$prefix][$name] : null;
  1012. }
  1013. } else {
  1014. if (strpos($name, '.')) {
  1015. list($name1, $name2) = explode('.', $name);
  1016. return isset($_SESSION[$name1][$name2]) ? $_SESSION[$name1][$name2] : null;
  1017. } else {
  1018. return isset($_SESSION[$name]) ? $_SESSION[$name] : null;
  1019. }
  1020. }
  1021. } elseif (is_null($value)) {
  1022. // 删除session
  1023. if ($prefix) {
  1024. unset($_SESSION[$prefix][$name]);
  1025. } else {
  1026. unset($_SESSION[$name]);
  1027. }
  1028. } else {
  1029. // 设置session
  1030. if ($prefix) {
  1031. if (!is_array($_SESSION[$prefix])) {
  1032. $_SESSION[$prefix] = array();
  1033. }
  1034. $_SESSION[$prefix][$name] = $value;
  1035. } else {
  1036. $_SESSION[$name] = $value;
  1037. }
  1038. }
  1039. }
  1040. /**
  1041. * Cookie 设置、获取、删除
  1042. * @param string $name cookie名称
  1043. * @param mixed $value cookie值
  1044. * @param mixed $options cookie参数
  1045. * @return mixed
  1046. */
  1047. function cookie($name, $value = '', $option = null)
  1048. {
  1049. // 默认设置
  1050. $config = array(
  1051. 'prefix' => C('COOKIE_PREFIX'), // cookie 名称前缀
  1052. 'expire' => C('COOKIE_EXPIRE'), // cookie 保存时间
  1053. 'path' => C('COOKIE_PATH'), // cookie 保存路径
  1054. 'domain' => C('COOKIE_DOMAIN'), // cookie 有效域名
  1055. );
  1056. // 参数设置(会覆盖黙认设置)
  1057. if (!is_null($option)) {
  1058. if (is_numeric($option)) {
  1059. $option = array('expire' => $option);
  1060. } elseif (is_string($option)) {
  1061. parse_str($option, $option);
  1062. }
  1063. $config = array_merge($config, array_change_key_case($option));
  1064. }
  1065. // 清除指定前缀的所有cookie
  1066. if (is_null($name)) {
  1067. if (empty($_COOKIE)) {
  1068. return;
  1069. }
  1070. // 要删除的cookie前缀,不指定则删除config设置的指定前缀
  1071. $prefix = empty($value) ? $config['prefix'] : $value;
  1072. if (!empty($prefix)) {
  1073. // 如果前缀为空字符串将不作处理直接返回
  1074. foreach ($_COOKIE as $key => $val) {
  1075. if (0 === stripos($key, $prefix)) {
  1076. setcookie($key, '', time() - 3600, $config['path'], $config['domain']);
  1077. unset($_COOKIE[$key]);
  1078. }
  1079. }
  1080. }
  1081. return;
  1082. }
  1083. $name = $config['prefix'] . $name;
  1084. if ('' === $value) {
  1085. if (isset($_COOKIE[$name])) {
  1086. $value = $_COOKIE[$name];
  1087. if (0 === strpos($value, 'think:')) {
  1088. $value = substr($value, 6);
  1089. return array_map('urldecode', json_decode(MAGIC_QUOTES_GPC ? stripslashes($value) : $value, true));
  1090. } else {
  1091. return $value;
  1092. }
  1093. } else {
  1094. return null;
  1095. }
  1096. } else {
  1097. if (is_null($value)) {
  1098. setcookie($name, '', time() - 3600, $config['path'], $config['domain']);
  1099. unset($_COOKIE[$name]); // 删除指定cookie
  1100. } else {
  1101. // 设置cookie
  1102. if (is_array($value)) {
  1103. $value = 'think:' . json_encode(array_map('urlencode', $value));
  1104. }
  1105. $expire = !empty($config['expire']) ? time() + intval($config['expire']) : 0;
  1106. setcookie($name, $value, $expire, $config['path'], $config['domain']);
  1107. $_COOKIE[$name] = $value;
  1108. }
  1109. }
  1110. }
  1111. /**
  1112. * 加载动态扩展文件
  1113. * @return void
  1114. */
  1115. function load_ext_file($path)
  1116. {
  1117. // 加载自定义外部文件
  1118. if (C('LOAD_EXT_FILE')) {
  1119. $files = explode(',', C('LOAD_EXT_FILE'));
  1120. foreach ($files as $file) {
  1121. $file = $path . 'Common/' . $file . '.php';
  1122. if (is_file($file)) {
  1123. include $file;
  1124. }
  1125. }
  1126. }
  1127. // 加载自定义的动态配置文件
  1128. if (C('LOAD_EXT_CONFIG')) {
  1129. $configs = C('LOAD_EXT_CONFIG');
  1130. if (is_string($configs)) {
  1131. $configs = explode(',', $configs);
  1132. }
  1133. foreach ($configs as $key => $config) {
  1134. $file = $path . 'Conf/' . $config . '.php';
  1135. if (is_file($file)) {
  1136. is_numeric($key) ? C(include $file) : C($key, include $file);
  1137. }
  1138. }
  1139. }
  1140. }
  1141. /**
  1142. * 获取客户端IP地址
  1143. * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字
  1144. * @return mixed
  1145. */
  1146. function get_client_ip($type = 0)
  1147. {
  1148. $type = $type ? 1 : 0;
  1149. static $ip = null;
  1150. if (null !== $ip) {
  1151. return $ip[$type];
  1152. }
  1153. if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
  1154. $arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
  1155. $pos = array_search('unknown', $arr);
  1156. if (false !== $pos) {
  1157. unset($arr[$pos]);
  1158. }
  1159. $ip = trim($arr[0]);
  1160. } elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
  1161. $ip = $_SERVER['HTTP_CLIENT_IP'];
  1162. } elseif (isset($_SERVER['REMOTE_ADDR'])) {
  1163. $ip = $_SERVER['REMOTE_ADDR'];
  1164. }
  1165. // IP地址合法验证
  1166. $long = sprintf("%u", ip2long($ip));
  1167. $ip = $long ? array($ip, $long) : array('0.0.0.0', 0);
  1168. return $ip[$type];
  1169. }
  1170. /**
  1171. * 发送HTTP状态
  1172. * @param integer $code 状态码
  1173. * @return void
  1174. */
  1175. function send_http_status($code)
  1176. {
  1177. static $_status = array(
  1178. // Success 2xx
  1179. 200 => 'OK',
  1180. // Redirection 3xx
  1181. 301 => 'Moved Permanently',
  1182. 302 => 'Moved Temporarily ', // 1.1
  1183. // Client Error 4xx
  1184. 400 => 'Bad Request',
  1185. 403 => 'Forbidden',
  1186. 404 => 'Not Found',
  1187. // Server Error 5xx
  1188. 500 => 'Internal Server Error',
  1189. 503 => 'Service Unavailable',
  1190. );
  1191. if (isset($_status[$code])) {
  1192. header('HTTP/1.1 ' . $code . ' ' . $_status[$code]);
  1193. // 确保FastCGI模式下正常
  1194. header('Status:' . $code . ' ' . $_status[$code]);
  1195. }
  1196. }
  1197. // 不区分大小写的in_array实现
  1198. function in_array_case($value, $array)
  1199. {
  1200. return in_array(strtolower($value), array_map('strtolower', $array));
  1201. }
  1202. function think_filter(&$value)
  1203. {
  1204. // TODO 其他安全过滤
  1205. // 过滤查询特殊字符
  1206. if (preg_match('/^(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOTIN|NOT IN|IN)$/i', $value)) {
  1207. $value .= ' ';
  1208. }
  1209. }