diff --git a/composer.json b/composer.json index 422dfe9..7671818 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,7 @@ { "name": "refkinscallv/cookie", "description": "Cookies Library for PHP", + "version": "1.0.5", "type": "library", "license": "MIT", "autoload": { @@ -14,8 +15,5 @@ "email": "refkinscallv@gmail.com" } ], - "minimum-stability": "stable", - "require": { - "refkinscallv/crypto": "^1.0" - } + "minimum-stability": "stable" } diff --git a/path/to/encrypt.txt b/path/to/encrypt.txt deleted file mode 100644 index b53b399..0000000 --- a/path/to/encrypt.txt +++ /dev/null @@ -1,8 +0,0 @@ -eGtibFNUbDlBVk9IcXZaWlZIcWRmUDBmaUxmSjNrMzF1aEhpb3c1blVSV3UyaHdMaEsyY09aRW1nSUw4TXdkYzo60Tvq3TW+1SMJLKBJrBUdpQ==:ba82819125aa9f98e8926faefe5f8b15 -aDdUUzNCZnF4Kzl0cDRGNlo5ODhMREpjeTYrdVhWbjRVWnZlOUVGL0pmOG55WS9JUTIxSDFHdGp0ZW8raTFVTTo6ug8Jl+6w9hHSHbekUp0xWw==:64f98efe04dde1ef180270ee87fd89c5 -TjFIWGZORWttWVNHQkNsK0kwcXlFVVBBQ2NXRnhaMGsrNXlJZFdFM0dsM0xhMzFmM3Z1RHlpRVNqWWlSdWV3VDo6R2HH8KIHZ2x0hU5h25HGIw==:92faa2c37e297a59f339018bb7cb4426 -RG4zMUFHSkFiVmQ2VWRKV1pQekdjTjVoS0hqUnNpSzhiOGZ4aWdTT3NlS1lUek02YkE1d0ZOSE1KbS9abjhhMDo6QU0HtnVqcqrY8tEKPC7dWQ==:48cfc6b4453024662a2760c3a7e02383 -NE5NaWlNblRjUVplWVA4SmhNeXIyaXo5SER6U1JITXAwV1QxOGZ3eVljcTBJSXo2RmI1bStWNzViOUM1S2dCdTo6DVQ8/eIbVJSxDG1PiIRBSw==:266b0f794608ed9fec5d03f0984802e2 -SGxsSWFtTDFJQUQxMkw1YmN0d0cySUh1Z0k2K2JMY2VBY1d4VmV1M0pWTDlLVW01RExZK3p6TjVBRjJRREhsTzo6ckkGhoXdqTxY0eZhoY2Bag==:767c31ffb73777997c36857cbad92ca8 -cXkybGt3Yk00Y1NrRXVITWEzSnZyY0YvOEQxVWNJcEhaVkViYWdJeTZSaFY4bzhtWGFkSUFQL3pFVnVkZVhNQk9TN040U2l3MFNyZmprTlVkUVJwdUE9PTo6xhlp/kXwtWrUEbQzAqZRjA==:8df15200e6cfb14f9965422bdf7b4692 -MEpyUXp6ZEcvYWp3WUl0YkpwYWJjdGdwMll1SW9LZ2J1QkovUmIwNEkrRks1YjFxd1FDZ2hCYll6aGpjV3BvVGtmZ2RSL2g5NzdEUnI5Q0NsTStML0xXcVNGMmlkNE12emNQWGVzNjA0Ykk9OjowoX8xHmhcJhsPRfhq0YYr:eaeafe3738b2316bbee56840c1867258 diff --git a/src/Cookie.php b/src/Cookie.php index 1c99897..c87861d 100644 --- a/src/Cookie.php +++ b/src/Cookie.php @@ -2,172 +2,216 @@ namespace RF\Cookie; - use RF\Crypto\Crypto; use Exception; - class Cookie { - + /** + * Class to handle encrypted cookies with enhanced functionality. + */ + class Cookie + { + /** - * @var string $cookieName + * @var string Cookie name. */ protected string $cookieName; /** - * @var int $cookieExpire + * @var int Cookie expiration time in hours. */ protected int $cookieExpire; /** - * @var string $cookiePath + * @var string Cookie path. */ protected string $cookiePath; /** - * @var string $cookieDomain + * @var string|null Cookie domain. */ - protected string $cookieDomain; + protected ?string $cookieDomain; /** - * @var bool $cookieSecure + * @var bool Cookie secure flag. */ protected bool $cookieSecure; /** - * @var bool $cookieHttpOnly + * @var mixed|null Encryption handler or null if encryption is disabled. */ - protected bool $cookieHttpOnly; + protected mixed $crypto; /** - * @var Crypto|null $crypto + * @var bool Whether encryption is enabled. */ - protected ?Crypto $crypto; + protected bool $cookieEncrypt; /** - * @var callable|null $cookieEncrypt + * Cookie constructor. + * + * @param mixed|null $db Encryption handler or null to disable encryption. */ - protected $cookieEncrypt; - - public function __construct(array $args = []) { - $this->validateArgs($args); - - if ($this->cookieEncrypt) { - $this->crypto = new Crypto($this->cookieEncrypt); - } else { - $this->crypto = null; - } - } - - private function validateArgs(array $args): void { - if (!isset($args["cookieName"])) { - throw new Exception("Invalid Cookie Config. Array index 'cookieName' not found."); - } - - $this->cookieName = $args["cookieName"]; - $this->cookieExpire = $args["cookieExpires"] ?? 24; - $this->cookiePath = $args["cookiePath"] ?? "/"; - $this->cookieDomain = $args["cookieDomain"] ?? $_SERVER["SERVER_NAME"]; - $this->cookieSecure = $args["cookieSecure"] ?? false; - $this->cookieHttpOnly = $args["cookieHttpOnly"] ?? true; - $this->cookieEncrypt = $args["cookieEncrypt"] ?? []; + public function __construct(mixed $db = null) + { + $this->cookieName = $_SERVER['COOKIE_NAME'] ?? 'web_cookie'; + $this->cookieExpire = (int)($_SERVER['COOKIE_EXPIRES'] ?? 24); + $this->cookiePath = $_SERVER['COOKIE_PATH'] ?? '/'; + $this->cookieDomain = $_SERVER['SERVER_NAME'] ?? null; + $this->cookieSecure = filter_var($_SERVER['COOKIE_SECURE'] ?? false, FILTER_VALIDATE_BOOLEAN); + $this->crypto = $db; + $this->cookieEncrypt = $db !== null; } /** - * Retrieve all encrypted cookie data. + * Retrieve all cookies. * - * @return array + * @return array Parsed cookie data or an empty array. + * @throws Exception If cookie data cannot be decrypted or unserialized. */ - public function all(): array { + public function all(): array + { if (!isset($_COOKIE[$this->cookieName])) { return []; } $cookieData = $_COOKIE[$this->cookieName]; - if ($this->crypto) { - $decryptedData = $this->crypto->decrypt($cookieData, "array"); - return $decryptedData; + try { + if ($this->cookieEncrypt) { + return $this->crypto->decrypt($cookieData, 'array'); + } + $unserializedData = @unserialize($cookieData); + if ($unserializedData === false && $cookieData !== 'b:0;') { + throw new Exception('Failed to unserialize cookie data.'); + } + return $unserializedData ?: []; + } catch (Exception $e) { + throw new Exception('Failed to retrieve cookies: ' . $e->getMessage(), 0, $e); } - - return $cookieData ? @unserialize($cookieData) : []; } /** - * Get specific value from decrypted cookie data. + * Get a specific cookie value by key. * - * @param string $value - * @return mixed|null + * @param string $key The key of the cookie to retrieve. + * @return mixed|null The value of the cookie or null if not found. */ - public function get(string $value) { - $getCookie = $this->all(); + public function get(string $key): mixed + { + $allCookies = $this->all(); + return $allCookies[$key] ?? null; + } - return $getCookie[$value] ?? null; + /** + * Check if a specific cookie key exists. + * + * @param string $key The key to check. + * @return bool True if the key exists, false otherwise. + */ + public function has(string $key): bool + { + return $this->get($key) !== null; } /** - * Set encrypted cookie data. + * Set a cookie value or values. * - * @param mixed $key - * @param mixed $value - * @return bool + * @param string|array $key The key or an array of key-value pairs to set. + * @param mixed|null $value The value to set if $key is a string. + * @return bool True on success. + * @throws Exception If the headers are already sent or setting the cookie fails. */ - public function set($key, $value = null): bool { - $getCookie = $this->all(); + public function set(string|array $key, mixed $value = null): bool + { + $allCookies = $this->all(); if (is_array($key)) { - foreach ($key as $index => $val) { - $getCookie[$index] = $val; + foreach ($key as $idx => $val) { + $allCookies[$idx] = $val; } } else { - $getCookie[$key] = $value; + $allCookies[$key] = $value; } - $setCookie = $this->crypto ? $this->crypto->encrypt($getCookie, "array") : serialize($getCookie); + $setCookie = $this->cookieEncrypt + ? $this->crypto->encrypt($allCookies, 'array') + : serialize($allCookies); - return setcookie( + if (headers_sent()) { + throw new Exception('Cannot set cookie; headers already sent.'); + } + + if (!setcookie( $this->cookieName, $setCookie, - time() + ($this->cookieExpire * 3600), - $this->cookiePath, - $this->cookieDomain, - $this->cookieSecure, - $this->cookieHttpOnly - ); + [ + 'expires' => time() + ($this->cookieExpire * 3600), + 'path' => $this->cookiePath, + 'secure' => $this->cookieSecure, + 'httponly' => true + ] + )) { + throw new Exception('Failed to set cookie: ' . $this->cookieName); + } + + return true; } /** - * Unset encrypted cookie data. + * Unset a cookie by key. * - * @param mixed $key - * @return bool + * @param string|array $key The key or an array of keys to unset. + * @return bool True on success. + * @throws Exception If setting the cookie fails. */ - public function unset($key = null): bool { - $getCookie = $this->all(); + public function unset(string|array $key): bool + { + $allCookies = $this->all(); if (is_array($key)) { - foreach ($key as $index) { - unset($getCookie[$index]); + foreach ($key as $idx) { + unset($allCookies[$idx]); } } else { - unset($getCookie[$key]); + unset($allCookies[$key]); } - $setCookie = $this->crypto ? $this->crypto->encrypt($getCookie, "array") : serialize($getCookie); + $setCookie = $this->cookieEncrypt + ? $this->crypto->encrypt($allCookies, 'array') + : serialize($allCookies); - return setcookie( + if (!setcookie( $this->cookieName, $setCookie, - time() + ($this->cookieExpire * 3600), - $this->cookiePath, - $this->cookieDomain, - $this->cookieSecure, - $this->cookieHttpOnly - ); + [ + 'expires' => time() + ($this->cookieExpire * 3600), + 'path' => $this->cookiePath, + 'secure' => $this->cookieSecure, + 'httponly' => true + ] + )) { + throw new Exception('Failed to unset cookie: ' . $this->cookieName); + } + + return true; } /** - * Destroy cookie data. + * Destroy all cookies. + * + * @return bool True on success. */ - public function destroy() { - return setcookie($this->cookieName, "", time() - 3600, "/"); + public function destroy(): bool + { + return setcookie( + $this->cookieName, + '', + [ + 'expires' => time() - 3600, + 'path' => $this->cookiePath, + 'secure' => $this->cookieSecure, + 'httponly' => true + ] + ); } + } diff --git a/test/index.php b/test/index.php deleted file mode 100644 index ea08642..0000000 --- a/test/index.php +++ /dev/null @@ -1,35 +0,0 @@ - 'myCookie', - 'cookieExpires' => 24, // Cookie expiration in hours - 'cookiePath' => '/', - 'cookieDomain' => $_SERVER['SERVER_NAME'], - 'cookieSecure' => false, // Set to true if using HTTPS - 'cookieHttpOnly' => true, - 'cookieEncrypt' => [ - "encryptKey" => "your-secret-key", - "encryptCipher" => "AES-256-CBC", - "encryptStoreMethod" => "local", - "encryptFile" => "/path/to/encrypt.txt" - ] - ]); - - // Set a cookie value - $cookie->set('key', 'value'); - - // Get a cookie value - $value = $cookie->get('key'); - - // Retrieve all cookie data - $allData = $cookie->all(); - - // Unset a cookie value - $cookie->unset('key'); - - // Destroy the cookie - $cookie->destroy(); \ No newline at end of file