wp/wp-includes/class-wp-http-streams.php
changeset 16 a86126ab1dd4
parent 9 177826044cd9
child 18 be944660c56a
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
    20 	 * @see WP_Http::request For default options descriptions.
    20 	 * @see WP_Http::request For default options descriptions.
    21 	 *
    21 	 *
    22 	 * @since 2.7.0
    22 	 * @since 2.7.0
    23 	 * @since 3.7.0 Combined with the fsockopen transport and switched to stream_socket_client().
    23 	 * @since 3.7.0 Combined with the fsockopen transport and switched to stream_socket_client().
    24 	 *
    24 	 *
    25 	 * @param string $url The request URL.
    25 	 * @param string       $url  The request URL.
    26 	 * @param string|array $args Optional. Override the defaults.
    26 	 * @param string|array $args Optional. Override the defaults.
    27 	 * @return array|WP_Error Array containing 'headers', 'body', 'response', 'cookies', 'filename'. A WP_Error instance upon error
    27 	 * @return array|WP_Error Array containing 'headers', 'body', 'response', 'cookies', 'filename'. A WP_Error instance upon error
    28 	 */
    28 	 */
    29 	public function request( $url, $args = array() ) {
    29 	public function request( $url, $args = array() ) {
    30 		$defaults = array(
    30 		$defaults = array(
    36 			'headers'     => array(),
    36 			'headers'     => array(),
    37 			'body'        => null,
    37 			'body'        => null,
    38 			'cookies'     => array(),
    38 			'cookies'     => array(),
    39 		);
    39 		);
    40 
    40 
    41 		$r = wp_parse_args( $args, $defaults );
    41 		$parsed_args = wp_parse_args( $args, $defaults );
    42 
    42 
    43 		if ( isset( $r['headers']['User-Agent'] ) ) {
    43 		if ( isset( $parsed_args['headers']['User-Agent'] ) ) {
    44 			$r['user-agent'] = $r['headers']['User-Agent'];
    44 			$parsed_args['user-agent'] = $parsed_args['headers']['User-Agent'];
    45 			unset( $r['headers']['User-Agent'] );
    45 			unset( $parsed_args['headers']['User-Agent'] );
    46 		} elseif ( isset( $r['headers']['user-agent'] ) ) {
    46 		} elseif ( isset( $parsed_args['headers']['user-agent'] ) ) {
    47 			$r['user-agent'] = $r['headers']['user-agent'];
    47 			$parsed_args['user-agent'] = $parsed_args['headers']['user-agent'];
    48 			unset( $r['headers']['user-agent'] );
    48 			unset( $parsed_args['headers']['user-agent'] );
    49 		}
    49 		}
    50 
    50 
    51 		// Construct Cookie: header if any cookies are set.
    51 		// Construct Cookie: header if any cookies are set.
    52 		WP_Http::buildCookieHeader( $r );
    52 		WP_Http::buildCookieHeader( $parsed_args );
    53 
    53 
    54 		$arrURL = parse_url( $url );
    54 		$arrURL = parse_url( $url );
    55 
    55 
    56 		$connect_host = $arrURL['host'];
    56 		$connect_host = $arrURL['host'];
    57 
    57 
    58 		$secure_transport = ( $arrURL['scheme'] == 'ssl' || $arrURL['scheme'] == 'https' );
    58 		$secure_transport = ( 'ssl' === $arrURL['scheme'] || 'https' === $arrURL['scheme'] );
    59 		if ( ! isset( $arrURL['port'] ) ) {
    59 		if ( ! isset( $arrURL['port'] ) ) {
    60 			if ( $arrURL['scheme'] == 'ssl' || $arrURL['scheme'] == 'https' ) {
    60 			if ( 'ssl' === $arrURL['scheme'] || 'https' === $arrURL['scheme'] ) {
    61 				$arrURL['port']   = 443;
    61 				$arrURL['port']   = 443;
    62 				$secure_transport = true;
    62 				$secure_transport = true;
    63 			} else {
    63 			} else {
    64 				$arrURL['port'] = 80;
    64 				$arrURL['port'] = 80;
    65 			}
    65 			}
    66 		}
    66 		}
    67 
    67 
    68 		// Always pass a Path, defaulting to the root in cases such as http://example.com
    68 		// Always pass a path, defaulting to the root in cases such as http://example.com.
    69 		if ( ! isset( $arrURL['path'] ) ) {
    69 		if ( ! isset( $arrURL['path'] ) ) {
    70 			$arrURL['path'] = '/';
    70 			$arrURL['path'] = '/';
    71 		}
    71 		}
    72 
    72 
    73 		if ( isset( $r['headers']['Host'] ) || isset( $r['headers']['host'] ) ) {
    73 		if ( isset( $parsed_args['headers']['Host'] ) || isset( $parsed_args['headers']['host'] ) ) {
    74 			if ( isset( $r['headers']['Host'] ) ) {
    74 			if ( isset( $parsed_args['headers']['Host'] ) ) {
    75 				$arrURL['host'] = $r['headers']['Host'];
    75 				$arrURL['host'] = $parsed_args['headers']['Host'];
    76 			} else {
    76 			} else {
    77 				$arrURL['host'] = $r['headers']['host'];
    77 				$arrURL['host'] = $parsed_args['headers']['host'];
    78 			}
    78 			}
    79 			unset( $r['headers']['Host'], $r['headers']['host'] );
    79 			unset( $parsed_args['headers']['Host'], $parsed_args['headers']['host'] );
    80 		}
    80 		}
    81 
    81 
    82 		/*
    82 		/*
    83 		 * Certain versions of PHP have issues with 'localhost' and IPv6, It attempts to connect
    83 		 * Certain versions of PHP have issues with 'localhost' and IPv6, It attempts to connect
    84 		 * to ::1, which fails when the server is not set up for it. For compatibility, always
    84 		 * to ::1, which fails when the server is not set up for it. For compatibility, always
    85 		 * connect to the IPv4 address.
    85 		 * connect to the IPv4 address.
    86 		 */
    86 		 */
    87 		if ( 'localhost' == strtolower( $connect_host ) ) {
    87 		if ( 'localhost' === strtolower( $connect_host ) ) {
    88 			$connect_host = '127.0.0.1';
    88 			$connect_host = '127.0.0.1';
    89 		}
    89 		}
    90 
    90 
    91 		$connect_host = $secure_transport ? 'ssl://' . $connect_host : 'tcp://' . $connect_host;
    91 		$connect_host = $secure_transport ? 'ssl://' . $connect_host : 'tcp://' . $connect_host;
    92 
    92 
    93 		$is_local   = isset( $r['local'] ) && $r['local'];
    93 		$is_local   = isset( $parsed_args['local'] ) && $parsed_args['local'];
    94 		$ssl_verify = isset( $r['sslverify'] ) && $r['sslverify'];
    94 		$ssl_verify = isset( $parsed_args['sslverify'] ) && $parsed_args['sslverify'];
    95 		if ( $is_local ) {
    95 		if ( $is_local ) {
    96 			/**
    96 			/**
    97 			 * Filters whether SSL should be verified for local requests.
    97 			 * Filters whether SSL should be verified for local requests.
    98 			 *
    98 			 *
    99 			 * @since 2.8.0
    99 			 * @since 2.8.0
   112 
   112 
   113 		$context = stream_context_create(
   113 		$context = stream_context_create(
   114 			array(
   114 			array(
   115 				'ssl' => array(
   115 				'ssl' => array(
   116 					'verify_peer'       => $ssl_verify,
   116 					'verify_peer'       => $ssl_verify,
   117 					//'CN_match' => $arrURL['host'], // This is handled by self::verify_ssl_certificate()
   117 					// 'CN_match' => $arrURL['host'], // This is handled by self::verify_ssl_certificate().
   118 					'capture_peer_cert' => $ssl_verify,
   118 					'capture_peer_cert' => $ssl_verify,
   119 					'SNI_enabled'       => true,
   119 					'SNI_enabled'       => true,
   120 					'cafile'            => $r['sslcertificates'],
   120 					'cafile'            => $parsed_args['sslcertificates'],
   121 					'allow_self_signed' => ! $ssl_verify,
   121 					'allow_self_signed' => ! $ssl_verify,
   122 				),
   122 				),
   123 			)
   123 			)
   124 		);
   124 		);
   125 
   125 
   126 		$timeout         = (int) floor( $r['timeout'] );
   126 		$timeout         = (int) floor( $parsed_args['timeout'] );
   127 		$utimeout        = $timeout == $r['timeout'] ? 0 : 1000000 * $r['timeout'] % 1000000;
   127 		$utimeout        = $timeout == $parsed_args['timeout'] ? 0 : 1000000 * $parsed_args['timeout'] % 1000000;
   128 		$connect_timeout = max( $timeout, 1 );
   128 		$connect_timeout = max( $timeout, 1 );
   129 
   129 
   130 		// Store error number.
   130 		// Store error number.
   131 		$connection_error = null;
   131 		$connection_error = null;
   132 
   132 
   133 		// Store error string.
   133 		// Store error string.
   134 		$connection_error_str = null;
   134 		$connection_error_str = null;
   135 
   135 
   136 		if ( ! WP_DEBUG ) {
   136 		if ( ! WP_DEBUG ) {
   137 			// In the event that the SSL connection fails, silence the many PHP Warnings.
   137 			// In the event that the SSL connection fails, silence the many PHP warnings.
   138 			if ( $secure_transport ) {
   138 			if ( $secure_transport ) {
   139 				$error_reporting = error_reporting( 0 );
   139 				$error_reporting = error_reporting( 0 );
   140 			}
   140 			}
   141 
   141 
   142 			if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) {
   142 			if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) {
       
   143 				// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
   143 				$handle = @stream_socket_client( 'tcp://' . $proxy->host() . ':' . $proxy->port(), $connection_error, $connection_error_str, $connect_timeout, STREAM_CLIENT_CONNECT, $context );
   144 				$handle = @stream_socket_client( 'tcp://' . $proxy->host() . ':' . $proxy->port(), $connection_error, $connection_error_str, $connect_timeout, STREAM_CLIENT_CONNECT, $context );
   144 			} else {
   145 			} else {
       
   146 				// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
   145 				$handle = @stream_socket_client( $connect_host . ':' . $arrURL['port'], $connection_error, $connection_error_str, $connect_timeout, STREAM_CLIENT_CONNECT, $context );
   147 				$handle = @stream_socket_client( $connect_host . ':' . $arrURL['port'], $connection_error, $connection_error_str, $connect_timeout, STREAM_CLIENT_CONNECT, $context );
   146 			}
   148 			}
   147 
   149 
   148 			if ( $secure_transport ) {
   150 			if ( $secure_transport ) {
   149 				error_reporting( $error_reporting );
   151 				error_reporting( $error_reporting );
   172 			}
   174 			}
   173 		}
   175 		}
   174 
   176 
   175 		stream_set_timeout( $handle, $timeout, $utimeout );
   177 		stream_set_timeout( $handle, $timeout, $utimeout );
   176 
   178 
   177 		if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) { //Some proxies require full URL in this field.
   179 		if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) { // Some proxies require full URL in this field.
   178 			$requestPath = $url;
   180 			$requestPath = $url;
   179 		} else {
   181 		} else {
   180 			$requestPath = $arrURL['path'] . ( isset( $arrURL['query'] ) ? '?' . $arrURL['query'] : '' );
   182 			$requestPath = $arrURL['path'] . ( isset( $arrURL['query'] ) ? '?' . $arrURL['query'] : '' );
   181 		}
   183 		}
   182 
   184 
   183 		$strHeaders = strtoupper( $r['method'] ) . ' ' . $requestPath . ' HTTP/' . $r['httpversion'] . "\r\n";
   185 		$strHeaders = strtoupper( $parsed_args['method'] ) . ' ' . $requestPath . ' HTTP/' . $parsed_args['httpversion'] . "\r\n";
   184 
   186 
   185 		$include_port_in_host_header = (
   187 		$include_port_in_host_header = (
   186 			( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) ||
   188 			( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) ||
   187 			( 'http' == $arrURL['scheme'] && 80 != $arrURL['port'] ) ||
   189 			( 'http' === $arrURL['scheme'] && 80 != $arrURL['port'] ) ||
   188 			( 'https' == $arrURL['scheme'] && 443 != $arrURL['port'] )
   190 			( 'https' === $arrURL['scheme'] && 443 != $arrURL['port'] )
   189 		);
   191 		);
   190 
   192 
   191 		if ( $include_port_in_host_header ) {
   193 		if ( $include_port_in_host_header ) {
   192 			$strHeaders .= 'Host: ' . $arrURL['host'] . ':' . $arrURL['port'] . "\r\n";
   194 			$strHeaders .= 'Host: ' . $arrURL['host'] . ':' . $arrURL['port'] . "\r\n";
   193 		} else {
   195 		} else {
   194 			$strHeaders .= 'Host: ' . $arrURL['host'] . "\r\n";
   196 			$strHeaders .= 'Host: ' . $arrURL['host'] . "\r\n";
   195 		}
   197 		}
   196 
   198 
   197 		if ( isset( $r['user-agent'] ) ) {
   199 		if ( isset( $parsed_args['user-agent'] ) ) {
   198 			$strHeaders .= 'User-agent: ' . $r['user-agent'] . "\r\n";
   200 			$strHeaders .= 'User-agent: ' . $parsed_args['user-agent'] . "\r\n";
   199 		}
   201 		}
   200 
   202 
   201 		if ( is_array( $r['headers'] ) ) {
   203 		if ( is_array( $parsed_args['headers'] ) ) {
   202 			foreach ( (array) $r['headers'] as $header => $headerValue ) {
   204 			foreach ( (array) $parsed_args['headers'] as $header => $headerValue ) {
   203 				$strHeaders .= $header . ': ' . $headerValue . "\r\n";
   205 				$strHeaders .= $header . ': ' . $headerValue . "\r\n";
   204 			}
   206 			}
   205 		} else {
   207 		} else {
   206 			$strHeaders .= $r['headers'];
   208 			$strHeaders .= $parsed_args['headers'];
   207 		}
   209 		}
   208 
   210 
   209 		if ( $proxy->use_authentication() ) {
   211 		if ( $proxy->use_authentication() ) {
   210 			$strHeaders .= $proxy->authentication_header() . "\r\n";
   212 			$strHeaders .= $proxy->authentication_header() . "\r\n";
   211 		}
   213 		}
   212 
   214 
   213 		$strHeaders .= "\r\n";
   215 		$strHeaders .= "\r\n";
   214 
   216 
   215 		if ( ! is_null( $r['body'] ) ) {
   217 		if ( ! is_null( $parsed_args['body'] ) ) {
   216 			$strHeaders .= $r['body'];
   218 			$strHeaders .= $parsed_args['body'];
   217 		}
   219 		}
   218 
   220 
   219 		fwrite( $handle, $strHeaders );
   221 		fwrite( $handle, $strHeaders );
   220 
   222 
   221 		if ( ! $r['blocking'] ) {
   223 		if ( ! $parsed_args['blocking'] ) {
   222 			stream_set_blocking( $handle, 0 );
   224 			stream_set_blocking( $handle, 0 );
   223 			fclose( $handle );
   225 			fclose( $handle );
   224 			return array(
   226 			return array(
   225 				'headers'  => array(),
   227 				'headers'  => array(),
   226 				'body'     => '',
   228 				'body'     => '',
   234 
   236 
   235 		$strResponse  = '';
   237 		$strResponse  = '';
   236 		$bodyStarted  = false;
   238 		$bodyStarted  = false;
   237 		$keep_reading = true;
   239 		$keep_reading = true;
   238 		$block_size   = 4096;
   240 		$block_size   = 4096;
   239 		if ( isset( $r['limit_response_size'] ) ) {
   241 		if ( isset( $parsed_args['limit_response_size'] ) ) {
   240 			$block_size = min( $block_size, $r['limit_response_size'] );
   242 			$block_size = min( $block_size, $parsed_args['limit_response_size'] );
   241 		}
   243 		}
   242 
   244 
   243 		// If streaming to a file setup the file handle.
   245 		// If streaming to a file setup the file handle.
   244 		if ( $r['stream'] ) {
   246 		if ( $parsed_args['stream'] ) {
   245 			if ( ! WP_DEBUG ) {
   247 			if ( ! WP_DEBUG ) {
   246 				$stream_handle = @fopen( $r['filename'], 'w+' );
   248 				$stream_handle = @fopen( $parsed_args['filename'], 'w+' );
   247 			} else {
   249 			} else {
   248 				$stream_handle = fopen( $r['filename'], 'w+' );
   250 				$stream_handle = fopen( $parsed_args['filename'], 'w+' );
   249 			}
   251 			}
   250 			if ( ! $stream_handle ) {
   252 			if ( ! $stream_handle ) {
   251 				return new WP_Error(
   253 				return new WP_Error(
   252 					'http_request_failed',
   254 					'http_request_failed',
   253 					sprintf(
   255 					sprintf(
   254 						/* translators: 1: fopen(), 2: file name */
   256 						/* translators: 1: fopen(), 2: File name. */
   255 						__( 'Could not open handle for %1$s to %2$s.' ),
   257 						__( 'Could not open handle for %1$s to %2$s.' ),
   256 						'fopen()',
   258 						'fopen()',
   257 						$r['filename']
   259 						$parsed_args['filename']
   258 					)
   260 					)
   259 				);
   261 				);
   260 			}
   262 			}
   261 
   263 
   262 			$bytes_written = 0;
   264 			$bytes_written = 0;
   273 					}
   275 					}
   274 				}
   276 				}
   275 
   277 
   276 				$this_block_size = strlen( $block );
   278 				$this_block_size = strlen( $block );
   277 
   279 
   278 				if ( isset( $r['limit_response_size'] ) && ( $bytes_written + $this_block_size ) > $r['limit_response_size'] ) {
   280 				if ( isset( $parsed_args['limit_response_size'] ) && ( $bytes_written + $this_block_size ) > $parsed_args['limit_response_size'] ) {
   279 					$this_block_size = ( $r['limit_response_size'] - $bytes_written );
   281 					$this_block_size = ( $parsed_args['limit_response_size'] - $bytes_written );
   280 					$block           = substr( $block, 0, $this_block_size );
   282 					$block           = substr( $block, 0, $this_block_size );
   281 				}
   283 				}
   282 
   284 
   283 				$bytes_written_to_file = fwrite( $stream_handle, $block );
   285 				$bytes_written_to_file = fwrite( $stream_handle, $block );
   284 
   286 
   288 					return new WP_Error( 'http_request_failed', __( 'Failed to write request to temporary file.' ) );
   290 					return new WP_Error( 'http_request_failed', __( 'Failed to write request to temporary file.' ) );
   289 				}
   291 				}
   290 
   292 
   291 				$bytes_written += $bytes_written_to_file;
   293 				$bytes_written += $bytes_written_to_file;
   292 
   294 
   293 				$keep_reading = ! isset( $r['limit_response_size'] ) || $bytes_written < $r['limit_response_size'];
   295 				$keep_reading = ! isset( $parsed_args['limit_response_size'] ) || $bytes_written < $parsed_args['limit_response_size'];
   294 			}
   296 			}
   295 
   297 
   296 			fclose( $stream_handle );
   298 			fclose( $stream_handle );
   297 
   299 
   298 		} else {
   300 		} else {
   302 				$strResponse .= $block;
   304 				$strResponse .= $block;
   303 				if ( ! $bodyStarted && strpos( $strResponse, "\r\n\r\n" ) ) {
   305 				if ( ! $bodyStarted && strpos( $strResponse, "\r\n\r\n" ) ) {
   304 					$header_length = strpos( $strResponse, "\r\n\r\n" ) + 4;
   306 					$header_length = strpos( $strResponse, "\r\n\r\n" ) + 4;
   305 					$bodyStarted   = true;
   307 					$bodyStarted   = true;
   306 				}
   308 				}
   307 				$keep_reading = ( ! $bodyStarted || ! isset( $r['limit_response_size'] ) || strlen( $strResponse ) < ( $header_length + $r['limit_response_size'] ) );
   309 				$keep_reading = ( ! $bodyStarted || ! isset( $parsed_args['limit_response_size'] ) || strlen( $strResponse ) < ( $header_length + $parsed_args['limit_response_size'] ) );
   308 			}
   310 			}
   309 
   311 
   310 			$process = WP_Http::processResponse( $strResponse );
   312 			$process = WP_Http::processResponse( $strResponse );
   311 			unset( $strResponse );
   313 			unset( $strResponse );
   312 
   314 
   320 			'headers'  => $arrHeaders['headers'],
   322 			'headers'  => $arrHeaders['headers'],
   321 			// Not yet processed.
   323 			// Not yet processed.
   322 			'body'     => null,
   324 			'body'     => null,
   323 			'response' => $arrHeaders['response'],
   325 			'response' => $arrHeaders['response'],
   324 			'cookies'  => $arrHeaders['cookies'],
   326 			'cookies'  => $arrHeaders['cookies'],
   325 			'filename' => $r['filename'],
   327 			'filename' => $parsed_args['filename'],
   326 		);
   328 		);
   327 
   329 
   328 		// Handle redirects.
   330 		// Handle redirects.
   329 		if ( false !== ( $redirect_response = WP_Http::handle_redirects( $url, $r, $response ) ) ) {
   331 		$redirect_response = WP_Http::handle_redirects( $url, $parsed_args, $response );
       
   332 		if ( false !== $redirect_response ) {
   330 			return $redirect_response;
   333 			return $redirect_response;
   331 		}
   334 		}
   332 
   335 
   333 		// If the body was chunk encoded, then decode it.
   336 		// If the body was chunk encoded, then decode it.
   334 		if ( ! empty( $process['body'] ) && isset( $arrHeaders['headers']['transfer-encoding'] ) && 'chunked' == $arrHeaders['headers']['transfer-encoding'] ) {
   337 		if ( ! empty( $process['body'] ) && isset( $arrHeaders['headers']['transfer-encoding'] )
       
   338 			&& 'chunked' === $arrHeaders['headers']['transfer-encoding']
       
   339 		) {
   335 			$process['body'] = WP_Http::chunkTransferDecode( $process['body'] );
   340 			$process['body'] = WP_Http::chunkTransferDecode( $process['body'] );
   336 		}
   341 		}
   337 
   342 
   338 		if ( true === $r['decompress'] && true === WP_Http_Encoding::should_decode( $arrHeaders['headers'] ) ) {
   343 		if ( true === $parsed_args['decompress'] && true === WP_Http_Encoding::should_decode( $arrHeaders['headers'] ) ) {
   339 			$process['body'] = WP_Http_Encoding::decompress( $process['body'] );
   344 			$process['body'] = WP_Http_Encoding::decompress( $process['body'] );
   340 		}
   345 		}
   341 
   346 
   342 		if ( isset( $r['limit_response_size'] ) && strlen( $process['body'] ) > $r['limit_response_size'] ) {
   347 		if ( isset( $parsed_args['limit_response_size'] ) && strlen( $process['body'] ) > $parsed_args['limit_response_size'] ) {
   343 			$process['body'] = substr( $process['body'], 0, $r['limit_response_size'] );
   348 			$process['body'] = substr( $process['body'], 0, $parsed_args['limit_response_size'] );
   344 		}
   349 		}
   345 
   350 
   346 		$response['body'] = $process['body'];
   351 		$response['body'] = $process['body'];
   347 
   352 
   348 		return $response;
   353 		return $response;
   385 		$certificate_hostnames = array();
   390 		$certificate_hostnames = array();
   386 		if ( ! empty( $cert['extensions']['subjectAltName'] ) ) {
   391 		if ( ! empty( $cert['extensions']['subjectAltName'] ) ) {
   387 			$match_against = preg_split( '/,\s*/', $cert['extensions']['subjectAltName'] );
   392 			$match_against = preg_split( '/,\s*/', $cert['extensions']['subjectAltName'] );
   388 			foreach ( $match_against as $match ) {
   393 			foreach ( $match_against as $match ) {
   389 				list( $match_type, $match_host ) = explode( ':', $match );
   394 				list( $match_type, $match_host ) = explode( ':', $match );
   390 				if ( $host_type == strtolower( trim( $match_type ) ) ) { // IP: or DNS:
   395 				if ( strtolower( trim( $match_type ) ) === $host_type ) { // IP: or DNS:
   391 					$certificate_hostnames[] = strtolower( trim( $match_host ) );
   396 					$certificate_hostnames[] = strtolower( trim( $match_host ) );
   392 				}
   397 				}
   393 			}
   398 			}
   394 		} elseif ( ! empty( $cert['subject']['CN'] ) ) {
   399 		} elseif ( ! empty( $cert['subject']['CN'] ) ) {
   395 			// Only use the CN when the certificate includes no subjectAltName extension.
   400 			// Only use the CN when the certificate includes no subjectAltName extension.
   396 			$certificate_hostnames[] = strtolower( $cert['subject']['CN'] );
   401 			$certificate_hostnames[] = strtolower( $cert['subject']['CN'] );
   397 		}
   402 		}
   398 
   403 
   399 		// Exact hostname/IP matches.
   404 		// Exact hostname/IP matches.
   400 		if ( in_array( strtolower( $host ), $certificate_hostnames ) ) {
   405 		if ( in_array( strtolower( $host ), $certificate_hostnames, true ) ) {
   401 			return true;
   406 			return true;
   402 		}
   407 		}
   403 
   408 
   404 		// IP's can't be wildcards, Stop processing.
   409 		// IP's can't be wildcards, Stop processing.
   405 		if ( 'ip' == $host_type ) {
   410 		if ( 'ip' === $host_type ) {
   406 			return false;
   411 			return false;
   407 		}
   412 		}
   408 
   413 
   409 		// Test to see if the domain is at least 2 deep for wildcard support.
   414 		// Test to see if the domain is at least 2 deep for wildcard support.
   410 		if ( substr_count( $host, '.' ) < 2 ) {
   415 		if ( substr_count( $host, '.' ) < 2 ) {
   412 		}
   417 		}
   413 
   418 
   414 		// Wildcard subdomains certs (*.example.com) are valid for a.example.com but not a.b.example.com.
   419 		// Wildcard subdomains certs (*.example.com) are valid for a.example.com but not a.b.example.com.
   415 		$wildcard_host = preg_replace( '/^[^.]+\./', '*.', $host );
   420 		$wildcard_host = preg_replace( '/^[^.]+\./', '*.', $host );
   416 
   421 
   417 		return in_array( strtolower( $wildcard_host ), $certificate_hostnames );
   422 		return in_array( strtolower( $wildcard_host ), $certificate_hostnames, true );
   418 	}
   423 	}
   419 
   424 
   420 	/**
   425 	/**
   421 	 * Determines whether this class can be used for retrieving a URL.
   426 	 * Determines whether this class can be used for retrieving a URL.
   422 	 *
   427 	 *