Skip to content

Commit 6200ba9

Browse files
authored
Merge pull request #1083 from WordPress/feature/php-8.6-trim-compatibility
PHP 8.6 | Make "characters to be trimmed" explicit
2 parents eeb4f4f + 6d9e419 commit 6200ba9

7 files changed

Lines changed: 84 additions & 20 deletions

File tree

build/ghpages/UpdateMarkdown.php

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
*
2121
* @package Requests\GHPages
2222
*
23+
* @phpcs:disable PHPCompatibility.Classes.NewConstVisibility.Found
2324
* @phpcs:disable PHPCompatibility.FunctionDeclarations.NewParamTypeDeclarations.stringFound
2425
* @phpcs:disable PHPCompatibility.FunctionDeclarations.NewReturnTypeDeclarations.intFound
2526
* @phpcs:disable PHPCompatibility.FunctionDeclarations.NewReturnTypeDeclarations.stringFound
@@ -28,6 +29,13 @@
2829
*/
2930
class UpdateMarkdown {
3031

32+
/**
33+
* The ASCII whitespace characters and the null byte.
34+
*
35+
* @var string
36+
*/
37+
private const WHITESPACE_CHARS = " \f\n\r\t\v\x00";
38+
3139
/**
3240
* Target directory for the updated/transformed files.
3341
*
@@ -282,7 +290,7 @@ private function update_docs_navigation(string $source): void {
282290
/*
283291
* Create the docs index file.
284292
*/
285-
$docs_index = trim($parts[0]);
293+
$docs_index = trim($parts[0], self::WHITESPACE_CHARS);
286294

287295
// Grab the title.
288296
$title = $this->get_title_from_contents($contents);
@@ -300,7 +308,7 @@ private function update_docs_navigation(string $source): void {
300308
/*
301309
* Create the docs navigation file.
302310
*/
303-
$navigation = trim($parts[1]);
311+
$navigation = trim($parts[1], self::WHITESPACE_CHARS);
304312

305313
// Write the file.
306314
$target = $this->target . '/_includes/navigation.md';
@@ -349,7 +357,7 @@ private function put_contents(string $target, string $contents, string $type = '
349357
} // phpcs:enable WordPress
350358

351359
// Make sure the file always ends on a new line.
352-
$contents = rtrim($contents) . "\n";
360+
$contents = rtrim($contents, self::WHITESPACE_CHARS) . "\n";
353361
if (file_put_contents($target, $contents) === false) {
354362
throw new RuntimeException(sprintf('Failed to write %s to target location: %s', $type, $target));
355363
}
@@ -363,7 +371,7 @@ private function put_contents(string $target, string $contents, string $type = '
363371
* @return string
364372
*/
365373
private function get_title_from_contents(string $contents): string {
366-
return trim(substr($contents, 0, (strpos($contents, '===') - 1)));
374+
return trim(substr($contents, 0, (strpos($contents, '===') - 1)), self::WHITESPACE_CHARS);
367375
}
368376

369377
/**

src/Cookie.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use WpOrg\Requests\Response\Headers;
1515
use WpOrg\Requests\Utility\CaseInsensitiveDictionary;
1616
use WpOrg\Requests\Utility\InputValidator;
17+
use WpOrg\Requests\Utility\Trim;
1718

1819
/**
1920
* Cookie storage object
@@ -440,7 +441,7 @@ public static function parse($cookie_header, $name = '', $reference_time = null)
440441
}
441442

442443
if (is_string($name)) {
443-
$name = trim($name);
444+
$name = trim($name, Trim::WHITESPACE_CHARS_NO_FF);
444445
}
445446

446447
if ($name !== '' && InputValidator::is_valid_rfc2616_token($name) === false) {
@@ -464,8 +465,8 @@ public static function parse($cookie_header, $name = '', $reference_time = null)
464465
list($name, $value) = explode('=', $kvparts, 2);
465466
}
466467

467-
$name = trim($name);
468-
$value = trim($value);
468+
$name = trim($name, Trim::WHITESPACE_CHARS_NO_FF);
469+
$value = trim($value, Trim::WHITESPACE_CHARS_NO_FF);
469470

470471
if ($name !== '' && InputValidator::is_valid_rfc2616_token($name) === false) {
471472
throw InvalidArgument::create(2, '$name', 'integer|string and conform to RFC 2616', gettype($name));
@@ -481,10 +482,10 @@ public static function parse($cookie_header, $name = '', $reference_time = null)
481482
$part_value = true;
482483
} else {
483484
list($part_key, $part_value) = explode('=', $part, 2);
484-
$part_value = trim($part_value);
485+
$part_value = trim($part_value, Trim::WHITESPACE_CHARS_NO_FF);
485486
}
486487

487-
$part_key = trim($part_key);
488+
$part_key = trim($part_key, Trim::WHITESPACE_CHARS_NO_FF);
488489
$attributes[$part_key] = $part_value;
489490
}
490491
}

src/Requests.php

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use WpOrg\Requests\Transport\Curl;
2323
use WpOrg\Requests\Transport\Fsockopen;
2424
use WpOrg\Requests\Utility\InputValidator;
25+
use WpOrg\Requests\Utility\Trim;
2526

2627
/**
2728
* Requests for PHP
@@ -762,7 +763,7 @@ protected static function parse_response($headers, $url, $req_headers, $req_data
762763

763764
foreach ($headers as $header) {
764765
list($key, $value) = explode(':', $header, 2);
765-
$value = trim($value);
766+
$value = trim($value, Trim::WHITESPACE_CHARS_NO_FF);
766767
preg_replace('#(\s+)#i', ' ', $value);
767768
$return->headers[$key] = $value;
768769
}
@@ -851,7 +852,7 @@ public static function parse_multiple(&$response, $request) {
851852
* @return string Decoded body
852853
*/
853854
protected static function decode_chunked($data) {
854-
if (!preg_match('/^([0-9a-f]+)(?:;(?:[\w-]*)(?:=(?:(?:[\w-]*)*|"(?:[^\r\n])*"))?)*\r\n/i', trim($data))) {
855+
if (!preg_match('/^([0-9a-f]+)(?:;(?:[\w-]*)(?:=(?:(?:[\w-]*)*|"(?:[^\r\n])*"))?)*\r\n/i', trim($data, Trim::WHITESPACE_CHARS_NO_FF))) {
855856
return $data;
856857
}
857858

@@ -865,7 +866,7 @@ protected static function decode_chunked($data) {
865866
return $data;
866867
}
867868

868-
$length = hexdec(trim($matches[1]));
869+
$length = hexdec(trim($matches[1], Trim::WHITESPACE_CHARS_NO_FF));
869870
if ($length === 0) {
870871
// Ignore trailer headers
871872
return $decoded;
@@ -875,7 +876,7 @@ protected static function decode_chunked($data) {
875876
$decoded .= substr($encoded, $chunk_length, $length);
876877
$encoded = substr($encoded, $chunk_length + $length + 2);
877878

878-
if (trim($encoded) === '0' || empty($encoded)) {
879+
if (trim($encoded, Trim::WHITESPACE_CHARS_NO_FF) === '0' || empty($encoded)) {
879880
return $decoded;
880881
}
881882
}
@@ -922,7 +923,7 @@ public static function decompress($data) {
922923
throw InvalidArgument::create(1, '$data', 'string', gettype($data));
923924
}
924925

925-
if (trim($data) === '') {
926+
if (trim($data, Trim::WHITESPACE_CHARS_NO_FF) === '') {
926927
// Empty body does not need further processing.
927928
return $data;
928929
}
@@ -989,7 +990,7 @@ public static function compatible_gzinflate($gz_data) {
989990
throw InvalidArgument::create(1, '$gz_data', 'string', gettype($gz_data));
990991
}
991992

992-
if (trim($gz_data) === '') {
993+
if (trim($gz_data, Trim::WHITESPACE_CHARS_NO_FF) === '') {
993994
return false;
994995
}
995996

src/Ssl.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
use WpOrg\Requests\Exception\InvalidArgument;
1313
use WpOrg\Requests\Utility\InputValidator;
14+
use WpOrg\Requests\Utility\Trim;
1415

1516
/**
1617
* SSL utilities for Requests
@@ -49,15 +50,15 @@ public static function verify_certificate($host, $cert) {
4950
if (!empty($cert['extensions']['subjectAltName'])) {
5051
$altnames = explode(',', $cert['extensions']['subjectAltName']);
5152
foreach ($altnames as $altname) {
52-
$altname = trim($altname);
53+
$altname = trim($altname, Trim::WHITESPACE_CHARS_NO_FF);
5354
if (strpos($altname, 'DNS:') !== 0) {
5455
continue;
5556
}
5657

5758
$has_dns_alt = true;
5859

5960
// Strip the 'DNS:' prefix and trim whitespace
60-
$altname = trim(substr($altname, 4));
61+
$altname = trim(substr($altname, 4), Trim::WHITESPACE_CHARS_NO_FF);
6162

6263
// Check for a match
6364
if (self::match_domain($host, $altname) === true) {

src/Transport/Curl.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use WpOrg\Requests\Requests;
1919
use WpOrg\Requests\Transport;
2020
use WpOrg\Requests\Utility\InputValidator;
21+
use WpOrg\Requests\Utility\Trim;
2122

2223
/**
2324
* HTTP transport using libcurl.
@@ -500,7 +501,7 @@ public function process_response($response, $options) {
500501

501502
if ($options['filename'] !== false && $this->stream_handle) {
502503
fclose($this->stream_handle);
503-
$this->headers = trim($this->headers);
504+
$this->headers = trim($this->headers, Trim::WHITESPACE_CHARS_NO_FF);
504505
} else {
505506
$this->headers .= $response;
506507
}

src/Transport/Fsockopen.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use WpOrg\Requests\Transport;
1919
use WpOrg\Requests\Utility\CaseInsensitiveDictionary;
2020
use WpOrg\Requests\Utility\InputValidator;
21+
use WpOrg\Requests\Utility\Trim;
2122

2223
/**
2324
* fsockopen HTTP transport
@@ -182,7 +183,7 @@ public function request($url, $headers = [], $data = [], $options = []) {
182183
if (!$socket) {
183184
if ($errno === 0) {
184185
// Connection issue
185-
throw new Exception(rtrim($this->connect_error), 'fsockopen.connect_error');
186+
throw new Exception(rtrim($this->connect_error, Trim::WHITESPACE_CHARS), 'fsockopen.connect_error');
186187
}
187188

188189
throw new Exception($errstr, 'fsockopenerror', null, $errno);
@@ -492,7 +493,7 @@ public function verify_certificate_from_context($host, $context) {
492493
// If we don't have SSL options, then we couldn't make the connection at
493494
// all
494495
if (empty($meta) || empty($meta['ssl']) || empty($meta['ssl']['peer_certificate'])) {
495-
throw new Exception(rtrim($this->connect_error), 'ssl.connect_error');
496+
throw new Exception(rtrim($this->connect_error, Trim::WHITESPACE_CHARS), 'ssl.connect_error');
496497
}
497498

498499
$cert = openssl_x509_parse($meta['ssl']['peer_certificate']);

src/Utility/Trim.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
/**
3+
* Requests for PHP, an HTTP library.
4+
*
5+
* @copyright 2012-2023 Requests Contributors
6+
* @license https://github.com/WordPress/Requests/blob/stable/LICENSE ISC
7+
* @link https://github.com/WordPress/Requests
8+
*/
9+
10+
namespace WpOrg\Requests\Utility;
11+
12+
/**
13+
* Poor person's (backed) enum with the PHP native trim `$characters` defaults to choose from.
14+
*
15+
* In PHP 8.6, the default value for the `$characters` parameter of the `[rl]trim()` function
16+
* changed to include the form feed character.
17+
*
18+
* This "enum" allows calls to `[rl]trim()` throughout the code to document and make it explicit
19+
* which characters should be trimmed from the text string in question.
20+
*
21+
* @link https://wiki.php.net/rfc/trim_form_feed
22+
*
23+
* ---------------------------------------------------------------------------------------------
24+
* This class is only intended for internal use by Requests and is not part of the public API.
25+
* This also means that it has no promise of backward compatibility. Use at your own risk.
26+
* ---------------------------------------------------------------------------------------------
27+
*
28+
* @internal
29+
* @package Requests\Utilities
30+
* @since 2.1.0
31+
*/
32+
final class Trim {
33+
34+
/**
35+
* The ASCII whitespace characters and the NUL byte, excluding the form feed character.
36+
*
37+
* This is the PHP native default in PHP < 8.6.
38+
*
39+
* @var string
40+
*/
41+
const WHITESPACE_CHARS_NO_FF = " \n\r\t\v\x00";
42+
43+
/**
44+
* The ASCII whitespace characters, including the form feed character, and the NUL byte.
45+
*
46+
* This is the PHP native default in PHP >= 8.6.
47+
*
48+
* @var string
49+
*/
50+
const WHITESPACE_CHARS = " \f\n\r\t\v\x00";
51+
}

0 commit comments

Comments
 (0)