Discuz x版本论坛的核心文件class_core.php分析
这个文章主要是分析下discuz x版本论坛的class_core.php文件, $Id: class_core.php 6914 2010-03-26 12:52:36Z cnteacher $ 。<?php
02
03 /**
04* (C)2001-2099 Comsenz Inc.
05* This is NOT a freeware, use is subject to license terms
06*
07* $Id: class_core.php 6914 2010-03-26 12:52:36Z cnteacher $
08*/
09
10 /**
11* Discuz 核心引擎
12* 其他处理代码当中用到的变量不要在本核心 new 之前设置, 否则会自动清空
13* 初始化功能,需要先加载核心文件
14*/
15
16 define('IN_DISCUZ', true);
17 class discuz_core {
18
19 // 数据库存储引擎
20 var $db = null;
21
22 // 内存缓冲object
23 var $mem = null;
24
25 // 会话 object
26 var $session = null;
27
28 // 程序配置
29 var $config = array();
30
31 // $_G 数组的映射
32 var $var = array();
33
34 // 加载缓存的数组
35 var $cachelist = array();
36
37 // 是否初始化
38 var $init_setting = true; //设置
39 var $init_user = true; //用户
40 var $init_session = true; //会话
41 var $init_cron = true; //任务计划
42 var $init_misc = true; //其他功能
43 var $init_memory = true; //内存
44
45 // 是否已经初始化
46 var $initated = false;
47
48 var $superglobal = array(
49 'GLOBALS' => 1,
50 '_GET' => 1,
51 '_POST' => 1,
52 '_REQUEST' => 1,
53 '_COOKIE' => 1,
54 '_SERVER' => 1,
55 '_ENV' => 1,
56 '_FILES' => 1,
57 );
58
59 function &instance() {
60 static $object;
61 if(empty($object)) {
62 $object = new discuz_core();
63 }
64 return $object;
65 }
66
67 function discuz_core() {
68 $this->_init_env();
69 $this->_init_config();
70 $this->_init_input();
71 $this->_init_output();
72 }
73
74 function init() {
75 if(!$this->initated) {
76 $this->_init_db();
77 $this->_init_memory();
78 $this->_init_user();
79 $this->_init_session();
80 $this->_init_setting();
81 $this->_init_cron();
82 $this->_init_misc();
83 }
84 $this->initated = true;
85 }
86
87 function _init_env() {
88
89 error_reporting(E_ALL ^ E_NOTICE);
90 //error_reporting(E_ALL);
91
92 ///php 5.3前则关闭魔法引号匹配(自动转义)
93 if(phpversion() < '5.3.0') {
94 set_magic_quotes_runtime(0);
95 }
96
97 ///程序主目录,根据核心文件确定,原来是-7 代表在include下,现在是12代表在source/class下
98 define('DISCUZ_ROOT', substr(dirname(__FILE__), 0, -12));
99
100 ///和dz72一样,设置魔法引用(自动转义,单双引号反斜线)
101 define('MAGIC_QUOTES_GPC', function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc());
102
103 ///判断字符编码转换函数是否存在
104 define('ICONV_ENABLE', function_exists('iconv'));
105 ///亚洲字符转码函数是否存在, 因为mb_开头字符处理亚洲字符会比较高效,初步判断用于转码时先用mb_来处理:
106 define('MB_ENABLE', function_exists('mb_convert_encoding'));
107 ///是否存在输出缓存压缩函数,这个函数的目的,是在确认浏览器支持页面压缩后,才用该函数来压缩所有输出内容,否则直接传输
108 define('EXT_OBGZIP', function_exists('ob_gzhandler'));
109
110 ///和DZ72一样,不过当前时间戳被定义为一个常量,效率更高吧,也不用global了。
111 define('TIMESTAMP', time());
112 ///获取默认时区
113 discuz_core::timezone_set();
114
115 ///加载function_core.php,作用推测类似global.func.php
116 if(!defined('DISCUZ_CORE_FUNCTION') && !@include(DISCUZ_ROOT.'./source/function/function_core.php')) {
117 $this->error('function_core.php is missing');
118 }
119
120 //判断浏览器是否是蜘蛛
121 define('IS_ROBOT', checkrobot());
122
123 //清理全局变量
124 ///全清理了,真是彻底把所有变量都从内存中注销了
125 foreach ($GLOBALS as $key => $value) {
126 if (!isset($this->superglobal[$key])) {
127 $GLOBALS[$key] = null; unset($GLOBALS[$key]);
128 }
129 }
130
131 // 配置全局变量
132 ///和上一步结合,只留下自己需要的变量,并初始化。
133 ///这么做够狠,只要稍微小心点,就不会出现因为变量未初始化而出现的安全问题
134 global $_G;
135 $_G = array(
136 //公用全局定义
137 'uid' => 0,
138 'username' => '',
139 'adminid' => 0,
140 'groupid' => 1,
141 'sid' => '',
142 'formhash' => '',
143 'timestamp' => TIMESTAMP,
144 'starttime' => dmicrotime(),
145 'clientip' => $this->_get_client_ip(),
146 'referer' => '',
147 'charset' => '',
148 'gzipcompress' => '',
149 'authkey' => '',
150 'timenow' => array(),
151
152 'PHP_SELF' => '',
153 'siteurl' => '',
154
155 //公用全局数组定义
156 'config' => array(),
157 'setting' => array(),
158 'member' => array(),
159 'group' => array(),
160 'cookie' => array(),
161 'style' => array(),
162 'cache' => array(),
163 'session' => array(),
164 'lang' => array(),
165 'my_app' => array(),//默认应用
166 'my_userapp' => array(),//用户自添加应用
167
168 //论坛全局定义
169 'fid' => 0,
170 'tid' => 0,
171 'forum' => array(),
172 'rssauth' => '',
173
174 //uch 全局定义
175 'home' => array(),
176 'space' => array(),
177
178 //portal 全局定义
179 'block' => array(),
180 'article' => array(),
181
182 //Action
183 'action' => array(
184 'action' => APPTYPEID,
185 'fid' => 0,
186 'tid' => 0,
187 )
188 );
189 //相对主目录的相对地址及文件名
190 $_G['PHP_SELF'] = htmlspecialchars($_SERVER['PHP_SELF'] ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']);
191 //基本脚本名,每个功能脚本首页前都会定义
192 //比如forum.php,则定义CURSCRIPT为forum,而forum_forumdisplay.php则不定义,因为属于forum
193 $_G['basescript'] = CURSCRIPT;
194 //站点网址
195 $_G['siteurl'] = htmlspecialchars('http://'.$_SERVER['HTTP_HOST'].preg_replace("/\/+(api)?\/*$/i", '', substr($_G['PHP_SELF'], 0, strrpos($_G['PHP_SELF'], '/'))).'/');
196
197 ///$_G的映射,也即超级全局变量
198 $this->var = & $_G;
199
200 }
201
202 function _init_input() {
203
204 //注意 禁止对全局变量注入
205 ///禁止GLOBALS=xxx的方式注入
206 if (isset($_REQUEST['GLOBALS']) || isset($_FILES['GLOBALS'])) {
207 error('request_tainting');
208 }
209
210 if(!empty($_GET['rewrite'])) {
211 $query_string = '?mod=';
212 $param = explode('-', $_GET['rewrite']);
213 $query_string .= $_GET['mod'] = $param;
214 array_shift($param);
215 $paramc = count($param);
216 for($i = 0;$i < $paramc;$i+=2) {
217 $_REQUEST[$param[$i]] = $_GET[$param[$i]] = $param[$i + 1];
218 $query_string .= '&'.$param[$i].'='.$param[$i + 1];
219 }
220 $_SERVER['QUERY_STRING'] = $query_string;
221 unset($param, $paramc, $query_string);
222 }
223
224 // slashes 处理,如果没有魔法引号处理(自动转义),则手动转义GET/POST/COOKIE/FILES中的单双引号、null反斜线\
225 if(!MAGIC_QUOTES_GPC) {
226 $_GET = daddslashes($_GET);
227 $_POST = daddslashes($_POST);
228 $_COOKIE = daddslashes($_COOKIE);
229 $_FILES = daddslashes($_FILES);
230 }
231
232 //cookie 处理
233 ///验证cookie前缀与config中的设置值是否一致,一致则转为$cookie数组中的值
234 $prelength = strlen($this->config['cookie']['cookiepre']);
235 foreach($_COOKIE as $key => $val) {
236 if(substr($key, 0, $prelength) == $this->config['cookie']['cookiepre']) {
237 $this->var['cookie'] = $val;
238 }
239 }
240
241 $_GET['diy'] = empty($_GET['diy']) ? '' : $_GET['diy'];
242
243 ///$_GET和$_POST转成与索引同名加"gp_"前缀的变量
244 ///如$_GET['username']直接用$gp_username来访问
245 foreach(array_merge($_POST, $_GET) as $k => $v) {
246 $this->var['gp_'.$k] = $v;
247 }
248
249 ///根据$_GET['mod']来确定m的值,$this->var为全局数组,gp_为上个语句的附加前缀
250 $this->var['mod'] = empty($this->var['gp_mod']) ? '' : htmlspecialchars($this->var['gp_mod']);
251 ///如果使用ajax,再判断是post传值或get和xmlhttprequest同时有效
252 $this->var['inajax'] = empty($this->var['gp_inajax']) ? 0 : ($_SERVER['REQUEST_METHOD'] == 'GET' && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest' || $_SERVER['REQUEST_METHOD'] == 'POST' ? 1 : 0);
253 ///当前页码
254 $this->var['page'] = empty($this->var['gp_page']) ? 1 : max(1, intval($this->var['gp_page']));
255 ///确定cookie中的sid值
256 $this->var['sid'] = $this->var['cookie']['sid'] = isset($this->var['cookie']['sid']) ? htmlspecialchars($this->var['cookie']['sid']) : '';
257 }
258
259 ///初始化设置
260 function _init_config() {
261 ///加载设置文件
262 $_config = array();
263 @include DISCUZ_ROOT.'./config/config_global.php';
264 if(empty($_config)) {
265 error('config_notfound');
266 }
267 ///确定密钥,如果值为空,则密钥默认为cookie前缀与数据库名拼接的md5值,否则为配置文件中的值
268 ///authkey密钥是sid等参数加解密的重要参数
269 $_config['security']['authkey'] = empty($config['security']['authkey']) ? md5($_config['cookie']['cookiepre'].$_config['db']['dbname']) : ($config['security']['authkey']);
270
271 $this->config = & $_config;
272 ///Discuz的调试
273 if(empty($this->config['debug']) || !file_exists(libfile('function/debug'))) {
274 define('DISCUZ_DEBUG', false);
275 } elseif($this->config['debug'] === 1 || $this->config['debug'] === 2 || !empty($_REQUEST['debug']) && $_REQUEST['debug'] === $this->config['debug']) {
276 define('DISCUZ_DEBUG', true);
277 if($this->config['debug'] == 2) {
278 error_reporting(E_ALL);
279 }
280 }
281
282 $GLOBALS['_G']['config'] = & $this->config;
283 ///以浏览器版本为参考,进行密钥的二次md5加密
284 $GLOBALS['_G']['authkey'] = md5($this->config['security']['authkey'].$_SERVER['HTTP_USER_AGENT']);
285 }
286
287 function _init_output() {
288 ///如果设置中打开xss跨站脚本的防御模式,且网址中存在“<”和“"”等非法字符,则拒绝请求
289 if($this->config['security']['urlxssdefend'] && !empty($_SERVER['REQUEST_URI'])) {
290 $temp = urldecode($_SERVER['REQUEST_URI']);
291 if(strpos($temp, '<') !== false || strpos($temp, '"') !== false) {
292 error('request_tainting');
293 }
294 }
295
296 ///存在ob_gzhandler则启用输出缓存压缩
297 if($this->config['output']['gzip'] && EXT_OBGZIP) {
298 ob_start('ob_gzhandler');
299 setglobal('gzipcompress', true);
300 } else {
301 ob_start();
302 setglobal('gzipcompress', false);
303 }
304
305 ///确定HTML页面编码,及其他编码
306 if($this->config['output']['forceheader']) {
307 @header('Content-Type: text/html; charset='.$this->config['output']['charset']);
308 }
309
310 setglobal('charset', $this->config['output']['charset']);
311 define('CHARSET', $this->config['output']['charset']);
312 }
313
314 ///拒绝机器人访问
315 function reject_robot() {
316 if(IS_ROBOT) {
317 exit(header("HTTP/1.1 403 Forbidden"));
318 }
319 }
320
321 ///获取客户端ip,
322 function _get_client_ip() {
323 $clientip = '';
324 ///环境变量客户端ip有值且字符长度大于unknown,则说明该变量有效,确定为客户端ip
325 if(getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) {
326 $clientip = getenv('HTTP_CLIENT_IP');
327 ///否则取当前浏览用户的网关ip地址
328 } elseif(getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) {
329 $clientip = getenv('HTTP_X_FORWARDED_FOR');
330 ///用户计算机的ip地址
331 } elseif(getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) {
332 $clientip = getenv('REMOTE_ADDR');
333 } elseif(isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
334 $clientip = $_SERVER['REMOTE_ADDR'];
335 }
336
337 ///判断是否是数字与点组成的7-15位字符
338 preg_match("/[\d\.]{7,15}/", $clientip, $clientipmatches);
339 $clientip = $clientipmatches ? $clientipmatches : 'unknown';
340 return $clientip;
341 }
342
343 function _init_db() {
344 ///生成数据库对象
345 $this->db = & DB::object();
346 ///加载设置文件并连接数据库
347 $this->db->set_config($this->config['db']);
348 $this->db->connect();
349 }
350
351 function _init_session() {
352
353 $this->session = new discuz_session();
354
355 if($this->init_session)
356 {
357 ///传入sid,客户端ip与uid作为session判断机制,分新老用户,老用户则查session表,否则创建
358 $this->session->init($this->var['cookie']['sid'], $this->var['clientip'], $this->var['uid']);
359 $this->var['sid'] = $this->session->sid;
360 $this->var['session'] = $this->session->var;
361
362 if($this->var['sid'] != $this->var['cookie']['sid']) {
363 dsetcookie('sid', $this->var['sid'], 86400);
364 }
365
366 // 首次登陆更新最后访问时间,每隔 10 分钟更新用户最后动作时间
367 if($this->var['uid'] && ($this->session->isnew || ($this->session->get('lastactivity') + 600) < TIMESTAMP)) {
368
369 $this->session->set('lastactivity', TIMESTAMP);
370
371 $update = array('lastip' => $this->var['clientip'], 'lastactivity' => TIMESTAMP);
372 if($this->session->isnew) {
373 $update['lastvisit'] = TIMESTAMP;
374 }
375 更新会员状态
376 DB::update('common_member_status', $update, "uid='".$this->var['uid']."'");
377 }
378 }
379 }
380
381 function _init_user() {
382
383 if($this->init_user) {
384 if($auth = getglobal('auth', 'cookie')) {
385 $auth = daddslashes(explode("\t", authcode($auth, 'DECODE')));
386 }
387 list($discuz_pw, $discuz_uid) = empty($auth) || count($auth) < 2 ? array('', '') : $auth;
388
389 if($discuz_uid) {
390 $user = getuserbyuid($discuz_uid);
391 }
392
393 if(!empty($user) && $user['password'] == $discuz_pw) {
394 $this->var['member'] = $user;
395 } else {
396 $user = array();
397 $this->_init_guest();
398 }
399
400 $this->cachelist[] = 'usergroup_'.$this->var['member']['groupid'];
401 if($user && $user['adminid'] > 0 && $user['groupid'] != $user['adminid']) {
402 $this->cachelist[] = 'admingroup_'.$this->var['member']['adminid'];
403 }
404
405 } else {
406 $this->_init_guest();
407 }
408
409 if(empty($this->var['cookie']['lastvisit'])) {
410 $this->var['member']['lastvisit'] = TIMESTAMP - 3600;
411 dsetcookie('lastvisit', TIMESTAMP - 3600, 86400 * 30);
412 } else {
413 $this->var['member']['lastvisit'] = empty($this->var['cookie']['lastvisit']);
414 }
415
416 setglobal('uid', getglobal('uid', 'member'));
417 setglobal('username', addslashes(getglobal('username', 'member')));
418 setglobal('adminid', getglobal('adminid', 'member'));
419 setglobal('groupid', getglobal('groupid', 'member'));
420 }
421
422 function _init_guest() {
423 setglobal('member', array( 'uid' => 0, 'username' => '', 'groupid' => 7, 'credits' => 0, 'timeoffset' => 9999));
424 }
425
426 function _init_cron() {
427 if($this->init_cron && $this->init_setting) {
428 if($this->var['cache']['cronnextrun'] <= TIMESTAMP) {
429 discuz_cron::run();
430 }
431 }
432 }
433
434 function _init_misc() {
435
436 if(!$this->init_misc) {
437 return false;
438 }
439 // 调入核心语言包
440 lang('core');
441
442 //处理全局时区设置
443 if($this->init_setting && $this->init_user) {
444 if(!isset($this->var['member']['timeoffset']) || $this->var['member']['timeoffset'] == 9999 || $this->var['member']['timeoffset'] === '') {
445 $this->var['member']['timeoffset'] = $this->var['setting']['timeoffset'];
446 }
447 }
448
449 $timeoffset = $this->init_setting ? $this->var['member']['timeoffset'] : $this->var['setting']['timeoffset'];
450 $this->var['timenow'] = array(
451 'time' => dgmdate(TIMESTAMP),
452 'offset' => $timeoffset >= 0 ? ($timeoffset == 0 ? '' : '+'.$timeoffset) : $timeoffset
453 );
454 $this->timezone_set($timeoffset);
455
456 $this->var['formhash'] = formhash();
457 define('FORMHASH', $this->var['formhash']);
458
459 // 定义风格常量
460 if(is_array($this->var['style'])) {
461 foreach ($this->var['style'] as $key => $val) {
462 $key = strtoupper($key);
463 if(!defined($key) && !is_array($val)) {
464 define($key, $val);
465 }
466 }
467 }
468
469 //论坛开关检查
470 if($this->var['setting']['bbclosed'] && !(in_array($this->var['mod'], array('logging', 'seccode')) || getglobal('adminid', 'member') == 1)) {
471 $closedreason = DB::result_first("SELECT svalue FROM ".DB::table('common_setting')." WHERE skey='closedreason'");
472 showmessage($closedreason ? $closedreason : 'board_closed', NULL, array(), array('login' => 1));
473 }
474
475 $this->var['tpp'] = $this->var['setting']['topicperpage'] ? intval($this->var['setting']['topicperpage']) : 20;
476 $this->var['ppp'] = $this->var['setting']['postperpage'] ? intval($this->var['setting']['postperpage']) : 10;
477
478 if($this->var['setting']['nocacheheaders']) {
479 @header("Expires: -1");
480 @header("Cache-Control: no-store, private, post-check=0, pre-check=0, max-age=0", FALSE);
481 @header(";Pragma: no-cache");
482 }
483
484 $lastact = TIMESTAMP."\t".htmlspecialchars(basename($this->var['PHP_SELF']))."\t".htmlspecialchars($this->var['mod']);
485 dsetcookie('lastact', $lastact, 86400);
486
487 }
488
489 function _init_setting() {
490
491 if($this->init_setting) {
492
493 if(empty($this->var['setting'])) {
494 $this->cachelist[] = 'setting';
495 }
496
497 if(empty($this->var['style'])) {
498 $this->cachelist[] = 'style_default';
499 }
500
501 if(!isset($this->var['cache']['cronnextrun'])) {
502 $this->cachelist[] = 'cronnextrun';
503 }
504 }
505
506 !empty($this->cachelist) && loadcache($this->cachelist);
507
508 if(!is_array($this->var['setting'])) {
509 $this->var['setting'] = array();
510 }
511 if($this->var['member'] && $this->var['member']['adminid'] > 0 && $this->var['member']['groupid'] != $this->var['member']['adminid'] && !empty($this->var['cache']['admingroup_'.$this->var['member']['adminid']])) {
512 $this->var['group'] = array_merge($this->var['group'], $this->var['cache']['admingroup_'.$this->var['member']['adminid']]);
513 }
514 }
515
516 function _init_memory() {
517 $this->mem = new discuz_memory();
518 if($this->init_memory) {
519 $this->mem->init($this->config['memory']);
520 }
521 $this->var['memory'] = $this->mem->type;
522 }
523
524 function timezone_set($timeoffset = 0) {
525 if(function_exists('date_default_timezone_set')) {
526 @date_default_timezone_set('Etc/GMT'.($timeoffset > 0 ? '-' : '+').(abs($timeoffset)));
527 }
528 }
529
530 function error($msg, $halt = true) {
531 $this->error_log($msg);
532 echo $msg;
533 $halt && exit();
534 }
535
536 function error_log($message) {
537 $time = date("Y-m-d H:i:s", TIMESTAMP);
538 $file =DISCUZ_ROOT.'./data/log/errorlog_'.date("Ym").'.txt';
539 $message = "\n#{$time}:\t".str_replace(array("\t", "\r", "\n"), " ", $message);
540 error_log($message, 3, $file);
541 }
542
543 }
544
545 /**
546* Discuz MySQL 类的支持
547*
548*/
549 class db_mysql
550 {
551 var $tablepre;
552 var $version = '';
553 var $querynum = 0;
554 var $curlink;
555 var $link = array();
556 var $config = array();
557 var $sqldebug = array();
558
559 function db_mysql($config = array()) {
560 if(!empty($config)) {
561 $this->set_config($config);
562 }
563 }
564
565 function set_config($config) {
566 $this->config = &$config;
567 $this->tablepre = $config['1']['tablepre'];
568 }
569
570 function connect() {
571
572 if(empty($this->config) || empty($this->config)) {
573 $this->halt('notfound_config');
574 }
575
576 foreach ($this->config as $id => $config) {
577 $this->link[$id] = $this->_dbconnect(
578 $config['dbhost'],
579 $config['dbuser'],
580 $config['dbpw'],
581 $config['dbcharset'],
582 $config['dbname'],
583 $config['pconnect']
584 );
585 }
586 $this->curlink = $this->link;
587 }
588
589 function _dbconnect($dbhost, $dbuser, $dbpw, $dbcharset, $dbname, $pconnect) {
590 $link = null;
591 $func = empty($pconnect) ? 'mysql_connect' : 'mysql_pconnect';
592 if(!$link = @$func($dbhost, $dbuser, $dbpw, 1)) {
593 $this->halt('notconnect');
594 } else {
595 $this->curlink = $link;
596 if($this->version() > '4.1') {
597 $serverset = $dbcharset ? 'character_set_connection='.$dbcharset.', character_set_results='.$dbcharset.', character_set_client=binary' : '';
598 $serverset .= $this->version() > '5.0.1' ? ((empty($serverset) ? '' : ',').'sql_mode=\'\'') : '';
599 $serverset && mysql_query("SET $serverset", $link);
600 }
601 $dbname && @mysql_select_db($dbname, $link);
602 }
603 return $link;
604 }
605
606 function table_name($tablename) {
607 return $this->tablepre.$tablename;
608 }
609
610 function select_db($dbname) {
611 return mysql_select_db($dbname, $this->curlink);
612 }
613
614 function fetch_array($query, $result_type = MYSQL_ASSOC) {
615 return mysql_fetch_array($query, $result_type);
616 }
617
618 function fetch_first($sql) {
619 return $this->fetch_array($this->query($sql));
620 }
621
622 function result_first($sql) {
623 return $this->result($this->query($sql), 0);
624 }
625
626 function query($sql, $type = '') {
627
628 if(defined('DISCUZ_DEBUG') && DISCUZ_DEBUG) {
629 $starttime = dmicrotime();
630 }
631 $func = $type == 'UNBUFFERED' && @function_exists('mysql_unbuffered_query') ?
632 'mysql_unbuffered_query' : 'mysql_query';
633 if(!($query = $func($sql, $this->curlink))) {
634 if(in_array($this->errno(), array(2006, 2013)) && substr($type, 0, 5) != 'RETRY') {
635 $this->connect();
636 return $this->query($sql, 'RETRY'.$type);
637 }
638 if($type != 'SILENT' && substr($type, 5) != 'SILENT') {
639 $this->halt('query_error', $sql);
640 }
641 }
642
643 if(defined('DISCUZ_DEBUG') && DISCUZ_DEBUG) {
644 $this->sqldebug[] = array($sql, number_format((dmicrotime() - $starttime), 6), debug_backtrace());
645 }
646
647 $this->querynum++;
648 return $query;
649 }
650
651 function affected_rows() {
652 return mysql_affected_rows($this->curlink);
653 }
654
655 function error() {
656 return (($this->curlink) ? mysql_error($this->curlink) : mysql_error());
657 }
658
659 function errno() {
660 return intval(($this->curlink) ? mysql_errno($this->curlink) : mysql_errno());
661 }
662
663 function result($query, $row = 0) {
664 $query = @mysql_result($query, $row);
665 return $query;
666 }
667
668 function num_rows($query) {
669 $query = mysql_num_rows($query);
670 return $query;
671 }
672
673 function num_fields($query) {
674 return mysql_num_fields($query);
675 }
676
677 function free_result($query) {
678 return mysql_free_result($query);
679 }
680
681 function insert_id() {
682 return ($id = mysql_insert_id($this->curlink)) >= 0 ? $id : $this->result($this->query("SELECT last_insert_id()"), 0);
683 }
684
685 function fetch_row($query) {
686 $query = mysql_fetch_row($query);
687 return $query;
688 }
689
690 function fetch_fields($query) {
691 return mysql_fetch_field($query);
692 }
693
694 function version() {
695 if(empty($this->version)) {
696 $this->version = mysql_get_server_info($this->curlink);
697 }
698 return $this->version;
699 }
700
701 function close() {
702 return mysql_close($this->curlink);
703 }
704
705 function halt($message = '', $sql = '') {
706 global $_G;
707 $dberror = $this->error();
708 $dberrno = $this->errno();
709 $phperror = '<table style="font-size:11px" cellpadding="0"><tr><td width="270">File</td><td width="80">Line</td><td>Function</td></tr>';
710 foreach (debug_backtrace() as $error) {
711 $error['file'] = str_replace(DISCUZ_ROOT, '', $error['file']);
712 $error['class'] = isset($error['class']) ? $error['class'] : '';
713 $error['type'] = isset($error['type']) ? $error['type'] : '';
714 $error['function'] = isset($error['function']) ? $error['function'] : '';
715 $phperror .= "<tr><td>$error</td><td>$error</td><td>$error$error$error()</td></tr>";
716 }
717 $phperror .= '</table>';
718 $helplink = "http://faq.comsenz.com/?type=mysql&dberrno=".rawurlencode($dberrno)."&dberror=".rawurlencode($dberror);
719 @header('Content-Type: text/html; charset='.$_G['config']['output']['charset']);
720 echo '<div style="position:absolute;font-size:11px;font-family:verdana,arial;background:#EBEBEB;padding:0.5em;line-height:1.5em">'.
721 error('db_error', array(
722 '$message' => error('db_'.$message, array(), true),
723 '$info' => $dberror ? error('db_error_message', array('$dberror' => $dberror), true) : '',
724 '$sql' => $sql ? error('db_error_sql', array('$sql' => $sql), true) : '',
725 '$errorno' => $dberrno ? error('db_error_no', array('$dberrno' => $dberrno), true) : '',
726 '$helplink' => $helplink,
727 ), true);
728 echo "<b>;PHP Backtrace</b><br />$phperror<br /></div>";
729 exit();
730 }
731
732 }
733
734 /**
735* 对Discuz CORE 中 DB Object中的主要方法进行二次封装,方便程序调用
736*
737*/
738 class DB
739 {
740
741 /**
742 * 返回表名(pre_$table)
743 *
744 * @param 原始表名 $table
745 * @return 增加pre之后的名字
746 */
747 function table($table) {
748 $a = & DB::object();
749 return $a->table_name($table);
750 }
751
752 /**
753 * 删除一条或者多条记录
754 *
755 * @param string $table 原始表名
756 * @param string $condition 条件语句,不需要写WHERE
757 * @param int $limit 删除条目数
758 * @param boolean $unbuffered 立即返回?
759 */
760 function delete($table, $condition, $limit = 0, $unbuffered = true) {
761 if(empty($condition)) {
762 $where = '1';
763 } elseif(is_array($condition)) {
764 $where = DB::implode_field_value($condition, ' AND ');
765 } else {
766 $where = $condition;
767 }
768 $sql = "DELETE FROM ".DB::table($table)." WHERE $where ".($limit ? "LIMIT $limit" : '');
769 return DB::query($sql, ($unbuffered ? 'UNBUFFERED' : ''));
770 }
771
772 /**
773 * 插入一条记录
774 *
775 * @param string $table 原始表名
776 * @param array $data 数组field->vlaue 对
777 * @param boolen $return_insert_id 返回 InsertID?
778 * @param boolen $replace 是否是REPLACE模式
779 * @param boolen $silent 屏蔽错误?
780 * @return InsertID or Result
781 */
782 function insert($table, $data, $return_insert_id = false, $replace = false, $silent = false) {
783
784 $sql = DB::implode_field_value($data);
785
786 $cmd = $replace ? 'REPLACE INTO' : 'INSERT INTO';
787
788 $table = DB::table($table);
789 $silent = $silent ? 'SILENT' : '';
790
791 $return = DB::query("$cmd $table SET $sql", $silent);
792
793 return $return_insert_id ? DB::insert_id() : $return;
794
795 }
796
797 /**
798 * 更新一条或者多条数据记录
799 *
800 * @param string $table 原始表名
801 * @param array $data 数据field-value
802 * @param string $condition 条件语句,不需要写WHERE
803 * @param boolean $unbuffered 迅速返回?
804 * @param boolan $low_priority 延迟更新?
805 * @return result
806 */
807 function update($table, $data, $condition, $unbuffered = false, $low_priority = false) {
808 $sql = DB::implode_field_value($data);
809 $cmd = "UPDATE ".($low_priority ? 'LOW_PRIORITY' : '');
810 $table = DB::table($table);
811 $where = $comma = '';
812 if(empty($condition)) {
813 $where = '1';
814 } elseif(is_array($condition)) {
815 $where = DB::implode_field_value($condition, ' AND ');
816 } else {
817 $where = $condition;
818 }
819 $res = DB::query("$cmd $table SET $sql WHERE $where", $unbuffered ? 'UNBUFFERED' : '');
820 return $res;
821 }
822
823 /**
824 * 格式化field字段和value,并组成一个字符串
825 *
826 * @param array $array 格式为 key=>value 数组
827 * @param 分割符 $glue
828 * @return string
829 */
830 function implode_field_value($array, $glue = ',') {
831 //print_r(debug_backtrace());
832 $sql = $comma = '';
833 foreach ($array as $k => $v) {
834 $sql .= $comma."`$k`='$v'";
835 $comma = $glue;
836 }
837 return $sql;
838 }
839
840 /**
841 * 返回插入的ID
842 *
843 * @return int
844 */
845 function insert_id() {
846 $db = & DB::object();
847 return $db->insert_id();
848 }
849
850 /**
851 * 依据查询结果,返回一行数据
852 *
853 * @param resourceID $resourceid
854 * @return array
855 */
856 function fetch($resourceid) {
857 $db = & DB::object();
858 return $db->fetch_array($resourceid);
859 }
860
861 /**
862 * 依据SQL文,返回一条查询结果
863 *
864 * @param string $query 查询语句
865 * @return array
866 */
867 function fetch_first($sql) {
868 $db = & DB::object();
869 return $db->fetch_first($sql);
870 }
871
872 /**
873 * 依据查询结果,返回结果数值
874 *
875 * @param resourceid $resourceid
876 * @return string or int
877 */
878 function result($resourceid, $row = 0) {
879 $db = & DB::object();
880 return $db->result($resourceid, $row);
881 }
882
883 /**
884 * 依据查询语句,返回结果数值
885 *
886 * @param string $query SQL查询语句
887 * @return unknown
888 */
889 function result_first($sql) {
890 $db = & DB::object();
891 return $db->result_first($sql);
892 }
893
894 /**
895 * 执行查询
896 *
897 * @param string $sql
898 * @param 类型定义 $type UNBUFFERED OR SILENT
899 * @return Resource OR Result
900 */
901 function query($sql, $type = '') {
902 $db = & DB::object();
903 return $db->query($sql, $type);
904 }
905
906 /**
907 * 返回select的结果行数
908 *
909 * @param resource $resourceid
910 * @return int
911 */
912 function num_rows($resourceid) {
913 $db = & DB::object();
914 return $db->num_rows($resourceid);
915 }
916
917 /**
918 * 返回sql语句所影响的记录行数
919 *
920 * @return int
921 */
922 function affected_rows() {
923 $db = & DB::object();
924 return $db->affected_rows();
925 }
926
927 function free_result($query) {
928 $db = & DB::object();
929 return $db->free_result($query);
930 }
931
932 function error() {
933 $db = & DB::object();
934 return $db->error();
935 }
936
937 function errno() {
938 $db = & DB::object();
939 return $db->errno();
940 }
941
942 /**
943 * 返回 DB object 指针
944 *
945 * @return pointer of db object from discuz core
946 */
947 function &object() {
948 static $db;
949 if(empty($db)) {
950 $db = new db_mysql();
951 }
952 return $db;
953 }
954 }
955
956 class discuz_session {
957
958 ///sid,ip1-4, uid, username, groupid组id, invisible隐身与否,action行为,上次活动lastactivity,fid板块id,tid帖子id
959 var $sid = null;
960 var $var;
961 var $isnew = false;
962 var $newguest = array('sid' => 0, 'ip1' => 0, 'ip2' => 0, 'ip3' => 0, 'ip4' => 0,
963 'uid' => 0, 'username' => '', 'groupid' => 7, 'invisible' => 0, 'action' => 0,
964 'lastactivity' => 0, 'fid' => 0, 'tid' => 0);
965
966 var $old =array('sid' =>'', 'ip' =>'', 'uid' =>0);
967
968 ///与类同名的函数,构造函数,初始化session各值
969 function discuz_session($sid = '', $ip = '', $uid = 0) {
970 $this->old = array('sid' =>$sid, 'ip' =>$ip, 'uid' =>$uid);
971 $this->var = $this->newguest;
972 if(!empty($ip)) {
973 $this->init($sid, $ip, $uid);
974 }
975 }
976 ///设置$newguest各项值
977 function set($key, $value) {
978 if(isset($this->newguest[$key])) {
979 $this->var[$key] = $value;
980 } elseif ($key == 'ip') {
981 $ips = explode('.', $value);
982 $this->set('ip1', $ips);
983 $this->set('ip2', $ips);
984 $this->set('ip3', $ips);
985 $this->set('ip4', $ips);
986 }
987 }
988
989 ///获取
990 function get($key) {
991 if(isset($this->newguest[$key])) {
992 return $this->var[$key];
993 } elseif ($key == 'ip') {
994 return $this->get('ip1').'.'.$this->get('ip2').'.'.$this->get('ip3').'.'.$this->get('ip4');
995 }
996 }
997
998 ///初始化,sid有值则可能是老用户,去读session表,判断sid,ip符合的值是否存在,存在则赋值给$sid
999 function init($sid, $ip, $uid) {
1000 $this->old = array('sid' =>$sid, 'ip' =>$ip, 'uid' =>$uid);
1001 $session = array();
1002 if($sid) {
1003 $session = DB::fetch_first("SELECT * FROM ".DB::table('common_session').
1004 " WHERE sid='$sid' AND CONCAT_WS('.', ip1,ip2,ip3,ip4)='$ip'");
1005 }
1006
1007 if(empty($session) || $session['uid'] != $uid) {
1008 $session = $this->create($ip, $uid);
1009 }
1010
1011 $this->var = $session;
1012 $this->sid = $session['sid'];
1013 }
1014
1015 ///新用户
1016 function create($ip, $uid) {
1017
1018 $this->isnew = true;
1019 $this->var = $this->newguest;
1020 $this->set('sid', random(6));
1021 $this->set('uid', $uid);
1022 $this->set('ip', $ip);
1023 $this->set('lastactivity', time());
1024 $this->sid = $this->var['sid'];
1025
1026 return $this->var;
1027 }
1028
1029 function delete() {
1030
1031 $onlinehold = 1800; //此数值应当取自全局变量
1032 $guestspan = 60; //避免游客重复激活sid
1033
1034 $onlinehold = time() - $onlinehold;
1035 $guestspan = time() - $guestspan;
1036
1037 //当前用户的sid
1038 $condition = " sid='{$this->sid}' ";
1039 //过期的 session
1040 $condition .= " OR lastactivity<$onlinehold ";
1041 //频繁的同一ip游客
1042 $condition .= " OR (uid='0' AND ip1='{$this->var['ip1']}' AND ip2='{$this->var['ip2']}' AND ip3='{$this->var['ip3']}' AND ip4='{$this->var['ip4']}' AND lastactivity>$guestspan) ";
1043 //当前用户的uid
1044 $condition .= $this->var['uid'] ? " OR (uid='{$this->var['uid']}') " : '';
1045 DB::delete('common_session', $condition);
1046 }
1047
1048 function update() {
1049 if($this->sid !== null) {
1050
1051 $data = daddslashes($this->var);
1052
1053 if($this->isnew) {
1054 $this->delete();
1055 DB::insert('common_session', $data, false, false, true);
1056 } else {
1057 DB::update('common_session', $data, "sid='$data'");
1058 }
1059 dsetcookie('sid', $this->sid, 86400);
1060 }
1061 }
1062
1063 /**
1064 * 取在线用户数量
1065 *
1066 * @param int $type 0=全部 1=会员 2=游客
1067 */
1068 function onlinecount($type = 0) {
1069 $condition = $type == 1 ? ' WHERE uid>0 ' : ($type == 2 ? ' WHERE invisible=1 ' : '');
1070 return DB::result_first("SELECT count(*) FROM ".DB::table('common_session').$condition);
1071 }
1072
1073 }
1074
1075 class discuz_cron
1076 {
1077
1078 /**
1079 * 运行cron
1080 *
1081 * @param int $cronid 执行某个cron,如果不指定则运行当前需要运行的
1082 * @return true
1083 */
1084 function run($cronid = 0) {
1085
1086 $timestamp = TIMESTAMP;
1087 $cron = DB::fetch_first("SELECT * FROM ".DB::table('common_cron')."
1088 WHERE ".($cronid ? "cronid='$cronid'" : "available>'0' AND nextrun<='$timestamp'")."
1089 ORDER BY nextrun LIMIT 1");
1090
1091 $processname ='DZ_CRON_'.(empty($cron) ? 'CHECKER' : $cron['cronid']);
1092
1093 if(!discuz_process::create($processname, 600)) {
1094 return false;
1095 }
1096
1097 if($cron) {
1098
1099 $cron['filename'] = str_replace(array('..', '/', '\\'), '', $cron['filename']);
1100 $cronfile = DISCUZ_ROOT.'./source/include/cron/'.$cron['filename'];
1101
1102 $cron['minute'] = explode("\t", $cron['minute']);
1103 discuz_cron::setnextime($cron);
1104
1105 @set_time_limit(1000);
1106 @ignore_user_abort(TRUE);
1107
1108 if(!@include $cronfile) {
1109 //debug('CRON', $cron['name'].' : Cron script('.$cron['filename'].') not found or syntax error', 0);
1110 }
1111 }
1112
1113 discuz_cron::nextcron();
1114 discuz_process::delete($processname);
1115 return true;
1116 }
1117
1118 /**
1119 * 设定下一个计划任务将要执行的时间 here...
1120 *
1121 */
1122 function nextcron() {
1123 $nextrun = DB::result_first("SELECT nextrun FROM ".DB::table('common_cron')." WHERE available>'0' ORDER BY nextrun LIMIT 1");
1124 if($nextrun !== FALSE) {
1125 save_syscache('cronnextrun', $nextrun);
1126 } else {
1127 save_syscache('cronnextrun', TIMESTAMP + 86400 * 365);
1128 }
1129 return true;
1130 }
1131
1132 /**
1133 * 设定某个计划任务下次执行时间
1134 *
1135 * @param array $cron
1136 * @return true
1137 */
1138 function setnextime($cron) {
1139
1140 global $_G;
1141
1142 if(empty($cron)) return FALSE;
1143
1144 list($yearnow, $monthnow, $daynow, $weekdaynow, $hournow, $minutenow) = explode('-', gmdate('Y-m-d-w-H-i', TIMESTAMP + $_G['setting']['timeoffset'] * 3600));
1145
1146 if($cron['weekday'] == -1) {
1147 if($cron['day'] == -1) {
1148 $firstday = $daynow;
1149 $secondday = $daynow + 1;
1150 } else {
1151 $firstday = $cron['day'];
1152 $secondday = $cron['day'] + gmdate('t', TIMESTAMP + $_G['setting']['timeoffset'] * 3600);
1153 }
1154 } else {
1155 $firstday = $daynow + ($cron['weekday'] - $weekdaynow);
1156 $secondday = $firstday + 7;
1157 }
1158
1159 if($firstday < $daynow) {
1160 $firstday = $secondday;
1161 }
1162
1163 if($firstday == $daynow) {
1164 $todaytime = discuz_cron::todaynextrun($cron);
1165 if($todaytime['hour'] == -1 && $todaytime['minute'] == -1) {
1166 $cron['day'] = $secondday;
1167 $nexttime = discuz_cron::todaynextrun($cron, 0, -1);
1168 $cron['hour'] = $nexttime['hour'];
1169 $cron['minute'] = $nexttime['minute'];
1170 } else {
1171 $cron['day'] = $firstday;
1172 $cron['hour'] = $todaytime['hour'];
1173 $cron['minute'] = $todaytime['minute'];
1174 }
1175 } else {
1176 $cron['day'] = $firstday;
1177 $nexttime = discuz_cron::todaynextrun($cron, 0, -1);
1178 $cron['hour'] = $nexttime['hour'];
1179 $cron['minute'] = $nexttime['minute'];
1180 }
1181
1182 $nextrun = @gmmktime($cron['hour'], $cron['minute'] > 0 ? $cron['minute'] : 0, 0, $monthnow, $cron['day'], $yearnow) - $_G['setting']['timeoffset'] * 3600;
1183
1184 $availableadd = $nextrun > TIMESTAMP ? '' : ', available=\'0\'';
1185 DB::query("UPDATE ".DB::table('common_cron')." SET lastrun='$_G', nextrun='$nextrun' $availableadd WHERE cronid='$cron'");
1186
1187 return true;
1188 }
1189
1190 /**
1191 * 计算计划任务今日执行状态
1192 *
1193 * @param int $cron
1194 * @param int $hour
1195 * @param int $minute
1196 * @return int
1197 */
1198 function todaynextrun($cron, $hour = -2, $minute = -2) {
1199 global $_G;
1200
1201 $hour = $hour == -2 ? gmdate('H', TIMESTAMP + $_G['setting']['timeoffset'] * 3600) : $hour;
1202 $minute = $minute == -2 ? gmdate('i', TIMESTAMP + $_G['setting']['timeoffset'] * 3600) : $minute;
1203
1204 $nexttime = array();
1205 if($cron['hour'] == -1 && !$cron['minute']) {
1206 $nexttime['hour'] = $hour;
1207 $nexttime['minute'] = $minute + 1;
1208 } elseif($cron['hour'] == -1 && $cron['minute'] != '') {
1209 $nexttime['hour'] = $hour;
1210 if(($nextminute = discuz_cron::nextminute($cron['minute'], $minute)) === false) {
1211 ++$nexttime['hour'];
1212 $nextminute = $cron['minute'];
1213 }
1214 $nexttime['minute'] = $nextminute;
1215 } elseif($cron['hour'] != -1 && $cron['minute'] == '') {
1216 if($cron['hour'] < $hour) {
1217 $nexttime['hour'] = $nexttime['minute'] = -1;
1218 } elseif($cron['hour'] == $hour) {
1219 $nexttime['hour'] = $cron['hour'];
1220 $nexttime['minute'] = $minute + 1;
1221 } else {
1222 $nexttime['hour'] = $cron['hour'];
1223 $nexttime['minute'] = 0;
1224 }
1225 } elseif($cron['hour'] != -1 && $cron['minute'] != '') {
1226 $nextminute = discuz_cron::nextminute($cron['minute'], $minute);
1227 if($cron['hour'] < $hour || ($cron['hour'] == $hour && $nextminute === false)) {
1228 $nexttime['hour'] = -1;
1229 $nexttime['minute'] = -1;
1230 } else {
1231 $nexttime['hour'] = $cron['hour'];
1232 $nexttime['minute'] = $nextminute;
1233 }
1234 }
1235
1236 return $nexttime;
1237 }
1238
1239 /**
1240 * 计算计划任务执行时刻
1241 *
1242 * @param int $nextminutes
1243 * @param int $minutenow
1244 * @return int
1245 */
1246 function nextminute($nextminutes, $minutenow) {
1247 foreach($nextminutes as $nextminute) {
1248 if($nextminute > $minutenow) {
1249 return $nextminute;
1250 }
1251 }
1252 return false;
1253 }
1254 }
1255
1256 /**
1257* 功能进程管理
1258* 通常用于某些功能禁止?⒎⒃诵?
1259*
1260*/
1261
1262 class discuz_process
1263 {
1264
1265 /**
1266 * 获取某进程信息
1267 *
1268 * @param string $name 进程名字
1269 * @return array
1270 */
1271 function get($name) {
1272 $name5 = md5($name);
1273 $res = DB::fetch_first("SELECT * FROM ".DB::table('common_process')." WHERE processid='$name5'");
1274
1275 if(empty($res)) {
1276 $res = array();
1277 } elseif($res['expiry'] < TIMESTAMP) {
1278 discuz_process::delete($name);
1279 $res = array();
1280 }
1281 return $res;
1282 }
1283
1284 /**
1285 * 创建进程
1286 *
1287 * @param string $name 进程名
1288 * @param int $lifespan 进程过期时间
1289 * @param int $extra 进程附属信息
1290 * @return boolean
1291 */
1292 function create($name, $lifespan = 0, $extra = 0) {
1293 $check = discuz_process::get($name);
1294 if(empty($check)) {
1295 $lifespan = empty($lifespan) ? 600 : $lifespan;
1296 DB::insert('common_process', array(
1297 'processid' => md5($name),
1298 'expiry' => TIMESTAMP + $lifespan,
1299 'extra' =>$extra), false, true);
1300 return true;
1301 }
1302 else {
1303 return false;
1304 }
1305 }
1306
1307 /**
1308 * 删除某个进程或过期进程
1309 *
1310 * @param string $name 进程名
1311 */
1312 function delete($name = '') {
1313 $name = md5($name);
1314 DB::delete('common_process', "processid='$name' OR expiry<".TIMESTAMP);
1315 }
1316
1317 }
1318
1319 /**
1320* Discuz 内存读写引擎
1321* 支持 memcache, eAccelerator, XCache
1322*
1323* 使用的时候建议直接利用函数 memory()
1324*/
1325 class discuz_memory
1326 {
1327 var $config;
1328 var $extension = array();
1329 var $memory;
1330 var $prefix;
1331 var $type;
1332 var $keys;
1333 var $enable = false;
1334
1335 /**
1336 * 确认当前系统支持的内存读写接口
1337 * @return discuz_memory
1338 */
1339 function discuz_memory() {
1340 $this->extension['eaccelerator'] = extension_loaded('eAccelerator');
1341 $this->extension['xcache'] = extension_loaded('XCache');
1342 $this->extension['memcache'] = extension_loaded('memcache');
1343 }
1344
1345 /**
1346 * 依据config当中设置,初始化内存引擎
1347 * @param unknown_type $config
1348 */
1349 function init($config) {
1350
1351 $this->config = $config;
1352 $this->prefix = empty($config['prefix']) ? substr(md5($_SERVER['HTTP_HOST']), 0, 6).'_' : $config['prefix'];
1353 $this->keys = array();
1354
1355 // memcache 接口
1356 if($this->extension['memcache'] && !empty($config['memcache']['server'])) {
1357 require_once libfile('class/memcache');
1358 $this->memory = new discuz_memcache();
1359 $this->memory->init($this->config['memcache']);
1360 if(!$this->memory->enable) {
1361 $this->memory = null;
1362 }
1363 }
1364
1365 // eaccelerator 接口
1366 if(!is_object($this->memory) && $this->extension['eaccelerator'] && $this->config['eaccelerator']) {
1367 require_once libfile('class/eaccelerator');
1368 $this->memory = new discuz_eaccelerator();
1369 $this->memory->init(null);
1370 }
1371
1372 // xcache 接口
1373 if(!is_object($this->memory) && $this->extension['xcache'] && $this->config['xcache']) {
1374 require_once libfile('class/xcache');
1375 $this->memory = new discuz_xcache();
1376 $this->memory->init(null);
1377 }
1378
1379 // 当接口正常,引入当前已经缓存的变量数组
1380 if(is_object($this->memory)) {
1381 $this->enable = true;
1382 $this->type = str_replace('discuz_', '', get_class($this->memory));
1383 $this->keys = $this->get('memory_system_keys');
1384 $this->keys = !is_array($this->keys) ? array() : $this->keys;
1385 }
1386
1387 }
1388
1389 /**
1390 * 读取内存
1391 *
1392 * @param string $key
1393 * @return mix
1394 */
1395 function get($key) {
1396 $ret = null;
1397 if($this->enable && (isset($this->keys[$key]) || $key == 'memory_system_keys')) {
1398 $ret = $this->memory->get($this->_key($key));
1399 if(!is_array($ret)) {
1400 $ret = null;
1401 } else {
1402 return $ret;
1403 }
1404 }
1405 return $ret;
1406 }
1407
1408 /**
1409 * 写入内存
1410 *
1411 * @param string $key
1412 * @param array_string_number $value
1413 * @param int过期时间 $ttl
1414 * @return boolean
1415 */
1416 function set($key, $value, $ttl = 0) {
1417
1418 $ret = null;
1419 if($this->enable) {
1420 $ret = $this->memory->set($this->_key($key), array($value), $ttl);
1421 if($ret) {
1422 $this->keys[$key] = true;
1423 $this->memory->set($this->_key('memory_system_keys'), array($this->keys));
1424 }
1425 }
1426 return $ret;
1427 }
1428
1429 /**
1430 * 删除一个内存单元
1431 * @param 键值string $key
1432 * @return boolean
1433 */
1434 function rm($key) {
1435 $ret = null;
1436 if($this->enable) {
1437 $ret = $this->memory->rm($this->_key($key));
1438 if($ret) {
1439 unset($this->keys[$key]);
1440 $this->memory->set($this->_key('memory_system_keys'), array($this->keys));
1441 }
1442 }
1443 return $ret;
1444 }
1445
1446 /**
1447 * 清除当前使用的所有内存
1448 */
1449 function clear() {
1450 if($this->enable && is_array($this->keys)) {
1451 $this->keys['memory_system_keys'] = true;
1452 foreach ($this->keys as $k => $v) {
1453 $this->memory->rm($this->_key($k));
1454 }
1455 }
1456 $this->keys = array();
1457 return true;
1458 }
1459
1460 /**
1461 * 内部函数 追加键值前缀
1462 * @param string $str
146 * @return boolean
1464 */
1465 function _key($str) {
1466 return ($this->prefix).$str;
1467 }
1468
1469 }
1470
1471 ?>
页:
[1]