PHP Curl 405不允许

4

最终更新:看起来目标网站拦截了 DO 的 IP 地址,导致我连续几天都在解决问题。我启动了一个 EC2 实例,并管理好了代码,加入了缓存等功能,以减少对网站的访问压力,允许我的用户共享该网站。

-

更新:我将 curl 的错误设置为关闭后,成功获取了 HTML,但是除了返回 405 错误之外,该网站还未设置一些必须的 cookie 才能加载网站内容。

下面是我用于 ajax->PHP 从网站检索 og: meta 的代码。然而,有 1 或 2 个特定的网站会返回错误并无法检索信息。对于大多数网站,该代码都可以无缝运行。

警告:DOMDocument::loadHTML():在/my/home/path/getUrlMeta.php的第58行中没有提供输入字符串。

从我的 error_log 中的 curl_error 中:

请求的 URL 返回错误:405 Not Allowed

无法连接到 www.something.com 端口 443:拒绝连接

当我在服务器控制台上使用 curl 时,我没有任何问题获取网站的 HTML,并且使用以下代码检索大多数网站所需的信息也没有问题。

function file_get_contents_curl($url)
{
    $ch = curl_init();
    $header[0] = "Accept: text/html, text/xml,application/xml,application/xhtml+xml,";
    $header[0] .= "text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5";
    $header[] = "Cache-Control: max-age=0";
    $header[] = "Connection: keep-alive";
    $header[] = "Keep-Alive: 300";
    $header[] = "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7";
    $header[] = "Accept-Language: en-us,en;q=0.5";
    $header[] = "Pragma: no-cache";
    curl_setopt($ch, CURLOPT_HTTPHEADER, $header);

    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
    //curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');

    curl_setopt($ch, CURLOPT_FAILONERROR, true);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
    curl_setopt($ch, CURLOPT_USERAGENT,"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:31.0) Gecko/20100101 Firefox/31.0 " );
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    //The following 2 set up lines work with sites like www.nytimes.com

    //Update: Added option for cookie jar since some websites recommended it. cookies.txt is set to permission 777. Still doesn't work.
    $cookiefile = '/home/my/folder/cookies.txt';
    curl_setopt( $ch, CURLOPT_COOKIESESSION, true );
    curl_setopt( $ch, CURLOPT_COOKIEJAR,  $cookiefile );
    curl_setopt( $ch, CURLOPT_COOKIEFILE, $cookiefile );

    $data = curl_exec($ch);

  if(curl_error($ch))
    {
        error_log(curl_error($ch));
    }
    curl_close($ch);

    return $data;
}

$html = file_get_contents_curl($url);

libxml_use_internal_errors(true); // Yeah if you are so worried about using @ with warnings
$doc = new DomDocument();
$doc->loadHTML($html);
$xpath = new DOMXPath($doc);
$query = '//*/meta[starts-with(@property, \'og:\')]';
$metas = $xpath->query($query);
$rmetas = array();
foreach ($metas as $meta) {
    $property = substr($meta->getAttribute('property'),3);
    $content = $meta->getAttribute('content');
    $rmetas[$property] = $content;
}

/*below code retrieves the next bigger than 600px image should og:image be empty.*/
if (empty($rmetas['image'])) {
    //$src = $xpath->evaluate("string(//img/@src)");
    //echo "src=" . $src . "\n";
    $query = '//*/img';
    $srcs = $xpath->query($query);
    foreach ($srcs as $src) {

        $property = $src->getAttribute('src');


        if (substr($property,0,4) == 'http' && in_array(substr($property,-3), array('jpg','png','peg'), true)) {
            if (list($width, $height) = getimagesize($property)) {
            do if ($width > 600) {
                $rmetas['image'] = $property;
                break;
            } while (0);
            }
        }

    }
}

echo json_encode($rmetas);


die();

更新:我犯了错误,该网站未启用https,因此我仍然遇到405不允许的错误。

curl信息

{
    "url": "http://www.example.com/",
    "content_type": null,
    "http_code": 405,
    "header_size": 0,
    "request_size": 458,
    "filetime": -1,
    "ssl_verify_result": 0,
    "redirect_count": 0,
    "total_time": 0.326782,
    "namelookup_time": 0.004364,
    "connect_time": 0.007725,
    "pretransfer_time": 0.007867,
    "size_upload": 0,
    "size_download": 0,
    "speed_download": 0,
    "speed_upload": 0,
    "download_content_length": -1,
    "upload_content_length": -1,
    "starttransfer_time": 0.326634,
    "redirect_time": 0,
    "redirect_url": "",
    "primary_ip": "SOME IP",
    "certinfo": [],
    "primary_port": 80,
    "local_ip": "SOME IP",
    "local_port": 52966
}

更新:如果我从控制台执行curl -i,我会得到以下响应。一个错误的405,但它跟随着我需要的所有HTML。
Home> curl -i http://www.domain.com
HTTP/1.1 405 Not Allowed
Server: nginx
Date: Wed, 22 Feb 2017 17:57:03 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Vary: Accept-Encoding
Vary: Accept-Encoding
Set-Cookie: PHPSESSID2=ko67tfga36gpvrkk0rtqga4g94; path=/; domain=.domain.com
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Set-Cookie: __PAGE_REFERRER=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; domain=www.domain.com
Set-Cookie: __PAGE_SITE_REFERRER=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; domain=www.domain.com
X-Repository: legacy
X-App-Server: production-web23:8018
X-App-Server: distil2-kvm:80

如果它只在某些网站上停止工作,那么这是一个服务器端的问题。我们无法提供帮助。 - miken32
@miken32 但网页浏览器可以访问该URL。 Curl难道不是模拟浏览器吗?它是一个公开可访问的网站,不需要登录、没有SSL等。 - Someone Special
移除 CURLOPT_FAILONERROR,你将会得到完整的 405 内容,就像你展示的命令行等效方式一样。 - Daniel Stenberg
嗨,丹尼尔,你发表评论几分钟之前我就已经完成了。然而,我不知道网站是如何检测到我是一个爬虫的,因为我已经发送了所有的头信息。当faillonerror为false时返回的HTML并不包含网站的任何真实内容。显然,在出现405错误时,访客cookie没有设置,所以网页无法显示内容。 - Someone Special
3个回答

3

由于我自己在寻找解决方案时没有在评论中得到答案:在我的情况下,问题是:

     curl_setopt($ch, CURLOPT_NOBODY, 1);

简单地说,它发送HEAD方法,该方法可能不被服务器所认可/不支持 - 因此您会收到405。


这对我解决了检查Instagram链接的问题。对于大多数网站,将CURLOPT_NOBODY设置为true是有帮助的,因为在检查大量链接时可以节省时间。但是对于Instagram,您会得到一个405错误。相反,我首先使用CURLOPT_NOBODY进行检查,如果我得到了405错误,我就再次使用CURLOPT_NOBODY设置为false进行检查。 - xtempore

2
将以下内容添加到您的代码中以帮助调试问题:
$info = curl_getinfo($ch);
print_r( $info );

很可能存在以下问题:
  • 405不允许 - 您尝试进行的cURL调用不被允许。例如,只允许POST时进行GET调用。
  • 443:连接被拒绝 - 您尝试访问的网站不支持HTTPS。或者,该网站正在使用您的代码不支持的加密协议,例如仅使用TLSv1.2,而您的代码可能正在使用TLSv1.1。

我在我的问题中添加了curl_getinfo。该网站是一个公开可访问的网站,我正在尝试在用户在我的应用程序中分享网站URL时获取og标签(类似于Facebook URL共享)。 - Someone Special
结果发现该网站没有使用HTTPS,因此我不需要修复连接拒绝错误,但我仍然无法解决405错误。 - Someone Special
这让我感到困惑。从网站访问是好的,从服务器的命令行中使用curl也没有任何错误。我还可以通过Facebook分享网站。此外,我已经尝试了相同的代码来自不同位置的多个服务器,但都返回405。 - Someone Special
我还修改了curl选项以启用cookies和cookiejar,但仍然无济于事。 - Someone Special
我已经更新了我的问题,并附上了来自控制台的curl响应。它也返回405,但它带有我需要的所有HTML。但是从PHP中的curl无法获取这些HTML。 - Someone Special
显示剩余4条评论

2

由于这些解决方案对我不起作用,我将在此发布我的解决方案:

我添加了这行代码,并停止收到错误405。这与“GET”请求有关。

curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接