此次是逆雪寒分析common.inc.php的數據庫部分:php
1 <?php 2 // 包含數據庫操做類,下章詳說 3 require PHPCMS_ROOT.'/include/'.$db_file.'.class.php'; 4 5 // 遇到再說 6 require PHPCMS_ROOT.'/include/tag.func.php'; 7 8 // 遇到再說 9 require PHPCMS_ROOT.'/include/extension.inc.php'; 10 11 // 實例化數據庫類 12 $db = new $db_class; 13 14 // 鏈接數據庫@_@ 15 $db->connect($CONFIG['dbhost'], 16 $CONFIG['dbuser'], 17 $CONFIG['dbpw'], 18 $CONFIG['dbname'], 19 $CONFIG['pconnect']); 20 21 // 是否開啓SQL緩存 22 $db->iscache = $CONFIG['dbiscache']; 23 24 // 緩存時間 25 $db->expires = $CONFIG['dbexpires']; 26 27 if(!cache_read('table.php')) 28 { 29 require_once PHPCMS_ROOT.'/include/cache.func.php'; 30 31 cache_all(); //生成全部緩存 32 } 33 34 /* 35 cache_read() 函數 讀緩存文件函數存在 global.func.php 裏面.上菜先: 36 */ 37 /* 38 就這麼簡單.文本緩存,在一些大的開源的PHP項目中常常見到.主要是爲了減輕數據庫的負荷的. 39 好比在程序啓動文件裏面,就把一些後臺配置的經常使用信息緩存到php文件裏面.而後在之後的程序就能夠直接使用而不用每次都訪問數據庫了. 40 但對常常要更新的信息.最好不要用文本緩存這形式,由於PHP文件內置的文件鎖flock()不是很好用. 41 大系統中多用戶同時寫訪問的時候有可能會把緩存文件破壞.大系統建議使用 memcached mysql5.1 分區 mysql 主從 來實現負載均衡 @=@ 42 廢話太多了. 這個函數很簡單.本身看下就明白了.若是緩存和模式變量 $mode 是否爲 i 是就include 不是就 把文件以字符串形式讀到內存中. 43 若是 cache_read()找不到緩存文件'table.php'就會返回false,那麼就 加載 cache.func.php 文件.它裏面是些建立緩存的一些函數. 44 而後呢執行 cache_all()函數生成全部的經常使用信息緩存. 45 關於phpcms 的緩存更詳細包括生成原理.打算在弄完啓動文件common.inc.php 後再開篇寫個詳細的. 46 */ 47 function cache_read($file, $mode = 'i') // 'i' means 'include' 48 { 49 $cachefile = PHPCMS_CACHEDIR.$file; 50 51 if(!file_exists($cachefile)) { 52 return array(); 53 } 54 55 return $mode == 'i' ? (include $cachefile) : file_get_contents($cachefile); 56 } 57 58 59 /* 60 加載 common.php 緩存文件裏面的變量(數據) 這樣咱們不用從數據庫讀了每次.是吧 61 common.php 文件裏面是什麼來的呢?上菜: 62 */ 63 $CACHE = cache_read('common.php'); 64 65 66 /* 67 這個就是所有從數據庫裏面生成的文本緩存信息.咱們不用每次都鏈接數據庫讀數據庫. 68 而只要訪問裏面的數組就能夠獲得一些配置信息. 69 這個就是文本緩存的做用了,至於怎麼會生成這個文本緩存文件的.我會另外開一篇來介紹。 70 */ 71 return array ( 72 'module' => 73 array ( 74 'phpcms' => 75 array ( 76 'module' => 'phpcms', 77 'name' => 'phpcms', 78 'iscore' => '1', 79 'iscopy' => '0', 80 'isshare' => '0', 81 'moduledir' => '', 82 'linkurl' => '', 83 ), 84 'member' => 85 array ( 86 'module' => 'member', 87 'name' => '會員', 88 'iscore' => '1', 89 'iscopy' => '0', 90 'isshare' => '0', 91 'moduledir' => 'member', 92 'linkurl' => '/phpcms/member/', 93 ), 94 'article' => 95 array ( 96 'module' => 'article', 97 'name' => '文章', 98 'iscore' => '0', 99 'iscopy' => '1', 100 'isshare' => '0', 101 'moduledir' => 'article', 102 'linkurl' => '', 103 ))); 104 105 106 107 //緩存中的數據 108 $MODULE = $CACHE['module']; 109 110 $CHANNEL = $CACHE['channel']; 111 112 $PHPCMS = $CACHE['phpcms']; 113 114 $FIELD = $CACHE['field']; 115 116 /* 117 unset 掉不須要用的變量. 118 */ 119 unset($CACHE, $ipmatches, $CONFIG['timezone'], $CONFIG['cachedir'], 120 $CONFIG['dbhost'], $CONFIG['dbuser'], $CONFIG['dbpw'], 121 $CONFIG['pconnect'], $CONFIG['dbiscache'], $CONFIG['dbexpires']); 122 123 124 125 /* 126 $PHPCMS['enablebanip'] 是什麼.不用說應該知道了吧.這個就是後臺裏面設置是否開啓過濾IP訪問的功能. 127 (由於我沒用過phpcms,我是按照代碼猜的,不對的請指出)從這裏就看出了文本緩存也有他的做用的。 128 ip_banned()函數是什麼呢.上菜再說: 129 */ 130 if($PHPCMS['enablebanip'] && ip_banned($PHP_IP)) { 131 showmessage($LANG['administrator_banned_this_IP']); 132 } 133 134 135 /* 136 裏面也用到了 cache_read() 這個函數,仍是讀banip.php 這個文件.banip.php這個文件裏面存着你在後臺甚至的要過濾的IP列表. 137 裏面的邏輯比較簡單.本身消化下了.不明白跟帖問 138 showmessage() 函數是提示出錯信息封裝好的一個函數. 國家化的 $LANG['administrator_banned_this_IP']這個看到了吧. 139 這個就是讀語言包裏面的.這樣咱們就能夠出好多個語言版本的程序拉. 140 */ 141 function ip_banned($ip) 142 { 143 // 前面定義過的.當前的時間 144 global $PHP_TIME; 145 146 $ipbanneds = cache_read('banip.php'); 147 148 if(!is_array($ipbanneds)) { 149 return FALSE; 150 } 151 152 foreach($ipbanneds as $v) 153 { 154 if($v['overtime'] < $PHP_TIME) { 155 return FALSE; 156 } 157 158 if($ip == $v['ip'] 159 || preg_match("/^" 160 . str_replace('.', '[.]', $v['ip'])."$/", $ip)) { 161 return TRUE; 162 } 163 } 164 } 165 166 167 168 $TEMP = $MOD = $CHA = $CATEGORY = $CAT = array(); 169 170 $ftp = $enableftp = $tags = $html = 0; 171 172 /* 173 初始化變量.這個是好習慣咱們要模仿. 174 */ 175 176 if(!isset($mod)) 177 { 178 // phpcms 是默認加載的模塊 179 $mod = 'phpcms'; 180 } 181 182 elseif($mod != 'phpcms') 183 { 184 // 從緩存中讀加載的模塊是否開啓 185 isset($MODULE[$mod]) or exit($LANG['module_not_exists']); 186 /* 187 這個寫法,我十分喜歡,平時也用. xx && dd ; xx and dd ;與運算要同時兩邊都爲真整個公式才爲真,就是利用這個原理. 188 ; xx || dd ; xx or dd 或運算只要一個條件知足就不會執行下一個條件而繼續執行下去. 這樣寫是否是很酷. 189 */ 190 191 // 開始加載這個模塊的一些經常使用配置數值。 phpcms 對應的每一個模塊都有一個緩存配置文件。@@ 怪不得速度那麼快 192 $MOD = cache_read($mod.'_setting.php'); 193 194 @include PHPCMS_ROOT.'/languages/' 195 .(defined('IN_ADMIN') 196 ? $CONFIG['adminlanguage'].'/'.$mod.'_admin.lang.php' 197 : $CONFIG['language'].'/'.$mod.'.lang.php'); 198 199 /* 200 加載想對應的模塊語言包. 201 */ 202 } 203 204 // 記錄前一個URL地址。估計之後下面程序有須要用這個變量 205 if(!isset($forward)) { 206 $forward = $PHP_REFERER; 207 } 208 209 // 記錄是否有表單提交過.也是之後有用 210 $dosubmit = isset($dosubmit) ? 1 : 0; 211 212 /* 213 * 記錄當前頻道的id 若是$channelid 沒有 isset 那麼就爲 0. 214 * intval() 十分有用。數字和數字的比較加減速度會快不少。記得哦 215 */ 216 $channelid = isset($channelid) ? intval($channelid) : 0; 217 218 // 加載默認phpcms皮膚 219 $skindir = PHPCMS_PATH.'templates/' . $CONFIG['defaulttemplate'] 220 . '/skins/' . $CONFIG['defaultskin']; 221 222 /* 223 $PHPCMS['enablegzip'] 這個變量就是存在於 phpcms_setting.php 文件裏。下面已經說過了。 224 每一個模塊都有相對應的模塊配置緩存文件(是從數據庫copy過來的信息) 這個變量標緻 是否開啓 壓縮傳輸。 225 壓縮傳輸,聽名字就知道。就是把數據按照必定的算法壓縮小羅。而後再傳送到客戶端。這樣就能夠在有限的帶寬中傳輸更大的數據拉。 226 固然速度快了很多。壓縮的數據到了你的瀏覽器,它就自動解壓縮,老版本的一些瀏覽器不支持解壓縮哦。不過如今還有誰用好久的瀏覽器呢。 227 用法很簡單的:看下面就知道:首先判斷下,看客戶老大們是否在後臺選擇了這個模塊的壓縮傳輸 228 (若是是的話。天然的已經加載到了相對應的文本緩存文件裏面拉) 標緻:$PHPCMS['enablegzip'] 和 判斷 回調函數 ob_gzhandler 是否開啓, 229 ob_gzhandler 其實不算是個函數。看手冊說明。 就這麼簡單。它只是一個專門給 ob_start() 作回調使用的一個參數函數。 230 詳細請看下手冊。別偷懶哦,在程序開頭ob_start('ob_gzhandler')就算是開始壓縮傳輸了;判斷完了 若是爲真。就繼續下面的代碼: 231 232 ($CONFIG['phpcache'] || defined('SHOWJS')) ? ob_start() : ob_start('ob_gzhandler'); 233 看代碼phpcms 是這樣的: 若是用戶在後臺開啓了壓縮傳輸。而用戶又開啓了 頁面緩存。那麼就默認不使用壓縮傳輸了。我也不知道爲何這樣設計。 234 我測試了下。後臺開啓壓縮傳輸。又同時又使用頁面緩存。沒發現有什麼問題。@@ 235 若是沒開啓壓縮傳輸,那麼咱們就ob_start(); 使用session 以前必需要 ob_start() ; 236 並且在ob_start() 以前不能有任何的 頭文件發送和輸出。好比:echo header等要不會出錯的哦。 237 */ 238 if($PHPCMS['enablegzip'] && function_exists('ob_gzhandler')) 239 { 240 ($CONFIG['phpcache'] || defined('SHOWJS')) ? ob_start() : ob_start('ob_gzhandler'); 241 } 242 else 243 { 244 $PHPCMS['enablegzip'] = 0; 245 246 ob_start(); 247 } 248 249 /* 250 $_userid,$_username,$_groupid 這幾個記錄用戶信息的變量初始化,不初始化危險就太大了。 251 @@ 若是給人家$_GET一個 _userid 變量過來。那麼就會把咱們這個變量覆蓋。可是咱們若是給這幾個變量一個值, 252 那麼按照就近原則。就算你GET個變量過來。你也同樣改不了我原來的變量值。你們好好本身想下。就會明白了。 253 getcookie() 這個自定義函數在 global.func.php文件裏定義的。上菜: 254 */ 255 function getcookie($var) 256 { 257 global $CONFIG; 258 259 $var = $CONFIG['cookiepre'].$var; 260 261 return isset($_COOKIE[$var]) ? $_COOKIE[$var] : FALSE; 262 } 263 264 /* 265 這個函數用來提取咱們設置的cookie 值. $CONFIG['cookiepre'] 在 config.inc.php 文件裏面設置,cookie 名的前綴. 函數很簡單。一看就明白不說了。 266 */ 267 $_userid = 0; 268 269 $_username = ''; 270 271 $_groupid = 3; 272 273 $_arrgroupid = array(); 274 275 $phpcms_auth = getcookie('auth'); 276 277 278 279 /* 280 list() = array(); 用戶你們本身試下。 意會下 281 phpcms_auth() 是加密和解密 函數, 由於cookie 是存在於客戶端。十分危險呀。 282 你看連用戶的密碼也存在cookie 不加密能行嗎。可是呢加密後又要能解密。由於用戶名和用戶密碼咱們往下操做要獲取的。 \ 283 這個函數存在於 global.func.php 文件裏面。你們想了解這個算法的本身去看下吧。挺簡單的。 284 其實就是圍繞着 $phpcms_auth_key 這個變量來加密解密和discuz 的cookie 機制差很少。 285 $phpcms_auth_key = md5($PHPCMS['authkey'].$_SERVER['HTTP_USER_AGENT']); 286 看$PHPCMS['authkey'],估計後臺有個 cookie 加密值讓你填,而後以這個值和 $_SERVER['HTTP_USER_AGENT'](系統信息) 287 */ 288 if($phpcms_auth) 289 { 290 $phpcms_auth_key = md5($PHPCMS['authkey'].$_SERVER['HTTP_USER_AGENT']); 291 292 list($_userid, $_password, $_answer) = $phpcms_auth 293 ? explode("\t", phpcms_auth($phpcms_auth, 'DECODE')) 294 : array(0, '', ''); 295 296 $_userid = intval($_userid); 297 298 if($_userid < 0) { 299 // 讀出的cookie 的用戶id 若是是 小於0 300 $_userid = 0; 301 } 302 303 // 若是 cookie 保存的這個uid 存在,那麼開始按照這個ID來查數據庫用戶表 來取出用戶信息 304 if($_userid) 305 { 306 /* 307 phpcms 封裝好的數據庫類,下篇開講這個你們就大概看行了。 308 你們看下 select sql語句。 也能夠學習下。 首先最好不要使用 select * from xx 的 * 形式,除非你想獲取全部字段的記錄。 309 只羅列你要的字段。這樣在數據量大的查詢中。速度明顯上去。 310 常量: TABLE_MEMBER 定義了表名。這樣作有什麼好處呢?想都知道了,爲了之後變動表名方便而定義爲常量。 311 這個東西那裏來的。估計在一個文件裏面定義好的。遇到了再講吧懶得找了。 312 */ 313 $memberinfo = $db->get_one( 314 "SELECT username,password,groupid,arrgroupid,email,chargetype, 315 begindate,enddate,money,point,credit,newmessages FROM " 316 .TABLE_MEMBER." WHERE userid=$_userid LIMIT 0,1"); 317 318 // 用查詢出來的密碼和 cookie 中存在的密碼想對比.爲了在效率: 在比較前 先判斷查詢是否成功先。不少phper每每忽略。 319 320 /* 321 通過下面的讀cookie 和查數據庫用戶信息後。當肯定這個用戶信息是合法之後。就會自動登錄了。好比phpchina論壇。 322 當你登錄後沒註銷。下次訪問的時候仍是登錄狀態。就是這個原理。記得模仿哦 323 這裏詳細解釋下 mkcookie ()函數 上菜: 324 */ 325 326 /* 327 $time 爲cookie 的存活時間: 若是爲 0 就是關閉瀏覽器 cookie 就自動失效 , 328 $PHP_TIME 在前面定義了:當前時間。 $PHP_TIME -3600 減去3600秒。就是一個小時前的意思,那確定是設置cookie 失效的意思了。 329 $s 變量是 獲取 是否開啓SSL安全傳輸的標緻。 cookie 有一個參數是ssl傳輸的。若是服務器已經opensll 了那麼咱們確定不能浪費這麼好的安全資源了。 330 $var cookie名的前綴,主要防止混淆。 331 $CONFIG['cookiedomain'] 這個傢伙在 config.inc.php裏面已經配置的了。定義爲: '/' 意思就是說 332 在當前域 的全部目錄的PHP程序都能訪問這個COOKIE ,還有限制目錄訪問COOKIE 的弄法。具體請看 setcookie () 函數手冊上說明。 333 */ 334 function mkcookie($var, $value = '', $time = 0) 335 { 336 global $CONFIG,$PHP_TIME; 337 338 $time = $time > 0 339 ? $time 340 : (empty($value) 341 ? $PHP_TIME - 3600 342 : 0); 343 344 $s = $_SERVER['SERVER_PORT'] == '443' ? 1 : 0; 345 346 $var = $CONFIG['cookiepre'].$var; 347 348 return setcookie($var, $value, $time, $CONFIG['cookiepath'], $CONFIG['cookiedomain'], $s); 349 } 350 351 352 if($memberinfo && $memberinfo['password'] == $_password) 353 { 354 // 若是用戶屬於的組的ID 爲 2 那麼這個用戶是被管理員禁止訪問的了。 355 if($memberinfo['groupid'] == 2) 356 { 357 // 清除cookie 358 mkcookie('auth', ''); 359 360 // 提示出錯菜單 361 showmessage($LANG['userid_banned_by_administrator']); 362 } 363 364 //又來這招,應該明白了吧各位老大:把字段 變成 咱們能直接使用的變量 365 @extract($memberinfo, EXTR_PREFIX_ALL, ''); 366 367 unset($memberinfo, $_password, $_answer); 368 369 // 把字段爲 arrgroupid 值爲 FALSE 過濾掉。array_filter()不帶回調參數的用法,請看手冊。 370 $_arrgroupid = $_arrgroupid ? array_filter(explode(',', $_arrgroupid)) : array(); 371 } 372 else 373 { 374 mkcookie('auth', ''); 375 } 376 } 377 } 378 379 unset($db_class, $db_file, $phpcms_auth, $phpcms_auth_key, $memberinfo); 380 381 /* 382 下章我就分析 PHPCMS 的數據庫操做類文件和 PHPCMS的文本緩存機制.:victory: 但願你們繼續支持哦第一 383 384 [ 本帖最後由 逆雪寒 於 2008-1-2 11:54 編輯 ] 385 386 ?>