-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Expand file tree
/
Copy pathcompat-php.php
More file actions
218 lines (196 loc) · 6.38 KB
/
compat-php.php
File metadata and controls
218 lines (196 loc) · 6.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
<?php
/**
* Returns the numeric byte size value for numeric php.ini directives.
*
* Generally this can be used in combination with {@see \ini_get()}
* for values that accept a numeric "byte" size, such as `post_max_size`.
* It will return the value which PHP interprets from the "shorthand"
* syntax, such as "128m" being 128 MiB and "128mb" being 128 B.
*
* @see \ini_parse_quantity()
*
* @since 7.0.0
*
* @param false|int|string $value
* @return int
*/
function wp_ini_parse_quantity( $value ) {
// A missing value is an implicit lack of limit, thus we return `0`, meaning "no limit."
if ( false === $value ) {
return 0;
}
/*
* Directly return pre-parsed values so we can repeatedly call
* this without tracking if we've already parsed a given value.
*/
if ( is_int( $value ) ) {
return $value;
}
/*
* Non-string inputs "fail" to no limit, because there's
* no limit we could ascribe to this invalid value.
*/
if ( ! is_string( $value ) ) {
return 0;
}
return function_exists( 'ini_parse_quantity' )
? ini_parse_quantity( $value )
: ini_parse_quantity_fallback( $value );
}
/**
* Returns larger of two php.ini directive quantity values.
*
* Example:
* wp_ini_greater_quantity( '256m', -1 ) === -1
* wp_ini_greater_quantity( '64K', '64') === '64K'
* wp_ini_greater_quantity( 1000, 2000 ) === 2000
*
* @since 7.0.0
*
* @param int|string|false $a Quantity value.
* @param int|string|false $b Quantity value.
* @return int|string|false Larger quantity value.
*/
function wp_ini_greater_quantity( $a, $b ) {
return wp_ini_quantity_cmp( $a, $b ) >= 0 ? $a : $b;
}
/**
* Returns smaller of two php.ini directive quantity values.
*
* Example:
* wp_ini_lesser_quantity( '256m', -1 ) === '256m'
* wp_ini_lesser_quantity( '64K', '64') === '64'
* wp_ini_lesser_quantity( 1000, 2000 ) === 1000
*
* @since 7.0.0
*
* @param int|string|false $a Quantity value.
* @param int|string|false $b Quantity value.
* @return int|string|false Smaller quantity value.
*/
function wp_ini_lesser_quantity( $a, $b ) {
return wp_ini_quantity_cmp( $a, $b ) <= 0 ? $a : $b;
}
/**
* Comparator for php.ini quantity values, can be used
* as the callback for functions such as `usort()`.
*
* Example:
* $a < $b => -1
* $a === $b => 0
* $a > $b => 1
*
* @since 7.0.0
*
* @param int|string|false $a Quantity being compared.
* @param int|string|false $b Quantity against which $a is compared.
* @return -1|0|1
*/
function wp_ini_quantity_cmp( $a, $b ): int {
return wp_ini_parse_quantity( $a ) <=> wp_ini_parse_quantity( $b );
}
/**
* Fallback function to get interpreted size from ini shorthand syntax for
* systems running versions of PHP up to, but not including, 8.2.0.
*
* @see https://www.php.net/manual/en/function.ini-parse-quantity.php
* @see https://www.php.net/manual/en/faq.using.php#faq.using.shorthandbytes
*
* @since 7.0.0
*
* @param string $shorthand Ini shorthand to parse, must be a number followed by an optional
* multiplier. The following multipliers are supported: k/K (1024),
* m/M (1048576), g/G (1073741824). The number can be a decimal,
* hex (prefixed with 0x or 0X), octal (prefixed with 0o, 0O or 0)
* or binary (prefixed with 0b or 0B).
* @return int the interpreted size in bytes as an int.
*/
function ini_parse_quantity_fallback( $shorthand ) {
$end = strlen( $shorthand );
$at = 0;
$scalar = 0;
/** Sign of numeric quantity, either positive (1) or negative (-1). */
$sign = 1;
/**
* Numeric base of digits determined by string prefix (e.g. "0x" or "0").
* Must be 8 for octal, 10 for decimal, or 16 for hexadecimal.
*/
$base = 10;
// Trim leading whitespace from the value.
$at += strspn( $shorthand, " \t\n\r\v\f", $at );
if ( $at >= $end ) {
return $scalar;
}
// Handle optional sign indicator.
switch ( $shorthand[ $at ] ) {
case '+':
$at++;
break;
case '-':
$sign = -1;
$at++;
break;
}
// Determine base for digit conversion, if not decimal.
$base_a = $shorthand[ $at ] ?? '';
$base_b = $shorthand[ $at + 1 ] ?? '';
if ( '0' === $base_a && ( 'x' === $base_b || 'X' === $base_b ) ) {
$base = 16;
$at += 2;
} else if ( '0' === $base_a && '0' <= $base_b && $base_b <= '9' ) {
$base = 8;
$at += 1;
}
// Trim leading zeros from the amount.
$at += strspn( $shorthand, '0', $at );
// Trap explicitly only the numeric digits for parsing to avoid PHP parsing strings like “1e5.”
$digits = 8 === $base ? '01234567' : ( 10 === $base ? '0123456789' : '0123456789abcdefABCDEF' );
$digit_length = strspn( $shorthand, $digits, $at );
$scalar = intval( substr( $shorthand, $at, $digit_length ), $base );
/*
* The internal call to `strtoll()` clamps its return value when the
* parsed value would lead to overflow, so recreate that here.
*/
if ( $sign > 0 && $scalar >= PHP_INT_MAX ) {
$scalar = PHP_INT_MAX;
} else if ( $sign < 0 && $scalar <= PHP_INT_MIN ) {
$scalar = PHP_INT_MIN;
}
/*
* Do not use WP constants here (GB_IN_BYTES, MB_IN_BYTES, KB_IN_BYTES)
* since they are re-definable; PHP shorthand values are hard-coded
* in PHP itself and stay the same regardless of these constants. Also,
* this file loads before these constants are defined.
*
* Note that it’s possible to overflow here, as happens in PHP itself.
* Overflow results will likely not match PHP’s value, but will likely
* break in most cases anyway and so leaving this loose is the best
* that can be done without PHP reporting the internal values.
*/
switch ( $shorthand[ $end - 1 ] ) {
case 'g':
case 'G':
$scalar *= 1073741824; // 1024^3
break;
case 'm':
case 'M':
$scalar *= 1048576; // 1024^2
break;
case 'k':
case 'K':
$scalar *= 1024;
break;
}
/**
* Since the overflow behavior is not reproduced here, any negative
* value will report as `-1`, which normalizes negative values for
* more consistent handling inside of plugin code, while large values
* are capped at the max integer value.
*
* These values would be wrong, they are also undefined behavior in
* PHP, so they are also not wrong in any specific way. This function
* only needs to be reliable enough, given that PHP 8.2.0 introduces
* the {@see \ini_parse_quantity()} function natively.
*/
return (int) max( -1, min( $scalar, PHP_INT_MAX ) );
}