1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace JoseJwt\Util; |
4
|
|
|
|
5
|
|
|
use JoseJwt\Error\JoseJwtException; |
6
|
|
|
use JoseJwt\Json\JsonMapper; |
7
|
|
|
|
8
|
|
|
class StringUtils |
9
|
|
|
{ |
10
|
|
|
private function __construct() |
11
|
|
|
{ |
12
|
|
|
} |
13
|
|
|
|
14
|
|
|
/** |
15
|
|
|
* Compares two strings. |
16
|
|
|
* |
17
|
|
|
* This method implements a constant-time algorithm to compare strings. |
18
|
|
|
* Regardless of the used implementation, it will leak length information. |
19
|
|
|
* |
20
|
|
|
* @param string $knownString The string of known length to compare against |
21
|
|
|
* @param string $userInput The string that the user can control |
22
|
|
|
* |
23
|
|
|
* @return bool true if the two strings are the same, false otherwise |
24
|
|
|
*/ |
25
|
|
|
public static function equals($knownString, $userInput) |
26
|
|
|
{ |
27
|
|
|
static $exists = null; |
28
|
|
|
if (null === $exists) { |
29
|
|
|
$exists = function_exists('hash_equals'); |
30
|
|
|
} |
31
|
|
|
$knownString = (string) $knownString; |
32
|
|
|
$userInput = (string) $userInput; |
33
|
|
|
if ($exists) { |
34
|
|
|
return hash_equals($knownString, $userInput); |
35
|
|
|
} |
36
|
|
|
$knownLen = strlen($knownString); |
37
|
|
|
$userLen = strlen($userInput); |
38
|
|
|
// Extend the known string to avoid uninitialized string offsets |
39
|
|
|
$knownString .= $userInput; |
40
|
|
|
// Set the result to the difference between the lengths |
41
|
|
|
$result = $knownLen - $userLen; |
42
|
|
|
// Note that we ALWAYS iterate over the user-supplied length |
43
|
|
|
// This is to mitigate leaking length information |
44
|
|
|
for ($i = 0; $i < $userLen; $i++) { |
45
|
|
|
$result |= (ord($knownString[$i]) ^ ord($userInput[$i])); |
46
|
|
|
} |
47
|
|
|
// They are only identical strings if $result is exactly 0... |
48
|
|
|
return 0 === $result; |
49
|
|
|
} |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* @param string $value |
53
|
|
|
* |
54
|
|
|
* @return int |
55
|
|
|
*/ |
56
|
|
|
public static function length($value) |
57
|
|
|
{ |
58
|
|
|
static $exists = null; |
59
|
|
|
if (null === $exists) { |
60
|
|
|
$exists = function_exists('mb_strlen'); |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
if ($exists) { |
64
|
|
|
return mb_strlen($value, '8bit'); |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
return strlen($value); |
68
|
|
|
} |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* @param string $value |
72
|
|
|
* @param int $start |
73
|
|
|
* @param int $length |
74
|
|
|
* |
75
|
|
|
* @return string |
76
|
|
|
*/ |
77
|
|
|
public static function substring($value, $start = 0, $length = null) |
78
|
|
|
{ |
79
|
|
|
static $exists = null; |
80
|
|
|
if (null === $exists) { |
81
|
|
|
$exists = function_exists('mb_substr'); |
82
|
|
|
} |
83
|
|
|
|
84
|
|
|
if ($exists) { |
85
|
|
|
return mb_substr($value, $start, $length, '8bit'); |
86
|
|
|
} elseif ($length !== null) { |
87
|
|
|
return substr($value, $start, $length); |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
return substr($value, $start); |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
/** |
94
|
|
|
* @param string|array|object $payload |
95
|
|
|
* @param JsonMapper $mapper |
96
|
|
|
* |
97
|
|
|
* @return string |
98
|
|
|
*/ |
99
|
|
|
public static function payload2string($payload, JsonMapper $mapper = null) |
100
|
|
|
{ |
101
|
|
|
if (is_array($payload)) { |
102
|
|
|
return json_encode($payload, JSON_UNESCAPED_SLASHES); |
103
|
|
View Code Duplication |
} elseif (is_string($payload)) { |
|
|
|
|
104
|
|
|
if (trim($payload) !== '') { |
105
|
|
|
return $payload; |
106
|
|
|
} else { |
107
|
|
|
throw new JoseJwtException('Payload can not be empty'); |
108
|
|
|
} |
109
|
|
|
} elseif (is_object($payload) && $payload instanceof \JsonSerializable) { |
110
|
|
|
return json_encode($payload, JSON_UNESCAPED_SLASHES); |
111
|
|
|
} elseif (is_object($payload) && $mapper) { |
112
|
|
|
return $mapper->getJsonString($payload); |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
throw new JoseJwtException('Unable to serialize payload'); |
116
|
|
|
} |
117
|
|
|
} |
118
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.