1. Origin of the problemSlightly larger websites usually have several servers. Each server runs modules with different functions and uses different second-level domain names. A comprehensive website , the user system is unified, that is, a set of user names and passwords can be used to log in to each module of the entire website. It is relatively easy for each server to share user data. You only need to put a database server on the back end, and each server can access user data through a unified interface. But there is still a problem, that is, after the user logs in to this server, when entering other modules of another server, he still needs to log in again. This is a one-time login, and all common problems are mapped to technology. In fact, it is between various servers. How to share SESSION data.
2. The working principle of PHP SESSION
Before solving the problem, let’s first understand the working principle of PHP SESSION. When the client (such as a browser) logs in to the website, the visited PHP page can use session_start() to open SESSION, which will generate the client's unique identification SESSION ID (this ID can be obtained/set through the function session_id()). The SESSION ID can be retained on the client in two ways, so that the PHP program can learn the client's SESSION ID when requesting different pages; one is to automatically add the SESSION ID to the GET URL, or the POST form, by default. Under the first method, the variable name is PHPSESSID; the other method is to save the SESSION ID in the COOKIE through COOKIE. By default, the name of this COOKIE is PHPSESSID. Here we mainly use the COOKIE method for explanation, because it is widely used.
So where is the SESSION data stored? On the server side of course, but instead of saving in memory, it's saved in a file or database. By default, the SESSION saving method set in php.ini is files (session.save_handler = files), that is, the SESSION data is saved by reading and writing files, and the directory where the SESSION file is saved is specified by session.save_path, and the file name starts with sess_ is the prefix, followed by SESSION ID, such as: sess_c72665af28a8b14c0fe11afe3b59b51b. The data in the file is the SESSION data after serialization. If the number of visits is large, there may be more SESSION files generated. In this case, you can set up a hierarchical directory to save SESSION files, which will improve the efficiency a lot. The setting method is: session.save_path="N;/save_path", N is hierarchical. level, save_path is the starting directory. When writing SESSION data, PHP will obtain the client's SESSION_ID, and then use this SESSION ID to find the corresponding SESSION file in the specified SESSION file storage directory. If it does not exist, create it, and finally serialize the data and write it to the file. . Reading SESSION data is a similar operation process. The read data needs to be deserialized and the corresponding SESSION variable is generated.
3. The main obstacles and solutions to multi-server sharing SESSIONBy understanding the working principle of SESSION, we can find that by default, each server will each share the same
one client Generate SESSION ID. For example, for the same user browser, the SESSION ID generated by server A is 30de1e9de3192ba6ce2992d27a1b6a0a, while the SESSION ID generated by server B is c72665af28a8b14c0fe11afe3b59b51b. In addition, PHP's SESSION data are stored separately in the file system of
this server.
After identifying the problem, you can start to solve it. If you want to share SESSION data, you must achieve two goals: One is that the SESSION ID generated by each server for the same client must be the same and can be passed through the same COOKIE, which means that each server must be able to read the same SESSION ID. COOKIE named PHPSESSID;
The other is that the storage method/location of SESSION data must ensure that each server can access it. Simply put, multiple
servers share the client's SESSION ID and must also share the server's SESSION data.
The realization of the first goal is actually very simple. You only need to specially set the domain of COOKIE.
By default, the domain of COOKIE is the domain name/IP address of the current server, and the domain If they are different, the COOKIES set by each server cannot access each other.
4. Code ImplementationFirst create a data table. The SQL statement of MySQL is as follows: CREATE TABLE `sess` ( `sesskey` varchar(32) NOT NULL default '', `expiry` bigint(20) NOT NULL default '0', `data` longtext NOT NULL, PRIMARY KEY (`sesskey`), KEY `expiry` (`expiry`) ) TYPE=MyISAM sesskey is the SESSION ID, expiry is the SESSION expiration time, data is used to save SESSION data. By default, SESSION data is saved in file mode. If you want to save it in database mode, you must redefine the processing functions of each SESSION operation.PHP provides the session_set_save_handle() function. You can use this function to customize the SESSION processing process. Of course, you must first change session.save_handler to user, which can be set in PHP: session_module_name('user');
Next Let’s focus on the session_set_save_handle() function.
This function has six parameters: session_set_save_handler (string open, string close,
string read, string write, string destroy, string gc) Each parameter is the function name of each operation. , these operations are:
Open, close, read, write, destroy, garbage collection. There are detailed examples in the PHP manual.
Here we use OO to implement these operations. The detailed code is as follows:
<br><?php define ( 'MY_SESS_TIME' , 3600 ); <br>//SESSION 生存时长 <br>//类定义 class My_Sess { function init () { $domain = '.infor96.com' ; <br>//不使用 GET/POST 变量方式 ini_set ( 'session.use_trans_sid' , 0 ); <br>//设置垃圾回收最大生存时间 ini_set ( 'session.gc_maxlifetime' , MY_SESS_TIME ); <br>//使用 COOKIE 保存 SESSION ID 的方式 ini_set ( 'session.use_cookies' , 1 ); <br>ini_set ( 'session.cookie_path' , '/' );<br>//多主机共享保存 SESSION ID 的 COOKIE ini_set ( 'session.cookie_domain' , $domain ); <br>//将 session.save_handler 设置为 user, <br>//而不是默认的 files session_module_name ( 'user' ); <br>//定义 SESSION 各项操作所对应的方法名: session_set_save_handler ( array( 'My_Sess' , 'open' ), <br>//对应于静态方法 My_Sess::open(),<br>下同。 <br>array( 'My_Sess' , 'close' ), array( 'My_Sess' , 'read' ),<br>array( 'My_Sess' , 'write' ), array( 'My_Sess' , 'destroy' ),<br>array( 'My_Sess' , 'gc' ) ); }<br>//end function function open ( $save_path , $session_name ) { return true ; } <br>//end function function close () { global $MY_SESS_CONN ; if ( $MY_SESS_CONN ) {<br>//关闭数据库连接 $MY_SESS_CONN -> Close (); } return true ; }<br>//end function function read ( $sesskey ) { global $MY_SESS_CONN ;<br>$sql = 'SELECT data FROM sess WHERE sesskey=' <br>. $MY_SESS_CONN -> qstr ( $sesskey ) . ' AND expiry>=' . time ();<br>$rs =& $MY_SESS_CONN -> Execute ( $sql ); <br>if ( $rs ) { if ( $rs -> EOF ) { return '' ; } else {<br>//读取到对应于 SESSION ID 的 SESSION 数据 $v = $rs -> fields [ 0 ]; $rs -> Close (); return $v ; } <br>//end if } <br>//end if return '' ; } <br>//end function function write ( $sesskey , $data ) { global $MY_SESS_CONN ; $qkey = $MY_SESS_CONN -> qstr ( $sesskey );<br>$expiry = time () + My_SESS_TIME ; <br>//设置过期时间<br>//写入 SESSION $arr = array( 'sesskey' => $qkey , 'expiry' => $expiry , 'data' => $data );<br>$MY_SESS_CONN -> Replace ( 'sess' , $arr , 'sesskey' , $autoQuote = true );<br>return true ; } <br>//end function function destroy ( $sesskey ) { global $MY_SESS_CONN ;<br>$sql = 'DELETE FROM sess WHERE sesskey=' . $MY_SESS_CONN -> qstr ( $sesskey );<br>$rs =& $MY_SESS_CONN -> Execute ( $sql ); return true ; }<br>//end function function gc ( $maxlifetime = null ) { global $MY_SESS_CONN ;<br>$sql = 'DELETE FROM sess WHERE expiry<' . time (); $MY_SESS_CONN -> Execute ( $sql );<br>//由于经常性的对表 sess 做删除操作,容易产生碎片,<br>//所以在垃圾回收中对该表进行优化操作。<br>$sql = 'OPTIMIZE TABLE sess' ;<br>$MY_SESS_CONN -> Execute ( $sql ); return true ; } <br>//end function } ///:~<br>//使用 ADOdb 作为数据库抽象层。 require_once( 'adodb/adodb.inc.php' );<br>//数据库配置项,可放入配置文件中(如:config.inc.php)。 $db_type = 'mysql' ;<br>$db_host = '192.168.212.1' ; <br>$db_user = 'sess_user' ; <br>$db_pass = 'sess_pass' ; $db_name = 'sess_db' ;<br>//创建数据库连接,这是一个全局变量。 $GLOBALS [ 'MY_SESS_CONN' ] =& ADONewConnection ( $db_type ); <br>$GLOBALS [ 'MY_SESS_CONN' ]-> Connect ( $db_host , $db_user , $db_pass , $db_name );<br>//初始化 SESSION 设置,必须在 session_start() 之前运行!! My_Sess :: init (); ?> <br> Copy after login |
(Editor: