【问题标题】:What is the best way to check if a URL exists in PHP?检查 PHP 中是否存在 URL 的最佳方法是什么?
【发布时间】:2011-05-25 03:30:45
【问题描述】:

查看 URL 存在且响应不是 404 的最佳方法是什么?

【问题讨论】:

    标签: php url http-status-codes link-checking


    【解决方案1】:

    你可以使用get_headers($url)

    来自Manual:的示例2

    <?php
    // By default get_headers uses a GET request to fetch the headers. If you
    // want to send a HEAD request instead, you can do so using a stream context:
    stream_context_set_default(
        array(
            'http' => array(
                'method' => 'HEAD'
            )
        )
    );
    print_r(get_headers('http://example.com'));
    
    // gives
    Array
    (
        [0] => HTTP/1.1 200 OK 
        [Date] => Sat, 29 May 2004 12:28:14 GMT
        [Server] => Apache/1.3.27 (Unix)  (Red-Hat/Linux)
        [Last-Modified] => Wed, 08 Jan 2003 23:11:55 GMT
        [ETag] => "3f80f-1b6-3e1cb03b"
        [Accept-Ranges] => bytes
        [Content-Length] => 438
        [Connection] => close
        [Content-Type] => text/html
    )
    

    第一个数组元素将包含 HTTP 响应状态代码。你必须解析它。

    请注意,示例中的 get_headers 函数将发出 HTTP HEAD 请求,这意味着它不会获取 URL 的正文。这比使用也会返回正文的 GET 请求更有效。

    另外请注意,通过设置 default 上下文,任何使用 http 流上下文的后续调用现在都将发出 HEAD 请求。因此,请确保重置默认上下文以在完成后再次使用 GET。

    PHP 还提供了variable $http_response_header

    $http_response_header 数组类似于get_headers() 函数。使用HTTP wrapper 时,$http_response_header 将填充 HTTP 响应标头。 $http_response_header 将在本地范围内创建。

    如果你想下载远程资源的内容,你不想做两个请求(一个是查看资源是否存在,一个是获取它),而只是一个。在这种情况下,请使用 file_get_contents 之类的东西来获取内容,然后检查变量中的标头。

    【讨论】:

    • 在开头添加@字符,当被测试的url不存在时禁止php警告。这样你就可以抛出你自己的自定义异常。
    • @FranciscoLuz 我认为使用错误抑制是不行的,并且赞成使用适当的错误处理程序。
    • 嗨@Gordon,您将另一个问题标记为该问题的副本,我看到您对此有最佳答案,但它不是重复的。你介意撤消它吗?谢谢你的回答,这很有帮助..但我需要知道这个问题和另一个问题的答案,它们不一样。
    • @ftrotter 是否愿意将我链接到相关问题?
    【解决方案2】:

    @Gordon - 根据您的回答,这是一个更完整的库例程。它包括对 URL 有效性的一些初步检查、更多错误处理以及对返回的标头的解析。它还遵循任何重定向链进行合理数量的步骤。

    class cLib {
        static $lasterror = 'No error set yet';
        /**
         * @brief See with a URL is valid - i.e. a page can be successfully retrieved from it without error
         * @param string $url The URL to be checked
         * @param int $nredirects The number of redirects check so far
         * @return boolean True if OK, false if the URL cannot be fetched
         */
        static function checkUrl($url, $nredirects = 0) {
            // First, see if the URL is sensible
            if (filter_var($url, FILTER_VALIDATE_URL) === false) {
                self::$lasterror = sprintf('URL "%s" did not validate', $url);
                return false;
            }
            // Now try to fetch it
            $headers = @get_headers($url);
            if ($headers == false) {
                $error = error_get_last();
                self::$lasterror = sprintf('URL "%s" could not be read: %s', $url, $error['message']);
                return false;
            }
            $status = $headers[0];
            $rbits = explode(' ', $status);
            if (count($rbits) < 2) {
                self::$lasterror = sprintf('Cannot parse status "%s" from URL "%s"', $status, $url);
                return false;
            }
            if (in_array($rbits[1], array(301, 302, 304, 307, 308))) {
                // This URL has been redirected. Follow the redirection chain
                foreach ($headers as $header) {
                    if (cLib::startsWith($header, 'Location:')) {
                        if (++$nredirects > 10) {
                            self::$lasterror = sprintf('URL "%s" was redirected over 10 times: abandoned check', $url);
                            return false;
                        }
                        return self::checkUrl(trim(substr($header, strlen('Location:'))), $nredirects);
                    }
                }
                self::$lasterror = sprintf('URL "%s" was redirected but location could not be identified', $url);
                return false;
            } 
            if ($rbits[1] != 200) {
                self::$lasterror = sprintf('URL "%s" returned status "%s"', $url, $status);
                return false;
            }
            return true;
        }
    }
    

    向@FranciscoLuz 道歉 - 如果您预计基于用户输入的错误,“@ 和 error_get_last” 方法对我来说似乎非常明智 - 我认为使用 set_error_handler 没有什么更合适的。

    顺便说一句,我不确定我是否应该将其作为对@Gordon 答案的编辑,而不是作为单独的答案。有人可以建议吗?

    【讨论】:

      【解决方案3】:
      public function isLink($url)
      {
          $result = false;
          if (!filter_var($url, FILTER_VALIDATE_URL) === false) {
              $getHeaders = get_headers($url);
              $result = strpos($getHeaders[0], '200') !== false;
          }
          return $result;
      }
      

      【讨论】:

        【解决方案4】:

        我正在使用此函数,因为它还会验证并返回 URL 的协议(如果未找到)。

        $theUrl = 'google.com';
        
        function isValidURL($url) { 
            $urlRegex = '@(http(s)?)?(://)?(([a-zA-Z])([-\w]+\.)+([^\s\.]+[^\s]*)+[^,.\s])@';
            if(preg_match($urlRegex, $url)){
                return preg_replace($urlRegex, "http$2://$4", $url);
            } else {
                return false;
            }
        }
        
        var_dump(isValidURL($theUrl));
        

        【讨论】:

          【解决方案5】:

          我开发的一种用于识别 URL 是否确实存在的方法是以下 scrypt。可以通过更精细地分析错误返回来改进它。在那里,我通过估计只有“无法解析主机”的 URL 是错误的,执行了一个简单的错误返回。

          function URL_EXIST($pUrl)
          {
              $etat = true;
              $ch = curl_init($pUrl);
              curl_setopt($ch, CURLOPT_FAILONERROR, true);
              curl_setopt($ch, CURLOPT_NOBODY, true);
              if (curl_exec($ch) === false)
              {
                  $mes = strtolower(curl_error($ch));
                  $cdt_wrong = preg_match('#could not resolve host#',$mes);
                  $cdt_wrong |= preg_match('#404 not found#',$mes);
                  if($cdt_wrong==true)
                  {
                      $etat = false;
                  }
              }
              curl_close($ch);
          
              return $etat;
          }
          

          有一些例子,它工作得很好

          【讨论】:

            猜你喜欢
            • 2012-08-29
            • 2010-09-18
            • 2012-06-17
            • 2011-03-20
            • 2011-12-25
            相关资源
            最近更新 更多