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.

201 lines
4.1 KiB

<?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;
}
}