-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
374 additions
and
109 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
<?php | ||
|
||
/** | ||
* This file is part of CodeIgniter 4 framework. | ||
* | ||
* (c) CodeIgniter Foundation <admin@codeigniter.com> | ||
* | ||
* For the full copyright and license information, please view | ||
* the LICENSE file that was distributed with this source code. | ||
*/ | ||
|
||
namespace CodeIgniter\Session\Handlers\Database; | ||
|
||
use CodeIgniter\Session\Handlers\DatabaseHandler; | ||
|
||
/** | ||
* Session handler for MySQLi | ||
*/ | ||
class MySQLiHandler extends DatabaseHandler | ||
{ | ||
/** | ||
* Lock the session. | ||
*/ | ||
protected function lockSession(string $sessionID): bool | ||
{ | ||
$arg = md5($sessionID . ($this->matchIP ? '_' . $this->ipAddress : '')); | ||
if ($this->db->query("SELECT GET_LOCK('{$arg}', 300) AS ci_session_lock")->getRow()->ci_session_lock) { | ||
$this->lock = $arg; | ||
|
||
return true; | ||
} | ||
|
||
return $this->fail(); | ||
} | ||
|
||
/** | ||
* Releases the lock, if any. | ||
*/ | ||
protected function releaseLock(): bool | ||
{ | ||
if (! $this->lock) { | ||
return true; | ||
} | ||
|
||
if ($this->db->query("SELECT RELEASE_LOCK('{$this->lock}') AS ci_session_lock")->getRow()->ci_session_lock) { | ||
$this->lock = false; | ||
|
||
return true; | ||
} | ||
|
||
return $this->fail(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
<?php | ||
|
||
/** | ||
* This file is part of CodeIgniter 4 framework. | ||
* | ||
* (c) CodeIgniter Foundation <admin@codeigniter.com> | ||
* | ||
* For the full copyright and license information, please view | ||
* the LICENSE file that was distributed with this source code. | ||
*/ | ||
|
||
namespace CodeIgniter\Session\Handlers\Database; | ||
|
||
use CodeIgniter\Session\Handlers\DatabaseHandler; | ||
use ReturnTypeWillChange; | ||
|
||
/** | ||
* Session handler for Postgre | ||
*/ | ||
class PostgreHandler extends DatabaseHandler | ||
{ | ||
/** | ||
* Reads the session data from the session storage, and returns the results. | ||
* | ||
* @param string $id The session ID | ||
* | ||
* @return false|string Returns an encoded string of the read data. | ||
* If nothing was read, it must return false. | ||
*/ | ||
#[ReturnTypeWillChange] | ||
public function read($id) | ||
{ | ||
if ($this->lockSession($id) === false) { | ||
$this->fingerprint = md5(''); | ||
|
||
return ''; | ||
} | ||
|
||
if (! isset($this->sessionID)) { | ||
$this->sessionID = $id; | ||
} | ||
|
||
$builder = $this->db->table($this->table) | ||
->select("encode(data, 'base64') AS data") | ||
->where('id', $id); | ||
|
||
if ($this->matchIP) { | ||
$builder = $builder->where('ip_address', $this->ipAddress); | ||
} | ||
|
||
$result = $builder->get()->getRow(); | ||
|
||
if ($result === null) { | ||
// PHP7 will reuse the same SessionHandler object after | ||
// ID regeneration, so we need to explicitly set this to | ||
// FALSE instead of relying on the default ... | ||
$this->rowExists = false; | ||
$this->fingerprint = md5(''); | ||
|
||
return ''; | ||
} | ||
|
||
$result = is_bool($result) ? '' : base64_decode(rtrim($result->data), true); | ||
|
||
$this->fingerprint = md5($result); | ||
$this->rowExists = true; | ||
|
||
return $result; | ||
} | ||
|
||
/** | ||
* Writes the session data to the session storage. | ||
* | ||
* @param string $id The session ID | ||
* @param string $data The encoded session data | ||
*/ | ||
public function write($id, $data): bool | ||
{ | ||
if ($this->lock === false) { | ||
return $this->fail(); | ||
} | ||
|
||
if ($this->sessionID !== $id) { | ||
$this->rowExists = false; | ||
$this->sessionID = $id; | ||
} | ||
|
||
if ($this->rowExists === false) { | ||
$insertData = [ | ||
'id' => $id, | ||
'ip_address' => $this->ipAddress, | ||
'data' => '\x' . bin2hex($data), | ||
]; | ||
|
||
if (! $this->db->table($this->table)->set('timestamp', 'now()', false)->insert($insertData)) { | ||
return $this->fail(); | ||
} | ||
|
||
$this->fingerprint = md5($data); | ||
$this->rowExists = true; | ||
|
||
return true; | ||
} | ||
|
||
$builder = $this->db->table($this->table)->where('id', $id); | ||
|
||
if ($this->matchIP) { | ||
$builder = $builder->where('ip_address', $this->ipAddress); | ||
} | ||
|
||
$updateData = []; | ||
|
||
if ($this->fingerprint !== md5($data)) { | ||
$updateData['data'] = '\x' . bin2hex($data); | ||
} | ||
|
||
if (! $builder->set('timestamp', 'now()', false)->update($updateData)) { | ||
return $this->fail(); | ||
} | ||
|
||
$this->fingerprint = md5($data); | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* Cleans up expired sessions. | ||
* | ||
* @param int $max_lifetime Sessions that have not updated | ||
* for the last max_lifetime seconds will be removed. | ||
* | ||
* @return false|int Returns the number of deleted sessions on success, or false on failure. | ||
*/ | ||
#[ReturnTypeWillChange] | ||
public function gc($max_lifetime) | ||
{ | ||
$separator = '\''; | ||
$interval = implode($separator, ['', "{$max_lifetime} second", '']); | ||
|
||
return $this->db->table($this->table)->where('timestamp <', "now() - INTERVAL {$interval}", false)->delete() ? 1 : $this->fail(); | ||
} | ||
|
||
/** | ||
* Lock the session. | ||
*/ | ||
protected function lockSession(string $sessionID): bool | ||
{ | ||
$arg = "hashtext('{$sessionID}')" . ($this->matchIP ? ", hashtext('{$this->ipAddress}')" : ''); | ||
if ($this->db->simpleQuery("SELECT pg_advisory_lock({$arg})")) { | ||
$this->lock = $arg; | ||
|
||
return true; | ||
} | ||
|
||
return $this->fail(); | ||
} | ||
|
||
/** | ||
* Releases the lock, if any. | ||
*/ | ||
protected function releaseLock(): bool | ||
{ | ||
if (! $this->lock) { | ||
return true; | ||
} | ||
|
||
if ($this->db->simpleQuery("SELECT pg_advisory_unlock({$this->lock})")) { | ||
$this->lock = false; | ||
|
||
return true; | ||
} | ||
|
||
return $this->fail(); | ||
} | ||
} |
Oops, something went wrong.