diff --git a/.idea/Session.iml b/.idea/Session.iml
deleted file mode 100644
index c956989..0000000
--- a/.idea/Session.iml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index 8b47dd8..0000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/php.xml b/.idea/php.xml
deleted file mode 100644
index 4f0611e..0000000
--- a/.idea/php.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 94a25f7..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/README.md b/README.md
index 9e6c643..179550f 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@ Basic usage:
## Registering Error Handler (optional)
```php
#This method must be implemented before Session::start
-Session::registerErrorHandler(function($error, $error_code)
+Session::registerErrorHandler(function(string $error, int $error_code)
{
#Debug::Log($error);
});
@@ -118,3 +118,37 @@ $session = Session::start($optional_session_namespace, $auto_save);
```
Which allows uncommitted (forgot to commit) changes to saves automatically. Is set to `false`, uncommitted changes will be discarded.
+
+## Change Log *v1.03.0*
+ - `start` method now accepts `null` arg as namespace.
+ - Default session driver is now set to `file`.
+ - Auto delete session after rotate is now defaulted to `false`.
+ - A `setConfigPath` method has been added.
+ ```php
+ #This method must be implemented before Session::start
+ Session::setConfigPath('my/config/path/config.php');
+ ```
+ - A set queue has been added
+ ```php
+ $session->name = 'foo';
+ $session->name = 'foo1';
+
+var_dump($session->name); # Outputs 'foo1'
+
+ $session->name('foo')
+ $session->name('foo1');
+
+ var_dump($session->name); # Outputs ['foo', 'foo1'];
+
+ # Array
+ $session->name = ['foo', 'bar', ...];
+ # is same as
+ $session->name('foo', 'bar', ...);
+ ```
+
+When flash are placed using the new queue method, they will be dispatched one after another on each request
+```php
+$session->flash->message('invalid 1', 'invalid 2');
+```
+With the above `invalid 1` will disptach on first load/reload and `invalid 2` on second.
+
diff --git a/src/Session.php b/src/Session.php
index 41f32a8..b4745a6 100644
--- a/src/Session.php
+++ b/src/Session.php
@@ -44,22 +44,18 @@
class Session
{
private static $initialized = [];
-
private static $started = false;
-
private static $class = null;
-
private static $ssl_enabled = true;
-
public static $write = false;
-
+ private static $custom_config = null;
public static $id = '';
private static function init()
{
$DS = DIRECTORY_SEPARATOR;
- $path = __DIR__ . $DS . 'Session' . $DS;
- $config = include($path . 'config.php');
+ $path = __DIR__ . "{$DS}Session{$DS}";
+ $config = include(self::$custom_config ?? $path . 'config.php');
self::$initialized = $config;
$driver = $config['driver'];
@@ -67,13 +63,13 @@ private static function init()
if(! is_dir($path . self::$class))
{
- throw new \RuntimeException('No driver found for ' . self::$class);
+ throw new RuntimeException('No driver found for ' . self::$class);
}
self::$ssl_enabled = self::$initialized['encrypt_data'];
if (self::$ssl_enabled && ! extension_loaded('openssl'))
{
- throw new \RuntimeException('The openssl extension is missing. Please check your PHP configuration.');
+ throw new RuntimeException('The openssl extension is missing. Please check your PHP configuration.');
}
@@ -81,7 +77,7 @@ private static function init()
{
if (! extension_loaded(self::$class))
{
- throw new \RuntimeException('The ' . self::$class . ' extension is missing. Please check your PHP configuration.');
+ throw new RuntimeException('The ' . self::$class . ' extension is missing. Please check your PHP configuration.');
}
}
@@ -89,7 +85,7 @@ private static function init()
$secured = $config['secure'];
if ($secured !== true && $secured !== false && $secured !== null)
{
- throw new \RuntimeException('config.secure expected value to be a boolean or null');
+ throw new RuntimeException('config.secure expected value to be a boolean or null');
}
if ($secured == null)
@@ -145,11 +141,11 @@ public static function id(string $id = ''): string
{
if (self::$started)
{
- throw new \RuntimeException('Session is active. The session id must be set before Session::start().');
+ throw new RuntimeException('Session is active. The session id must be set before Session::start().');
}
elseif (headers_sent($filename, $line_num))
{
- throw new \RuntimeException(sprintf('ID must be set before any output is sent to the browser (file: %s, line: %s)', $filename, $line_num));
+ throw new RuntimeException(sprintf('ID must be set before any output is sent to the browser (file: %s, line: %s)', $filename, $line_num));
}
elseif (preg_match('/^[-,a-zA-Z0-9]{1,128}$/', $id) < 1)
{
@@ -165,6 +161,19 @@ public static function id(string $id = ''): string
}
+ /**
+ * Sets a file where config settings will be loaded from.
+ *
+ * @param string $path_to_file
+ */
+ public static function setConfigFile(string $path_to_file)
+ {
+ if (! is_file($path_to_file))
+ {
+ throw new RuntimeException('config was not found in (' . $path_to_file . ') or not enough permission.');
+ }
+ self::$custom_config = $path_to_file;
+ }
/**
* starts a new session
*
@@ -172,7 +181,7 @@ public static function id(string $id = ''): string
* @param bool $auto_commit (Alternative for https://github.com/Ghostff/Session/issues/4)
* @return Save
*/
- public static function start(string $namespace = '__GLOBAL', bool $auto_commit = true): Save
+ public static function start(string $namespace = null, bool $auto_commit = true): Save
{
if (empty(self::$initialized))
{
@@ -180,7 +189,7 @@ public static function start(string $namespace = '__GLOBAL', bool $auto_commit =
}
self::$started = true;
- self::$initialized['namespace'] = $namespace;
+ self::$initialized['namespace'] = $namespace ?? '__GLOBAL';
$handler = new Save(self::$initialized);
if ($auto_commit)
{
@@ -296,6 +305,7 @@ public static function encrypt(string $data): string
$iv = substr($salted, 32,16);
$encrypted_data = openssl_encrypt($data, 'AES-256-CBC', $key, 1, $iv);
+
return base64_encode($salt . $encrypted_data);
}
-}
\ No newline at end of file
+}
diff --git a/src/Session/Cookie/Handler.php b/src/Session/Cookie/Handler.php
index a918c3a..264f331 100644
--- a/src/Session/Cookie/Handler.php
+++ b/src/Session/Cookie/Handler.php
@@ -40,12 +40,11 @@
declare(strict_types=1);
namespace Session\Cookie;
-use Session;
+use Session, SessionHandlerInterface;
-class Handler implements \SessionHandlerInterface
+class Handler implements SessionHandlerInterface
{
-
public function open($savePath, $sessionName)
{
return true;
@@ -87,4 +86,4 @@ public function gc($max_life_time): bool
{
return true;
}
-}
\ No newline at end of file
+}
diff --git a/src/Session/File/Handler.php b/src/Session/File/Handler.php
index d6dfe5a..4cb0307 100644
--- a/src/Session/File/Handler.php
+++ b/src/Session/File/Handler.php
@@ -39,12 +39,11 @@
declare(strict_types=1);
-
namespace Session\File;
-use Session;
+use Session, SessionHandlerInterface;
-class Handler implements \SessionHandlerInterface
+class Handler implements SessionHandlerInterface
{
private $savePath;
@@ -100,4 +99,4 @@ public function gc($max_life_time): bool
return true;
}
-}
\ No newline at end of file
+}
diff --git a/src/Session/Memcached/Handler.php b/src/Session/Memcached/Handler.php
index ca90bd4..cabcc42 100644
--- a/src/Session/Memcached/Handler.php
+++ b/src/Session/Memcached/Handler.php
@@ -37,28 +37,23 @@
*
*/
-
declare(strict_types=1);
namespace Session\Memcached;
-use Session, Memcached;
+use Memcached, RuntimeException, Session, SessionHandlerInterface;
-class Handler implements \SessionHandlerInterface
+class Handler implements SessionHandlerInterface
{
- private $config = [];
-
private $conn = null;
-
private $expire = 0;
-
private $name = null;
public function __construct(array $config)
{
if (! isset($config['memcached']))
{
- throw new \RuntimeException('No memcached configuration found in config file.');
+ throw new RuntimeException('No memcached configuration found in config file.');
}
$this->expire = $config['expiration'];
@@ -112,4 +107,4 @@ public function gc($max_life_time): bool
{
return true;
}
-}
\ No newline at end of file
+}
diff --git a/src/Session/Pdo/Handler.php b/src/Session/Pdo/Handler.php
index 3635d01..2995067 100644
--- a/src/Session/Pdo/Handler.php
+++ b/src/Session/Pdo/Handler.php
@@ -37,28 +37,23 @@
*
*/
-
declare(strict_types=1);
namespace Session\Pdo;
-use PDO, Session;
+use PDO, PDOException, RuntimeException, Session, SessionHandlerInterface;
-class Handler implements \SessionHandlerInterface
+class Handler implements SessionHandlerInterface
{
-
private $conn = null;
-
private $table = null;
-
private $persistent = false;
-
public function __construct(array $config)
{
if (! isset($config['pdo']))
{
- throw new \RuntimeException('No pdo configuration found in config file.');
+ throw new RuntimeException('No pdo configuration found in config file.');
}
$config = $config['pdo'];
@@ -77,7 +72,7 @@ public function __construct(array $config)
{
$this->conn->query('SELECT 1 FROM `' . $table . '` LIMIT 1');
}
- catch (\PDOException $e)
+ catch (PDOException $e)
{
$this->conn->query('CREATE TABLE `' . $table . '` (
`id` varchar(250) NOT NULL,
@@ -151,4 +146,4 @@ public function gc($max_life_time): bool
$statement = null;
return $completed;
}
-}
\ No newline at end of file
+}
diff --git a/src/Session/Redis/Handler.php b/src/Session/Redis/Handler.php
index 0f32b6e..8e4be36 100644
--- a/src/Session/Redis/Handler.php
+++ b/src/Session/Redis/Handler.php
@@ -37,28 +37,23 @@
*
*/
-
declare(strict_types=1);
namespace Session\Redis;
-use Session, Redis;
+use Redis, RuntimeException, Session, SessionHandlerInterface;
-class Handler implements \SessionHandlerInterface
+class Handler implements SessionHandlerInterface
{
- private $config = [];
-
private $conn = null;
-
private $expire = 0;
-
private $name = null;
public function __construct(array $config)
{
if (! isset($config['redis']))
{
- throw new \RuntimeException('No Redis configuration found in config file.');
+ throw new RuntimeException('No Redis configuration found in config file.');
}
$this->expire = $config['expiration'];
@@ -114,4 +109,4 @@ public function gc($max_life_time): bool
{
return true;
}
-}
\ No newline at end of file
+}
diff --git a/src/Session/Save.php b/src/Session/Save.php
index b78f135..37b42fd 100644
--- a/src/Session/Save.php
+++ b/src/Session/Save.php
@@ -37,30 +37,66 @@
*
*/
-
declare(strict_types=1);
namespace Session;
+
+use RuntimeException;
use Session;
+/**
+ * @property Save $flash
+ * @property Save $remove
+ */
class Save
{
+ /**
+ * @var array
+ */
private $config = [];
+ /**
+ * @var bool
+ */
+ private $internal = false;
+
+ /**
+ * @var array
+ */
+ private static $checkpoint = [];
+
+ /**
+ * @var bool
+ */
public $all_was_committed = true;
+ /**
+ * Gets client IP address.
+ *
+ * @return string
+ */
private function ip(): string
{
return $_SERVER['HTTP_CLIENT_IP'] ?? ($_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR']);
}
- private function browser()
+ /**
+ * Gets clients browser.
+ *
+ * @return string
+ */
+ private function browser(): string
{
#you can make this more sophisticated lol
- return $_SERVER['HTTP_USER_AGENT'];
+ return $_SERVER['HTTP_USER_AGENT'] ?? '';
}
+ /**
+ * Session validation.
+ *
+ * @return bool
+ */
private function checkSession(): bool
{
@@ -190,7 +226,7 @@ public function __set(string $name, $value)
if ($last == 'remove')
{
- throw new \RuntimeException('you cant use remove to set a value');
+ throw new RuntimeException('you cant use remove to set a value');
}
else
{
@@ -199,6 +235,54 @@ public function __set(string $name, $value)
}
}
+ /**
+ * Append data to an existing session. (cast existing to array)
+ *
+ * @param string $name
+ * @param array $values
+ * @return Save
+ */
+ public function __call(string $name, array $values): Save
+ {
+ $this->internal = true;
+ $called = $this->config['last'];
+
+ $stack = ($called == 'flash') ? ($this->{$called}->{$name} ?? []) : $this->{$name};
+
+ $key = "{$called}:{$name}";
+ if (! array_key_exists($key, self::$checkpoint))
+ {
+ self::$checkpoint[$key] = 0;
+ }
+
+ foreach ($values as $value)
+ {
+ if ($called == 'flash')
+ {
+ $stack[':bittr_queued'][self::$checkpoint[$key]] = $value;
+ }
+ else
+ {
+ $stack[self::$checkpoint[$key]] = $value;
+ }
+
+ self::$checkpoint[$key]++;
+ }
+
+ if ($called == 'flash')
+ {
+ $this->{$called}->{$name} = $stack;
+ }
+ else
+ {
+ $this->{$name} = $stack;
+ }
+
+ $this->internal = false;
+
+ return $this;
+ }
+
/**
* Retrieves value from active session or segment
*
@@ -233,8 +317,23 @@ public function __get(string $name)
elseif ($last == 'flash')
{
$value = $this->config['session'][$namespace][$segment][$last][$name];
- unset($this->config['session'][$namespace][$segment][$last][$name]);
- $this->commit();
+ if (! $this->internal)
+ {
+ $flash =& $this->config['session'][$namespace][$segment][$last][$name];
+ if (isset($flash[':bittr_queued']))
+ {
+ $value = array_shift($flash[':bittr_queued']);
+ if (empty($flash[':bittr_queued']))
+ {
+ $flash = null;
+ }
+ }
+ else
+ {
+ unset($flash);
+ }
+ $this->commit();
+ }
return $value;
}
if ($last == 'remove')
@@ -270,7 +369,7 @@ public function all(string $segment = ''): array
}
else
{
- throw new \RuntimeException('segment ' . $segment . ' does not exist.');
+ throw new RuntimeException('segment ' . $segment . ' does not exist.');
}
}
}
@@ -304,11 +403,11 @@ public function commit()
* @param bool $delete_old
* @param bool $write_nd_close
*/
- public function rotate(bool $delete_old = true, bool $write_nd_close = true)
+ public function rotate(bool $delete_old = false, bool $write_nd_close = true)
{
if (headers_sent($filename, $line_num))
{
- throw new \RuntimeException(sprintf('ID must be regenerated before any output is sent to the browser. (file: %s, line: %s)', $filename, $line_num));
+ throw new RuntimeException(sprintf('ID must be regenerated before any output is sent to the browser. (file: %s, line: %s)', $filename, $line_num));
}
session_start();
@@ -323,6 +422,8 @@ public function rotate(bool $delete_old = true, bool $write_nd_close = true)
}
/**
+ * Clears all data in a specific segment or current namespace.
+ *
* Clears all the data is a specific namespace or segment
* @param string $segment
*/
@@ -353,7 +454,10 @@ public function clear(string $segment = '')
}
/**
+ * Checks if data exist is current namespace or segment.
+ *
* @param string $name
+ * @param string|null $segment
* @param bool $in_flash
* @return bool
*/
@@ -388,4 +492,4 @@ public function destroy()
$this->config['session'] = [];
}
-}
\ No newline at end of file
+}
diff --git a/src/Session/Segment.php b/src/Session/Segment.php
index 2fa2e58..e4dae58 100644
--- a/src/Session/Segment.php
+++ b/src/Session/Segment.php
@@ -37,20 +37,33 @@
*
*/
-
declare(strict_types=1);
-
namespace Session;
class Segment
{
+ /**
+ * @var null|string
+ */
private $segment = null;
+ /**
+ * @var array|null
+ */
private $config = null;
+ /**
+ * @var null
+ */
private $handler = null;
+ /**
+ * Segment constructor.
+ * @param string $name
+ * @param array $config
+ * @param $handler
+ */
public function __construct(string $name, array &$config, $handler)
{
$this->segment = 'segment:' . $name;
@@ -58,15 +71,24 @@ public function __construct(string $name, array &$config, $handler)
$this->handler = $handler;
}
+ /**
+ * @param string $name
+ * @param $value
+ * @return mixed
+ */
public function __set(string $name, $value)
{
$this->config['segment'] = $this->segment;
return $this->handler->{$name} = $value;
}
+ /**
+ * @param string $name
+ * @return mixed
+ */
public function __get(string $name)
{
$this->config['segment'] = $this->segment;
return $this->handler->{$name};
}
-}
\ No newline at end of file
+}
diff --git a/src/Session/config.php b/src/Session/config.php
index dbcb379..7ccc3cd 100644
--- a/src/Session/config.php
+++ b/src/Session/config.php
@@ -38,7 +38,7 @@
*/
return [
- 'driver' => 'cookie', # Name of session driver to use: [file|pdo|cookie|redis|memcached]
+ 'driver' => 'file', # Name of session driver to use: [file|pdo|cookie|redis|memcached]
'name' => '_Bittr_SESSID', # session name
'cache_limiter' => 'none', # http://php.net/manual/en/function.session-cache-limiter.php