ice framework documentation ice doc v1.10.1
Class Ice

Cookies

    
namespace Ice;

/**
 * Cookie helper.
 *
 * @package     Ice/Cookies
 * @category    Helper
 * @author      Ice Team
 * @copyright   (c) 2014-2023 Ice Team
 * @license     http://iceframework.org/license
 */
class Cookies
{
    protected di;
    protected salt { get, set };
    protected expiration = 0 { get, set };
    protected path = "/" { get, set };
    protected domain = null { get, set };
    protected secure = false { get, set };
    protected httpOnly = false { get, set };
    protected encrypt = true { get, set };

    public function __construct(string salt = null)
    {
        let this->di = Di::$fetch();
        let this->salt = salt;

        //let this->data = &_COOKIE;
    }

    /**
     * Does cookie contain a key
     *
     * @param string key The cookie key
     * @return boolean
     */
    public function has(string key) -> boolean
    {
        return isset _COOKIE[key];
    }

    /**
     * Gets the value of a signed cookie.
     * Cookies without signatures will not be returned. If the cookie signature is present, but invalid, the cookie
     * will be deleted.
     *
     * @param string key Cookie name
     * @param mixed defaultValue Default value to return
     */
    public function get(string key, var defaultValue = null)
    {
        var cookie, tmp, hash, value;

        if !fetch cookie, _COOKIE[key] {
            return defaultValue;
        }

        // Find the position of the split between salt and contents
        if strpos(cookie, "~") !== false {
            // Separate the salt and the value
            //list (hash, value) = explode("~", cookie, 2);
            let tmp = explode("~", cookie, 2),
                hash = tmp[0],
                value = tmp[1];

            if this->salt(key, value) == hash {
                // Cookie signature is valid
                if this->encrypt {
                    let value = this->di->get("crypt")->decrypt(value);
                }

                return value;
            }

            // The cookie signature is invalid, delete it
            this->remove(key);
        }

        return defaultValue;
    }

    /**
     * Sets a signed cookie.
     * Note that all cookie values must be strings and no automatic serialization will be performed!
     *
     * @param string key Name of cookie
     * @param string value Value of cookie
     * @param integer lifetime Expired time in seconds
     * @return boolean
     */
    public function set(string key, string value, int lifetime = 0)
    {
        if !lifetime {
            // Use the default expiration
            let lifetime = (int) this->expiration;
        }

        if this->encrypt {
            if !empty value {
                let value = this->di->get("crypt")->encrypt(value);
            }
        }

        // Add the salt to the cookie value
        let value = this->salt(key, value) . "~" . value;

        return this->setcookie(key, value, lifetime, this->path, (string) this->domain, this->secure, this->httpOnly);
    }

    /**
     * Deletes a cookie by making the value NULL and expiring it.
     *
     * @param string key cookie name
     * @return boolean
     */
    public function remove(string key) -> boolean
    {
        // Remove the cookie
        unset _COOKIE[key];

        // Nullify the cookie and make it expire
        return this->setcookie(key, "", -86400, this->path, (string) this->domain, this->secure, this->httpOnly);
    }

    /**
     * Generates a salt string for a cookie based on the name and value.
     *
     * @param string name Name of cookie
     * @param string value Value of cookie
     * @throws Exception if salt is not configured
     * @return string
     */
    public function salt(name, value) -> string
    {
        var userAgent;

        // Require a valid salt
        if !this->salt {
            throw new Exception("A valid cookie salt is required.");
        }

        // Determine the user agent
        let userAgent = this->di->get("request")->getUserAgent();

        return sha1(userAgent . name . value . this->salt);
    }

    /**
     * Proxy for the native setcookie function - to allow mocking in unit tests so that they do not fail when headers
     * have been sent.
     *
     * @param string name
     * @param string value
     * @param integer expire
     * @param string path
     * @param string domain
     * @param boolean secure
     * @param boolean httpOnly
     * @return bool
     * @see setcookie
     */
    protected function setcookie(string name, string value, int expire, string path, string domain, boolean secure, boolean httpOnly)
    {
        return setcookie(name, value, expire, path, domain, secure, httpOnly);
    }
}