Passed
Branch main (b87c23)
by Garbuz
02:55
created

Coder::jsonDecode()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 4
c 2
b 0
f 0
dl 0
loc 7
ccs 0
cts 5
cp 0
rs 10
cc 2
nc 2
nop 1
crap 6
1
<?php
2
3
namespace Garbuzivan\Laraveltokens;
4
5
use Exception;
6
7
class Coder
8
{
9
    /**
10
     * @param array  $payload
11
     * @param string $key
12
     * @param array  $head [exp - expiration]
13
     *
14
     * @return string
15
     * @throws Exception
16
     */
17
    public function encode(array $payload, string $key, array $head = []): string
18
    {
19
        $header = ['typ' => 'JWT', 'alg' => 'HS256'];
20
        $header = \array_merge($head, $header);
21
        $segments = [];
22
        $segments[] = $this->urlsafeB64Encode($this->jsonEncode($header));
23
        $segments[] = $this->urlsafeB64Encode($this->jsonEncode($payload));
24
        $signing_input = \implode('.', $segments);
25
        $signature = $this->sign($signing_input, $key);
26
        $segments[] = $this->urlsafeB64Encode($signature);
27
        return \implode('.', $segments);
28
    }
29
30
    /**
31
     * @param string $token
32
     * @param string $key
33
     *
34
     * @return array
35
     * @throws Exception
36
     */
37
    public function decode(string $token, string $key): array
38
    {
39
        $data = [];
40
        $tks = \explode('.', $token);
41
        if (\count($tks) != 3) {
42
            return $data;
43
        }
44
        [$headb64, $bodyb64, $cryptob64] = $tks;
45
        $header = $this->jsonDecode($this->urlsafeB64Decode($headb64));
46
        $payload = $this->jsonDecode($this->urlsafeB64Decode($bodyb64));
47
        $sig = $this->urlsafeB64Decode($cryptob64);
48
        $segments = [];
49
        $segments[] = $this->urlsafeB64Encode($this->jsonEncode($header));
50
        $segments[] = $this->urlsafeB64Encode($this->jsonEncode($payload));
51
        $signing_input = \implode('.', $segments);
52
        if ($this->sign($signing_input, $key) == $sig) {
53
            return \array_merge($header, $payload);
54
        }
55
        return $data;
56
    }
57
58
    /**
59
     * Decode a JSON string into a PHP object.
60
     *
61
     * @param string $input JSON string
62
     *
63
     * @return array Object representation of JSON string
64
     *
65
     * @throws Exception Provided string was invalid JSON
66
     */
67
    public function jsonDecode(string $input): array
68
    {
69
        $obj = \json_decode($input, true);
70
        if (is_null($obj)) {
71
            throw new Exception('Null result with non-null input');
72
        }
73
        return $obj;
74
    }
75
76
    /**
77
     * Encode a PHP object into a JSON string.
78
     *
79
     * @param array $input A PHP object or array
80
     *
81
     * @return string JSON representation of the PHP object or array
82
     *
83
     * @throws Exception Provided object could not be encoded to valid JSON
84
     */
85
    public function jsonEncode(array $input): string
86
    {
87
        $json = \json_encode($input);
88
        if ($errno = \json_last_error()) {
89
            $this->handleJsonError($errno);
90
        }
91
        return $json;
92
    }
93
94
    /**
95
     * Helper method to create a JSON error.
96
     *
97
     * @param int $errno An error number from json_last_error()
98
     *
99
     * @return void
100
     * @throws Exception
101
     */
102
    private function handleJsonError(int $errno)
103
    {
104
        $messages = [
105
            JSON_ERROR_DEPTH          => 'Maximum stack depth exceeded',
106
            JSON_ERROR_STATE_MISMATCH => 'Invalid or malformed JSON',
107
            JSON_ERROR_CTRL_CHAR      => 'Unexpected control character found',
108
            JSON_ERROR_SYNTAX         => 'Syntax error, malformed JSON',
109
            JSON_ERROR_UTF8           => 'Malformed UTF-8 characters' //PHP >= 5.3.3
110
        ];
111
        throw new Exception($messages[$errno] ?? 'Unknown JSON error: ' . $errno);
112
    }
113
114
    /**
115
     * @param string $msg
116
     * @param string $key
117
     *
118
     * @return false|string
119
     */
120
    public function sign(string $msg, string $key)
121
    {
122
        return \hash_hmac('SHA256', $msg, $key, true);
123
    }
124
125
    /**
126
     * Decode a string with URL-safe Base64.
127
     *
128
     * @param string $input A Base64 encoded string
129
     *
130
     * @return string A decoded string
131
     */
132
    public function urlsafeB64Decode($input)
133
    {
134
        $remainder = \strlen($input) % 4;
135
        if ($remainder) {
136
            $padlen = 4 - $remainder;
137
            $input .= \str_repeat('=', $padlen);
138
        }
139
        return \base64_decode(\strtr($input, '-_', '+/'));
140
    }
141
142
    /**
143
     * Encode a string with URL-safe Base64.
144
     *
145
     * @param string $input The string you want encoded
146
     *
147
     * @return string The base64 encode of what you passed in
148
     */
149
    public function urlsafeB64Encode($input)
150
    {
151
        return \str_replace('=', '', \strtr(\base64_encode($input), '+/', '-_'));
152
    }
153
}
154