A super easy PHP Framework for web development!
https://github.com/exacti/phacil-framework
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
202 lines
4.1 KiB
202 lines
4.1 KiB
10 months ago
|
<?php
|
||
|
/**
|
||
|
* Copyright © 2024 ExacTI Technology Solutions. All rights reserved.
|
||
|
* GPLv3 General License.
|
||
|
* https://exacti.com.br
|
||
|
* Phacil PHP Framework - https://github.com/exacti/phacil-framework
|
||
|
*/
|
||
|
|
||
|
|
||
|
namespace Phacil\Framework\Session\Handlers;
|
||
|
|
||
|
/**
|
||
|
* File session handler
|
||
|
*
|
||
|
* @since 2.0.0
|
||
|
* @package Phacil\Framework\Session;
|
||
|
*/
|
||
|
class File implements \Phacil\Framework\Session\Api\HandlerInterface
|
||
|
{
|
||
|
const KEY_EXPIRES = 'session_expires';
|
||
|
|
||
|
const SHORT_NAME = 'file';
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* @var \Phacil\Framework\Config
|
||
|
*/
|
||
|
private $config;
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* @var \Phacil\Framework\Encryption
|
||
|
*/
|
||
|
private $encryptor;
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* @var \Phacil\Framework\Json
|
||
|
*/
|
||
|
private $json;
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* @var bool
|
||
|
*/
|
||
|
protected $isFirstSession = true;
|
||
|
|
||
|
/**
|
||
|
* Constructor
|
||
|
*
|
||
|
* @param \Phacil\Framework\Config $config
|
||
|
*/
|
||
|
public function __construct(
|
||
|
\Phacil\Framework\Config $config,
|
||
|
\Phacil\Framework\Encryption $encryption,
|
||
|
\Phacil\Framework\Json $json
|
||
|
){
|
||
|
$this->config = $config;
|
||
|
$this->encryptor = $encryption;
|
||
|
$this->json = $json;
|
||
|
if(!\Phacil\Framework\Config::DIR_SESSION())
|
||
|
\Phacil\Framework\Config::DIR_SESSION(\Phacil\Framework\Config::DIR_CACHE()."sessions/");
|
||
|
|
||
|
$this->checkDir();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return void
|
||
|
* @throws \Phacil\Framework\Exception
|
||
|
*/
|
||
|
protected function checkDir()
|
||
|
{
|
||
|
if (!is_dir(\Phacil\Framework\Config::DIR_SESSION())) {
|
||
|
mkdir(\Phacil\Framework\Config::DIR_SESSION(), 0764, true);
|
||
|
}
|
||
|
if (!is_writable(\Phacil\Framework\Config::DIR_SESSION())) {
|
||
|
throw new \Phacil\Framework\Exception(
|
||
|
"The session dir storage doesn't exist or isn't writable. Verify the permissions and try again."
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** {@inheritdoc} */
|
||
|
public function getFailedLockAttempts() { }
|
||
|
|
||
|
/** {@inheritdoc} */
|
||
|
public function setName($name) { }
|
||
|
|
||
|
/** @return int */
|
||
|
protected function getLifetime()
|
||
|
{
|
||
|
return (int)$this->config->get('session_expire') ?: self::DEFAULT_SESSION_LIFETIME;
|
||
|
}
|
||
|
|
||
|
/** @return int */
|
||
|
protected function getFirstLifetime()
|
||
|
{
|
||
|
return (int)$this->config->get('session_first_lifetime') ?: self::DEFAULT_SESSION_FIRST_LIFETIME;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $hash
|
||
|
* @return string|false
|
||
|
*/
|
||
|
private function hashed($hash)
|
||
|
{
|
||
|
//$this->encryptor->setHashAlgo('sha256');
|
||
|
return $this->encryptor->hash($hash) ?: $hash;
|
||
|
//return $hash;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritdoc}
|
||
|
*/
|
||
|
#[\ReturnTypeWillChange]
|
||
|
public function close()
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritdoc}
|
||
|
*/
|
||
|
#[\ReturnTypeWillChange]
|
||
|
public function open($savePath, $sessionName)
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritdoc}
|
||
|
*/
|
||
|
#[\ReturnTypeWillChange]
|
||
|
public function read($session_id)
|
||
|
{
|
||
|
$file = \Phacil\Framework\Config::DIR_SESSION() . 'sess_' . $this->hashed(basename($session_id));
|
||
|
|
||
|
if (is_file($file)) {
|
||
|
$data = $this->json->decode(file_get_contents($file));
|
||
|
if($data && $data[self::KEY_EXPIRES] >= time()){
|
||
|
$this->isFirstSession = false;
|
||
|
return $data['data'];
|
||
|
} else {
|
||
|
$this->destroy($session_id);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritdoc}
|
||
|
*/
|
||
|
#[\ReturnTypeWillChange]
|
||
|
public function write($session_id, $data)
|
||
|
{
|
||
|
$data = [
|
||
|
'data' => $data,
|
||
|
self::KEY_EXPIRES => time() + ($this->isFirstSession ? $this->getFirstLifetime() : $this->getLifetime())
|
||
|
];
|
||
|
file_put_contents(\Phacil\Framework\Config::DIR_SESSION() . 'sess_' . $this->hashed(basename($session_id)), $this->json->encode($data));
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritdoc}
|
||
|
*/
|
||
|
#[\ReturnTypeWillChange]
|
||
|
public function destroy($session_id)
|
||
|
{
|
||
|
$file = \Phacil\Framework\Config::DIR_SESSION() . 'sess_' . $this->hashed(basename($session_id));
|
||
|
|
||
|
if (is_file($file) && is_writable($file)) {
|
||
|
return unlink($file);
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritdoc}
|
||
|
*/
|
||
|
#[\ReturnTypeWillChange]
|
||
|
public function gc($maxLifeTime)
|
||
|
{
|
||
|
if (round(mt_rand(1, $this->config->get('session_divisor') / $this->config->get('session_probability'))) == 1) {
|
||
|
$expire = time() - $this->config->get('session_expire');
|
||
|
|
||
|
$files = scandir(\Phacil\Framework\Config::DIR_SESSION());
|
||
|
|
||
|
foreach ($files as $file) {
|
||
|
if (is_file($file) && filemtime($file) < $expire && is_writable($file)) {
|
||
|
unlink($file);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
}
|