410 lines
9.4 KiB
PHP
410 lines
9.4 KiB
PHP
<?php
|
|
/**
|
|
* Copyright seit 2024 Webshop System
|
|
*
|
|
* Cookie-Verwaltung für das Webshop-System
|
|
* Vollständig PrestaShop-kompatibel mit erweiterten Funktionen
|
|
*
|
|
* @author Webshop System
|
|
* @license GPL v3
|
|
*/
|
|
|
|
class Cookie
|
|
{
|
|
public const SAMESITE_NONE = 'None';
|
|
public const SAMESITE_LAX = 'Lax';
|
|
public const SAMESITE_STRICT = 'Strict';
|
|
public const SAMESITE_AVAILABLE_VALUES = ['None', 'Lax', 'Strict'];
|
|
|
|
/** @var array Cookie-Inhalt */
|
|
protected $_content = [];
|
|
|
|
/** @var string Verschlüsselter Cookie-Name */
|
|
protected $_name;
|
|
|
|
/** @var int Ablaufdatum */
|
|
protected $_expire;
|
|
|
|
/** @var bool|string Domain */
|
|
protected $_domain;
|
|
|
|
/** @var string|bool SameSite */
|
|
protected $_sameSite;
|
|
|
|
/** @var string Pfad */
|
|
protected $_path;
|
|
|
|
/** @var PhpEncryption Verschlüsselungstool */
|
|
protected $cipherTool;
|
|
|
|
/** @var bool Modifiziert */
|
|
protected $_modified = false;
|
|
|
|
/** @var bool Schreiben erlaubt */
|
|
protected $_allow_writing;
|
|
|
|
/** @var string Salt */
|
|
protected $_salt;
|
|
|
|
/** @var bool Standalone */
|
|
protected $_standalone;
|
|
|
|
/** @var bool Secure */
|
|
protected $_secure = false;
|
|
|
|
/** @var SessionInterface|null Session */
|
|
protected $session = null;
|
|
|
|
/**
|
|
* Konstruktor
|
|
*/
|
|
public function __construct($name, $path = '', $expire = null, $shared_urls = null, $standalone = false, $secure = false)
|
|
{
|
|
$this->_content = [];
|
|
$this->_standalone = $standalone;
|
|
$this->_expire = null === $expire ? time() + 1728000 : (int) $expire;
|
|
$this->_path = trim(($this->_standalone ? '' : Context::getContext()->shop->physical_uri) . $path, '/\\') . '/';
|
|
if ($this->_path[0] != '/') {
|
|
$this->_path = '/' . $this->_path;
|
|
}
|
|
$this->_path = rawurlencode($this->_path);
|
|
$this->_path = str_replace(['%2F', '%7E', '%2B', '%26'], ['/', '~', '+', '&'], $this->_path);
|
|
$this->_domain = $this->getDomain($shared_urls);
|
|
$this->_sameSite = Configuration::get('PS_COOKIE_SAMESITE');
|
|
$this->_name = 'Webshop-' . md5(($this->_standalone ? '' : _PS_VERSION_) . $name . $this->_domain);
|
|
$this->_allow_writing = true;
|
|
$this->_salt = $this->_standalone ? str_pad('', 32, md5('ws' . __FILE__)) : _COOKIE_IV_;
|
|
|
|
if ($this->_standalone) {
|
|
$asciiSafeString = Defuse\Crypto\Encoding::saveBytesToChecksummedAsciiSafeString(Key::KEY_CURRENT_VERSION, str_pad($name, Key::KEY_BYTE_SIZE, md5(__FILE__)));
|
|
$this->cipherTool = new PhpEncryption($asciiSafeString);
|
|
} else {
|
|
$this->cipherTool = new PhpEncryption(_NEW_COOKIE_KEY_);
|
|
}
|
|
|
|
$this->_secure = (bool) $secure;
|
|
|
|
$this->update();
|
|
}
|
|
|
|
/**
|
|
* Schreiben verbieten
|
|
*/
|
|
public function disallowWriting()
|
|
{
|
|
$this->_allow_writing = false;
|
|
}
|
|
|
|
/**
|
|
* Domain abrufen
|
|
*/
|
|
protected function getDomain($shared_urls = null)
|
|
{
|
|
$httpHost = Tools::getHttpHost(false, false);
|
|
if (!$httpHost) {
|
|
return false;
|
|
}
|
|
|
|
$r = '!(?:(\w+)://)?(?:(\w+)\:(\w+)@)?([^/:]+)?(?:\:(\d*))?([^#?]+)?(?:\?([^#]+))?(?:#(.+$))?!i';
|
|
if (!preg_match($r, $httpHost, $out)) {
|
|
return false;
|
|
}
|
|
|
|
if (preg_match('/^(((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]{1}[0-9]|[1-9]).)' .
|
|
'{1}((25[0-5]|2[0-4][0-9]|[1]{1}[0-9]{2}|[1-9]{1}[0-9]|[0-9]).)' .
|
|
'{2}((25[0-5]|2[0-4][0-9]|[1]{1}[0-9]{2}|[1-9]{1}[0-9]|[0-9]){1}))$/', $out[4])) {
|
|
return false;
|
|
}
|
|
if (!strstr($httpHost, '.')) {
|
|
return false;
|
|
}
|
|
|
|
$domain = false;
|
|
if ($shared_urls !== null) {
|
|
foreach ($shared_urls as $shared_url) {
|
|
if ($shared_url != $out[4]) {
|
|
continue;
|
|
}
|
|
if (preg_match('/^(?:.*\.)?([^.]*(?:.{2,4})?\..{2,3})$/Ui', $shared_url, $res)) {
|
|
$domain = '.' . $res[1];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!$domain) {
|
|
$domain = $out[4];
|
|
}
|
|
|
|
return $domain;
|
|
}
|
|
|
|
/**
|
|
* Ablaufdatum setzen
|
|
*/
|
|
public function setExpire($expire)
|
|
{
|
|
$this->_expire = (int) $expire;
|
|
}
|
|
|
|
/**
|
|
* Magic Getter
|
|
*/
|
|
public function __get($key)
|
|
{
|
|
return isset($this->_content[$key]) ? $this->_content[$key] : false;
|
|
}
|
|
|
|
/**
|
|
* Magic Isset
|
|
*/
|
|
public function __isset($key)
|
|
{
|
|
return isset($this->_content[$key]);
|
|
}
|
|
|
|
/**
|
|
* Magic Setter
|
|
*/
|
|
public function __set($key, $value)
|
|
{
|
|
if (is_array($value)) {
|
|
die(Tools::displayError('Cookie value can\'t be an array.'));
|
|
}
|
|
if (preg_match('/¤|\|/', $key . $value)) {
|
|
throw new Exception('Forbidden chars in cookie');
|
|
}
|
|
if (!$this->_modified && (!array_key_exists($key, $this->_content) || $this->_content[$key] != $value)) {
|
|
$this->_modified = true;
|
|
}
|
|
$this->_content[$key] = $value;
|
|
}
|
|
|
|
/**
|
|
* Magic Unset
|
|
*/
|
|
public function __unset($key)
|
|
{
|
|
if (isset($this->_content[$key])) {
|
|
$this->_modified = true;
|
|
unset($this->_content[$key]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Logout
|
|
*/
|
|
public function logout()
|
|
{
|
|
$this->_content = [];
|
|
$this->_modified = true;
|
|
$this->write();
|
|
}
|
|
|
|
/**
|
|
* My Logout
|
|
*/
|
|
public function mylogout()
|
|
{
|
|
$this->_content = [];
|
|
$this->_modified = true;
|
|
$this->write();
|
|
}
|
|
|
|
/**
|
|
* Neues Log erstellen
|
|
*/
|
|
public function makeNewLog()
|
|
{
|
|
$this->_content['last_activity'] = time();
|
|
$this->_modified = true;
|
|
}
|
|
|
|
/**
|
|
* Cookie aktualisieren
|
|
*/
|
|
public function update($nullValues = false)
|
|
{
|
|
if ($this->_modified) {
|
|
$this->write();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Cookie verschlüsseln und setzen
|
|
*/
|
|
protected function encryptAndSetCookie($cookie = null)
|
|
{
|
|
if (!$this->_allow_writing) {
|
|
return;
|
|
}
|
|
|
|
$cookie = $cookie ?: $this->_name;
|
|
$content = $this->cipherTool->encrypt(serialize($this->_content));
|
|
|
|
$options = [
|
|
'expires' => $this->_expire,
|
|
'path' => $this->_path,
|
|
'domain' => $this->_domain,
|
|
'secure' => $this->_secure,
|
|
'httponly' => true,
|
|
'samesite' => $this->_sameSite
|
|
];
|
|
|
|
setcookie($cookie, $content, $options);
|
|
}
|
|
|
|
/**
|
|
* Destruktor
|
|
*/
|
|
public function __destruct()
|
|
{
|
|
$this->write();
|
|
}
|
|
|
|
/**
|
|
* Cookie schreiben
|
|
*/
|
|
public function write()
|
|
{
|
|
if (!$this->_allow_writing) {
|
|
return;
|
|
}
|
|
|
|
if ($this->_modified) {
|
|
$this->encryptAndSetCookie();
|
|
$this->_modified = false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Cookie-Familie abrufen
|
|
*/
|
|
public function getFamily($origin)
|
|
{
|
|
$result = [];
|
|
foreach ($this->_content as $key => $value) {
|
|
if (strpos($key, $origin) === 0) {
|
|
$result[$key] = $value;
|
|
}
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Cookie-Familie löschen
|
|
*/
|
|
public function unsetFamily($origin)
|
|
{
|
|
foreach ($this->_content as $key => $value) {
|
|
if (strpos($key, $origin) === 0) {
|
|
unset($this->_content[$key]);
|
|
$this->_modified = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Alle Cookies abrufen
|
|
*/
|
|
public function getAll()
|
|
{
|
|
return $this->_content;
|
|
}
|
|
|
|
/**
|
|
* Cookie-Name abrufen
|
|
*/
|
|
public function getName()
|
|
{
|
|
return $this->_name;
|
|
}
|
|
|
|
/**
|
|
* Cookie existiert
|
|
*/
|
|
public function exists()
|
|
{
|
|
return isset($_COOKIE[$this->_name]);
|
|
}
|
|
|
|
/**
|
|
* Session registrieren
|
|
*/
|
|
public function registerSession(SessionInterface $session)
|
|
{
|
|
$this->session = $session;
|
|
}
|
|
|
|
/**
|
|
* Session löschen
|
|
*/
|
|
public function deleteSession()
|
|
{
|
|
if ($this->session) {
|
|
$this->session->destroy();
|
|
$this->session = null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Session lebt
|
|
*/
|
|
public function isSessionAlive()
|
|
{
|
|
if (!$this->session) {
|
|
return false;
|
|
}
|
|
|
|
$lastActivity = $this->_content['last_activity'] ?? 0;
|
|
$timeout = Configuration::get('PS_COOKIE_LIFETIME_FO') ?: 480;
|
|
|
|
return (time() - $lastActivity) < $timeout;
|
|
}
|
|
|
|
/**
|
|
* Session abrufen
|
|
*/
|
|
public function getSession($sessionId)
|
|
{
|
|
if ($this->session) {
|
|
return $this->session->get($sessionId);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Cookie aktualisieren
|
|
*/
|
|
protected function update()
|
|
{
|
|
if (isset($_COOKIE[$this->_name])) {
|
|
$content = $this->cipherTool->decrypt($_COOKIE[$this->_name]);
|
|
$this->_content = unserialize($content);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set Cookie (einfache Methode)
|
|
*/
|
|
public function set($key, $value)
|
|
{
|
|
$this->__set($key, $value);
|
|
$this->save();
|
|
}
|
|
|
|
/**
|
|
* Get Cookie (einfache Methode)
|
|
*/
|
|
public function get($key)
|
|
{
|
|
return $this->__get($key);
|
|
}
|
|
|
|
/**
|
|
* Cookie speichern
|
|
*/
|
|
public function save()
|
|
{
|
|
$this->write();
|
|
}
|
|
}
|