Ok. The answer is going to be a bit longer - so patience!
1) Whatever I am going to write is based on the experiments I have done over last couple of days. There may be some knobs/settings/inner working I may not be aware of. If you spot mistakes/ or do not agree then please shout!
2) İlk açıklama - OTURUM veri okuma ve yazılı olduğu
Birden $ _SESSION Betiğinize içinde okur olsa bile oturum verileri tam olarak bir kere okumak olacak. Oturumdan okuma bir bir senaryo bazında olduğunu. Ayrıca veri session_id değil tuşlar dayalı umulur getir.
2) İkinci açıklama - HER ZAMAN SENARYO SONUNDA DİYE YAZMA
A) The write to session save_set_handler is always fired, even for scripts that only "read" from session and never do any writes.
B) The write is only fired once, at the end of the script or if you explicitly call session_write_close. Again, the write is based on session_id and not keys
3) Üçüncü Açıklama: NEDEN BİZ kilitlemeyi İHTİYACINIZ
- Bu yaygara her ne hakkında?
- Biz gerçekten oturum kilitleri ihtiyacınız var mı?
- Biz gerçekten bir Big Lock sarma OKU + yaz İhtiyacım Var
Yaygara açıklamak
Script1
- 1: $ x = S_SESSION ["X"];
- 2: sleep (20);
- 3: if ($ x == 1) {
- 4: / / bir şeyler yap
- 5: $ _SESSION ["X"] = 3;
- 6:}
- 4: exit;
Script 2
- 1: $ x = $ _SESSION ["X"];
- 2: ($ x == 1) {$ _SESSION ["X"] = 2 ise; }
- 3: exit;
Komut-1 zaten çalışırken başka bir komut dosyası tarafından değişti değeri: tutarsızlık bu komut 1 bir oturum değişkeni (3 hat) dayalı bir şey yapıyor olmasıdır. Bu bir iskelet örnek ama noktayı göstermektedir. Artık DOĞRU bir şey dayalı kararlar alıyor olması.
PHP varsayılan oturum kilitleme (Request Seviye kilitleme) kullanırken bu komut 1 kablosu1 okumaya başladım dosyadan okunamıyor çünkü script2 1. hatta engeller. Yani oturum verilerine istekleri tefrika edilir. Script2 bir değer okuduğunda, yeni değerini okumak için garanti edilir.
Açıklanması 4: PHP OTURUM SENKRONİZASYONU DEĞİŞKEN senkronizasyon FARKLI
Değişken bir senkronizasyon gibi sanki insanlar çok PHP oturum eşitleme hakkında konuşmak, kısa sürede herhangi bir komut değişken değeri ve sonraki okuma üzerine yazma gibi oluyor hafıza konumuna yazma yeni değeri almak olacaktır. Biz AÇIKLAMA # 1 gördüğünüz gibi - Bu doğru değil. Komut komut boyunca senaryonun başlangıcında okunan değerleri kullanır ve bazı diğer komut değerleri değişmiş olsa bile, çalışan betik sonraki refresh kadar yeni değerler hakkında bilemezsiniz. Bu çok important noktasıdır.
Ayrıca, hatta PHP büyük kilitleme ile oturum değişiklikleri değerlerin unutmayın. , Gibi şeyler "birinci oluyor komut değeri üzerine olacak" diyerek çok doğru değil. Değer değişimi ne peşinde yani, bu benim bilgim olmadan değiştirmek gerektiğini, tutarsızlık olduğunu, kötü değil.
AÇIKLAMA 5: GERÇEKTEN BÜYÜK KİLİT İHTİYACINIZ musunuz?
Şimdi, biz gerçekten Big Lock (istek düzeyi) ihtiyacım var? Cevap, DB izolasyon durumunda olduğu gibi, bu şeyleri yapmak istiyorum nasıl bağlıdır olmasıdır. $ _SESSION Varsayılan uygulama ile, IMHO, sadece büyük kilit mantıklı. Ben kullanımına benim betik boyunca başında okunan değer gidiyorum o zaman sadece büyük kilit mantıklı. Ben "her zaman", "taze" değerini almak için $ _SESSION uygulanmasını değiştirmek ise o zaman büyük kilit gerekmez.
Biz nesne sürüm gibi bir oturum veri sürüm düzeni uygulamak varsayalım. Komut-1 henüz noktasını yazmak gelmedi çünkü Şimdi, komut dosyası 2 yazma başarılı olacaktır. komut-2 oturum deposuna ve 1 ile sürümünü artırır script 1 çalışır oturumuna yazmak Şimdi zaman, bu (line: 5) başarısız olur -. yapılabilir olsa da, ben bu arzu olduğunu sanmıyorum.
===================================
Dan (1) ve (2), onu takip olursa olsun ne kadar karmaşık komut dosyası, X okur ve Y oturumu yazar ile,
- oturum işleyicisi (okuma) ve yazma () yöntemleri yalnızca bir kez denir
- ve her zaman denir
Şimdi, bazıları hala anlamaya çalışıyorum vb "değişken" düzeyinde kilitleme yapmaya çalışın net özel PHP oturum işlemcileri vardır. Ancak ben karmaşık şemaları lehine değilim.
$ _SESSION Ile PHP betikleri web sayfaları hizmet gerekiyordu ve Mili saniye işlenir olduğunu varsayarsak, ben ek karmaşıklık buna değer olduğunu sanmıyorum. Yazma hile yapmak gerekir sonra Like Peter Zaitsev mentions here ile güncelleme için bir seçme taahhüt.
İşte ben kilitlemeyi uygulamak için yazdığı kodu dahil. Bazı "Yarış simülasyonu" komut ile test etmek güzel olurdu. Ben işe gerektiğine inanıyoruz. Ben net üzerinde bulunan birçok doğru uygulamaları yoktur. Eğer hataları işaret edebilir eğer iyi olurdu. Ben çıplak mysqli'nin ile yaptım.
<?php
namespace com\indigloo\core {
use \com\indigloo\Configuration as Config;
use \com\indigloo\Logger as Logger;
/*
* @todo - examine row level locking between read() and write()
*
*/
class MySQLSession {
private $mysqli ;
function __construct() {
}
function open($path,$name) {
$this->mysqli = new \mysqli(Config::getInstance()->get_value("mysql.host"),
Config::getInstance()->get_value("mysql.user"),
Config::getInstance()->get_value("mysql.password"),
Config::getInstance()->get_value("mysql.database"));
if (mysqli_connect_errno ()) {
trigger_error(mysqli_connect_error(), E_USER_ERROR);
exit(1);
}
//remove old sessions
$this->gc(1440);
return TRUE ;
}
function close() {
$this->mysqli->close();
$this->mysqli = null;
return TRUE ;
}
function read($sessionId) {
Logger::getInstance()->info("reading session data from DB");
//start Tx
$this->mysqli->query("START TRANSACTION");
$sql = " select data from sc_php_session where session_id = '%s' for update ";
$sessionId = $this->mysqli->real_escape_string($sessionId);
$sql = sprintf($sql,$sessionId);
$result = $this->mysqli->query($sql);
$data = '' ;
if ($result) {
$record = $result->fetch_array(MYSQLI_ASSOC);
$data = $record['data'];
}
$result->free();
return $data ;
}
function write($sessionId,$data) {
$sessionId = $this->mysqli->real_escape_string($sessionId);
$data = $this->mysqli->real_escape_string($data);
$sql = "REPLACE INTO sc_php_session(session_id,data,updated_on) VALUES('%s', '%s', now())" ;
$sql = sprintf($sql,$sessionId, $data);
$stmt = $this->mysqli->prepare($sql);
if ($stmt) {
$stmt->execute();
$stmt->close();
} else {
trigger_error($this->mysqli->error, E_USER_ERROR);
}
//end Tx
$this->mysqli->query("COMMIT");
Logger::getInstance()->info("wrote session data to DB");
}
function destroy($sessionId) {
$sessionId = $this->mysqli->real_escape_string($sessionId);
$sql = "DELETE FROM sc_php_session WHERE session_id = '%s' ";
$sql = sprintf($sql,$sessionId);
$stmt = $this->mysqli->prepare($sql);
if ($stmt) {
$stmt->execute();
$stmt->close();
} else {
trigger_error($this->mysqli->error, E_USER_ERROR);
}
}
/*
* @param $age - number in seconds set by session.gc_maxlifetime value
* default is 1440 or 24 mins.
*
*/
function gc($age) {
$sql = "DELETE FROM sc_php_session WHERE updated_on < (now() - INTERVAL %d SECOND) ";
$sql = sprintf($sql,$age);
$stmt = $this->mysqli->prepare($sql);
if ($stmt) {
$stmt->execute();
$stmt->close();
} else {
trigger_error($this->mysqli->error, E_USER_ERROR);
}
}
}
}
?>
Nesne oturum Handler kaydetmek için,
$sessionHandler = new \com\indigloo\core\MySQLSession();
session_set_save_handler(array($sessionHandler,"open"),
array($sessionHandler,"close"),
array($sessionHandler,"read"),
array($sessionHandler,"write"),
array($sessionHandler,"destroy"),
array($sessionHandler,"gc"));
ini_set('session_use_cookies',1);
//Defaults to 1 (enabled) since PHP 5.3.0
//no passing of sessionID in URL
ini_set('session.use_only_cookies',1);
// the following prevents unexpected effects
// when using objects as save handlers
// @see http://php.net/manual/en/function.session-set-save-handler.php
register_shutdown_function('session_write_close');
session_start();
Burada PDO ile yapılan başka bir versiyonudur. Bu bir OturumKimliği varlığı için kontrol ve güncelleştirme veya Ekle yapar. Gereksiz yere her sayfa yük bir SQL sorgusu patlar gibi ben de () açık gelen gc işlevini kaldırdık. Bayat oturumu temizleme kolayca cron script ile yapılabilir. Bu PHP 5.x ise kullanmak sürümü olmalıdır Eğer herhangi bir hata bulursanız bana bildirin!
=========================================
namespace com\indigloo\core {
use \com\indigloo\Configuration as Config;
use \com\indigloo\mysql\PDOWrapper;
use \com\indigloo\Logger as Logger;
/*
* custom session handler to store PHP session data into mysql DB
* we use a -select for update- row leve lock
*
*/
class MySQLSession {
private $dbh ;
function __construct() {
}
function open($path,$name) {
$this->dbh = PDOWrapper::getHandle();
return TRUE ;
}
function close() {
$this->dbh = null;
return TRUE ;
}
function read($sessionId) {
//start Tx
$this->dbh->beginTransaction();
$sql = " select data from sc_php_session where session_id = :session_id for update ";
$stmt = $this->dbh->prepare($sql);
$stmt->bindParam(":session_id",$sessionId, \PDO::PARAM_STR);
$stmt->execute();
$result = $stmt->fetch(\PDO::FETCH_ASSOC);
$data = '' ;
if($result) {
$data = $result['data'];
}
return $data ;
}
function write($sessionId,$data) {
$sql = " select count(session_id) as total from sc_php_session where session_id = :session_id" ;
$stmt = $this->dbh->prepare($sql);
$stmt->bindParam(":session_id",$sessionId, \PDO::PARAM_STR);
$stmt->execute();
$result = $stmt->fetch(\PDO::FETCH_ASSOC);
$total = $result['total'];
if($total > 0) {
//existing session
$sql2 = " update sc_php_session set data = :data, updated_on = now() where session_id = :session_id" ;
} else {
$sql2 = "insert INTO sc_php_session(session_id,data,updated_on) VALUES(:session_id, :data, now())" ;
}
$stmt2 = $this->dbh->prepare($sql2);
$stmt2->bindParam(":session_id",$sessionId, \PDO::PARAM_STR);
$stmt2->bindParam(":data",$data, \PDO::PARAM_STR);
$stmt2->execute();
//end Tx
$this->dbh->commit();
}
/*
* destroy is called via session_destroy
* However it is better to clear the stale sessions via a CRON script
*/
function destroy($sessionId) {
$sql = "DELETE FROM sc_php_session WHERE session_id = :session_id ";
$stmt = $this->dbh->prepare($sql);
$stmt->bindParam(":session_id",$sessionId, \PDO::PARAM_STR);
$stmt->execute();
}
/*
* @param $age - number in seconds set by session.gc_maxlifetime value
* default is 1440 or 24 mins.
*
*/
function gc($age) {
$sql = "DELETE FROM sc_php_session WHERE updated_on < (now() - INTERVAL :age SECOND) ";
$stmt = $this->dbh->prepare($sql);
$stmt->bindParam(":age",$age, \PDO::PARAM_INT);
$stmt->execute();
}
}
}
?>