📄 正在查看:twcms/kongphp/base/base.func.php
大小:13,419 字节 · 修改:2014-04-07 07:15:32 · 行数:464
1<?php
2/**
3 * Copyright (C) 2013-2014 www.kongphp.com All rights reserved.
4 * Licensed http://www.gnu.org/licenses/lgpl.html
5 * Author: wuzhaohuan <kongphp@gmail.com>
6 */
7
8// 统计程序运行时间
9function runtime() {
10 return number_format(microtime(1) - $_ENV['_start_time'], 4);
11}
12
13// 统计程序内存开销
14function runmem() {
15 return MEMORY_LIMIT_ON ? get_byte(memory_get_usage() - $_ENV['_start_memory']) : 'unknown';
16}
17
18// 安全获取IP
19function ip() {
20 if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
21 preg_match('#[\d\.]{7,15}#', $_SERVER['HTTP_X_FORWARDED_FOR'], $mat);
22 $ip = $mat[0];
23 }elseif(isset($_SERVER['HTTP_CLIENT_IP'])) {
24 $ip = $_SERVER['HTTP_CLIENT_IP'];
25 }elseif(isset($_SERVER['REMOTE_ADDR'])) {
26 $ip = $_SERVER['REMOTE_ADDR'];
27 }
28 return long2ip(ip2long($ip));
29}
30
31// 返回消息JSON (注意:不要含有 " \ 等之类破坏 JSON 结构的字符)
32function E($err, $msg, $name = '') {
33 exit('{"err":'.$err.', "msg":"'.$msg.'", "name":"'.$name.'"}');
34}
35
36/**
37 * 无Notice快捷取变量 (Request 的缩写)
38 * @param string $k 键值
39 * @param string $var 类型 GET|POST|COOKIE|REQUEST|SERVER
40 * @return mixed
41 */
42function R($k, $var = 'G') {
43 switch($var) {
44 case 'G': $var = &$_GET; break;
45 case 'P': $var = &$_POST; break;
46 case 'C': $var = &$_COOKIE; break;
47 case 'R': $var = isset($_GET[$k]) ? $_GET : (isset($_POST[$k]) ? $_POST : $_COOKIE); break;
48 case 'S': $var = &$_SERVER; break;
49 }
50 return isset($var[$k]) ? $var[$k] : null;
51}
52
53/**
54 * 读取/设置 配置信息 (Config 的缩写)
55 * @param string $key 键值
56 * @param string $val 设置值
57 * @return mixed
58 */
59function C($key, $val = null) {
60 if(is_null($val)) return isset($_ENV['_config'][$key]) ? $_ENV['_config'][$key] : $val;
61 return $_ENV['_config'][$key] = $val;
62}
63
64/**
65 * 具有递归自动创建文件夹和写入文件数据的功能 (File Write 的缩写)
66 * @param string filename 要被写入数据的文件名
67 * @param string $data 要写入的数据
68 * @return boot
69 */
70function FW($filename, $data) {
71 $dir = dirname($filename);
72 // 目录不存在则创建
73 is_dir($dir) || mkdir($dir, 0755, true);
74
75 return file_put_contents($filename, $data); // 不使用 LOCK_EX,多线程访问时会有同步问题
76}
77
78// 方便记忆 以 _ 开始的都是改造系统函数
79// cookie 设置/删除
80function _setcookie($name, $value='', $expire=0, $path='', $domain='', $secure=false, $httponly=false) {
81 $name = $_ENV['_config']['cookie_pre'].$name;
82 if(!$path) $path = $_ENV['_config']['cookie_path'];
83 if(!$domain) $domain = $_ENV['_config']['cookie_domain'];
84 $_COOKIE[$name] = $value;
85 return setcookie($name, $value, $expire, $path, $domain, $secure, $httponly);
86}
87
88// 递归加反斜线
89function _addslashes(&$var) {
90 if(is_array($var)) {
91 foreach($var as $k=>&$v) _addslashes($v);
92 }else{
93 $var = addslashes($var);
94 }
95}
96
97// 递归清理反斜线
98function _stripslashes(&$var) {
99 if(is_array($var)) {
100 foreach($var as $k=>&$v) _stripslashes($v);
101 }else{
102 $var = stripslashes($var);
103 }
104}
105
106// 递归转换为HTML实体代码
107function _htmls(&$var) {
108 if(is_array($var)) {
109 foreach($var as $k=>&$v) _htmls($v);
110 }else{
111 $var = htmlspecialchars($var);
112 }
113}
114
115// 递归清理两端空白字符
116function _trim(&$var) {
117 if(is_array($var)) {
118 foreach($var as $k=>&$v) _trim($v);
119 }else{
120 $var = trim($var);
121 }
122}
123
124// 编码 URL 字符串
125function _urlencode($s) {
126 return str_replace('-', '%2D', urlencode($s));
127}
128
129// 对 JSON 格式的字符串进行解码
130function _json_decode($s) {
131 return $s === FALSE ? FALSE : json_decode($s, true);
132}
133
134// 简单的数组转JSON
135function _json_encode($arr) {
136 if(!is_array($arr) && empty($arr)) return '';
137 $s = '{';
138 foreach($arr as $k=>$v) {
139 $s .= '"'.$k.'":"'.strtr($v, array('\\'=>'\\\\', '"'=>'\"')).'",';
140 }
141 return rtrim($s, ',').'}';
142}
143
144// 增强多维数组进行排序,最多支持两个字段排序
145function _array_multisort(&$data, $c_1, $c_2 = true, $a_1 = 1, $a_2 = 1) {
146 if(!is_array($data)) return $data;
147
148 $col_1 = $col_2 = array();
149 foreach($data as $key => $row) {
150 $col_1[$key] = $row[$c_1];
151 $col_2[$key] = $c_2===true ? $key : $row[$c_2];
152 }
153
154 $asc_1 = $a_1 ? SORT_ASC : SORT_DESC;
155 $asc_2 = $a_2 ? SORT_ASC : SORT_DESC;
156 array_multisort($col_1, $asc_1, $col_2, $asc_2, $data);
157
158 return $data;
159}
160
161// 返回安全整数
162function _int(&$c, $k, $v = 0) {
163 if(isset($c[$k])) {
164 $i = intval($c[$k]);
165 return $i ? $i : $v;
166 }else{
167 return $v;
168 }
169}
170
171// 列出文件和目录
172function _scandir($dir) {
173 if(function_exists('scandir')) return scandir($dir); // 有些服务器禁用了scandir
174 $dh = opendir($dir);
175 $arr = array();
176 while($file = readdir($dh)) {
177 if($file == '.' || $file == '..') continue;
178 $arr[] = $file;
179 }
180 closedir($dh);
181 return $arr;
182}
183
184// 递归删除目录
185function _rmdir($dir, $keepdir = 0) {
186 if(!is_dir($dir) || $dir == '/' || $dir == '../') return FALSE; // 避免意外删除整站数据
187 $files = _scandir($dir);
188 foreach($files as $file) {
189 if($file == '.' || $file == '..') continue;
190 $filepath = $dir.'/'.$file;
191 if(!is_dir($filepath)) {
192 try{unlink($filepath);}catch(Exception $e){}
193 }else{
194 _rmdir($filepath);
195 }
196 }
197 if(!$keepdir) try{rmdir($dir);}catch(Exception $e){}
198 return TRUE;
199}
200
201// 检测文件或目录是否可写 (兼容 windows)
202function _is_writable($file) {
203 try{
204 if(is_dir($file)) {
205 $tmpfile = $file.'/_test.tmp';
206 $n = @file_put_contents($tmpfile, 'test');
207 if($n > 0) {
208 unlink($tmpfile);
209 return TRUE;
210 }else{
211 return FALSE;
212 }
213 }elseif(is_file($file)) {
214 if(strpos(strtoupper(PHP_OS), 'WIN') !== FALSE) {
215 $fp = @fopen($file, 'a'); // 写入方式打开,将文件指针指向文件末尾。如果文件不存在则尝试创建之。
216 @fclose($fp);
217 return (bool)$fp;
218 }else{
219 return is_writable($file);
220 }
221 }
222 }catch(Exception $e) {}
223 return FALSE;
224}
225
226// 清理PHP代码中的空格和注释
227function _strip_whitespace($content) {
228 $tokens = token_get_all($content);
229 $last = FALSE;
230 $s = '';
231 for($i = 0, $j = count($tokens); $i < $j; $i++) {
232 if(is_string($tokens[$i])) {
233 $last = FALSE;
234 $s .= $tokens[$i];
235 }else{
236 switch($tokens[$i][0]) {
237 case T_COMMENT: //清理PHP注释
238 case T_DOC_COMMENT:
239 break;
240 case T_WHITESPACE: //清理多余空格
241 if(!$last) {
242 $s .= ' ';
243 $last = TRUE;
244 }
245 break;
246 case T_START_HEREDOC:
247 $s .= "<<<KONG\n";
248 break;
249 case T_END_HEREDOC: // 修正 HEREDOC
250 $s .= "KONG;\n";
251 for($k = $i+1; $k < $j; $k++) {
252 if(is_string($tokens[$k]) && $tokens[$k] == ';') {
253 $i = $k;
254 break;
255 }elseif($tokens[$k][0] == T_CLOSE_TAG) {
256 break;
257 }
258 }
259 break;
260 default:
261 $last = FALSE;
262 $s .= $tokens[$i][1];
263 }
264 }
265 }
266 return $s;
267}
268
269/**
270 * 产生随机字符串
271 * @param int $length 输出长度
272 * @param int $type 输出类型 1为数字 2为a1 3为Aa1
273 * @param string $chars 随机字符 可自定义
274 * @return string
275 */
276function random($length, $type = 1, $chars = '0123456789abcdefghijklmnopqrstuvwxyz') {
277 if($type == 1) {
278 $hash = sprintf('%0'.$length.'d', mt_rand(0, pow(10, $length) - 1));
279 } else {
280 $hash = '';
281 if($type == 3) $chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
282 $max = strlen($chars) - 1;
283 for($i = 0; $i < $length; $i++) $hash .= $chars[mt_rand(0, $max)];
284 }
285 return $hash;
286}
287
288/**
289 * 获取数据大小单位
290 * @param int $byte 字节
291 * @return string
292 */
293function get_byte($byte) {
294 if($byte < 1024) {
295 return $byte.' Byte';
296 }elseif($byte < 1048576) {
297 return round($byte/1024, 2).' KB';
298 }elseif($byte < 1073741824) {
299 return round($byte/1048576, 2).' MB';
300 }elseif($byte < 1099511627776) {
301 return round($byte/1073741824, 2).' GB';
302 }else{
303 return round($byte/1099511627776, 2).' TB';
304 }
305}
306
307// 转换为人性化时间
308function human_date($dateline, $dateformat = 'Y-m-d H:i:s') {
309 $second = $_ENV['_time'] - $dateline;
310 if($second > 31536000) {
311 return date($dateformat, $dateline);
312 }elseif($second > 2592000) {
313 return floor($second / 2592000).'月前';
314 }elseif($second > 86400) {
315 return floor($second / 86400).'天前';
316 }elseif($second > 3600) {
317 return floor($second / 3600).'小时前';
318 }elseif($second > 60) {
319 return floor($second / 60).'分钟前';
320 }else{
321 return $second.'秒前';
322 }
323}
324
325// 安全过滤 (过滤非空格、英文、数字、下划线、中文、日文、朝鲜文,其他语言通过 $ext 添加 Unicode 编码)
326// 4E00-9FA5(中文) 30A0-30FF(日文片假名) 3040-309F(日文平假名) 1100-11FF(朝鲜文) 3130-318F(朝鲜文兼容字母) AC00-D7AF(朝鲜文音节)
327function safe_str($s, $ext = '') {
328 $ext = preg_quote($ext);
329 $s = preg_replace('#[^\040\w\x{4E00}-\x{9FA5}\x{30A0}-\x{30FF}\x{3040}-\x{309F}\x{1100}-\x{11FF}\x{3130}-\x{318F}\x{AC00}-\x{D7AF}'.$ext.']+#u', '', $s);
330 $s = trim($s);
331 return $s;
332}
333
334// 获取下级所有目录名 (严格限制目录名只能是 数字 字母 _)
335function get_dirs($path, $fullpath = false) {
336 $arr = array();
337 $dh = opendir($path);
338 while($dir = readdir($dh)) {
339 if(preg_match('#\W#', $dir) || !is_dir($path.$dir)) continue;
340 $arr[] = $fullpath ? $path.$dir.'/' : $dir;
341 }
342 sort($arr); // 排序方式:目录名升序
343 return $arr;
344}
345
346/**
347 * 字符串只替换一次
348 * @param string $search 查找的字符串
349 * @param string $replace 替换的字符串
350 * @param string $content 执行替换的字符串
351 * @return string
352 */
353function str_replace_once($search, $replace, $content) {
354 $pos = strpos($content, $search);
355 if($pos === false) return $content;
356 return substr_replace($content, $replace, $pos, strlen($search));
357}
358
359/**
360 * 字符串加密、解密函数
361 * @param string $string 字符串
362 * @param string $operation ENCODE为加密,DECODE为解密,可选参数,默认为ENCODE
363 * @param string $key 密钥:数字、字母、下划线
364 * @param string $expiry 过期时间
365 * @return string
366 */
367function str_auth($string, $operation = 'DECODE', $key = '', $expiry = 0) {
368 $ckey_length = 4;
369 $key = md5($key != '' ? $key : C('auth_key'));
370 $keya = md5(substr($key, 0, 16));
371 $keyb = md5(substr($key, 16, 16));
372 $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
373
374 $cryptkey = $keya.md5($keya.$keyc);
375 $key_length = strlen($cryptkey);
376
377 $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
378 $string_length = strlen($string);
379
380 $result = '';
381 $box = range(0, 255);
382
383 $rndkey = array();
384 for($i = 0; $i <= 255; $i++) {
385 $rndkey[$i] = ord($cryptkey[$i % $key_length]);
386 }
387
388 for($j = $i = 0; $i < 256; $i++) {
389 $j = ($j + $box[$i] + $rndkey[$i]) % 256;
390 $tmp = $box[$i];
391 $box[$i] = $box[$j];
392 $box[$j] = $tmp;
393 }
394
395 for($a = $j = $i = 0; $i < $string_length; $i++) {
396 $a = ($a + 1) % 256;
397 $j = ($j + $box[$a]) % 256;
398 $tmp = $box[$a];
399 $box[$a] = $box[$j];
400 $box[$j] = $tmp;
401 $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
402 }
403
404 if($operation == 'DECODE') {
405 if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
406 return substr($result, 26);
407 }else{
408 return '';
409 }
410 }else{
411 return $keyc.str_replace('=', '', base64_encode($result));
412 }
413}
414
415// 生成 form hash
416function form_hash() {
417 return substr(md5(substr($_ENV['_time'], 0, -5).$_ENV['_config']['auth_key']), 16);
418}
419
420// 校验 form hash
421function form_submit() {
422 return R('FORM_HASH', 'P') == form_hash();
423}
424
425// 远程抓取数据
426function fetch_url($url, $timeout = 30) {
427 $opts = array ('http'=>array('method'=>'GET', 'timeout'=>$timeout));
428 $context = stream_context_create($opts);
429 $html = file_get_contents($url, false, $context);
430 return $html;
431}
432
433/**
434 * 分页函数
435 * @param int $page 当前页
436 * @param int $maxpage 最大页
437 * @param string $url 完整路径
438 * @param int $offset 偏移数
439 * @param array $lang 上下页数组
440 * @return string
441 */
442function pages($page, $maxpage, $url, $offset = 5, $lang = array('&#171;', '&#187;')) {
443 if($maxpage < 2) return '';
444 $pnum = $offset*2;
445 $ismore = $maxpage > $pnum;
446 $s = '';
447 $ua = explode('{page}', $url);
448 if($page > 1) $s .= '<a href="'.$ua[0].($page-1).$ua[1].'">'.$lang[0].'</a>';
449 if($ismore) {
450 $i_end = min($maxpage, max($pnum, $page+$offset)) - 1;
451 $i = max(2, $i_end-$pnum+2);
452 }else{
453 $i_end = min($maxpage, $pnum)-1;
454 $i = 2;
455 }
456 $s .= $page == 1 ? '<b>1</b>' : '<a href="'.$ua[0].'1'.$ua[1].'">1'.($ismore && $i > 2 ? ' ...' : '').'</a>';
457 for($i; $i<=$i_end; $i++){
458 $s .= $page == $i ? '<b>'.$i.'</b>' : '<a href="'.$ua[0].$i.$ua[1].'">'.$i.'</a>';
459 }
460 $s .= $page == $maxpage ? '<b>'.$maxpage.'</b>' : '<a href="'.$ua[0].$maxpage.$ua[1].'">'.($ismore && $i_end < $maxpage-1 ? '... ' : '').$maxpage.'</a>';
461 if($page < $maxpage) $s .= '<a href="'.$ua[0].($page+1).$ua[1].'">'.$lang[1].'</a>';
462 return $s;
463}
464