functions.php 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772
  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 系统函数库
  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 = strtoupper($name);
  32. if (is_null($value)) {
  33. return isset($_config[$name]) ? $_config[$name] : $default;
  34. }
  35. $_config[$name] = $value;
  36. return null;
  37. }
  38. // 二维数组设置和获取支持
  39. $name = explode('.', $name);
  40. $name[0] = strtoupper($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 null;
  46. }
  47. // 批量设置
  48. if (is_array($name)) {
  49. $_config = array_merge($_config, array_change_key_case($name, CASE_UPPER));
  50. return null;
  51. }
  52. return null; // 避免非法参数
  53. }
  54. /**
  55. * 加载配置文件 支持格式转换 仅支持一级配置
  56. * @param string $file 配置文件名
  57. * @param string $parse 配置解析方法 有些格式需要用户自己解析
  58. * @return array
  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. * 解析yaml文件返回一个数组
  84. * @param string $file 配置文件名
  85. * @return array
  86. */
  87. if (!function_exists('yaml_parse_file')) {
  88. function yaml_parse_file($file)
  89. {
  90. vendor('spyc.Spyc');
  91. return Spyc::YAMLLoad($file);
  92. }
  93. }
  94. /**
  95. * 抛出异常处理
  96. * @param string $msg 异常消息
  97. * @param integer $code 异常代码 默认为0
  98. * @throws Think\Exception
  99. * @return void
  100. */
  101. function E($msg, $code = 0)
  102. {
  103. throw new Think\Exception($msg, $code);
  104. }
  105. /*
  106. * 记录和统计时间(微秒)和内存使用情况
  107. * 使用方法:
  108. * <code>
  109. * G('begin'); // 记录开始标记位
  110. * // ... 区间运行代码
  111. * G('end'); // 记录结束标签位
  112. * echo G('begin','end',6); // 统计区间运行时间 精确到小数后6位
  113. * echo G('begin','end','m'); // 统计区间内存使用情况
  114. * 如果end标记位没有定义,则会自动以当前作为标记位
  115. * 其中统计内存使用需要 MEMORY_LIMIT_ON 常量为true才有效
  116. * </code>
  117. * @param string $start 开始标签
  118. * @param string $end 结束标签
  119. * @param integer|string $dec 小数位或者m
  120. * @return mixed
  121. */
  122. function G($start, $end = '', $dec = 4)
  123. {
  124. static $_info = array();
  125. static $_mem = array();
  126. if (is_float($end)) {
  127. // 记录时间
  128. $_info[$start] = $end;
  129. } elseif (!empty($end)) {
  130. // 统计时间和内存使用
  131. if (!isset($_info[$end])) {
  132. $_info[$end] = microtime(true);
  133. }
  134. if (MEMORY_LIMIT_ON && 'm' == $dec) {
  135. if (!isset($_mem[$end])) {
  136. $_mem[$end] = memory_get_usage();
  137. }
  138. return number_format(($_mem[$end] - $_mem[$start]) / 1024);
  139. } else {
  140. return number_format(($_info[$end] - $_info[$start]), $dec);
  141. }
  142. } else {
  143. // 记录时间和内存使用
  144. $_info[$start] = microtime(true);
  145. if (MEMORY_LIMIT_ON) {
  146. $_mem[$start] = memory_get_usage();
  147. }
  148. }
  149. return null;
  150. }
  151. /**
  152. * 获取和设置语言定义(不区分大小写)
  153. * @param string|array $name 语言变量
  154. * @param mixed $value 语言值或者变量
  155. * @return mixed
  156. */
  157. function L($name = null, $value = null)
  158. {
  159. static $_lang = array();
  160. // 空参数返回所有定义
  161. if (empty($name)) {
  162. return $_lang;
  163. }
  164. // 判断语言获取(或设置)
  165. // 若不存在,直接返回全大写$name
  166. if (is_string($name)) {
  167. $name = strtoupper($name);
  168. if (is_null($value)) {
  169. return isset($_lang[$name]) ? $_lang[$name] : $name;
  170. } elseif (is_array($value)) {
  171. // 支持变量
  172. $replace = array_keys($value);
  173. foreach ($replace as &$v) {
  174. $v = '{$' . $v . '}';
  175. }
  176. return str_replace($replace, $value, isset($_lang[$name]) ? $_lang[$name] : $name);
  177. }
  178. $_lang[$name] = $value; // 语言定义
  179. return null;
  180. }
  181. // 批量定义
  182. if (is_array($name)) {
  183. $_lang = array_merge($_lang, array_change_key_case($name, CASE_UPPER));
  184. }
  185. return null;
  186. }
  187. /**
  188. * 添加和获取页面Trace记录
  189. * @param string $value 变量
  190. * @param string $label 标签
  191. * @param string $level 日志级别
  192. * @param boolean $record 是否记录日志
  193. * @return void|array
  194. */
  195. function trace($value = '[think]', $label = '', $level = 'DEBUG', $record = false)
  196. {
  197. return Think\Think::trace($value, $label, $level, $record);
  198. }
  199. /**
  200. * 编译文件
  201. * @param string $filename 文件名
  202. * @return string
  203. */
  204. function compile($filename)
  205. {
  206. $content = php_strip_whitespace($filename);
  207. $content = trim(substr($content, 5));
  208. // 替换预编译指令
  209. $content = preg_replace('/\/\/\[RUNTIME\](.*?)\/\/\[\/RUNTIME\]/s', '', $content);
  210. if (0 === strpos($content, 'namespace')) {
  211. $content = preg_replace('/namespace\s(.*?);/', 'namespace \\1{', $content, 1);
  212. } else {
  213. $content = 'namespace {' . $content;
  214. }
  215. if ('?>' == substr($content, -2)) {
  216. $content = substr($content, 0, -2);
  217. }
  218. return $content . '}';
  219. }
  220. /**
  221. * 获取模版文件 格式 资源://模块@主题/控制器/操作
  222. * @param string $template 模版资源地址
  223. * @param string $layer 视图层(目录)名称
  224. * @return string
  225. */
  226. function T($template = '', $layer = '')
  227. {
  228. // 解析模版资源地址
  229. if (false === strpos($template, '://')) {
  230. $template = 'http://' . str_replace(':', '/', $template);
  231. }
  232. $info = parse_url($template);
  233. $file = $info['host'] . (isset($info['path']) ? $info['path'] : '');
  234. $module = isset($info['user']) ? $info['user'] . '/' : MODULE_NAME . '/';
  235. $extend = $info['scheme'];
  236. $layer = $layer ? $layer : C('DEFAULT_V_LAYER');
  237. // 获取当前主题的模版路径
  238. $auto = C('AUTOLOAD_NAMESPACE');
  239. if ($auto && isset($auto[$extend])) {
  240. // 扩展资源
  241. $baseUrl = $auto[$extend] . $module . $layer . '/';
  242. } elseif (C('VIEW_PATH')) {
  243. // 改变模块视图目录
  244. $baseUrl = C('VIEW_PATH');
  245. } elseif (defined('TMPL_PATH')) {
  246. // 指定全局视图目录
  247. $baseUrl = TMPL_PATH . $module;
  248. } else {
  249. $baseUrl = APP_PATH . $module . $layer . '/';
  250. }
  251. // 获取主题
  252. $theme = substr_count($file, '/') < 2 ? C('DEFAULT_THEME') : '';
  253. // 分析模板文件规则
  254. $depr = C('TMPL_FILE_DEPR');
  255. if ('' == $file) {
  256. // 如果模板文件名为空 按照默认规则定位
  257. $file = CONTROLLER_NAME . $depr . ACTION_NAME;
  258. } elseif (false === strpos($file, '/')) {
  259. $file = CONTROLLER_NAME . $depr . $file;
  260. } elseif ('/' != $depr) {
  261. $file = substr_count($file, '/') > 1 ? substr_replace($file, $depr, strrpos($file, '/'), 1) : str_replace('/', $depr, $file);
  262. }
  263. return $baseUrl . ($theme ? $theme . '/' : '') . $file . C('TMPL_TEMPLATE_SUFFIX');
  264. }
  265. /**
  266. * 获取输入参数 支持过滤和默认值
  267. * 使用方法:
  268. * <code>
  269. * I('id',0); 获取id参数 自动判断get或者post
  270. * I('post.name','','htmlspecialchars'); 获取$_POST['name']
  271. * I('get.'); 获取$_GET
  272. * </code>
  273. * @param string $name 变量的名称 支持指定类型
  274. * @param mixed $default 不存在的时候默认值
  275. * @param mixed $filter 参数过滤方法
  276. * @param mixed $datas 要获取的额外数据源
  277. * @return mixed
  278. */
  279. function I($name, $default = '', $filter = null, $datas = null)
  280. {
  281. static $_PUT = null;
  282. if (strpos($name, '/')) {
  283. // 指定修饰符
  284. list($name, $type) = explode('/', $name, 2);
  285. } elseif (C('VAR_AUTO_STRING')) {
  286. // 默认强制转换为字符串
  287. $type = 's';
  288. }
  289. if (strpos($name, '.')) {
  290. // 指定参数来源
  291. list($method, $name) = explode('.', $name, 2);
  292. } else {
  293. // 默认为自动判断
  294. $method = 'param';
  295. }
  296. switch (strtolower($method)) {
  297. case 'get':
  298. $input = &$_GET;
  299. break;
  300. case 'post':
  301. $input = &$_POST;
  302. break;
  303. case 'put':
  304. if (is_null($_PUT)) {
  305. parse_str(file_get_contents('php://input'), $_PUT);
  306. }
  307. $input = $_PUT;
  308. break;
  309. case 'param':
  310. switch ($_SERVER['REQUEST_METHOD']) {
  311. case 'POST':
  312. $input = $_POST;
  313. break;
  314. case 'PUT':
  315. if (is_null($_PUT)) {
  316. parse_str(file_get_contents('php://input'), $_PUT);
  317. }
  318. $input = $_PUT;
  319. break;
  320. default:
  321. $input = $_GET;
  322. }
  323. break;
  324. case 'path':
  325. $input = array();
  326. if (!empty($_SERVER['PATH_INFO'])) {
  327. $depr = C('URL_PATHINFO_DEPR');
  328. $input = explode($depr, trim($_SERVER['PATH_INFO'], $depr));
  329. }
  330. break;
  331. case 'request':
  332. $input = &$_REQUEST;
  333. break;
  334. case 'session':
  335. $input = &$_SESSION;
  336. break;
  337. case 'cookie':
  338. $input = &$_COOKIE;
  339. break;
  340. case 'server':
  341. $input = &$_SERVER;
  342. break;
  343. case 'globals':
  344. $input = &$GLOBALS;
  345. break;
  346. case 'data':
  347. $input = &$datas;
  348. break;
  349. default:
  350. return null;
  351. }
  352. if ('' == $name) {
  353. // 获取全部变量
  354. $data = $input;
  355. $filters = isset($filter) ? $filter : C('DEFAULT_FILTER');
  356. if ($filters) {
  357. if (is_string($filters)) {
  358. $filters = explode(',', $filters);
  359. }
  360. foreach ($filters as $filter) {
  361. $data = array_map_recursive($filter, $data); // 参数过滤
  362. }
  363. }
  364. } elseif (isset($input[$name])) {
  365. // 取值操作
  366. $data = $input[$name];
  367. $filters = isset($filter) ? $filter : C('DEFAULT_FILTER');
  368. if ($filters) {
  369. if (is_string($filters)) {
  370. if (0 === strpos($filters, '/')) {
  371. if (1 !== preg_match($filters, (string) $data)) {
  372. // 支持正则验证
  373. return isset($default) ? $default : null;
  374. }
  375. } else {
  376. $filters = explode(',', $filters);
  377. }
  378. } elseif (is_int($filters)) {
  379. $filters = array($filters);
  380. }
  381. if (is_array($filters)) {
  382. foreach ($filters as $filter) {
  383. $filter = trim($filter);
  384. if (function_exists($filter)) {
  385. $data = is_array($data) ? array_map_recursive($filter, $data) : $filter($data); // 参数过滤
  386. } else {
  387. $data = filter_var($data, is_int($filter) ? $filter : filter_id($filter));
  388. if (false === $data) {
  389. return isset($default) ? $default : null;
  390. }
  391. }
  392. }
  393. }
  394. }
  395. if (!empty($type)) {
  396. switch (strtolower($type)) {
  397. case 'a': // 数组
  398. $data = (array) $data;
  399. break;
  400. case 'd': // 数字
  401. $data = (int) $data;
  402. break;
  403. case 'f': // 浮点
  404. $data = (float) $data;
  405. break;
  406. case 'b': // 布尔
  407. $data = (boolean) $data;
  408. break;
  409. case 's': // 字符串
  410. default:
  411. $data = (string) $data;
  412. }
  413. }
  414. } else {
  415. // 变量默认值
  416. $data = isset($default) ? $default : null;
  417. }
  418. is_array($data) && array_walk_recursive($data, 'think_filter');
  419. return $data;
  420. }
  421. function array_map_recursive($filter, $data)
  422. {
  423. $result = array();
  424. foreach ($data as $key => $val) {
  425. $result[$key] = is_array($val)
  426. ? array_map_recursive($filter, $val)
  427. : call_user_func($filter, $val);
  428. }
  429. return $result;
  430. }
  431. /**
  432. * 设置和获取统计数据
  433. * 使用方法:
  434. * <code>
  435. * N('db',1); // 记录数据库操作次数
  436. * N('read',1); // 记录读取次数
  437. * echo N('db'); // 获取当前页面数据库的所有操作次数
  438. * echo N('read'); // 获取当前页面读取次数
  439. * </code>
  440. * @param string $key 标识位置
  441. * @param integer $step 步进值
  442. * @param boolean $save 是否保存结果
  443. * @return mixed
  444. */
  445. function N($key, $step = 0, $save = false)
  446. {
  447. static $_num = array();
  448. if (!isset($_num[$key])) {
  449. $_num[$key] = (false !== $save) ? S('N_' . $key) : 0;
  450. }
  451. if (empty($step)) {
  452. return $_num[$key];
  453. } else {
  454. $_num[$key] = $_num[$key] + (int) $step;
  455. }
  456. if (false !== $save) {
  457. // 保存结果
  458. S('N_' . $key, $_num[$key], $save);
  459. }
  460. return null;
  461. }
  462. /**
  463. * 字符串命名风格转换
  464. * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格
  465. * @param string $name 字符串
  466. * @param integer $type 转换类型
  467. * @return string
  468. */
  469. function parse_name($name, $type = 0)
  470. {
  471. if ($type) {
  472. return ucfirst(preg_replace_callback('/_([a-zA-Z])/', function ($match) {return strtoupper($match[1]);}, $name));
  473. } else {
  474. return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_"));
  475. }
  476. }
  477. /**
  478. * 优化的require_once
  479. * @param string $filename 文件地址
  480. * @return boolean
  481. */
  482. function require_cache($filename)
  483. {
  484. static $_importFiles = array();
  485. if (!isset($_importFiles[$filename])) {
  486. if (file_exists_case($filename)) {
  487. require $filename;
  488. $_importFiles[$filename] = true;
  489. } else {
  490. $_importFiles[$filename] = false;
  491. }
  492. }
  493. return $_importFiles[$filename];
  494. }
  495. /**
  496. * 区分大小写的文件存在判断
  497. * @param string $filename 文件地址
  498. * @return boolean
  499. */
  500. function file_exists_case($filename)
  501. {
  502. if (is_file($filename)) {
  503. if (IS_WIN && APP_DEBUG) {
  504. if (basename(realpath($filename)) != basename($filename)) {
  505. return false;
  506. }
  507. }
  508. return true;
  509. }
  510. return false;
  511. }
  512. /**
  513. * 导入所需的类库 同java的Import 本函数有缓存功能
  514. * @param string $class 类库命名空间字符串
  515. * @param string $baseUrl 起始路径
  516. * @param string $ext 导入的文件扩展名
  517. * @return boolean
  518. */
  519. function import($class, $baseUrl = '', $ext = EXT)
  520. {
  521. static $_file = array();
  522. $class = str_replace(array('.', '#'), array('/', '.'), $class);
  523. if (isset($_file[$class . $baseUrl])) {
  524. return true;
  525. } else {
  526. $_file[$class . $baseUrl] = true;
  527. }
  528. $class_strut = explode('/', $class);
  529. if (empty($baseUrl)) {
  530. if ('@' == $class_strut[0] || MODULE_NAME == $class_strut[0]) {
  531. //加载当前模块的类库
  532. $baseUrl = MODULE_PATH;
  533. $class = substr_replace($class, '', 0, strlen($class_strut[0]) + 1);
  534. } elseif ('Common' == $class_strut[0]) {
  535. //加载公共模块的类库
  536. $baseUrl = COMMON_PATH;
  537. $class = substr($class, 7);
  538. } elseif (in_array($class_strut[0], array('Think', 'Org', 'Behavior', 'Com', 'Vendor')) || is_dir(LIB_PATH . $class_strut[0])) {
  539. // 系统类库包和第三方类库包
  540. $baseUrl = LIB_PATH;
  541. } else {
  542. // 加载其他模块的类库
  543. $baseUrl = APP_PATH;
  544. }
  545. }
  546. if (substr($baseUrl, -1) != '/') {
  547. $baseUrl .= '/';
  548. }
  549. $classfile = $baseUrl . $class . $ext;
  550. if (!class_exists(basename($class), false)) {
  551. // 如果类不存在 则导入类库文件
  552. return require_cache($classfile);
  553. }
  554. return null;
  555. }
  556. /**
  557. * 基于命名空间方式导入函数库
  558. * load('@.Util.Array')
  559. * @param string $name 函数库命名空间字符串
  560. * @param string $baseUrl 起始路径
  561. * @param string $ext 导入的文件扩展名
  562. * @return void
  563. */
  564. function load($name, $baseUrl = '', $ext = '.php')
  565. {
  566. $name = str_replace(array('.', '#'), array('/', '.'), $name);
  567. if (empty($baseUrl)) {
  568. if (0 === strpos($name, '@/')) {
  569. //加载当前模块函数库
  570. $baseUrl = MODULE_PATH . 'Common/';
  571. $name = substr($name, 2);
  572. } else {
  573. //加载其他模块函数库
  574. $array = explode('/', $name);
  575. $baseUrl = APP_PATH . array_shift($array) . '/Common/';
  576. $name = implode('/', $array);
  577. }
  578. }
  579. if (substr($baseUrl, -1) != '/') {
  580. $baseUrl .= '/';
  581. }
  582. require_cache($baseUrl . $name . $ext);
  583. }
  584. /**
  585. * 快速导入第三方框架类库 所有第三方框架的类库文件统一放到 系统的Vendor目录下面
  586. * @param string $class 类库
  587. * @param string $baseUrl 基础目录
  588. * @param string $ext 类库后缀
  589. * @return boolean
  590. */
  591. function vendor($class, $baseUrl = '', $ext = '.php')
  592. {
  593. if (empty($baseUrl)) {
  594. $baseUrl = VENDOR_PATH;
  595. }
  596. return import($class, $baseUrl, $ext);
  597. }
  598. /**
  599. * 实例化模型类 格式 [资源://][模块/]模型
  600. * @param string $name 资源地址
  601. * @param string $layer 模型层名称
  602. * @return Think\Model
  603. */
  604. function D($name = '', $layer = '')
  605. {
  606. if (empty($name)) {
  607. return new Think\Model;
  608. }
  609. static $_model = array();
  610. $layer = $layer ?: C('DEFAULT_M_LAYER');
  611. if (isset($_model[$name . $layer])) {
  612. return $_model[$name . $layer];
  613. }
  614. $class = parse_res_name($name, $layer);
  615. if (class_exists($class)) {
  616. $model = new $class(basename($name));
  617. } elseif (false === strpos($name, '/')) {
  618. // 自动加载公共模块下面的模型
  619. if (!C('APP_USE_NAMESPACE')) {
  620. import('Common/' . $layer . '/' . $class);
  621. } else {
  622. $class = '\\Common\\' . $layer . '\\' . $name . $layer;
  623. }
  624. $model = class_exists($class) ? new $class($name) : new Think\Model($name);
  625. } else {
  626. Think\Log::record('D方法实例化没找到模型类' . $class, Think\Log::NOTICE);
  627. $model = new Think\Model(basename($name));
  628. }
  629. $_model[$name . $layer] = $model;
  630. return $model;
  631. }
  632. /**
  633. * 实例化一个没有模型文件的Model
  634. * @param string $name Model名称 支持指定基础模型 例如 MongoModel:User
  635. * @param string $tablePrefix 表前缀
  636. * @param mixed $connection 数据库连接信息
  637. * @return Think\Model
  638. */
  639. function M($name = '', $tablePrefix = '', $connection = '')
  640. {
  641. static $_model = array();
  642. if (strpos($name, ':')) {
  643. list($class, $name) = explode(':', $name);
  644. } else {
  645. $class = 'Think\\Model';
  646. }
  647. $guid = (is_array($connection) ? implode('', $connection) : $connection) . $tablePrefix . $name . '_' . $class;
  648. if (!isset($_model[$guid])) {
  649. $_model[$guid] = new $class($name, $tablePrefix, $connection);
  650. }
  651. return $_model[$guid];
  652. }
  653. /**
  654. * 解析资源地址并导入类库文件
  655. * 例如 module/controller addon://module/behavior
  656. * @param string $name 资源地址 格式:[扩展://][模块/]资源名
  657. * @param string $layer 分层名称
  658. * @param integer $level 控制器层次
  659. * @return string
  660. */
  661. function parse_res_name($name, $layer, $level = 1)
  662. {
  663. if (strpos($name, '://')) {
  664. // 指定扩展资源
  665. list($extend, $name) = explode('://', $name);
  666. } else {
  667. $extend = '';
  668. }
  669. if (strpos($name, '/') && substr_count($name, '/') >= $level) {
  670. // 指定模块
  671. list($module, $name) = explode('/', $name, 2);
  672. } else {
  673. $module = defined('MODULE_NAME') ? MODULE_NAME : '';
  674. }
  675. $array = explode('/', $name);
  676. if (!C('APP_USE_NAMESPACE')) {
  677. $class = parse_name($name, 1);
  678. import($module . '/' . $layer . '/' . $class . $layer);
  679. } else {
  680. $class = $module . '\\' . $layer;
  681. foreach ($array as $name) {
  682. $class .= '\\' . parse_name($name, 1);
  683. }
  684. // 导入资源类库
  685. if ($extend) {
  686. // 扩展资源
  687. $class = $extend . '\\' . $class;
  688. }
  689. }
  690. return $class . $layer;
  691. }
  692. /**
  693. * 用于实例化访问控制器
  694. * @param string $name 控制器名
  695. * @param string $path 控制器命名空间(路径)
  696. * @return Think\Controller|false
  697. */
  698. function controller($name, $path = '')
  699. {
  700. $layer = C('DEFAULT_C_LAYER');
  701. if (!C('APP_USE_NAMESPACE')) {
  702. $class = parse_name($name, 1) . $layer;
  703. import(MODULE_NAME . '/' . $layer . '/' . $class);
  704. } else {
  705. $class = ($path ? basename(ADDON_PATH) . '\\' . $path : MODULE_NAME) . '\\' . $layer;
  706. $array = explode('/', $name);
  707. foreach ($array as $name) {
  708. $class .= '\\' . parse_name($name, 1);
  709. }
  710. $class .= $layer;
  711. }
  712. if (class_exists($class)) {
  713. return new $class();
  714. } else {
  715. return false;
  716. }
  717. }
  718. /**
  719. * 实例化多层控制器 格式:[资源://][模块/]控制器
  720. * @param string $name 资源地址
  721. * @param string $layer 控制层名称
  722. * @param integer $level 控制器层次
  723. * @return Think\Controller|false
  724. */
  725. function A($name, $layer = '', $level = 0)
  726. {
  727. static $_action = array();
  728. $layer = $layer ?: C('DEFAULT_C_LAYER');
  729. $level = $level ?: (C('DEFAULT_C_LAYER') == $layer ? C('CONTROLLER_LEVEL') : 1);
  730. if (isset($_action[$name . $layer])) {
  731. return $_action[$name . $layer];
  732. }
  733. $class = parse_res_name($name, $layer, $level);
  734. if (class_exists($class)) {
  735. $action = new $class();
  736. $_action[$name . $layer] = $action;
  737. return $action;
  738. } else {
  739. return false;
  740. }
  741. }
  742. /**
  743. * 远程调用控制器的操作方法 URL 参数格式 [资源://][模块/]控制器/操作
  744. * @param string $url 调用地址
  745. * @param string|array $vars 调用参数 支持字符串和数组
  746. * @param string $layer 要调用的控制层名称
  747. * @return mixed
  748. */
  749. function R($url, $vars = array(), $layer = '')
  750. {
  751. $info = pathinfo($url);
  752. $action = $info['basename'];
  753. $module = $info['dirname'];
  754. $class = A($module, $layer);
  755. if ($class) {
  756. if (is_string($vars)) {
  757. parse_str($vars, $vars);
  758. }
  759. return call_user_func_array(array(&$class, $action . C('ACTION_SUFFIX')), $vars);
  760. } else {
  761. return false;
  762. }
  763. }
  764. /**
  765. * 处理标签扩展
  766. * @param string $tag 标签名称
  767. * @param mixed $params 传入参数
  768. * @return void
  769. */
  770. function tag($tag, &$params = null)
  771. {
  772. \Think\Hook::listen($tag, $params);
  773. }
  774. /**
  775. * 执行某个行为
  776. * @param string $name 行为名称
  777. * @param string $tag 标签名称(行为类无需传入)
  778. * @param Mixed $params 传入的参数
  779. * @return void
  780. */
  781. function B($name, $tag = '', &$params = null)
  782. {
  783. if ('' == $tag) {
  784. $name .= 'Behavior';
  785. }
  786. return \Think\Hook::exec($name, $tag, $params);
  787. }
  788. /**
  789. * 去除代码中的空白和注释
  790. * @param string $content 代码内容
  791. * @return string
  792. */
  793. function strip_whitespace($content)
  794. {
  795. $stripStr = '';
  796. //分析php源码
  797. $tokens = token_get_all($content);
  798. $last_space = false;
  799. for ($i = 0, $j = count($tokens); $i < $j; $i++) {
  800. if (is_string($tokens[$i])) {
  801. $last_space = false;
  802. $stripStr .= $tokens[$i];
  803. } else {
  804. switch ($tokens[$i][0]) {
  805. //过滤各种PHP注释
  806. case T_COMMENT:
  807. case T_DOC_COMMENT:
  808. break;
  809. //过滤空格
  810. case T_WHITESPACE:
  811. if (!$last_space) {
  812. $stripStr .= ' ';
  813. $last_space = true;
  814. }
  815. break;
  816. case T_START_HEREDOC:
  817. $stripStr .= "<<<THINK\n";
  818. break;
  819. case T_END_HEREDOC:
  820. $stripStr .= "THINK;\n";
  821. for ($k = $i + 1; $k < $j; $k++) {
  822. if (is_string($tokens[$k]) && ';' == $tokens[$k]) {
  823. $i = $k;
  824. break;
  825. } else if (T_CLOSE_TAG == $tokens[$k][0]) {
  826. break;
  827. }
  828. }
  829. break;
  830. default:
  831. $last_space = false;
  832. $stripStr .= $tokens[$i][1];
  833. }
  834. }
  835. }
  836. return $stripStr;
  837. }
  838. /**
  839. * 自定义异常处理
  840. * @param string $msg 异常消息
  841. * @param string $type 异常类型 默认为Think\Exception
  842. * @param integer $code 异常代码 默认为0
  843. * @return void
  844. */
  845. function throw_exception($msg, $type = 'Think\\Exception', $code = 0)
  846. {
  847. Think\Log::record('建议使用E方法替代throw_exception', Think\Log::NOTICE);
  848. if (class_exists($type, false)) {
  849. throw new $type($msg, $code);
  850. } else {
  851. Think\Think::halt($msg);
  852. }
  853. // 异常类型不存在则输出错误信息字串
  854. }
  855. /**
  856. * 浏览器友好的变量输出
  857. * @param mixed $var 变量
  858. * @param boolean $echo 是否输出 默认为True 如果为false 则返回输出字符串
  859. * @param string $label 标签 默认为空
  860. * @param boolean $strict 是否严谨 默认为true
  861. * @return void|string
  862. */
  863. function dump($var, $echo = true, $label = null, $strict = true)
  864. {
  865. $label = (null === $label) ? '' : rtrim($label) . ' ';
  866. if (!$strict) {
  867. if (ini_get('html_errors')) {
  868. $output = print_r($var, true);
  869. $output = '<pre>' . $label . htmlspecialchars($output, ENT_QUOTES) . '</pre>';
  870. } else {
  871. $output = $label . print_r($var, true);
  872. }
  873. } else {
  874. ob_start();
  875. var_dump($var);
  876. $output = ob_get_clean();
  877. if (!extension_loaded('xdebug')) {
  878. $output = preg_replace('/\]\=\>\n(\s+)/m', '] => ', $output);
  879. $output = '<pre>' . $label . htmlspecialchars($output, ENT_QUOTES) . '</pre>';
  880. }
  881. }
  882. if ($echo) {
  883. echo ($output);
  884. return null;
  885. } else {
  886. return $output;
  887. }
  888. }
  889. /**
  890. * 设置当前页面的布局
  891. * @param string|false $layout 布局名称 为false的时候表示关闭布局
  892. * @return void
  893. */
  894. function layout($layout)
  895. {
  896. if (false !== $layout) {
  897. // 开启布局
  898. C('LAYOUT_ON', true);
  899. if (is_string($layout)) {
  900. // 设置新的布局模板
  901. C('LAYOUT_NAME', $layout);
  902. }
  903. } else {
  904. // 临时关闭布局
  905. C('LAYOUT_ON', false);
  906. }
  907. }
  908. /**
  909. * URL组装 支持不同URL模式
  910. * @param string $url URL表达式,格式:'[模块/控制器/操作#锚点@域名]?参数1=值1&参数2=值2...'
  911. * @param string|array $vars 传入的参数,支持数组和字符串
  912. * @param string|boolean $suffix 伪静态后缀,默认为true表示获取配置值
  913. * @param boolean $domain 是否显示域名
  914. * @return string
  915. */
  916. function U($url = '', $vars = '', $suffix = true, $domain = false)
  917. {
  918. // 解析URL
  919. $info = parse_url($url);
  920. $url = !empty($info['path']) ? $info['path'] : ACTION_NAME;
  921. if (isset($info['fragment'])) {
  922. // 解析锚点
  923. $anchor = $info['fragment'];
  924. if (false !== strpos($anchor, '?')) {
  925. // 解析参数
  926. list($anchor, $info['query']) = explode('?', $anchor, 2);
  927. }
  928. if (false !== strpos($anchor, '@')) {
  929. // 解析域名
  930. list($anchor, $host) = explode('@', $anchor, 2);
  931. }
  932. } elseif (false !== strpos($url, '@')) {
  933. // 解析域名
  934. list($url, $host) = explode('@', $info['path'], 2);
  935. }
  936. // 解析子域名
  937. if (isset($host)) {
  938. $domain = $host . (strpos($host, '.') ? '' : strstr($_SERVER['HTTP_HOST'], '.'));
  939. } elseif (true === $domain) {
  940. $domain = $_SERVER['HTTP_HOST'];
  941. if (C('APP_SUB_DOMAIN_DEPLOY')) {
  942. // 开启子域名部署、
  943. if (C('APP_DOMAIN_SUFFIX')) {
  944. $domain_dot_count = substr_count(C('APP_DOMAIN_SUFFIX'), '.');
  945. }
  946. if ((1 + $domain_dot_count) === substr_count($_SERVER['HTTP_HOST'], '.')) {
  947. $domain = 'localhost' == $domain ? 'localhost' : 'www.' . $_SERVER['HTTP_HOST'];
  948. } else {
  949. $domain = 'localhost' == $domain ? 'localhost' : 'www' . strstr($_SERVER['HTTP_HOST'], '.');
  950. }
  951. // '子域名'=>array('模块[/控制器]');
  952. foreach (C('APP_SUB_DOMAIN_RULES') as $key => $rule) {
  953. $rule = is_array($rule) ? $rule[0] : $rule;
  954. if (false === strpos($key, '*') && 0 === strpos($url, $rule)) {
  955. $domain = $key . strstr($domain, '.'); // 生成对应子域名
  956. $url = substr_replace($url, '', 0, strlen($rule));
  957. break;
  958. }
  959. // 子域名部署特殊转换
  960. if (false === strpos($key, '*') && 0 === strpos($url, '/' . $rule)) {
  961. $domain = $key . strstr($domain, '.'); // 生成对应子域名
  962. $url = substr_replace($url, '', 0, strlen('/' . $rule));
  963. break;
  964. }
  965. }
  966. }
  967. }
  968. // 解析参数
  969. if (is_string($vars)) {
  970. // aaa=1&bbb=2 转换成数组
  971. parse_str($vars, $vars);
  972. } elseif (!is_array($vars)) {
  973. $vars = array();
  974. }
  975. if (isset($info['query'])) {
  976. // 解析地址里面参数 合并到vars
  977. parse_str($info['query'], $params);
  978. $vars = array_merge($params, $vars);
  979. }
  980. // URL组装
  981. $depr = C('URL_PATHINFO_DEPR');
  982. $urlCase = C('URL_CASE_INSENSITIVE');
  983. if ($url) {
  984. if (0 === strpos($url, '/')) {
  985. // 定义路由
  986. $route = true;
  987. $url = substr($url, 1);
  988. if ('/' != $depr) {
  989. $url = str_replace('/', $depr, $url);
  990. }
  991. } else {
  992. if ('/' != $depr) {
  993. // 安全替换
  994. $url = str_replace('/', $depr, $url);
  995. }
  996. // 解析模块、控制器和操作
  997. $url = trim($url, $depr);
  998. $path = explode($depr, $url);
  999. $var = array();
  1000. $varModule = C('VAR_MODULE');
  1001. $varController = C('VAR_CONTROLLER');
  1002. $varAction = C('VAR_ACTION');
  1003. $var[$varAction] = !empty($path) ? array_pop($path) : ACTION_NAME;
  1004. $var[$varController] = !empty($path) ? array_pop($path) : CONTROLLER_NAME;
  1005. if ($maps = C('URL_ACTION_MAP')) {
  1006. if (isset($maps[strtolower($var[$varController])])) {
  1007. $maps = $maps[strtolower($var[$varController])];
  1008. if ($action = array_search(strtolower($var[$varAction]), $maps)) {
  1009. $var[$varAction] = $action;
  1010. }
  1011. }
  1012. }
  1013. if ($maps = C('URL_CONTROLLER_MAP')) {
  1014. if ($controller = array_search(strtolower($var[$varController]), $maps)) {
  1015. $var[$varController] = $controller;
  1016. }
  1017. }
  1018. if ($urlCase) {
  1019. $var[$varController] = parse_name($var[$varController]);
  1020. }
  1021. $module = '';
  1022. if (!empty($path)) {
  1023. $var[$varModule] = implode($depr, $path);
  1024. } else {
  1025. // 如果为插件,自动转换路径
  1026. if (CONTROLLER_PATH) {
  1027. $var[$varModule] = MODULE_NAME;
  1028. $varAddon = C('VAR_ADDON');
  1029. if (MODULE_NAME != C('DEFAULT_MODULE')) {
  1030. $var[$varController] = MODULE_NAME;
  1031. }
  1032. $vars = array_merge(array($varAddon => CONTROLLER_PATH), $vars);
  1033. } elseif (C('MULTI_MODULE')) {
  1034. if (MODULE_NAME != C('DEFAULT_MODULE') || !C('MODULE_ALLOW_LIST')) {
  1035. $var[$varModule] = MODULE_NAME;
  1036. }
  1037. }
  1038. }
  1039. if ($maps = C('URL_MODULE_MAP')) {
  1040. if ($_module = array_search(strtolower($var[$varModule]), $maps)) {
  1041. $var[$varModule] = $_module;
  1042. }
  1043. }
  1044. if (isset($var[$varModule])) {
  1045. $module = defined('BIND_MODULE') && BIND_MODULE == $var[$varModule] ? '' : $var[$varModule];
  1046. unset($var[$varModule]);
  1047. }
  1048. }
  1049. }
  1050. if (0 == C('URL_MODEL')) {
  1051. // 普通模式URL转换
  1052. $url = __APP__ . '?' . C('VAR_MODULE') . "={$module}&" . http_build_query(array_reverse($var));
  1053. if ($urlCase) {
  1054. $url = strtolower($url);
  1055. }
  1056. if (!empty($vars)) {
  1057. $vars = http_build_query($vars);
  1058. $url .= '&' . $vars;
  1059. }
  1060. } else {
  1061. // PATHINFO模式或者兼容URL模式
  1062. if (isset($route)) {
  1063. $url = __APP__ . '/' . rtrim($url, $depr);
  1064. } else {
  1065. $path = implode($depr, array_reverse($var));
  1066. if (C('URL_ROUTER_ON')) {
  1067. $url = Think\Route::reverse($path, $vars, $depr, $suffix);
  1068. if (!$url) {
  1069. $url = $path;
  1070. }
  1071. } else {
  1072. $url = $path;
  1073. }
  1074. $url = __APP__ . '/' . ($module ? $module . MODULE_PATHINFO_DEPR : '') . $url;
  1075. }
  1076. if ($urlCase) {
  1077. $url = strtolower($url);
  1078. }
  1079. if (!empty($vars)) {
  1080. // 添加参数
  1081. foreach ($vars as $var => $val) {
  1082. if ('' !== trim($val)) {
  1083. $url .= $depr . $var . $depr . urlencode($val);
  1084. }
  1085. }
  1086. }
  1087. if ($suffix) {
  1088. $suffix = true === $suffix ? C('URL_HTML_SUFFIX') : $suffix;
  1089. if ($pos = strpos($suffix, '|')) {
  1090. $suffix = substr($suffix, 0, $pos);
  1091. }
  1092. if ($suffix && '/' != substr($url, -1)) {
  1093. $url .= '.' . ltrim($suffix, '.');
  1094. }
  1095. }
  1096. }
  1097. if (!empty($anchor)) {
  1098. $url .= '#' . $anchor;
  1099. }
  1100. if ($domain) {
  1101. $url = (is_ssl() ? 'https://' : 'http://') . $domain . $url;
  1102. }
  1103. return $url;
  1104. }
  1105. /**
  1106. * 渲染输出Widget
  1107. * @param string $name Widget名称
  1108. * @param array $data 传入的参数
  1109. * @return void
  1110. */
  1111. function W($name, $data = array())
  1112. {
  1113. return R($name, $data, 'Widget');
  1114. }
  1115. /**
  1116. * 判断是否SSL协议
  1117. * @return boolean
  1118. */
  1119. function is_ssl()
  1120. {
  1121. if (isset($_SERVER['HTTPS']) && ('1' == $_SERVER['HTTPS'] || 'on' == strtolower($_SERVER['HTTPS']))) {
  1122. return true;
  1123. } elseif (isset($_SERVER['SERVER_PORT']) && ('443' == $_SERVER['SERVER_PORT'])) {
  1124. return true;
  1125. }
  1126. return false;
  1127. }
  1128. /**
  1129. * URL重定向
  1130. * @param string $url 重定向的URL地址
  1131. * @param integer $time 重定向的等待时间(秒)
  1132. * @param string $msg 重定向前的提示信息
  1133. * @return void
  1134. */
  1135. function redirect($url, $time = 0, $msg = '')
  1136. {
  1137. //多行URL地址支持
  1138. $url = str_replace(array("\n", "\r"), '', $url);
  1139. if (empty($msg)) {
  1140. $msg = "系统将在{$time}秒之后自动跳转到{$url}!";
  1141. }
  1142. if (!headers_sent()) {
  1143. // redirect
  1144. if (0 === $time) {
  1145. header('Location: ' . $url);
  1146. } else {
  1147. header("refresh:{$time};url={$url}");
  1148. echo ($msg);
  1149. }
  1150. exit();
  1151. } else {
  1152. $str = "<meta http-equiv='Refresh' content='{$time};URL={$url}'>";
  1153. if (0 != $time) {
  1154. $str .= $msg;
  1155. }
  1156. exit($str);
  1157. }
  1158. }
  1159. /**
  1160. * 缓存管理
  1161. * @param mixed $name 缓存名称,如果为数组表示进行缓存设置
  1162. * @param mixed $value 缓存值
  1163. * @param mixed $options 缓存参数
  1164. * @return mixed
  1165. */
  1166. function S($name, $value = '', $options = null)
  1167. {
  1168. static $cache = '';
  1169. if (is_array($options)) {
  1170. // 缓存操作的同时初始化
  1171. $type = isset($options['type']) ? $options['type'] : '';
  1172. $cache = Think\Cache::getInstance($type, $options);
  1173. } elseif (is_array($name)) {
  1174. // 缓存初始化
  1175. $type = isset($name['type']) ? $name['type'] : '';
  1176. $cache = Think\Cache::getInstance($type, $name);
  1177. return $cache;
  1178. } elseif (empty($cache)) {
  1179. // 自动初始化
  1180. $cache = Think\Cache::getInstance();
  1181. }
  1182. if ('' === $value) {
  1183. // 获取缓存
  1184. return $cache->get($name);
  1185. } elseif (is_null($value)) {
  1186. // 删除缓存
  1187. return $cache->rm($name);
  1188. } else {
  1189. // 缓存数据
  1190. if (is_array($options)) {
  1191. $expire = isset($options['expire']) ? $options['expire'] : null;
  1192. } else {
  1193. $expire = is_numeric($options) ? $options : null;
  1194. }
  1195. return $cache->set($name, $value, $expire);
  1196. }
  1197. }
  1198. /**
  1199. * 快速文件数据读取和保存 针对简单类型数据 字符串、数组
  1200. * @param string $name 缓存名称
  1201. * @param mixed $value 缓存值
  1202. * @param string $path 缓存路径
  1203. * @return mixed
  1204. */
  1205. function F($name, $value = '', $path = DATA_PATH)
  1206. {
  1207. static $_cache = array();
  1208. $filename = $path . $name . '.php';
  1209. if ('' !== $value) {
  1210. if (is_null($value)) {
  1211. // 删除缓存
  1212. if (false !== strpos($name, '*')) {
  1213. return false; // TODO
  1214. } else {
  1215. unset($_cache[$name]);
  1216. return Think\Storage::unlink($filename, 'F');
  1217. }
  1218. } else {
  1219. Think\Storage::put($filename, serialize($value), 'F');
  1220. // 缓存数据
  1221. $_cache[$name] = $value;
  1222. return null;
  1223. }
  1224. }
  1225. // 获取缓存数据
  1226. if (isset($_cache[$name])) {
  1227. return $_cache[$name];
  1228. }
  1229. if (Think\Storage::has($filename, 'F')) {
  1230. $value = unserialize(Think\Storage::read($filename, 'F'));
  1231. $_cache[$name] = $value;
  1232. } else {
  1233. $value = false;
  1234. }
  1235. return $value;
  1236. }
  1237. /**
  1238. * 根据PHP各种类型变量生成唯一标识号
  1239. * @param mixed $mix 变量
  1240. * @return string
  1241. */
  1242. function to_guid_string($mix)
  1243. {
  1244. if (is_object($mix)) {
  1245. return spl_object_hash($mix);
  1246. } elseif (is_resource($mix)) {
  1247. $mix = get_resource_type($mix) . strval($mix);
  1248. } else {
  1249. $mix = serialize($mix);
  1250. }
  1251. return md5($mix);
  1252. }
  1253. /**
  1254. * XML编码
  1255. * @param mixed $data 数据
  1256. * @param string $root 根节点名
  1257. * @param string $item 数字索引的子节点名
  1258. * @param string $attr 根节点属性
  1259. * @param string $id 数字索引子节点key转换的属性名
  1260. * @param string $encoding 数据编码
  1261. * @return string
  1262. */
  1263. function xml_encode($data, $root = 'think', $item = 'item', $attr = '', $id = 'id', $encoding = 'utf-8')
  1264. {
  1265. if (is_array($attr)) {
  1266. $_attr = array();
  1267. foreach ($attr as $key => $value) {
  1268. $_attr[] = "{$key}=\"{$value}\"";
  1269. }
  1270. $attr = implode(' ', $_attr);
  1271. }
  1272. $attr = trim($attr);
  1273. $attr = empty($attr) ? '' : " {$attr}";
  1274. $xml = "<?xml version=\"1.0\" encoding=\"{$encoding}\"?>";
  1275. $xml .= "<{$root}{$attr}>";
  1276. $xml .= data_to_xml($data, $item, $id);
  1277. $xml .= "</{$root}>";
  1278. return $xml;
  1279. }
  1280. /**
  1281. * 数据XML编码
  1282. * @param mixed $data 数据
  1283. * @param string $item 数字索引时的节点名称
  1284. * @param string $id 数字索引key转换为的属性名
  1285. * @return string
  1286. */
  1287. function data_to_xml($data, $item = 'item', $id = 'id')
  1288. {
  1289. $xml = $attr = '';
  1290. foreach ($data as $key => $val) {
  1291. if (is_numeric($key)) {
  1292. $id && $attr = " {$id}=\"{$key}\"";
  1293. $key = $item;
  1294. }
  1295. $xml .= "<{$key}{$attr}>";
  1296. $xml .= (is_array($val) || is_object($val)) ? data_to_xml($val, $item, $id) : $val;
  1297. $xml .= "</{$key}>";
  1298. }
  1299. return $xml;
  1300. }
  1301. /**
  1302. * session管理函数
  1303. * @param string|array $name session名称 如果为数组则表示进行session设置
  1304. * @param mixed $value session值
  1305. * @return mixed
  1306. */
  1307. function session($name = '', $value = '')
  1308. {
  1309. $prefix = C('SESSION_PREFIX');
  1310. if (is_array($name)) {
  1311. // session初始化 在session_start 之前调用
  1312. if (isset($name['prefix'])) {
  1313. C('SESSION_PREFIX', $name['prefix']);
  1314. }
  1315. if (C('VAR_SESSION_ID') && isset($_REQUEST[C('VAR_SESSION_ID')])) {
  1316. session_id($_REQUEST[C('VAR_SESSION_ID')]);
  1317. } elseif (isset($name['id'])) {
  1318. session_id($name['id']);
  1319. }
  1320. if ('common' == APP_MODE) {
  1321. // 其它模式可能不支持
  1322. ini_set('session.auto_start', 0);
  1323. }
  1324. if (isset($name['name'])) {
  1325. session_name($name['name']);
  1326. }
  1327. if (isset($name['path'])) {
  1328. session_save_path($name['path']);
  1329. }
  1330. if (isset($name['domain'])) {
  1331. ini_set('session.cookie_domain', $name['domain']);
  1332. }
  1333. if (isset($name['expire'])) {
  1334. ini_set('session.gc_maxlifetime', $name['expire']);
  1335. ini_set('session.cookie_lifetime', $name['expire']);
  1336. }
  1337. if (isset($name['use_trans_sid'])) {
  1338. ini_set('session.use_trans_sid', $name['use_trans_sid'] ? 1 : 0);
  1339. }
  1340. if (isset($name['use_cookies'])) {
  1341. ini_set('session.use_cookies', $name['use_cookies'] ? 1 : 0);
  1342. }
  1343. if (isset($name['cache_limiter'])) {
  1344. session_cache_limiter($name['cache_limiter']);
  1345. }
  1346. if (isset($name['cache_expire'])) {
  1347. session_cache_expire($name['cache_expire']);
  1348. }
  1349. if (isset($name['type'])) {
  1350. C('SESSION_TYPE', $name['type']);
  1351. }
  1352. if (C('SESSION_TYPE')) {
  1353. // 读取session驱动
  1354. $type = C('SESSION_TYPE');
  1355. $class = strpos($type, '\\') ? $type : 'Think\\Session\\Driver\\' . ucwords(strtolower($type));
  1356. $hander = new $class();
  1357. session_set_save_handler(
  1358. array(&$hander, "open"),
  1359. array(&$hander, "close"),
  1360. array(&$hander, "read"),
  1361. array(&$hander, "write"),
  1362. array(&$hander, "destroy"),
  1363. array(&$hander, "gc"));
  1364. }
  1365. // 启动session
  1366. if (C('SESSION_AUTO_START')) {
  1367. session_start();
  1368. }
  1369. } elseif ('' === $value) {
  1370. if ('' === $name) {
  1371. // 获取全部的session
  1372. return $prefix ? $_SESSION[$prefix] : $_SESSION;
  1373. } elseif (0 === strpos($name, '[')) {
  1374. // session 操作
  1375. if ('[pause]' == $name) {
  1376. // 暂停session
  1377. session_write_close();
  1378. } elseif ('[start]' == $name) {
  1379. // 启动session
  1380. session_start();
  1381. } elseif ('[destroy]' == $name) {
  1382. // 销毁session
  1383. $_SESSION = array();
  1384. session_unset();
  1385. session_destroy();
  1386. } elseif ('[regenerate]' == $name) {
  1387. // 重新生成id
  1388. session_regenerate_id();
  1389. }
  1390. } elseif (0 === strpos($name, '?')) {
  1391. // 检查session
  1392. $name = substr($name, 1);
  1393. if (strpos($name, '.')) {
  1394. // 支持数组
  1395. list($name1, $name2) = explode('.', $name);
  1396. return $prefix ? isset($_SESSION[$prefix][$name1][$name2]) : isset($_SESSION[$name1][$name2]);
  1397. } else {
  1398. return $prefix ? isset($_SESSION[$prefix][$name]) : isset($_SESSION[$name]);
  1399. }
  1400. } elseif (is_null($name)) {
  1401. // 清空session
  1402. if ($prefix) {
  1403. unset($_SESSION[$prefix]);
  1404. } else {
  1405. $_SESSION = array();
  1406. }
  1407. } elseif ($prefix) {
  1408. // 获取session
  1409. if (strpos($name, '.')) {
  1410. list($name1, $name2) = explode('.', $name);
  1411. return isset($_SESSION[$prefix][$name1][$name2]) ? $_SESSION[$prefix][$name1][$name2] : null;
  1412. } else {
  1413. return isset($_SESSION[$prefix][$name]) ? $_SESSION[$prefix][$name] : null;
  1414. }
  1415. } else {
  1416. if (strpos($name, '.')) {
  1417. list($name1, $name2) = explode('.', $name);
  1418. return isset($_SESSION[$name1][$name2]) ? $_SESSION[$name1][$name2] : null;
  1419. } else {
  1420. return isset($_SESSION[$name]) ? $_SESSION[$name] : null;
  1421. }
  1422. }
  1423. } elseif (is_null($value)) {
  1424. // 删除session
  1425. if (strpos($name, '.')) {
  1426. list($name1, $name2) = explode('.', $name);
  1427. if ($prefix) {
  1428. unset($_SESSION[$prefix][$name1][$name2]);
  1429. } else {
  1430. unset($_SESSION[$name1][$name2]);
  1431. }
  1432. } else {
  1433. if ($prefix) {
  1434. unset($_SESSION[$prefix][$name]);
  1435. } else {
  1436. unset($_SESSION[$name]);
  1437. }
  1438. }
  1439. } else {
  1440. // 设置session
  1441. if (strpos($name, '.')) {
  1442. list($name1, $name2) = explode('.', $name);
  1443. if ($prefix) {
  1444. $_SESSION[$prefix][$name1][$name2] = $value;
  1445. } else {
  1446. $_SESSION[$name1][$name2] = $value;
  1447. }
  1448. } else {
  1449. if ($prefix) {
  1450. $_SESSION[$prefix][$name] = $value;
  1451. } else {
  1452. $_SESSION[$name] = $value;
  1453. }
  1454. }
  1455. }
  1456. return null;
  1457. }
  1458. /**
  1459. * Cookie 设置、获取、删除
  1460. * @param string $name cookie名称
  1461. * @param mixed $value cookie值
  1462. * @param mixed $option cookie参数
  1463. * @return mixed
  1464. */
  1465. function cookie($name = '', $value = '', $option = null)
  1466. {
  1467. // 默认设置
  1468. $config = array(
  1469. 'prefix' => C('COOKIE_PREFIX'), // cookie 名称前缀
  1470. 'expire' => C('COOKIE_EXPIRE'), // cookie 保存时间
  1471. 'path' => C('COOKIE_PATH'), // cookie 保存路径
  1472. 'domain' => C('COOKIE_DOMAIN'), // cookie 有效域名
  1473. 'secure' => C('COOKIE_SECURE'), // cookie 启用安全传输
  1474. 'httponly' => C('COOKIE_HTTPONLY'), // httponly设置
  1475. );
  1476. // 参数设置(会覆盖黙认设置)
  1477. if (!is_null($option)) {
  1478. if (is_numeric($option)) {
  1479. $option = array('expire' => $option);
  1480. } elseif (is_string($option)) {
  1481. parse_str($option, $option);
  1482. }
  1483. $config = array_merge($config, array_change_key_case($option));
  1484. }
  1485. if (!empty($config['httponly'])) {
  1486. ini_set("session.cookie_httponly", 1);
  1487. }
  1488. // 清除指定前缀的所有cookie
  1489. if (is_null($name)) {
  1490. if (empty($_COOKIE)) {
  1491. return null;
  1492. }
  1493. // 要删除的cookie前缀,不指定则删除config设置的指定前缀
  1494. $prefix = empty($value) ? $config['prefix'] : $value;
  1495. if (!empty($prefix)) {
  1496. // 如果前缀为空字符串将不作处理直接返回
  1497. foreach ($_COOKIE as $key => $val) {
  1498. if (0 === stripos($key, $prefix)) {
  1499. setcookie($key, '', time() - 3600, $config['path'], $config['domain'], $config['secure'], $config['httponly']);
  1500. unset($_COOKIE[$key]);
  1501. }
  1502. }
  1503. }
  1504. return null;
  1505. } elseif ('' === $name) {
  1506. // 获取全部的cookie
  1507. return $_COOKIE;
  1508. }
  1509. $name = $config['prefix'] . str_replace('.', '_', $name);
  1510. if ('' === $value) {
  1511. if (isset($_COOKIE[$name])) {
  1512. $value = $_COOKIE[$name];
  1513. if (0 === strpos($value, 'think:')) {
  1514. $value = substr($value, 6);
  1515. return array_map('urldecode', json_decode(MAGIC_QUOTES_GPC ? stripslashes($value) : $value, true));
  1516. } else {
  1517. return $value;
  1518. }
  1519. } else {
  1520. return null;
  1521. }
  1522. } else {
  1523. if (is_null($value)) {
  1524. setcookie($name, '', time() - 3600, $config['path'], $config['domain'], $config['secure'], $config['httponly']);
  1525. unset($_COOKIE[$name]); // 删除指定cookie
  1526. } else {
  1527. // 设置cookie
  1528. if (is_array($value)) {
  1529. $value = 'think:' . json_encode(array_map('urlencode', $value));
  1530. }
  1531. $expire = !empty($config['expire']) ? time() + intval($config['expire']) : 0;
  1532. setcookie($name, $value, $expire, $config['path'], $config['domain'], $config['secure'], $config['httponly']);
  1533. $_COOKIE[$name] = $value;
  1534. }
  1535. }
  1536. return null;
  1537. }
  1538. /**
  1539. * 加载动态扩展文件
  1540. * @var string $path 文件路径
  1541. * @return void
  1542. */
  1543. function load_ext_file($path)
  1544. {
  1545. // 加载自定义外部文件
  1546. if ($files = C('LOAD_EXT_FILE')) {
  1547. $files = explode(',', $files);
  1548. foreach ($files as $file) {
  1549. $file = $path . 'Common/' . $file . '.php';
  1550. if (is_file($file)) {
  1551. include $file;
  1552. }
  1553. }
  1554. }
  1555. // 加载自定义的动态配置文件
  1556. if ($configs = C('LOAD_EXT_CONFIG')) {
  1557. if (is_string($configs)) {
  1558. $configs = explode(',', $configs);
  1559. }
  1560. foreach ($configs as $key => $config) {
  1561. $file = is_file($config) ? $config : $path . 'Conf/' . $config . CONF_EXT;
  1562. if (is_file($file)) {
  1563. is_numeric($key) ? C(load_Config($file)) : C($key, load_Config($file));
  1564. }
  1565. }
  1566. }
  1567. }
  1568. /**
  1569. * 获取客户端IP地址
  1570. * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字
  1571. * @param boolean $adv 是否进行高级模式获取(有可能被伪装)
  1572. * @return mixed
  1573. */
  1574. function get_client_ip($type = 0, $adv = false)
  1575. {
  1576. $type = $type ? 1 : 0;
  1577. static $ip = null;
  1578. if (null !== $ip) {
  1579. return $ip[$type];
  1580. }
  1581. if ($adv) {
  1582. if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
  1583. $arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
  1584. $pos = array_search('unknown', $arr);
  1585. if (false !== $pos) {
  1586. unset($arr[$pos]);
  1587. }
  1588. $ip = trim($arr[0]);
  1589. } elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
  1590. $ip = $_SERVER['HTTP_CLIENT_IP'];
  1591. } elseif (isset($_SERVER['REMOTE_ADDR'])) {
  1592. $ip = $_SERVER['REMOTE_ADDR'];
  1593. }
  1594. } elseif (isset($_SERVER['REMOTE_ADDR'])) {
  1595. $ip = $_SERVER['REMOTE_ADDR'];
  1596. }
  1597. // IP地址合法验证
  1598. $long = sprintf("%u", ip2long($ip));
  1599. $ip = $long ? array($ip, $long) : array('0.0.0.0', 0);
  1600. return $ip[$type];
  1601. }
  1602. /**
  1603. * 发送HTTP状态
  1604. * @param integer $code 状态码
  1605. * @return void
  1606. */
  1607. function send_http_status($code)
  1608. {
  1609. static $_status = array(
  1610. // Informational 1xx
  1611. 100 => 'Continue',
  1612. 101 => 'Switching Protocols',
  1613. // Success 2xx
  1614. 200 => 'OK',
  1615. 201 => 'Created',
  1616. 202 => 'Accepted',
  1617. 203 => 'Non-Authoritative Information',
  1618. 204 => 'No Content',
  1619. 205 => 'Reset Content',
  1620. 206 => 'Partial Content',
  1621. // Redirection 3xx
  1622. 300 => 'Multiple Choices',
  1623. 301 => 'Moved Permanently',
  1624. 302 => 'Moved Temporarily ', // 1.1
  1625. 303 => 'See Other',
  1626. 304 => 'Not Modified',
  1627. 305 => 'Use Proxy',
  1628. // 306 is deprecated but reserved
  1629. 307 => 'Temporary Redirect',
  1630. // Client Error 4xx
  1631. 400 => 'Bad Request',
  1632. 401 => 'Unauthorized',
  1633. 402 => 'Payment Required',
  1634. 403 => 'Forbidden',
  1635. 404 => 'Not Found',
  1636. 405 => 'Method Not Allowed',
  1637. 406 => 'Not Acceptable',
  1638. 407 => 'Proxy Authentication Required',
  1639. 408 => 'Request Timeout',
  1640. 409 => 'Conflict',
  1641. 410 => 'Gone',
  1642. 411 => 'Length Required',
  1643. 412 => 'Precondition Failed',
  1644. 413 => 'Request Entity Too Large',
  1645. 414 => 'Request-URI Too Long',
  1646. 415 => 'Unsupported Media Type',
  1647. 416 => 'Requested Range Not Satisfiable',
  1648. 417 => 'Expectation Failed',
  1649. // Server Error 5xx
  1650. 500 => 'Internal Server Error',
  1651. 501 => 'Not Implemented',
  1652. 502 => 'Bad Gateway',
  1653. 503 => 'Service Unavailable',
  1654. 504 => 'Gateway Timeout',
  1655. 505 => 'HTTP Version Not Supported',
  1656. 509 => 'Bandwidth Limit Exceeded',
  1657. );
  1658. if (isset($_status[$code])) {
  1659. header('HTTP/1.1 ' . $code . ' ' . $_status[$code]);
  1660. // 确保FastCGI模式下正常
  1661. header('Status:' . $code . ' ' . $_status[$code]);
  1662. }
  1663. }
  1664. function think_filter(&$value)
  1665. {
  1666. // TODO 其他安全过滤
  1667. // 过滤查询特殊字符
  1668. if (preg_match('/^(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOTIN|NOT IN|IN)$/i', $value)) {
  1669. $value .= ' ';
  1670. }
  1671. }
  1672. // 不区分大小写的in_array实现
  1673. function in_array_case($value, $array)
  1674. {
  1675. return in_array(strtolower($value), array_map('strtolower', $array));
  1676. }