cURL을 사용하여 리디렉션 될 위치를 어떻게 찾을 수 있습니까?


149

curl이 리디렉션을 따르도록하려고하지만 제대로 작동하지 않습니다. 서버에 GET 매개 변수로 보내고 결과 URL을 얻으려는 문자열이 있습니다.

예:

문자열 = Kobold Vermin
Url = www.wowhead.com/search?q=Kobold+Worker

해당 URL로 이동하면 "www.wowhead.com/npc=257"로 리디렉션됩니다. curl이 "npc = 257"을 추출하여 사용할 수 있도록이 URL을 PHP 코드로 반환하려고합니다.

현재 코드 :

function npcID($name) {
    $urltopost = "http://www.wowhead.com/search?q=" . $name;
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1");
    curl_setopt($ch, CURLOPT_URL, $urltopost);
    curl_setopt($ch, CURLOPT_REFERER, "http://www.wowhead.com");
    curl_setopt($ch, CURLOPT_HTTPHEADER, Array("Content-Type:application/x-www-form-urlencoded"));
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
    return curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
}

그러나 이것은 www.wowhead.com/npc=257 이 아닌 www.wowhead.com/search?q=Kobold+Worker를 반환합니다 .

외부 리디렉션이 발생하기 전에 PHP가 돌아 오는 것 같습니다. 이 문제를 어떻게 해결할 수 있습니까?


8
"curl follow redirects"에 대한 주요 질문 중 하나입니다. curl명령을 사용하여 리디렉션을 자동으로 수행하려면 -L또는 --location플래그를 전달하십시오 . 예curl -L http://example.com/
롭 W

답변:


256

cURL이 리디렉션을 따르게하려면 다음을 사용하십시오.

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

음 ... 당신이 실제로 컬을 실행하고 있다고 생각하지 않습니다 ... 시도 :

curl_exec($ch);

... 옵션을 설정 한 후와 curl_getinfo()통화 전에 .

편집 : 페이지가 리디렉션되는 위치를 찾으려면 here 여기 에서 조언을 사용하고 Curl을 사용하여 헤더를 잡고 Location : 헤더를 추출하십시오.

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
if (preg_match('~Location: (.*)~i', $result, $match)) {
   $location = trim($match[1]);
}

2
이것은 PHP가 리디렉션을 따르게합니다. 리디렉션을 따르고 싶지 않고 리디렉션 된 페이지의 URL을 알고 싶습니다.
Thomas Van Nuffel

9
아, 실제로 페이지를 가져오고 싶지 않습니까? 위치를 찾으세요? 이 경우 여기에 사용 된 전술을 제안합니다. zzz.rezo.net/HowTo-Expand-Short-URLs.html- 기본적으로 리디렉션되는 페이지에서 헤더를 잡고 Location : 헤더를 가져옵니다. 어쨌든 컬이 실제로 무엇 이든 하기 위해서는 exec ()를 해야 합니다.
Matt Gibson

1
이 솔루션은 다중 리디렉션을 고려하지 않기 때문에 아래의 Luca Camillos 솔루션을 살펴 보는 것이 좋습니다.
Christian Engel

이 솔루션은 동일한 URL 내에서 새 웹 페이지를 엽니 다. 해당 URL에 매개 변수를 게시하는 동시에 URL을 변경하고 싶습니다. 어떻게하면 되나요?
amanpurohit

$ httpCode = curl_getinfo ($ handle, CURLINFO_HTTP_CODE)를 사용할 때 @MattGibson; CURLOPT_FOLLOWLOCATION을 true로 설정하면 httpcode가 무엇입니까? 나는 그것이 첫 번째 URL 또는 리디렉션 URL에 대한 것입니다 의미
Manigandan 아쥬 난

26

이 라인을 추가하여 inizialization을 컬하십시오

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

curl_close 전에 getinfo를 사용하십시오.

$redirectURL = curl_getinfo($ch,CURLINFO_EFFECTIVE_URL );

es :

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_USERAGENT,'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT ,0); 
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
$html = curl_exec($ch);
$redirectURL = curl_getinfo($ch,CURLINFO_EFFECTIVE_URL );
curl_close($ch);

2
나는 이것이 다중 리디렉션을 전개하기 때문에 이것이 더 나은 해결책이라고 생각합니다.
Christian Engel

기억하십시오 : (ok, duh) POST 데이터는 리디렉션 후 다시 제출되지 않습니다. 내 경우에는 이것이 일어 났고 그 이후로 어리석은 느낌이 들었습니다. 적절한 URL을 사용하면 수정되었습니다.
twicejr

사용 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);은 보안 취약점입니다. "SSL 오류가 발생하면 무시하십시오. 암호화되지 않은 URL과 동일하게 신뢰하십시오."라고 기본적으로 표시되어 있습니다.
Finesse

8

위의 대답은 서버 중 하나에서 기반으로 작동하지 않았으므로 기반 서버와 관련이 있으므로 조금 해시했습니다. 아래 코드는 모든 서버에서 작동합니다.

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
$a = curl_exec($ch);
curl_close( $ch ); 
// the returned headers
$headers = explode("\n",$a);
// if there is no redirection this will be the final url
$redir = $url;
// loop through the headers and check for a Location: str
$j = count($headers);
for($i = 0; $i < $j; $i++){
// if we find the Location header strip it and fill the redir var       
if(strpos($headers[$i],"Location:") !== false){
        $redir = trim(str_replace("Location:","",$headers[$i]));
        break;
    }
}
// do whatever you want with the result
echo redir;

Location: 헤더는 리디렉션을 수행하는 것이 아니다. 또한 curl
hakre

5

여기에 선택된 답변은 괜찮지 만 대소 문자를 구분하며 location:실제로는 문구가있을 수있는 상대 헤더 (일부 사이트) 또는 페이지를 보호하지 않습니다.Location: 내용에 (현재는 zillow)를 보호하지 않습니다.

조금 더 부드럽지만 이것을 조금 더 똑똑하게 만들기 위해 몇 가지 빠른 편집은 다음과 같습니다.

function getOriginalURL($url) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HEADER, true);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    $result = curl_exec($ch);
    $httpStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    // if it's not a redirection (3XX), move along
    if ($httpStatus < 300 || $httpStatus >= 400)
        return $url;

    // look for a location: header to find the target URL
    if(preg_match('/location: (.*)/i', $result, $r)) {
        $location = trim($r[1]);

        // if the location is a relative URL, attempt to make it absolute
        if (preg_match('/^\/(.*)/', $location)) {
            $urlParts = parse_url($url);
            if ($urlParts['scheme'])
                $baseURL = $urlParts['scheme'].'://';

            if ($urlParts['host'])
                $baseURL .= $urlParts['host'];

            if ($urlParts['port'])
                $baseURL .= ':'.$urlParts['port'];

            return $baseURL.$location;
        }

        return $location;
    }
    return $url;
}

이것은 여전히 ​​하나의 리디렉션 깊이에만 해당됩니다. 더 깊이 들어가려면 실제로 콘텐츠를 가져 와서 리디렉션을 따라야합니다.


5

때로는 HTTP 헤더를 가져와야하지만 동시에 해당 헤더를 반환하지 않으려는 경우도 있습니다. **

이 스켈레톤은 재귀를 사용하여 쿠키 및 HTTP 리디렉션을 처리합니다. 여기서 주요 아이디어 는 클라이언트 헤더HTTP 헤더반환하지 않는 것 입니다.

매우 강한 컬 클래스를 만들 수 있습니다. POST 기능 추가 등

<?php

class curl {

  static private $cookie_file            = '';
  static private $user_agent             = '';  
  static private $max_redirects          = 10;  
  static private $followlocation_allowed = true;

  function __construct()
  {
    // set a file to store cookies
    self::$cookie_file = 'cookies.txt';

    // set some general User Agent
    self::$user_agent = 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)';

    if ( ! file_exists(self::$cookie_file) || ! is_writable(self::$cookie_file))
    {
      throw new Exception('Cookie file missing or not writable.');
    }

    // check for PHP settings that unfits
    // correct functioning of CURLOPT_FOLLOWLOCATION 
    if (ini_get('open_basedir') != '' || ini_get('safe_mode') == 'On')
    {
      self::$followlocation_allowed = false;
    }    
  }

  /**
   * Main method for GET requests
   * @param  string $url URI to get
   * @return string      request's body
   */
  static public function get($url)
  {
    $process = curl_init($url);    

    self::_set_basic_options($process);

    // this function is in charge of output request's body
    // so DO NOT include HTTP headers
    curl_setopt($process, CURLOPT_HEADER, 0);

    if (self::$followlocation_allowed)
    {
      // if PHP settings allow it use AUTOMATIC REDIRECTION
      curl_setopt($process, CURLOPT_FOLLOWLOCATION, true);
      curl_setopt($process, CURLOPT_MAXREDIRS, self::$max_redirects); 
    }
    else
    {
      curl_setopt($process, CURLOPT_FOLLOWLOCATION, false);
    }

    $return = curl_exec($process);

    if ($return === false)
    {
      throw new Exception('Curl error: ' . curl_error($process));
    }

    // test for redirection HTTP codes
    $code = curl_getinfo($process, CURLINFO_HTTP_CODE);
    if ($code == 301 || $code == 302)
    {
      curl_close($process);

      try
      {
        // go to extract new Location URI
        $location = self::_parse_redirection_header($url);
      }
      catch (Exception $e)
      {
        throw $e;
      }

      // IMPORTANT return 
      return self::get($location);
    }

    curl_close($process);

    return $return;
  }

  static function _set_basic_options($process)
  {

    curl_setopt($process, CURLOPT_USERAGENT, self::$user_agent);
    curl_setopt($process, CURLOPT_COOKIEFILE, self::$cookie_file);
    curl_setopt($process, CURLOPT_COOKIEJAR, self::$cookie_file);
    curl_setopt($process, CURLOPT_RETURNTRANSFER, 1);
    // curl_setopt($process, CURLOPT_VERBOSE, 1);
    // curl_setopt($process, CURLOPT_SSL_VERIFYHOST, false);
    // curl_setopt($process, CURLOPT_SSL_VERIFYPEER, false);
  }

  static function _parse_redirection_header($url)
  {
    $process = curl_init($url);    

    self::_set_basic_options($process);

    // NOW we need to parse HTTP headers
    curl_setopt($process, CURLOPT_HEADER, 1);

    $return = curl_exec($process);

    if ($return === false)
    {
      throw new Exception('Curl error: ' . curl_error($process));
    }

    curl_close($process);

    if ( ! preg_match('#Location: (.*)#', $return, $location))
    {
      throw new Exception('No Location found');
    }

    if (self::$max_redirects-- <= 0)
    {
      throw new Exception('Max redirections reached trying to get: ' . $url);
    }

    return trim($location[1]);
  }

}

0

여기에 내가 정말 좋아하는 사실에도 불구하고 여기에 많은 정규 표현식이 나에게 더 안정적 일 수 있습니다.

$resultCurl=curl_exec($curl); //get curl result
//Optional line if you want to store the http status code
$headerHttpCode=curl_getinfo($curl,CURLINFO_HTTP_CODE);

//let's use dom and xpath
$dom = new \DOMDocument();
libxml_use_internal_errors(true);
$dom->loadHTML($resultCurl, LIBXML_HTML_NODEFDTD);
libxml_use_internal_errors(false);
$xpath = new \DOMXPath($dom);
$head=$xpath->query("/html/body/p/a/@href");

$newUrl=$head[0]->nodeValue;

위치 부분은 아파치가 보낸 HTML의 링크입니다. 따라서 Xpath는이를 완벽하게 복구합니다.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.