此次是逆雪寒的文件緩存實現代碼分析:php
1 /* 2 [/php] 3 4 PHPCMS的文本緩存實現: 5 6 [php] 7 <?php 8 9 /* 10 這個文件裏面全是有關生成文本緩存的函數。文本緩存是個好東西。通常的項目,咱們用不着內存緩存 : memcached ,文本搞定。 11 原理是這樣的: 咱們在後臺是否是能夠設置不少有關網站的參數。而這些參數不少都是固定的。就不變化的。都存到咱的數據庫上。而咱們程序那裏呢 12 每次都要訪問數據庫讀出參數來進行咱們程序中的操做。首先數據庫查詢是個很耗硬盤IO資源的一個東西,因此文本緩存恰好能減輕數據庫那邊的承重。 13 咱們在程序開始就把數據庫裏面的配置都轉化爲數組 等 放到 php文件裏面。這樣咱們能夠直接訪問php文件而不用每次都訪問數據庫了。 14 php文本緩存其實成了咱們程序和數據庫的一箇中間件。 因此咱們本身寫本身的文本緩存的時候其實要實現的很簡單: 15 讀數據庫 -> 寫到PHP文件 -> 程序中include ;來吧。開始文本緩存學習 16 */ 17 18 defined('IN_PHPCMS') or exit('Access Denied'); 19 20 // 生成全部緩存的總操做函數 21 function cache_all() 22 { 23 // 生成全部的數據庫表名,表名是根據數據庫裏面當前的表名而生成。請看這個函數的詳細分析 24 cache_table(); 25 26 // 包含表常量 27 require_once PHPCMS_CACHEDIR.'table.php'; 28 29 cache_common(); 30 31 cache_member_group(); 32 33 $modules = cache_module(); 34 35 $channelids = cache_channel(0); 36 37 $keyids = array_merge($modules, $channelids); 38 39 foreach($keyids as $keyid) 40 { 41 $catids = cache_categorys($keyid); 42 43 if(is_array($catids)) 44 { 45 foreach($catids as $catid) 46 { 47 cache_category($catid); 48 } 49 } 50 } 51 52 cache_type(0); 53 54 return TRUE; 55 } 56 57 function cache_common() 58 { 59 global $db; 60 61 // 查詢全部能用的模塊 62 $query = $db->query("SELECT module,name,iscore,iscopy,isshare,moduledir,moduledomain FROM " 63 .TABLE_MODULE." WHERE disabled=0"); 64 65 while($r = $db->fetch_array($query)) 66 { 67 $r['linkurl'] = ''; 68 69 // 若是模塊存在目錄的就取它目錄地址 70 if($r['module'] != 'phpcms' && $r['iscopy'] == 0) { 71 $r['linkurl'] = linkurl($r['moduledomain'] 72 ? dir_path($r['moduledomain']) 73 : $r['moduledir'].'/'); 74 } 75 76 unset($r['moduledomain']); 77 78 $key = $r['module']; 79 80 $data[$key] = $r; 81 } 82 83 // 存到緩存數組,等一下一塊兒把 $CACHE 數組寫到文本里去 84 $CACHE['module'] = $data; 85 86 $data = array(); 87 88 // 羅列能用的頻道列表 89 $query = $db->query("SELECT channelid, module, channelname, channeldir, channeldomain, 90 channelpic, introduce, style, islink, linkurl, cat_html_urlruleid, 91 item_html_urlruleid, special_html_urlruleid, cat_php_urlruleid, 92 item_php_urlruleid, special_php_urlruleid FROM ".TABLE_CHANNEL 93 ." WHERE disabled=0 ORDER by listorder"); 94 95 while($r = $db->fetch_array($query)) 96 { 97 $r['linkurl'] = linkurl($r['linkurl']); 98 99 $key = $r['channelid']; 100 101 $data[$key] = $r; 102 } 103 104 // 存到緩存數組 105 $CACHE['channel'] = $data; 106 107 $data = array(); 108 109 // 查詢 phpcms這個模塊的設置信息,你們能夠看下數據庫這個表內容。setting 字段裏面的信息是通過serialize 函數串行化的 110 $r = $db->get_one("SELECT setting FROM ".TABLE_MODULE." WHERE module='phpcms'"); 111 112 /* 113 * 因此取出的內容要unserialize 反串行.我是挺喜歡使用serialize 函數的。 114 * 他能夠實現把一個數組存到數據庫或把一個對象存到數據庫。或是拿來GET傳遞都行。 115 * 太強了。你們能夠試用下。可能你項目某個地方須要用到哦。 116 */ 117 $CACHE['phpcms'] = unserialize($r['setting']); 118 119 $fields = array(); 120 121 // 下載模塊的信息,請本身看下這個表的數據就明白 122 $result = $db->query("SELECT * FROM ".TABLE_FIELD." ORDER BY fieldid"); 123 124 while($r = $db->fetch_array($result)) 125 { 126 $tablename = $r['tablename']; 127 128 $fields[$tablename] .= ','.$r['name']; 129 } 130 131 $CACHE['field'] = $fields; 132 133 // 開始把$CACHE 數組寫到 common.php 這個文本緩存裏。你們能夠本身去打開這個文件看下內容。一切瞭然 134 cache_write('common.php', $CACHE); 135 136 return $CACHE; 137 } 138 139 // 更新文本緩存。最好在後臺操做使用。由於PHP的文件flock 文件鎖在某些平臺使用不是很好。會出現多用戶同寫一個文件從而破壞緩存文件 140 function cache_update($action = '') 141 { 142 global $db; 143 144 $data=array(); 145 146 switch($action) 147 { 148 case 'keylink': 149 $query=$db->query("SELECT linktext,linkurl FROM ".TABLE_KEYLINK." where passed=1"); 150 151 while($r=$db->fetch_array($query)) 152 { 153 $data[]=$r; 154 } 155 break; 156 157 case 'reword': 158 $query = $db->query("SELECT word,replacement FROM ".TABLE_REWORD." where passed=1"); 159 160 while($r = $db->fetch_array($query)) 161 { 162 $data[]=$r; 163 } 164 break; 165 166 default: 167 $actions = array('keylink','reword'); 168 169 array_map('cache_update', $actions); 170 171 return TRUE; 172 } 173 174 cache_write('cache_'.$action.'.php', $data); 175 176 return $data; 177 } 178 179 function cache_table() 180 { 181 global $db,$CONFIG; 182 183 /* 184 顯示數據庫裏面的全部表名 185 */ 186 $query = $db->query("SHOW TABLES FROM `".$CONFIG['dbname']."`"); 187 188 189 while($r = $db->fetch_row($query)) 190 { 191 $table = $r[0]; 192 193 // 尋找表前綴等於 $CONFIG['tablepre'] (在config.inc.php裏設置) @@表前綴還有這個做用 嘿嘿 194 if(preg_match("/^".$CONFIG['tablepre']."/i", $table)) 195 { 196 $tablename = str_replace($CONFIG['tablepre'], 'table_', $table); 197 198 // $data['table_xx'] = xx; 形式 只能意會下了 199 $data[$tablename] = $table; 200 } 201 } 202 203 // $db->free_result() 這個類方法實際上是調用了函數:mysql_free_result() 函數 204 // 主要是爲了清除數據庫大量的查詢而佔用的內存。仍是有必要的哦 205 $db->free_result($query); 206 207 // 常量 PHPCMS_CACHEDIR 在 common.inc.php 裏面定義的。你們不記得了去看看吧。 208 // 是存放phpcms 緩存目錄的路徑,這裏意思是:若是緩存目錄不存在 209 if(!is_dir(PHPCMS_CACHEDIR)) 210 { 211 // 若是緩存目錄不存在那麼就建立 212 dir_create(PHPCMS_CACHEDIR); 213 214 // 建立編譯後的PHP模板目錄,有關phpcms模板引擎編寫。在下一章合適就開講 215 dir_create($CONFIG['templatescachedir']); 216 /* 217 dir_create() 函數爲建立 目錄函數。PHPCMS本身封裝的,剛看了下。phpcms 挺強。 218 這個函數還能夠經過ftp 來建立目錄。這樣就能夠解決一些 開啓了安全模式下的服務器對於建立目錄等出現的問題 219 由於涉及到PHP FTP 知識。因此打算講解到下面再說。 220 */ 221 } 222 223 /* 224 cache_write() 函數在global.func.php裏面定義的。是把 已經從數據庫取出來的數組信息寫到 PHP文本上去。 225 @@文本緩存關鍵的一步 廢話少說上菜: 226 */ 227 cache_write('table.php', $data , 'constant'); //不少朋友說找不到phpcms 表常量在那裏定義的。就是在這裏。 228 229 function cache_write($file, $string, $type = 'array') 230 { 231 // 檢測 $string 內容是字符串的呢仍是數組的,是數組的那就繼續 .. 232 if(is_array($string)) 233 { 234 $type = strtolower($type); 235 236 // 而後再判斷這個函數的模式標誌 ,是否爲數組模式,默認爲數組模式 237 if($type == 'array') 238 { 239 /*這個太關鍵了。由於咱們把數據庫的信息寫到文本上去的時候。是以符合PHP語法的格式寫進去的。爲何呢?@@ 240 * 十分廢話,由於若是不是以PHP格式寫到文件裏面去,那麼這個PHP文件怎麼能給咱們include 進程序運行調用呢? 241 * 呵呵。 知道這一點就真的明白文本緩存的實現了。忒簡單。 這裏使用了個小技巧:使用了 var_export() 函數 242 * 這個函數會返回一個變量的字符串形式。這個函數太有幫助了。若是沒有這個函數,咱們還要本身想辦法實現呢。 243 * 本身寫一次文本緩存就明白了。會碰到這個問題的。 '\n' 這個是文本文件的換行。初學者 別把<br> 和 '\n' 搞混羅。 244 * 一個是html 的 一個是文本文件的。 245 */ 246 $string = "<?php\n return ".var_export($string,TRUE).";\n?>"; 247 } 248 249 // 之內容形式 250 elseif($type == 'constant') 251 { 252 $data=''; 253 254 foreach($string as $key => $value) $data .= "define('".strtoupper($key)."','".addslashes($value)."');\n"; 255 256 // 若是之內容形式的話。就不是寫數組到文本里面了。而是把內容都定義成常量。 257 $string = "<?php\n".$data."\n?>"; 258 } 259 } 260 261 // file_put_contents()函數 是PHP5才支持的 效率最好。建議使用 262 $strlen = file_put_contents(PHPCMS_CACHEDIR.$file, $string); 263 264 // 設置目錄 爲可讀可寫可執行 265 chmod(PHPCMS_CACHEDIR.$file, 0777); 266 267 // 返回寫到文本的字節數 268 return $strlen; 269 } 270 271 // 再說多一個讀 緩存文件的操做函數 :上菜 272 function cache_read($file, $mode = 'i') 273 { 274 $cachefile = PHPCMS_CACHEDIR.$file; 275 276 if(!file_exists($cachefile)) { 277 return array(); 278 } 279 280 return $mode == 'i' ? include $cachefile : file_get_contents($cachefile); 281 } 282 283 // 讀緩存其實就是 include php 緩存文件。 講完走人 284 285 return $data; 286 } 287 /* 288 phpcms 的全部數據庫表名 都用根據數據庫當前的表名來用常量來進行定義。我認爲這樣設計不是很好。 289 不夠靈活:好比若是咱們更改數據庫的一個表名的話。那麼會出現找不到表的錯誤信息。 290 並且想要修復還很麻煩。就是說不能隨便更改表名了。不推薦你們這樣寫。咱們能夠把表名都定義在一個PHP文件裏面。 291 這樣咱們之後要改某個表名,就很方便了。 292 */ 293 294 function cache_module($module = '') 295 { 296 global $db; 297 if($module) 298 { 299 // 模塊具體信息 300 $r = $db->get_one("SELECT setting,module,name,iscopy,moduledir,moduledomain FROM " 301 .TABLE_MODULE." WHERE module='$module'"); 302 303 if($r['setting']) 304 { 305 // 講過了反串行。由於裏面信息是串行化後再存到數據庫的 306 $setting = unserialize($r['setting']); 307 } 308 309 $setting['name'] = $r['name']; 310 311 $setting['moduledir'] = $r['moduledir']; 312 313 $setting['moduledomain'] = $r['moduledomain']; 314 315 $setting['linkurl'] = ''; 316 317 if($r['module'] != 'phpcms' && $r['iscopy'] == 0) 318 { 319 $setting['linkurl'] = linkurl($r['moduledomain'] 320 ? dir_path($r['moduledomain']) 321 : $r['moduledir'].'/'); 322 323 cache_categorys($module); 324 } 325 326 unset($r['moduledomain']); 327 328 cache_write($module.'_setting.php', $setting); 329 330 return $setting; 331 } 332 333 else 334 { 335 $query = $db->query("SELECT module FROM ".TABLE_MODULE 336 ." WHERE disabled=0 ORDER by moduleid"); 337 338 while($r = $db->fetch_array($query)) 339 { 340 cache_module($r['module']); 341 342 $modules[] = $r['module']; 343 } 344 345 return $modules; 346 } 347 } 348 349 function cache_channel($channelid = 0) 350 { 351 global $db; 352 353 if($channelid) 354 { 355 $data = $db->get_one("SELECT * FROM ".TABLE_CHANNEL 356 ." WHERE channelid=$channelid"); 357 358 if($data && !$data['islink']) 359 { 360 if($data['setting']) 361 { 362 $setting = unserialize($data['setting']); 363 unset($data['setting']); 364 $data = is_array($setting) ? array_merge($data, $setting) : $data; 365 } 366 367 $data['linkurl'] = linkurl($data['linkurl']); 368 369 cache_write('channel_'.$channelid.'.php', $data); 370 371 cache_categorys($channelid); 372 373 return $data; 374 } 375 } 376 377 else 378 { 379 $query = $db->query("SELECT channelid FROM ".TABLE_CHANNEL 380 ." WHERE islink=0 AND disabled=0 ORDER by channelid"); 381 382 while($r = $db->fetch_array($query)) 383 { 384 cache_channel($r['channelid']); 385 386 $channelids[] = $r['channelid']; 387 } 388 389 return $channelids; 390 } 391 } 392 393 function cache_categorys($keyid) 394 { 395 global $db, $PHPCMS, $CHANNEL; 396 397 $urlpre = ''; 398 399 if(is_numeric($keyid)) 400 { 401 $keyid = intval($keyid); 402 403 $module = $CHANNEL[$keyid]['module']; 404 405 $sql = " channelid=$keyid "; 406 } 407 408 else 409 { 410 $sql = " module='$keyid' "; 411 } 412 413 $catids = $data = array(); 414 415 $query = $db->query("SELECT module,channelid,catid,catname,style,introduce,catpic,islink,catdir, 416 linkurl,parentid,arrparentid,parentdir,child,arrchildid,items,itemordertype, 417 itemtarget,ismenu,islist,ishtml,htmldir,prefix,urlruleid,item_prefix,item_html_urlruleid, 418 item_php_urlruleid FROM ".TABLE_CATEGORY." WHERE $sql ORDER by listorder,catid"); 419 420 while($r = $db->fetch_array($query)) 421 { 422 $r['linkurl'] = str_replace($PHPCMS['index'].'.'.$PHPCMS['fileext'], '', $r['linkurl']); 423 424 $r['linkurl'] = $urlpre 425 ? preg_replace("|^".$urlpre."|", '', $r['linkurl']) 426 : linkurl($r['linkurl']); 427 428 $catid = $r['catid']; 429 430 $data[$catid] = $r; 431 432 $catids[] = $catid; 433 } 434 435 // 寫緩存羅。 436 if($data) { 437 cache_write('categorys_'.$keyid.'.php', $data); 438 } 439 440 return $catids; 441 } 442 443 function cache_category($catid) 444 { 445 global $db,$PHPCMS; 446 447 if(!$catid) { 448 return FALSE; 449 } 450 451 $data = $db->get_one("SELECT * FROM ".TABLE_CATEGORY 452 ." WHERE catid=$catid"); 453 454 $setting = unserialize($data['setting']); 455 456 unset($data['setting']); 457 458 $data = is_array($setting) ? array_merge($data, $setting) : $data; 459 460 $data['linkurl'] = linkurl(str_replace($PHPCMS['index'].'.'.$PHPCMS['fileext'], '', $data['linkurl'])); 461 462 cache_write('category_'.$catid.'.php', $data); 463 464 return $data; 465 } 466 467 function cache_type($keyid=0) 468 { 469 global $db; 470 471 if($keyid) 472 { 473 $result = $db->query("SELECT * FROM ".TABLE_TYPE 474 ." WHERE keyid='$keyid'"); 475 $data = array(); 476 477 while($r = $db->fetch_array($result)) 478 { 479 $r['introduce'] = $r['introduce'] 480 ? $r['introduce'] 481 : ' '; 482 483 $data[$r['typeid']] = $r; 484 } 485 486 if($data) 487 { 488 cache_write('type_'.$keyid.'.php', $data); 489 } 490 491 return $data; 492 } 493 else 494 { 495 $modules = array(); 496 497 $query = $db->query("SELECT module FROM ".TABLE_MODULE 498 ." WHERE disabled=0 ORDER by moduleid"); 499 500 while($r = $db->fetch_array($query)) 501 { 502 $modules[] = $r['module']; 503 } 504 505 $channelids = array(); 506 507 $query = $db->query("SELECT channelid FROM ".TABLE_CHANNEL 508 ." WHERE islink=0 AND disabled=0 ORDER by channelid"); 509 510 while($r = $db->fetch_array($query)) 511 { 512 $channelids[] = $r['channelid']; 513 } 514 515 $modulechannels = array_merge($modules, $channelids); 516 517 foreach($modulechannels as $m) 518 { 519 $result = $db->query("SELECT * FROM ".TABLE_TYPE." WHERE keyid='$m'"); 520 521 $TYPE = array(); 522 523 while($r = $db->fetch_array($result)) 524 { 525 $r['introduce'] = $r['introduce']? $r['introduce']:' '; 526 527 $TYPE[$r['typeid']] = $r; 528 } 529 530 cache_write('type_'.$m.'.php',$TYPE); 531 } 532 533 return $modulechannels; 534 } 535 } 536 537 function cache_member_group() 538 { 539 global $db; 540 541 // 用戶組信息 542 $query = $db->query("SELECT * FROM ".TABLE_MEMBER_GROUP." ORDER BY groupid"); 543 544 while($r = $db->fetch_array($query)) 545 { 546 $groupid = $r['groupid']; 547 cache_write('member_group_'.$groupid.'.php', $r); 548 $data[$groupid] = $r; 549 } 550 551 // 明白了吧。寫緩存羅 552 cache_write('member_group.php', $data); 553 554 return $data; 555 } 556 557 function cache_banip() 558 { 559 global $db, $PHP_TIME; 560 561 $result = $db->query("SELECT ip,overtime FROM ".TABLE_BANIP 562 ." WHERE ifban=1 and overtime>=$PHP_TIME order by id desc "); 563 564 while($r = $db->fetch_array($result)) 565 { 566 $data[] = array('ip'=>$r['ip'], 567 'overtime'=>$r['overtime']); 568 } 569 570 $db->free_result($result); 571 572 cache_write('banip.php', $data); 573 574 return $data; 575 } 576