Passed
Branch master (bfd3f5)
by Wilder
01:18
created

Cookie::set()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 5
c 1
b 0
f 0
nc 4
nop 4
dl 0
loc 11
rs 10
1
<?php
2
3
namespace ElePHPant\Cookie\Cookie;
4
5
6
/**
7
 * Class Cookie
8
 *
9
 * Please report bugs on https://github.com/wilderamorim/cookie/issues
10
 *
11
 * @author Wilder Amorim <https://github.com/wilderamorim>
12
 * @link https://www.linkedin.com/in/wilderamorim/
13
 */
14
class Cookie
15
{
16
    use CookieTrait;
17
18
    /**
19
     * @param array $configs
20
     */
21
    public function __construct(array $configs = [])
22
    {
23
        $this->processConfig($configs);
24
    }
25
26
    /**
27
     * Set a cookie.
28
     *
29
     * @param string        $name       The name of the cookie.
30
     * @param mixed         $value      The value of the cookie.
31
     * @param int           $expiration The expiration time of the cookie in seconds.
32
     * @param string|null   $path       The path on the server in which the cookie will be available.
33
     * @return bool                     True if the cookie is set successfully, false otherwise.
34
     */
35
    public static function set(string $name, $value, int $expiration, ?string $path = null): bool
36
    {
37
        if (is_array($value)) {
38
            $value = json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
39
        }
40
41
        if (self::$isEncrypted) {
42
            $value = self::$encryptionStrategy->encrypt($value);
0 ignored issues
show
Bug introduced by
The method encrypt() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

42
            /** @scrutinizer ignore-call */ 
43
            $value = self::$encryptionStrategy->encrypt($value);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
43
        }
44
45
        return self::$storage->set($name, $value, strtotime("+{$expiration} " . self::$configs['expiration']), $path);
46
    }
47
48
    /**
49
     * Get the value of a cookie.
50
     *
51
     * @param string|null $name The name of the cookie. If null, returns all cookies.
52
     * @return mixed            The value of the cookie, or an array of all cookies if $name is null.
53
     */
54
    public static function get(?string $name = null)
55
    {
56
        if (!$name) {
57
            return self::all();
58
        }
59
60
        $cookie = self::$storage->get($name);
61
        if ($cookie) {
62
            $cookie = self::$isEncrypted ? self::$encryptionStrategy->decrypt($cookie) : $cookie;
63
            return json_decode($cookie, true) ?? $cookie;
0 ignored issues
show
Bug introduced by
It seems like $cookie can also be of type null; however, parameter $json of json_decode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

63
            return json_decode(/** @scrutinizer ignore-type */ $cookie, true) ?? $cookie;
Loading history...
64
        }
65
66
        return null;
67
    }
68
69
    /**
70
     * Delete a cookie.
71
     *
72
     * @param string|null $name The name of the cookie. If null, deletes all cookies.
73
     * @param string|null $path The path on the server in which the cookie was available.
74
     * @return bool             True if the cookie is deleted successfully, false otherwise.
75
     */
76
    public static function destroy(?string $name = null, ?string $path = null): bool
77
    {
78
        return self::$storage->delete($name, $path);
79
    }
80
81
    /**
82
     * Check if a cookie exists and optionally check its value.
83
     *
84
     * @param string      $name  The name of the cookie.
85
     * @param string|null $value The expected value of the cookie. If null, only checks for existence.
86
     * @return bool              True if the cookie exists and its value matches the expected value (or only existence is checked), false otherwise.
87
     */
88
    public static function has(string $name, ?string $value = null): bool
89
    {
90
        $getCookie = self::$storage->get($name);
91
92
        if (!$value) {
93
            return $getCookie !== null;
94
        }
95
96
        $expectedValue = self::$isEncrypted ? self::$encryptionStrategy->encrypt($value) : $value;
97
        return $getCookie === $expectedValue;
98
    }
99
100
    /**
101
     * Set a cookie if it doesn't already exist, with an option to remove the existing cookie.
102
     *
103
     * @param string      $name         The name of the cookie.
104
     * @param mixed       $value        The value of the cookie.
105
     * @param int         $expiration   The expiration time of the cookie in seconds.
106
     * @param string|null $path         The path on the server in which the cookie will be available.
107
     * @param bool        $removeHas    Whether to remove the existing cookie if it exists.
108
     * @return bool|null                True if the cookie is set successfully, null if the cookie already exists and $removeHas is false.
109
     */
110
    public static function setDoesntHave(string $name, $value, int $expiration, ?string $path = null, bool $removeHas = false): ?bool
111
    {
112
        if (!self::has($name)) {
113
            return self::set($name, $value, $expiration, $path);
114
        }
115
116
        if ($removeHas) {
117
            return self::destroy($name);
118
        }
119
120
        return null;
121
    }
122
123
    /**
124
     * Get all cookies.
125
     *
126
     * @return array An associative array of all cookies, where the keys are the cookie names and the values are the cookie values.
127
     */
128
    private static function all(): array
129
    {
130
        $cookies = self::$storage->get() ?? [];
131
        $isBase64Encoded = fn(string $string): bool => $string === base64_encode(base64_decode($string));
132
        $isJson = fn(string $string): bool => json_decode($string) && json_last_error() === JSON_ERROR_NONE;
133
134
        return array_reduce(
135
            array_keys($cookies),
136
            fn($result, $key) => $result += [
137
                $key => self::$isEncrypted && $isBase64Encoded($cookies[$key])
138
                    ? (
139
                    $isJson(self::$encryptionStrategy->decrypt($cookies[$key]))
140
                        ? json_decode(self::$encryptionStrategy->decrypt($cookies[$key]), true)
0 ignored issues
show
Bug introduced by
It seems like self::encryptionStrategy->decrypt($cookies[$key]) can also be of type null; however, parameter $json of json_decode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

140
                        ? json_decode(/** @scrutinizer ignore-type */ self::$encryptionStrategy->decrypt($cookies[$key]), true)
Loading history...
141
                        : self::$encryptionStrategy->decrypt($cookies[$key])
142
                    )
143
                    : (
144
                    $isJson($cookies[$key])
145
                        ? json_decode($cookies[$key], true)
146
                        : $cookies[$key]
147
                    )
148
            ], []
149
        );
150
    }
151
}
152