diff --git a/WordPressVIPMinimum/Sniffs/Performance/FetchingRemoteDataSniff.php b/WordPressVIPMinimum/Sniffs/Performance/FetchingRemoteDataSniff.php index e5b3eb11..27cf4aa9 100644 --- a/WordPressVIPMinimum/Sniffs/Performance/FetchingRemoteDataSniff.php +++ b/WordPressVIPMinimum/Sniffs/Performance/FetchingRemoteDataSniff.php @@ -66,7 +66,18 @@ public function process_parameters( $stackPtr, $group_name, $matched_content, $p $search_start = $param_start; // phpcs:ignore Generic.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition -- Valid usage. while ( ( $has_text_string = $this->phpcsFile->findNext( Tokens::$stringTokens, $search_start, $search_end ) ) !== false ) { - if ( strpos( $this->tokens[ $has_text_string ]['content'], '://' ) !== false ) { + $string_content = $this->tokens[ $has_text_string ]['content']; + if ( strpos( $string_content, '://' ) !== false ) { + /* + * The `php://` stream wrappers (php://input, php://stdin, php://memory, + * php://temp, etc.) are local, in-process streams rather than remote + * requests, so should not be flagged. The scheme is case-insensitive. + */ + if ( preg_match( '`^["\']?php://`i', $string_content ) === 1 ) { + $search_start = ( $has_text_string + 1 ); + continue; + } + $isRemoteFile = true; break; } diff --git a/WordPressVIPMinimum/Tests/Performance/FetchingRemoteDataUnitTest.inc b/WordPressVIPMinimum/Tests/Performance/FetchingRemoteDataUnitTest.inc index 40e48b7f..0dbf7c8f 100644 --- a/WordPressVIPMinimum/Tests/Performance/FetchingRemoteDataUnitTest.inc +++ b/WordPressVIPMinimum/Tests/Performance/FetchingRemoteDataUnitTest.inc @@ -86,3 +86,13 @@ $result = file_get_contents(( is_ssl() ? 'http' : 'https' ) . '://example.com'); // Bug: don't presume if the parameter contains a text string token, that will be the only token. \file_get_contents( $url . '/filename.css' ); // Warning FileGetContentsUnknown. + +// Bug #506: the `php://` stream wrappers are local, in-process streams, not remote requests, so should not be flagged. +$webhook_body = file_get_contents( 'php://input' ); // OK. +$std_input = \file_get_contents( 'php://stdin' ); // OK. +$in_memory = file_get_contents( "php://memory" ); // OK. +$temp_stream = file_get_contents( 'php://temp/maxmemory:1048576' ); // OK. +$case_insensitive = file_get_contents( 'PHP://input' ); // OK. The scheme is case-insensitive. + +// Bug #506: a `php://` substring which is not the URL scheme must still be flagged as remote. +$masked_remote = file_get_contents( 'https://example.com/?redirect=php://input' ); // Warning FileGetContentsRemoteFile. diff --git a/WordPressVIPMinimum/Tests/Performance/FetchingRemoteDataUnitTest.php b/WordPressVIPMinimum/Tests/Performance/FetchingRemoteDataUnitTest.php index 9f9ede3a..3975915d 100644 --- a/WordPressVIPMinimum/Tests/Performance/FetchingRemoteDataUnitTest.php +++ b/WordPressVIPMinimum/Tests/Performance/FetchingRemoteDataUnitTest.php @@ -45,6 +45,7 @@ public function getWarningList() { 79 => 1, 85 => 1, 88 => 1, + 98 => 1, ]; } }