1
2
3
4
5
6
7
8
9
10
11

知識拓展

發(fā)布時(shí)間:2017-07-20 08:03&n著唱bsp;  用笑 發(fā)布人:毛書朋照藍   現雪 浏覽次數:6461

     當用戶量非常大,需要多台服務器女算提供應用的時(shí)候,使用MySQ有南L存儲會(huì)話相對(duì)使用會(huì)話文年就件具有一定的優越性。比如具有最小的存儲開(kāi)銷,務有比如可以避免文件共享帶來的複雜性中事,比如可以更好(hǎo)的避免發(fā)生碰撞,比如相比麗器會(huì)話文件共享具有更好(hǎo)的性能(né會校ng)。總體上來說(shuō),當訪問量劇增的時(sh吃長í)候,如果使用數據庫保存會(huì)話帶來的問題是線性增長(ch拍章áng)的,那麼(me)使用會(huì)話文件帶來的問題幾那聽乎是爆炸性的。好(hǎo)吧,換一個更直白的說(shuō)法吧:如果話綠您的應用用戶量不大,其實讓PHP自己處理去體session就(jiù)好(hǎo)了個慢,沒(méi)必要考慮MySQL。

具體思路如下:

     1、使用MySQL保存ses這亮sion,需要保存三個關鍵性的數據:session id、ses紙這sion數據、session生命期。

     2、考慮到session的秒鐘使用方式,沒(méi)必要使用InnoDB引擎,MyISAM引擎可以獲海你得更好(hǎo)的性能(néng)。如果環境睡們允許,可以嘗試使用MEMORY引擎。

     3、保存s街去ession數據的列,有需要的話,可以使用utf8或utf8mb4字符集;保筆是存session id的列則沒(méi)有必要,一般情況使用as慢亮cii字符集就(jiù)可以了,可以節約存儲成(chéng)本。

     4、保存sessio這樹n生命期的列,可以根據工程需要進(jìn)行設計。比如datetim但訊e類型、timestamp類型、int類型。對(duì)于區區datetime、int類型可以保存sessio事會n生成(chéng)時(shí)間或過(guò)大短期時(shí)間。

     5白廠、如果有必要可以擴展sessio從員n表的列并修改讀、寫函數以支持(維護)相關列來保存諸如用戶名等信息。不是

     6、當前版本,隻要通過(guò)道小session_set_save_handler注冊自定義的會(huì畫懂)話維護函數就(jiù)可以,不需要在南現其之前使用session_module_name(黃新9;user')函數。

     7、當read函數獲取數據并返回,樂道PHP會(huì)自動對(duì)其進(jìn)行反序列化,一般情況請不刀也要對(duì)數據進(jìn)行更改。

     8、PHP傳遞給write微民函數的date參數是序列化之後(爸雨hòu)的session數據,直接保存即可,一般情況請不要對(du冷腦ì)數據進(jìn)行更改。

     9、按照本段代碼通生的邏輯,PHP配置選項關于會(huì)話生命期的設資玩置已經(jīng)不再有效,這(zhè)個值可以科花自行維護,不一定需要通過(guò)get_cfg_var新線獲取。

     10、s業服essionMysqlId()月時函數是爲了避免大用戶量、多台Web服務這校器情況下的碰撞,一般情況PHP自動生成(chéng)的ses站快sion id是可以滿足用戶要求的。

創建數據表代碼如下:

CREATE TABLE `sess飛可ion` (

  `skey` char(32) CHARAC做體TER SET ascii N區分OT NULL,

  `data` text COLLATE utf8mb4_b說們in,

  `expire` int開化(11) NOT NULL,

  PRIMARY KE也城Y (`skey`),

  KEY `index靜下_session_expire` (`exp店睡ire`) USING BTREE

) ENGINE=MyISAM DEFAUL兒熱T CHARSET=utf8mb4 COLLATE=utf8mb4_bin問服;

PHP代碼如下:

  1 <?php

  2 /*

  3  * 連接數據庫所需的DNS、用戶名、密碼等術湖,一般情況不會(huì)在代碼中進(jìn)行更改,

  4  * 所以線志使用常量的形式,可以避免在函數中引用而需要global。

  5  */

  6 define作時('SESSION_DNS門務', 'mysql:h開們ost=localhost;dbname=db;cha什畫rset=utf8mb4');

  7 define('SESSION_USR公明', 'usr');

  8 define('SESSI器玩ON_PWD', 'pwd'雜務);

  9 define('S線分ESSION_MAXLIFETIME&#校大39;, get_cfg_var('ses信開sion.gc_maxlifet算舊ime'));

 10 

 11 //創建PDO連接

 12 //持久化連接可以提供更好(hǎo)的效率

 13 functio行了n getConnection() {

 14   &nbs木朋p; try {

 15         $南小conn = new PDO(SESSION_DNS, SESSI空如ON_USR, SESSION_PWD, ar船公ray(

 16       &nbs算請p;     PDO::ATTR_PERSISTENT =錢可> TRUE,

 17   &nb月生sp;      一理   PDO::ATTR_ER亮工RMODE => PDO::ER通拿RMODE_EXCEPTION,

 18         飛光    PDO::土化ATTR_EMULATE_PREPARES => FALS間理E

 19       &n少店bsp; ));

 20         re冷西turn $conn;

 21     } catch (E筆對xception $ex) {熱站

 22 

 23     }

 24 }

 25 

 26 //自定義的sess多相ion的open函數

 27 function session頻睡MysqlOpen($savePath, $sessionName) {

 28     retur問計n TRUE;

 29 }

 30 

 31 //自定義的session的close函數店件

 32 functi土弟on sessionMysqlClose(報路) {

 33     retur妹木n TRUE;

 34 }

 35 /*

 36  * 由于一般不會(huì)把用戶提交的數據直接能高保存到session,所以普通情況不存在注入問題。

 37  * 且處理sessio和子n數據的SQL語句也不會(huì)多次使用。因此預處理功能(唱請néng)的效益無法體現。

 38  制報* 所以,實際工程中可以不必教條的使用預處理功能(子照néng)。

 39  */

 40 /*

 41  * sessionM舞慢ysqlRead()函數中,首先化現通過(guò)SELECT count(*)友慢來判斷sessionID是否存在。

 42  * 由于MySQL數據庫提供SELECT對(d區綠uì)PDOStatement::rowCount()的支持,

 43  * 因此,實際的現從工程中可以直接使用rowCount()錯道進(jìn)行判斷。

 44  照都*/

 45 //自定義的sessi車裡on的read函數

 46 //SQL語句中增加了“expire年這 > time()”判斷,用以避免讀取過(guò動通)期的session。

 47 function sessionMysqlRead($se好資ssionId) {

 48     try大有 {

 49     &nbs場男p;   $dbh = ge姐相tConnection();

 50         美那$time = time();

 51     &新計nbsp;   

 52     &nbs外畫p;   $sql = 'SEL子朋ECT count(*) AS `count` FROM session 大會'

 53       土信    &nbs姐錢p;     . 'WHERE skey = ?村子 and expire > ?';綠紅

 54       &nbs村你p; $stmt = $dbh->prepa理妹re($sql);

 55   &n到明bsp;     $s小美tmt->execute(array($sessionId, $time海能));

 56      快紙   $data = $stmt->fetch(PD藍自O::FETCH_ASSOC);

 57         i好的f ($data['co關你unt'] = 0) {

 58     坐購       歌筆 return '';

 59        事得 }

 60       &n醫子bsp; 

 61       匠技  $sql = 'SELECT 多請`data` FROM `session` '

 62     &nbs吃學p;          嗎男 . 'WHERE `skey` = ? and `expir金草e` > ?';

 63     &n是吃bsp;   $stmt =國腦 $dbh->prepare($sql);

 64     &nbs南花p;   $stmt->e訊舞xecute(array($sessionId, $time));

 65         答唱$data = $stmt->現少fetch(PDO::FETCH_ASSOC舊河);

 66     &nbs對術p;   return $data['data'錢用];

 67     } catch (窗行Exception $e) {

 68       &nbs遠個p; return '';

 69   &nb湖不sp; }

 70 }

 71 

 72 //自定義的session的火文write函數

 73 //expire字段存儲的數據爲當前時(s媽技hí)間 session生命期,當這(zhè)個值離在小于time()時(shí)表明session失效。

 74 function sessionMysql師計Write($sessionId, $data) {

 75   &n雜章bsp; try {

 76       &媽物nbsp; $dbh = get姐雨Connection();

 77   &nb聽中sp;     $expire = tim樹跳e()   SESS照雪ION_MAXLIFETIME;

 78 

 79        風理 $sql = 'INSERT INTO土視 `session` (`skey你學`, `data`, `expire`) '

 80   &船制nbsp;       &nb道兵sp;    不友; . 'values (?, ?, ?) '快窗;

 81     &森森nbsp;         &nb和拿sp; . 'ON DUPLICATE KEY U她們PDATE data = ?, expire = ?';

 82   習玩      $stmt = $dbh-&通微gt;prepare($sql);

 83         $s謝船tmt->execute(a長視rray($sessionId, $data, $expire, $data,資朋 $expire));

 84     } catch (Excepti雨這on $e) {

 85     &nb窗愛sp;   echo $e-報的>getMessage();

 86     筆冷}

 87 }

 88 

 89 //自定義的session的destroy函數

 90 function session開訊MysqlDestroy($sessionId) {

 91     try {

 92   &nbs金區p;     $dbh = getConnection()畫司;

 93 

 94         體行$sql = 'DELETE FROM `sessi相年on` where skey = ?了體9;;

 95       她上  $stmt = $dbh->pr科線epare($sql);

 96       &n腦小bsp; $stmt->可放execute(array($sess相森ionId));

 97        著船 return TRUE;

 98     } catch (Exce吃腦ption $e) {

 99   服兵     影刀 return FALSE;

100    事綠 }

101 }

102 

103 //自定義的sessi鄉金on的gc函數

104 function sessionMysqlGc($lifeti都什me) {

105     try {

106   &nbs人分p;     $dbh = getCon身慢nection();

107 

108         $師大sql = 'DELETE FROM `session` WHER輛熱E expire < ?';

109       &師討nbsp; $stmt = $dbh->prepare那年($sql);

110         $月知stmt->execute(array(time()));

111         $dbh聽微 = NULL;

112    有土     return TRUE;

113     } catch (Excepti輛日on $e) {

114       &nb懂海sp; return FALSE;

115     }

116 }

117 

118 //自定義的session的session id設置函數

119 /*

120  * 由于在session_start()之前,S玩輛ID和session_id()均無效,

121  * 故使用$_GET[session和工_name()]和$_COOK商家IE[session_name()]進(jìn)行檢測。

122  * 如果此兩(liǎng)者均爲空,則媽機表明session尚未建立,需要爲化話新session設置session id。

123  * 通過(guò)MySQL數據庫獲取uuid作科筆爲session id可以更好(hǎo)的避免session房照 id碰撞。

124  */

125 function sessionMysqlId() {

126     if (filter_inpu月放t(INPUT_GET, session_name()) =技訊= '' and

127    子畫;        嗎師 filter_input(INPUT_COOKIE,理森 session_name()) == '') {

128         答白try {

129        件雨     $dbh = getConnection快外();

130     &票那nbsp;       $s購草tmt = $dbh->窗理query('SELEC志熱T uuid() AS uuid就長9;);

131     喝器    &nb如西sp;   $data = $stmt->fetch(PDO身兵::FETCH_ASSOC);

132        在區;     $data = str_repla飛站ce('-', '', $data[東道9;uuid']);

133     &n白關bsp;      年近 session_id($data);

134         &nbs近那p;   return TRUE;

135       &nb來匠sp; } catch (Exception $ex) {

136    行煙;     &城木nbsp;   retu開北rn FALSE;

137         }

138       &n都習bsp; 

139     }

140 }

141 

142 //session啓動函數,包括了sessio哥也n_start()及其之前的所有步驟。

143 function st姐還artSession() {

144    河能 session_set_save_handler(

145    內光;         和刀9;sessionMysqlOpen',

146         &場站nbsp;   '市高;sessionMysqlClo明一se',

147        家兵;     'sessio高友nMysqlRead',

148         &nb雨厭sp;   'sessionMysq是媽lWrite',

149      厭白      南喝 'sessionMysq腦章lDestroy',

150       &nbs哥去p;     'sessionMys個新qlGc');

151     科熱register_shutdown_function(照木'session_write_close聽時9;);

152     sessionMysqlId();

153     session_start喝物();

154 }



  • 姜瑞祥 2018-01-07 17:34:06
    在建站的時(shí)候,都(dōu)會(huì)采用單一入口(多見爲從服子index1.html)的形式,我覺得,單一入口得醫的好(hǎo)處有下面(miàn)兩(liǎng)點: 信村   1.後(hòu)面(mi火新àn)的程序可以統一處理,比如村校說(shuō)要開(kāi)發(fā)時(sh很音í)候用到某個第三方類庫,隻需要在入口文件引入,其餘的程序都(dōu)會(說姐huì)可以引用   2.路徑可以統一處理。因白銀爲都(dōu)是從index1.html開(kāi)始,所以引入文件隻要學短相對(duì)于index1.html的路徑即亮訊可。