HTTPステータスコードが302のときにcURLを使用して宛先URLを取得するにはどうすればよいですか?
<?PHP
$url = "http://www.ecs.soton.ac.uk/news/";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$html = curl_exec($ch);
$status_code = curl_getinfo($ch,CURLINFO_HTTP_CODE);
if($status_code=302 or $status_code=301){
$url = "";
// I want to to get the destination url
}
curl_close($ch);
?>
次を使用できます。
echo curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_HEADER, TRUE); // We'll parse redirect url from header.
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, FALSE); // We want to just get redirect url but not to follow it.
$response = curl_exec($ch);
preg_match_all('/^Location:(.*)$/mi', $response, $matches);
curl_close($ch);
echo !empty($matches[1]) ? trim($matches[1][0]) : 'No redirect found';
少し古い回答ですが、完全な実例を示すことを望んでいましたが、いくつかの解決策があります:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url); //set url
curl_setopt($ch, CURLOPT_HEADER, true); //get header
curl_setopt($ch, CURLOPT_NOBODY, true); //do not include response body
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); //do not show in browser the response
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); //follow any redirects
curl_exec($ch);
$new_url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL); //extract the url from the header response
curl_close($ch);
これは、301や302などのリダイレクトで機能しますが、404では、リクエストされた元のURLが返されます(見つからなかったため)。これは、サイトのリンクを更新または削除するために使用できます。とにかくこれは私の必要でした。
リダイレクトされたURLのLocationヘッダーを取得する必要があります。
Tamik Sozievの答えに対するuser437797のコメントに対する回答(残念ながら、直接コメントする評判はありません):
CURLINFO_EFFECTIVE_URLは正常に機能しますが、opが望むようにするためには、もちろんCURLOPT_FOLLOWLOCATIONをTRUEに設定する必要があります。これは、CURLINFO_EFFECTIVE_URLが正確に、実際にロードされる有効なURLを返すためです。リダイレクトに従わない場合、これは要求されたURLになり、リダイレクトに従う場合、リダイレクト先の最終URLになります。
このアプローチの良い点は、複数のリダイレクトでも機能することです。一方、HTTPヘッダーを自分で取得および解析するときは、最終的な宛先URLが公開される前にそれを複数回行う必要があります。
また、curlが従うリダイレクトの最大数は、CURLOPT_MAXREDIRSを介して制御できることに注意してください。デフォルトでは無制限(-1)ですが、誰かが(おそらく意図的に)構成したURLに無限のリダイレクトループがあると、問題が発生する可能性があります。
302リダイレクトの新しい宛先は、httpヘッダーフィールド「location」にあります。例:
HTTP/1.1 302 Found
Date: Tue, 30 Jun 2002 1:20:30 GMT
Server: Apache
Location: http://www.foobar.com/foo/bar
Content-Type: text/html; charset=iso-8859-1
正規表現でそれをgrepするだけです。
すべてのHTTPヘッダー情報を含めるには、curlオプションCURLOPT_HEADERで結果に含めます。以下で設定します:
curl_setopt($c, CURLOPT_HEADER, true);
単にcurlがリダイレクトに従うようにする場合は、CURLOPT_FOLLOWLOCATIONを使用します。
curl_setopt($c, CURLOPT_FOLLOWLOCATION, true);
とにかく、HTTP Statuscode 302は一時リダイレクトに過ぎないため、新しいURIを使用しないでください。
Curl httpリクエストによって返されるすべてのヘッダー、および各ヘッダーのステータスコードとヘッダー行の配列を取得する方法を次に示します。
$url = 'http://google.com';
$opts = array(CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => true,
CURLOPT_FOLLOWLOCATION => true);
$ch = curl_init();
curl_setopt_array($ch, $opts);
$return = curl_exec($ch);
curl_close($ch);
$headers = http_response_headers($return);
foreach ($headers as $header) {
$str = http_response_code($header);
$hdr_arr = http_response_header_lines($header);
if (isset($hdr_arr['Location'])) {
$str .= ' - Location: ' . $hdr_arr['Location'];
}
echo $str . '<br />';
}
function http_response_headers($ret_str)
{
$hdrs = array();
$arr = explode("\r\n\r\n", $ret_str);
foreach ($arr as $each) {
if (substr($each, 0, 4) == 'HTTP') {
$hdrs[] = $each;
}
}
return $hdrs;
}
function http_response_header_lines($hdr_str)
{
$lines = explode("\n", $hdr_str);
$hdr_arr['status_line'] = trim(array_shift($lines));
foreach ($lines as $line) {
list($key, $val) = explode(':', $line, 2);
$hdr_arr[trim($key)] = trim($val);
}
return $hdr_arr;
}
function http_response_code($str)
{
return substr(trim(strstr($str, ' ')), 0, 3);
}
curl_getinfo($ch)
を使用すると、最初の要素(url
)は有効なURLを示します。