【问题标题】:PHP - Check if url is valid or notPHP - 检查网址是否有效
【发布时间】:2021-07-03 05:14:16
【问题描述】:

我正在检查 url,如果 url 状态代码为“200”,则返回“valid”,如果“invalid”为“404",

url 是重定向到某个页面 (url) 的链接,我需要检查该页面 (url) 的状态,以根据其状态代码确定其有效还是无效。

<?php

// From URL to get redirected URL
$url = 'https://www.shareasale.com/m-pr.cfm?merchantID=83483&userID=1860618&productID=916465625';
  
// Initialize a CURL session.
$ch = curl_init();
  
// Grab URL and pass it to the variable.
curl_setopt($ch, CURLOPT_URL, $url);
  
// Catch output (do NOT print!)
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
  
// Return follow location true
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
$html = curl_exec($ch);
  
// Getinfo or redirected URL from effective URL
$redirectedUrl = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
  
// Close handle
curl_close($ch);
echo "Original URL:   " . $url . "<br/> </br>";
echo "Redirected URL: " . $redirectedUrl . "<br/>";

 function is_url_valid($url) {
  $handle = curl_init($url);
  curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($handle, CURLOPT_NOBODY, true);
  curl_exec($handle);
 
  $httpCode = intval(curl_getinfo($handle, CURLINFO_HTTP_CODE));
  curl_close($handle);
 
  if ($httpCode == 200) {
    return 'valid link';
  }
  else {
    return 'invalid link';
  }
}

// 
echo "<br/>".is_url_valid($redirectedUrl)."<br/>";

如您所见,上述链接的状态为 400,但仍显示“有效” 我正在使用上面的代码,有什么想法或更正吗?为了使其按预期工作? 似乎该网站有不止一个重定向 url 和脚本检查只有一个,这就是它显示有效的原因。 有什么想法可以解决吗?

这是我正在检查的链接

问题 -

例如 - 如果我检查此链接 https://www.shareasale.com/m-pr.cfm?merchantID=66802&userID=1860618&productID=1186005518 然后在浏览器中它继续 "404" 但在脚本 o/p 中它是 "200"

【问题讨论】:

  • 上面的链接有状态码:302 & 重定向到状态码为 200 的新 url,我想检查结束 url(最后一个 url)。
  • $httpCode = intval(curl_getinfo($handle, CURLINFO_HTTP_CODE)); - 为了安全起见,请确保它是用于比较的整数
  • 感谢您的评论和建议,尽管我在输出中得到 404 作为状态码
  • @devhs - 我不确定这是否是正确的解决方案。但是我检查了上面的一些链接,它们正在管理 404 的自定义页面。作为一种快速解决方案,您可以使用“file_get_contents”获取 URL 的内容并检查“页面标题”。
  • 通过“刷新”标头,我的意思是 header("Refresh:5; url=page2.php"); 在这种情况下 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE); 不遵循重定向,另一个是 元刷新 http-equiv 标头和 javascript 重定向

标签: php url curl status


【解决方案1】:

注意:我们使用 CURLOPT_NOBODY 只是检查连接,而不是获取整个正文。

  $url = "Your URL";
  $curl = curl_init($url);
  curl_setopt($curl, CURLOPT_NOBODY, true);
  $result = curl_exec($curl);
 if ($result !== false)
 {
    $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);  
 if ($statusCode == 404)
 {
   echo "URL Not Exists"
 }
 else
 {
   echo "URL Exists";
  }
 }
else
{
  echo "URL not Exists";
}

【讨论】:

    【解决方案2】:

    我为此使用get_headers() 函数。如果我在数组中找到状态 2xx,则 URL 正常。

    function urlExists($url){
      $headers = @get_headers($url);
      if($headers === false) return false;
      return preg_grep('~^HTTP/\d+\.\d+\s+2\d{2}~',$headers) ? true : false;
    }
    

    【讨论】:

    • 感谢您的回答,但是如果主 url 有重定向(多个重定向)怎么办?假设这个网址 - shareasale.com/…
    • 该函数为该 URL 返回 true。可以吗?
    • 不,因为页面的状态码是 404(未找到)所以它不应该返回 true
    • 如果在我的浏览器中禁用了 Javascript,我不会收到广告。我认为这种转发是通过 javascript 完成的。这个问题不能单独用PHP解决。
    • 我没有快速解决办法。
    【解决方案3】:

    这是我对这个问题的看法。基本上,要点是:

    1. 您不需要提出多个请求。使用 CURLOPT_FOLLOWLOCATION 将为您完成所有工作,最后,您将获得的 http 响应代码是来自最终调用的响应代码,以防发生/某些重定向。
    2. 由于您使用的是CURLOPT_NOBODY,因此请求将使用HEAD 方法并且不会返回任何内容。因此,CURLOPT_RETURNTRANSFER 毫无用处。
    3. 我冒昧地使用了自己的编码风格(无意冒犯)。
    4. 由于我从 Phpstorm 的 Scratch 文件运行代码,我添加了一些 PHP_EOL 作为换行符来格式化输出。随意删除它们。

    ...

    <?php
    
    $linksToCheck = [
        'https://click.linksynergy.com/link?id=GsILx6E5APM&offerid=547531.5112&type=15&murl=https%3A%2F%2Fwww.peopletree.co.uk%2Fwomen%2Fdresses%2Fanna-checked-dress',
        'https://click.linksynergy.com/link?id=GsILx6E5APM&offerid=330522.2335&type=15&murl=https%3A%2F%2Fwww.wearethought.com%2Fagnetha-black-floral-print-bamboo-dress-midnight-navy%2F%2392%3D1390%26142%3D198',
        'https://click.linksynergy.com/link?id=GsILx6E5APM&offerid=330522.752&type=15&murl=https%3A%2F%2Fwww.wearethought.com%2Fbernice-floral-tunic-dress%2F%2392%3D1273%26142%3D198',
        'https://click.linksynergy.com/link?id=GsILx6E5APM&offerid=330522.6863&type=15&murl=https%3A%2F%2Fwww.wearethought.com%2Fjosefa-smock-shift-dress-in-midnight-navy-hemp%2F%2392%3D1390%26142%3D208',
        'https://www.shareasale.com/m-pr.cfm?merchantID=16570&userID=1860618&productID=546729471',
        'https://www.shareasale.com/m-pr.cfm?merchantID=53661&userID=1860618&productID=680698793',
        'https://www.shareasale.com/m-pr.cfm?merchantID=66802&userID=1860618&productID=1186005518',
        'https://www.shareasale.com/m-pr.cfm?merchantID=83483&userID=1860618&productID=916465625',
    ];
    
    function isValidUrl($url) {
        echo "Original URL:   " . $url . "<br/>\n";
    
        $handle = curl_init($url);
    
        // Follow any redirection.
        curl_setopt($handle, CURLOPT_FOLLOWLOCATION, TRUE);
    
        // Use a HEAD request and do not return a body.
        curl_setopt($handle, CURLOPT_NOBODY, true);
    
        // Execute the request.
        curl_exec($handle);
    
        // Get the effective URL.
        $effectiveUrl = curl_getinfo($handle, CURLINFO_EFFECTIVE_URL);
        echo "Effective URL:   " . $effectiveUrl . "<br/> </br>";
    
        $httpResponseCode = (int) curl_getinfo($handle, CURLINFO_HTTP_CODE);
    
        // Close this request.
        curl_close($handle);
    
        if ($httpResponseCode == 200) {
            return '✅';
        }
        else {
            return '❌';
        }
    }
    
    foreach ($linksToCheck as $linkToCheck) {
        echo PHP_EOL . "Result: " . isValidUrl($linkToCheck) . PHP_EOL . PHP_EOL;
    }
    

    【讨论】:

    • 哈哈 utf8 的使用很酷!不幸的是,OP 也想关注 javascript 重定向,请参阅下面的答案以获取信息:(
    【解决方案4】:

    下面的代码运行良好,但是当我将 url 放入数组并测试相同的功能时,它没有给出正确的结果? 任何想法为什么? 此外,如果任何机构想要更新答案以使其在某种意义上具有动态性(应在提供 url 数组时一次检查多个 url)。

      <?php
        
        // URL to check
        $url = 'https://www.shareasale.com/m-pr.cfm?merchantID=66802&userID=1860618&productID=1186005518';
          
        $ch = curl_init(); // Initialize a CURL session.
        curl_setopt($ch, CURLOPT_URL, $url); // Grab URL and pass it to the variable.
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); // Catch output (do NOT print!)
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE); // Return follow location true
        $html = curl_exec($ch);
        $redirectedUrl = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL); // Getinfo or redirected URL from effective URL
        curl_close($ch); // Close handle
        
        $get_final_url = get_final_url($redirectedUrl);
        if($get_final_url){
            echo is_url_valid($get_final_url);
        }else{
            echo $redirectedUrl ? is_url_valid($redirectedUrl) : is_url_valid($url);
        }
        
        function is_url_valid($url) {
          $handle = curl_init($url);
          curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
          curl_setopt($handle, CURLOPT_NOBODY, true);
          curl_exec($handle);
         
          $httpCode = intval(curl_getinfo($handle, CURLINFO_HTTP_CODE));
          curl_close($handle);
          echo $httpCode;
          if ($httpCode == 200) {
            return '<b> Valid link </b>';
          }
          else {
            return '<b> Invalid link </b>';
          }
        }
        
        function get_final_url($url) {
                $ch = curl_init();
                if (!$ch) {
                    return false;
                }
                $ret = curl_setopt($ch, CURLOPT_URL,            $url);
                $ret = curl_setopt($ch, CURLOPT_HEADER,         1);
                $ret = curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
                $ret = curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
                $ret = curl_setopt($ch, CURLOPT_TIMEOUT,        30);
                $ret = curl_exec($ch);
        
                if (!empty($ret)) {
                    $info = curl_getinfo($ch);
                    curl_close($ch);
                    return false;
                if (empty($info['http_code'])) {
                    return false;
                } else {
                    preg_match('#(https:.*?)\'\)#', $ret, $match);
                    $final_url = stripslashes($match[1]);
                    return stripslashes($match[1]);
                }
            }
        } 
    

    【讨论】:

    • 只是一个想法:来自您的脚本的请求带有主机检测然后抵消您的意图的模式。或者你可能会说:为什么那个主持人会破坏我的期望?这是他们的服务器,您只能发送请求,并且您必须接受答案(响应);)
    【解决方案5】:

    看,这里的问题是你想遵循 JAVASCRIPT 重定向, 您抱怨https://www.shareasale.com/m-pr.cfm?merchantID=66802&amp;userID=1860618&amp;productID=1186005518 的网址确实重定向到响应HTTP 200 OK 的网址,并且该页面包含javascript

    <script LANGUAGE="JavaScript1.2">
                    window.location.replace('https:\/\/www.tenthousandvillages.com\/bicycle-statue?sscid=71k5_4yt9r ')
                    </script>
    

    所以你的浏览器,它理解 javascript,遵循 javascript 重定向,并且 js 重定向到 404 页面。不幸的是,PHP 没有很好的方法来做到这一点,你最好的选择可能是一个无头网络浏览器,例如 PhantomJS 或 puppeteer 或 Selenium 或类似的东西。

    不过,您仍然可以在正则表达式搜索中破解 javascript 重定向并希望获得最好的结果,例如

    <?php
    function is_url_valid(string $url):bool{
        if(0!==strncasecmp($url,"http",strlen("http"))){
            // file:///etc/passwd and stuff like that aren't considered valid urls right?
            return false;
        }
        $ch=curl_init();
        if(!curl_setopt_array($ch,array(
            CURLOPT_URL=>$url,
            CURLOPT_FOLLOWLOCATION=>1,
            CURLOPT_RETURNTRANSFER=>1
        ))){
            // best guess: the url is so malformed that even CURLOPT_URL didn't accept it.
            return false;
        }
        $resp= curl_exec($ch);
        if(false===$resp){
            return false;
        }
        if(curl_getinfo($ch,CURLINFO_RESPONSE_CODE) != 200){
            // only HTTP 200 OK is accepted
            return false;
        }
        // attempt to detect javascript redirects... sigh
        // window.location.replace('https:\/\/www.tenthousandvillages.com\/bicycle-statue?sscid=71k5_4yt9r ')
        $rex = '/location\.replace\s*\(\s*(?<redirect>(?:\'|\")[\s\S]*?(?:\'|\"))/';
        if(!preg_match($rex, $resp, $matches)){
            // no javascript redirects detected..
            return true;
        }else{
            // javascript redirect detected..
            $url = trim($matches["redirect"]);
            // javascript allows both ' and " for strings, but json only allows " for strings
            $url = str_replace("'",'"',$url);
            $url = json_decode($url, true,512,JSON_THROW_ON_ERROR); // we extracted it from javascript, need json decoding.. (well, strictly speaking, it needs javascript decoding, but json decoding is probably sufficient, and we only have a json decoder nearby)
            curl_close($ch);
            return is_url_valid($url);
        }
    }
    var_dump(
    
        is_url_valid('https://www.shareasale.com/m-pr.cfm?merchantID=66802&userID=1860618&productID=1186005518'),
        is_url_valid('http://example.org'),
        is_url_valid('http://example12k34jr43r5ehjegeesfmwefdc.org'),
        
    );
    

    但委婉地说,这是一个狡猾的 hacky 解决方案..

    【讨论】:

    • 感谢您的回答,让我检查一下它是否可以同时处理多个 url,就像我创建一个发布在问题中的 url 数组并在循环中调用方法“is_url_valid”
    • @devhs 应该不是问题,顺便说一句,我刚刚注意到这种方法还有一个明显的弱点:它不能处理无限重定向。例如,如果 page1 重定向到 page2 重定向到 page1 重定向到 page2.... ,这个脚本将永远跟随重定向,直到达到 php max_execution_time,或者直到调用堆栈耗尽。 (虽然可以修复)
    • 谢谢,我会检查一下,我刚刚在这里测试过 - paiza.io/projects/N3m4E11HZAmq5uTb8gLjcg 但 ii 似乎没有工作。
    • @devhs 如果确保将它从 paiza.io 更改为 https://paiza.io ,那么 url 会为我返回 bool(true) ,你会得到什么?
    • 当您访问此链接时,它是一个编译器,我在其中测试了您的代码 paiza.io/projects/N3m4E11HZAmq5uTb8gLjcg
    猜你喜欢
    • 1970-01-01
    • 2013-07-17
    • 1970-01-01
    • 2012-09-05
    • 2021-07-30
    • 2016-08-29
    • 2017-09-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多