代码之家  ›  专栏  ›  技术社区  ›  Weboide

如何在纯PHP中执行HTTP重定向后获得最终URL?

  •  14
  • Weboide  · 技术社区  · 15 年前

    我想做的是 查看重定向后的最后一个/最后一个URL是什么 .

    现在我有一个网址(比如 http://domain.test Location: 标题(请参阅 编辑 下面)。有没有一种方法可以使用这些头来构建最终的URL?或者有一个PHP函数可以自动做到这一点?

    编辑: get\u headers()跟踪重定向并返回每个响应/重定向的所有头,因此我拥有所有 地点: 标题。

    4 回复  |  直到 15 年前
        1
  •  37
  •   xaav    15 年前
    /**
     * get_redirect_url()
     * Gets the address that the provided URL redirects to,
     * or FALSE if there's no redirect. 
     *
     * @param string $url
     * @return string
     */
    function get_redirect_url($url){
        $redirect_url = null; 
    
        $url_parts = @parse_url($url);
        if (!$url_parts) return false;
        if (!isset($url_parts['host'])) return false; //can't process relative URLs
        if (!isset($url_parts['path'])) $url_parts['path'] = '/';
    
        $sock = fsockopen($url_parts['host'], (isset($url_parts['port']) ? (int)$url_parts['port'] : 80), $errno, $errstr, 30);
        if (!$sock) return false;
    
        $request = "HEAD " . $url_parts['path'] . (isset($url_parts['query']) ? '?'.$url_parts['query'] : '') . " HTTP/1.1\r\n"; 
        $request .= 'Host: ' . $url_parts['host'] . "\r\n"; 
        $request .= "Connection: Close\r\n\r\n"; 
        fwrite($sock, $request);
        $response = '';
        while(!feof($sock)) $response .= fread($sock, 8192);
        fclose($sock);
    
        if (preg_match('/^Location: (.+?)$/m', $response, $matches)){
            if ( substr($matches[1], 0, 1) == "/" )
                return $url_parts['scheme'] . "://" . $url_parts['host'] . trim($matches[1]);
            else
                return trim($matches[1]);
    
        } else {
            return false;
        }
    
    }
    
    /**
     * get_all_redirects()
     * Follows and collects all redirects, in order, for the given URL. 
     *
     * @param string $url
     * @return array
     */
    function get_all_redirects($url){
        $redirects = array();
        while ($newurl = get_redirect_url($url)){
            if (in_array($newurl, $redirects)){
                break;
            }
            $redirects[] = $newurl;
            $url = $newurl;
        }
        return $redirects;
    }
    
    /**
     * get_final_url()
     * Gets the address that the URL ultimately leads to. 
     * Returns $url itself if it isn't a redirect.
     *
     * @param string $url
     * @return string
     */
    function get_final_url($url){
        $redirects = get_all_redirects($url);
        if (count($redirects)>0){
            return array_pop($redirects);
        } else {
            return $url;
        }
    }
    

    并且,一如既往地,给予信任:

    http://w-shadow.com/blog/2008/07/05/how-to-get-redirect-url-in-php/

        2
  •  45
  •   Community Mohan Dere    9 年前
    function getRedirectUrl ($url) {
        stream_context_set_default(array(
            'http' => array(
                'method' => 'HEAD'
            )
        ));
        $headers = get_headers($url, 1);
        if ($headers !== false && isset($headers['Location'])) {
            return $headers['Location'];
        }
        return false;
    }
    

    另外。。。

    正如在评论中提到的那样 最终的 中的项目 $headers['Location'] 将是所有重定向后的最终URL。不过,值得注意的是,它不会 总是

    如果你只对最终的网址感兴趣,在所有的重定向之后,我建议改变

    return $headers['Location'];
    

    return is_array($headers['Location']) ? array_pop($headers['Location']) : $headers['Location'];
    

    ... 这只是 if short-hand

    if(is_array($headers['Location'])){
         return array_pop($headers['Location']);
    }else{
         return $headers['Location'];
    }
    

    此修复程序将处理任意一种情况(数组、非数组),并消除在调用函数后删除最终URL的需要。

    在没有重定向的情况下,函数将返回 false . 同样,函数也将返回 对于无效的URL(由于任何原因无效)。因此,重要的是 check the URL for validity 之前 运行此函数,或者将重定向检查合并到验证中。

        3
  •  6
  •   Paul Dixon    9 年前

    而警察想避免 cURL

    • location 标题名(xaav和webjay的答案都不能处理这个问题)
    • 允许你在放弃之前控制你想要的深度

    函数如下:

    function findUltimateDestination($url, $maxRequests = 10)
    {
        $ch = curl_init();
    
        curl_setopt($ch, CURLOPT_HEADER, true);
        curl_setopt($ch, CURLOPT_NOBODY, true);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_MAXREDIRS, $maxRequests);
        curl_setopt($ch, CURLOPT_TIMEOUT, 15);
    
        //customize user agent if you desire...
        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Link Checker)');
    
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_exec($ch);
    
        $url=curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
    
        curl_close ($ch);
        return $url;
    }
    

    下面是一个更详细的版本,它允许您检查重定向链,而不是让curl跟随它。

    function findUltimateDestination($url, $maxRequests = 10)
    {
        $ch = curl_init();
    
        curl_setopt($ch, CURLOPT_HEADER, true);
        curl_setopt($ch, CURLOPT_NOBODY, true);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 15);
    
        //customize user agent if you desire...
        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Link Checker)');
    
        while ($maxRequests--) {
    
            //fetch
            curl_setopt($ch, CURLOPT_URL, $url);
            $response = curl_exec($ch);
    
            //try to determine redirection url
            $location = '';
            if (in_array(curl_getinfo($ch, CURLINFO_HTTP_CODE), [301, 302, 303, 307, 308])) {
                if (preg_match('/Location:(.*)/i', $response, $match)) {
                    $location = trim($match[1]);
                }
            }
    
            if (empty($location)) {
                //we've reached the end of the chain...
                return $url;
            }
    
            //build next url
            if ($location[0] == '/') {
                $u = parse_url($url);
                $url = $u['scheme'] . '://' . $u['host'];
                if (isset($u['port'])) {
                    $url .= ':' . $u['port'];
                }
                $url .= $location;
            } else {
                $url = $location;
            }
        }
    
        return null;
    }
    

    echo findUltimateDestination('http://dx.doi.org/10.1016/j.infsof.2016.05.005')
    

    在撰写本文时,这涉及4个请求,其中包括 Location

        4
  •  3
  •   Houssem BDIOUI    11 年前

    xaav 答案很好;除了以下两个问题:

    以下是修改后的答案:

    /**
     * get_redirect_url()
     * Gets the address that the provided URL redirects to,
     * or FALSE if there's no redirect. 
     *
     * @param string $url
     * @return string
     */
    function get_redirect_url($url){
        $redirect_url = null; 
    
        $url_parts = @parse_url($url);
        if (!$url_parts) return false;
        if (!isset($url_parts['host'])) return false; //can't process relative URLs
        if (!isset($url_parts['path'])) $url_parts['path'] = '/';
    
        $sock = fsockopen($url_parts['host'], (isset($url_parts['port']) ? (int)$url_parts['port'] : 80), $errno, $errstr, 30);
        if (!$sock) return false;
    
        $request = "HEAD " . $url_parts['path'] . (isset($url_parts['query']) ? '?'.$url_parts['query'] : '') . " HTTP/1.1\r\n"; 
        $request .= 'Host: ' . $url_parts['host'] . "\r\n"; 
        $request .= "User-Agent: Mozilla/5.0 (Linux; U; Android 4.0.3; ko-kr; LG-L160L Build/IML74K) AppleWebkit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30\r\n";
        $request .= "Connection: Close\r\n\r\n"; 
        fwrite($sock, $request);
        $response = '';
        while(!feof($sock)) $response .= fread($sock, 8192);
        fclose($sock);
    
        if (preg_match('/^Location: (.+?)$/m', $response, $matches)){
            if ( substr($matches[1], 0, 1) == "/" )
                return $url_parts['scheme'] . "://" . $url_parts['host'] . trim($matches[1]);
            else
                return trim($matches[1]);
    
        } else {
            return false;
        }
    
    }
    
    /**
     * get_all_redirects()
     * Follows and collects all redirects, in order, for the given URL. 
     *
     * @param string $url
     * @return array
     */
    function get_all_redirects($url){
        $redirects = array();
        while ($newurl = get_redirect_url($url)){
            if (in_array($newurl, $redirects)){
                break;
            }
            $redirects[] = $newurl;
            $url = $newurl;
        }
        return $redirects;
    }
    
    /**
     * get_final_url()
     * Gets the address that the URL ultimately leads to. 
     * Returns $url itself if it isn't a redirect.
     *
     * @param string $url
     * @return string
     */
    function get_final_url($url){
        $redirects = get_all_redirects($url);
        if (count($redirects)>0){
            return array_pop($redirects);
        } else {
            return $url;
    }
    
        5
  •  0
  •   slava    6 年前

    添加到answers@xaav和@Houssem BDIOUI的代码中:404错误案例和URL没有响应时的案例。 get_final_url($url) 在这种情况下,返回字符串:“Error:404notfound”和“Error:No Responce”。

    /**
     * get_redirect_url()
     * Gets the address that the provided URL redirects to,
     * or FALSE if there's no redirect,
     * or 'Error: No Responce',
     * or 'Error: 404 Not Found'
     *
     * @param string $url
     * @return string
     */
    function get_redirect_url($url)
    {
        $redirect_url = null;
    
        $url_parts = @parse_url($url);
        if (!$url_parts)
            return false;
        if (!isset($url_parts['host']))
            return false; //can't process relative URLs
        if (!isset($url_parts['path']))
            $url_parts['path'] = '/';
    
        $sock = @fsockopen($url_parts['host'], (isset($url_parts['port']) ? (int)$url_parts['port'] : 80), $errno, $errstr, 30);
        if (!$sock) return 'Error: No Responce';
    
        $request = "HEAD " . $url_parts['path'] . (isset($url_parts['query']) ? '?' . $url_parts['query'] : '') . " HTTP/1.1\r\n";
        $request .= 'Host: ' . $url_parts['host'] . "\r\n";
        $request .= "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36\r\n";
        $request .= "Connection: Close\r\n\r\n";
        fwrite($sock, $request);
        $response = '';
        while (!feof($sock))
            $response .= fread($sock, 8192);
        fclose($sock);
    
        if (stripos($response, '404 Not Found') !== false)
        {
            return 'Error: 404 Not Found';
        }
    
        if (preg_match('/^Location: (.+?)$/m', $response, $matches))
        {
            if (substr($matches[1], 0, 1) == "/")
                return $url_parts['scheme'] . "://" . $url_parts['host'] . trim($matches[1]);
            else
                return trim($matches[1]);
    
        } else
        {
            return false;
        }
    
    }
    
    /**
     * get_all_redirects()
     * Follows and collects all redirects, in order, for the given URL.
     *
     * @param string $url
     * @return array
     */
    function get_all_redirects($url)
    {
        $redirects = array();
        while ($newurl = get_redirect_url($url))
        {
            if (in_array($newurl, $redirects))
            {
                break;
            }
            $redirects[] = $newurl;
            $url = $newurl;
        }
        return $redirects;
    }
    
    /**
     * get_final_url()
     * Gets the address that the URL ultimately leads to.
     * Returns $url itself if it isn't a redirect,
     * or 'Error: No Responce'
     * or 'Error: 404 Not Found',
     *
     * @param string $url
     * @return string
     */
    function get_final_url($url)
    {
        $redirects = get_all_redirects($url);
        if (count($redirects) > 0)
        {
            return array_pop($redirects);
        } else
        {
            return $url;
        }
    }
    
    推荐文章