PHP CURL HEAD请求返回404,但浏览器/GET请求可正常加载页面的问题
Zend Framework URL验证器S3跳转URL验证异常问题
我开发了一个Zend Framework URL验证器,先通过preg_match筛选格式无效的字符串,再用CURL发送HEAD请求(启用CURLOPT_NOBODY)排查404及连通性问题,还针对SSL相关错误做了兼容处理。但遇到一个用户常用的URL,它会跳转至S3的PDF链接:浏览器中原URL和S3链接均能正常显示PDF,但验证器返回404;直接访问S3链接则返回403,即使注释掉HTTP_X_REQUESTED_WITH请求头仍无效。我怀疑S3是否会针对HEAD请求做特殊限制,不想改为GET请求因为不需要响应体。
完整代码
<?php class Oshk_ZendX_Validate_Url { static $debug = true; const PATTERN = '/^(https?:\/\/)?[^" ]+(\.[^" ]+)*$/'; public static function isValid($value) { $STDERR = fopen("php://stderr", "w"); $value = (string) $value; $matches = array(); if (! preg_match(self::PATTERN, $value, $matches)) { fwrite($STDERR, sprintf("File '%s', line %d, value '%s' does not match pattern '%s'\n", __FILE__, __LINE__, $value, self::PATTERN)); fclose($STDERR); return false; } if (! array_key_exists(1, $matches)) { $value = "https://$value"; } if (self::$debug) { fwrite($STDERR, sprintf("File '%s', line %d, \$value = '%s', \$matches = %s", __FILE__, __LINE__, $value, print_r($matches, true))); } // URL looks well-formed. Ask curl to send a HEAD request to it $ch = curl_init($value); if ($ch === false) { throw new Exception("curl_init($value) failed!"); } curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_HTTPHEADER, array('HTTP_X_REQUESTED_WITH: XMLHttpRequest')); curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36'); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_NOBODY, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_FAILONERROR, true); if (self::$debug) { curl_setopt($ch, CURLOPT_VERBOSE, true); curl_setopt($ch, CURLOPT_STDERR, $STDERR); } $data = curl_exec($ch); $msg = curl_error($ch); $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); if (self::$debug) { $allinfo = curl_getinfo($ch); fwrite($STDERR, sprintf("File '%s', line %d, \$allinfo = %s\n", __FILE__, __LINE__, print_r($allinfo, true))); } curl_close($ch); if (self::$debug) { fwrite($STDERR, sprintf("File '%s', line %d, data = '%s'\n", __FILE__, __LINE__, substr($data, 0, 255))); } if(! strlen($data) && $status != 0 && false === strpos($msg, 'SSL')) { fwrite($STDERR, sprintf("File '%s', line %d, '%s' gives bad status code %d when accessed, with message '%s'\n", __FILE__, __LINE__, $value, $status, $msg)); fclose($STDERR); return false; } if (self::$debug) { fwrite($STDERR, sprintf("File '%s', line %d, url = '%s'\n", __FILE__, __LINE__, $value)); fwrite($STDERR, sprintf("File '%s', line %d, data = '%s'\n", __FILE__, __LINE__, substr($data, 0, 255))); } unset($data); if (self::$debug) { fwrite($STDERR, sprintf("File '%s', line %d, \$msg = '%s'\n", __FILE__, __LINE__, $msg)); fwrite($STDERR, sprintf("File '%s', line %d, \$status = '%s'\n", __FILE__, __LINE__, $status)); fwrite($STDERR, sprintf("File '%s', line %d, \$value = '%s'\n", __FILE__, __LINE__, $value)); } if (($status >= 100 & $status < 400) || false !== strpos($msg, 'SSL')) { fclose($STDERR); return true; } fwrite($STDERR, sprintf("File '%s', line %d, '%s' gives bad status code %d when accessed, with message '%s'\n", __FILE__, __LINE__, $value, $status, $msg)); fclose($STDERR); return false; } } echo var_dump(Oshk_ZendX_Validate_Url::isValid($argv[1]));
原URL测试输出
$ php curltest.php 'https://americandrivingsociety.org/docs.ashx?id=1037680' File 'C:\xampp1826\htdocs\OSH0\curltest.php', line 21, $value = 'https://americandrivingsociety.org/docs.ashx?id=1037680', $matches = Array ( [0] => https://americandrivingsociety.org/docs.ashx?id=1037680 [1] => https:// ) * Trying 208.66.171.71:443... * Connected to americandrivingsociety.org (208.66.171.71) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: \xampp7412\apache\bin\curl-ca-bundle.crt CApath: none * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 * ALPN, server did not agree to a protocol * Server certificate: * subject: CN=americandrivingsociety.org * start date: Sep 2 00:00:00 2022 GMT * expire date: Oct 3 23:59:59 2023 GMT * subjectAltName: host "americandrivingsociety.org" matched cert's "americandrivingsociety.org" * issuer: C=GB; ST=Greater Manchester; L=Salford; O=Sectigo Limited; CN=Sectigo RSA Domain Validation Secure Server CA * SSL certificate verify ok. > HEAD /docs.ashx?id=1037680 HTTP/1.1 Host: americandrivingsociety.org User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Accept: */* HTTP_X_REQUESTED_WITH: XMLHttpRequest * old SSL session ID is stale, removing * Mark bundle as not supporting multiuse * The requested URL returned error: 404 Not Found * Closing connection 0 File 'C:\xampp1826\htdocs\OSH0\curltest.php', line 46, $allinfo = Array ( [url] => https://americandrivingsociety.org/docs.ashx?id=1037680 [content_type] => [http_code] => 404 [header_size] => 0 [request_size] => 250 [filetime] => -1 [ssl_verify_result] => 0 [redirect_count] => 0 [total_time] => 0.132769 [namelookup_time] => 0.009406 [connect_time] => 0.035694 [pretransfer_time] => 0.090879 [size_upload] => 0 [size_download] => 0 [speed_download] => 0 [speed_upload] => 0 [download_content_length] => -1 [upload_content_length] => -1 [starttransfer_time] => 0.132714 [redirect_time] => 0 [redirect_url] => [primary_ip] => 208.66.171.71 [certinfo] => Array ( ) [primary_port] => 443 [local_ip] => 16.1.1.151 [local_port] => 55977 [http_version] => 2 [protocol] => 2 [ssl_verifyresult] => 0 [scheme] => HTTPS [appconnect_time_us] => 90757 [connect_time_us] => 35694 [namelookup_time_us] => 9406 [pretransfer_time_us] => 90879 [redirect_time_us] => 0 [starttransfer_time_us] => 132714 [total_time_us] => 132769 ) File 'C:\xampp1826\htdocs\OSH0\curltest.php', line 50, data = '' File 'C:\xampp1826\htdocs\OSH0\curltest.php', line 53, 'https://americandrivingsociety.org/docs.ashx?id=1037680' gives bad status code 404 when accessed, with message 'The requested URL returned error: 404 Not Found' C:\xampp1826\htdocs\OSH0\curltest.php:77: bool(false) repete@DESKTOP-CLQS7C1 /cygdrive/c/xampp1826/htdocs/OSH0 $
内容的提问来源于stack exchange,提问作者sootsnoot
相关产品推荐
相关产品推荐

