А я примерно так и сделал:
function abs_url($link, $base_url) { if (!$link) { return $base_url; } $parse_url = parse_url($link); $base = parse_url($base_url); $host_url = $base['scheme'] . "://" . $base['host']; if (isset($parse_url['scheme'])) { $abs_url = $link; } elseif (isset($parse_url['host'])) { $abs_url = "http://" . $link; } else { if (preg_match("!^/!", $link)) { $abs_url = $host_url . $link; } elseif (preg_match("!^(\.\./)+!", $link, $tt0)) { $num = preg_match_all("!\.\./!", $tt0['0'], $tt1); preg_match("!(.*)/(?:.+?/){{$num}}$!", dirname($base['path']) . "/", $tt2); $abs_url = $host_url . $tt2['1'] . "/" . preg_replace("!^(\.\./){{$num}}!", "", $link); } elseif (preg_match("!^\./!", $link)) { $abs_url = $host_url . dirname($base['path']) . substr($link, 1); } else { $abs_url = $base_url . ((preg_match("!/$!", $base_url)) ? "" : "/") . $link; } } return $abs_url; } function curl_flollow_exec($ch, $redirects = 0) { curl_setopt($ch, CURLOPT_HEADER, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); $data = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); if (($http_code == 301 || $http_code == 302) && ++$redirects < 10) { preg_match('/(Location:|URI:)(.*?)\n/', $data, $matches); if (isset($matches[2])) { $redirect_url = trim($matches[2]); if (stripos($redirect_url, 'http') !== 0) { $download_url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL); $redirect_url = abs_url($redirect_url, $download_url); } if ($redirect_url !== '') { curl_setopt($ch, CURLOPT_URL, $redirect_url); return curl_flollow_exec($ch, $redirects); } } } return $data; } function curl_post($url, $data, $set_cookie) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_REFERER, $url); curl_setopt($ch, CURLOPT_AUTOREFERER, true); curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (X11; Linux i686; rv:16.0) Gecko/20100101 Firefox/16.0 Iceweasel/16.0'); if ($set_cookie) { curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookie.txt'); } curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookie.txt'); if ($data) { curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, mk_post_data($data)); } else { curl_setopt($ch, CURLOPT_POST, false); } $result = curl_flollow_exec($ch); curl_close($ch); return $result; }
Но все равно, приходится сначала передавать данные по POST для установки куки, а потом передавать их снова, но уже через GET для правильного редиректа. Костыль, конечно...
Пробовал, не помогает, т.к. самый первый же редирект идет на 404 и куки передавать тупа некуда.
Я бы не сказал, что опоздали. То, что я сделал, это через попу. Т.е. я сначала передаю логин и пароль эмулятору через POST. Он создает куку, но редиректит на 404. Потом я повторно дергаю страницу через эмулятор, но передаю логин и пароль уже через GET. И только так я получаю то, что хотел.
Согласитесь, что это очень криво. Хотелось бы нормального решения. Т.е. чтобы эмулятор работал как и cURL с FOLLOWLOCATION - сразу, за один проход.
Этого, сожалению, у меня пока не получилось.---------- Добавлено 04.11.2013 в 21:17 ----------
Я именно так и делаю - добавляю к нему http://www.site.com/. В скрипте из этого топика я просто удалил ту строку, чтобы не отвлекала. Остальное там как есть.---------- Добавлено 04.11.2013 в 21:23 ----------
function curl_flollow_exec($ch, $redirects = 0) { curl_setopt($ch, CURLOPT_HEADER, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); $data = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); if (($http_code == 301 || $http_code == 302) && ++$redirects < 10) { preg_match('/(Location:|URI:)(.*?)\n/', $data, $matches); if (isset($matches[2])) { $redirect_url = trim($matches[2]); if ($redirect_url !== '') { $download_url = curl_getinfo ($ch, CURLINFO_EFFECTIVE_URL); $redirect_url = abs_url ($redirect_url, $download_url); curl_setopt($ch, CURLOPT_REFERER, $download_url); curl_setopt($ch, CURLOPT_URL, $redirect_url); return curl_flollow_exec($ch, $redirects); } } } return $data; } function abs_url ($link, $base_url) { if (!$link) return $base_url; $parse_url = parse_url($link); $base = parse_url($base_url); $host_url = $base['scheme'] . "://" . $base['host']; if ($parse_url['scheme']) { $abs_url = $link; } elseif ($parse_url['host']) { $abs_url = "http://" . $link; } else { // ссылка относительная if (preg_match("!^/!", $link)) { $abs_url = $host_url . $link; } elseif (preg_match("!^(\.\./)+!", $link, $tt0)) { $num = preg_match_all("!\.\./!", $tt0['0'], $tt1); preg_match("!(.*)/(?:.+?/){{$num}}$!", dirname($base['path']) . "/", $tt2); $abs_url = $host_url . $tt2['1'] . "/" . preg_replace("!^(\.\./){{$num}}!", "", $link); } elseif (preg_match("!^\./!", $link)) { $abs_url = $host_url . dirname($base['path']) . substr($link, 1); } else { $abs_url = $base_url . ((preg_match("!/$!", $base_url))?"":"/") . $link; } } return $abs_url; }
Не с подстановкой реферера все равно 404. Дело не в нем, видимо...
Вот с VERBOSE:
> POST /login HTTP/1.1
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:11.0) Gecko/20100101 Firefox/11.0
Host: www.site.com
Accept: */*
Referer: http://www.site.com/login
Cookie: STGSHYTEFG=E1320FD3211D6AAFD65ABC19...
Content-Length: 86
Content-Type: application/x-www-form-urlencoded
* upload completely sent off: 86 out of 86 bytes
< HTTP/1.1 302 Found
< Cache-Control: private
< Content-Type: text/html; charset=utf-8
< Location: /account_page
< Server: Microsoft-IIS/7.5
* Replaced cookie STGSHYTEFG="899227A88B4B3C8992..." for domain www.site.com, path /, expire 0
< Set-Cookie: STGSHYTEFG=899227A88B4B3C8992...; path=/; HttpOnly
< Date: Mon, 04 Nov 2013 15:54:55 GMT
< Content-Length: 137
<
* Ignoring the response-body
* Connection #0 to host www.site.com left intact
* Issue another request to this URL: 'http://www.site.com/account_page'
* Violate RFC 2616/10.3.3 and switch from POST to GET
* Re-using existing connection! (#0) with host (nil)
* Connected to (nil) (50.56.211.113) port 80 (#0)
> GET //account_page HTTP/1.1
Cookie: STGSHYTEFG=899227A88B4B3C8992...
< HTTP/1.1 200 OK
< Cache-Control: no-cache, no-store, must-revalidate
< Pragma: no-cache
< Expires: -1
< Vary: Content-Encoding
* Added cookie ASP.NET_SessionId="3yadwkzanursnnypckx3bt0y" for domain www.site.com, path /, expire 0
< Set-Cookie: ASP.NET_SessionId=3yadwkzanursnnypckx3bt0y; path=/; HttpOnly
< Content-Length: 42550
* Connection #0 to host (nil) left intact
* Closing connection #0
Как видно, в случае с cURL (CURLOPT_FOLLOWLOCATION = true) и куки ставятся другие и редирект тоже другой. В случае с эмутятором кука всего одна и редирект сразу идет на 404 (см. заголовки на предыдущей странице).
Как бы научить эмулятор делать то же самое?---------- Добавлено 04.11.2013 в 20:13 ----------Я это сделал (через костыль). Почитал заголовки и просто заменил POST на GET и все заработало :)
Неа :(
Вот пошагово (на входе URL и данные POST с логином и паролем):
HTTP/1.1 302 Found
Cache-Control: private
Content-Type: text/html; charset=utf-8
Location: [тут правильная ссылка на правильную страницу аккаунта, которая открывается в браузере, но дает 404 череp скрипт-эмулятор (см. следующий заголовок)]
Server: Microsoft-IIS/7.5
Set-Cookie: STGSHYTEFG=25E3CB014B2A73591CB930B244D8F2A8BFE; path=/; HttpOnly
Date: Mon, 04 Nov 2013 15:43:02 GMT
Content-Length: 137
HTTP/1.1 404 Not Found
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: -1
Content-Length: 7586
Значит бывают чудеса, все же?
Вот что отдает сервер после редиректов:
Date: Mon, 04 Nov 2013 15:28:46 GMT
Content-Length: 7602
Если дергать его этим же эмулятором напрямую, то получается тот же 404 (см. выше). Если открыть в браузере или через cURL с включенным CURLOPT_FOLLOWLOCATION, то все нормально - выдает нужную страницу.
Тогда cURL с CURLOPT_FOLLOWLOCATION тоже не помог бы. Но я повторюсь, когда сервер выдает 404, остается авторизованным. Более того, у страницке есть версия, которая доступна всем неавторизованным пользователям. Так вот, сервер и ее не отдает. Он тупо выкидывает 404.
Даже вообще без авторизации я должен получить версию страницы, доступную для всех. Но вместо нее я все равно получаю 404.
Так я и даю. Скрипт эмулятора я привел выше (попробуйте его на каком-нибудь примере). Куки он прекрасно создает и они лежат в CURLOPT_COOKIEJAR/CURLOPT_COOKIEFILE, как и положено. Авторизация происходит, последний редирект идет на правильный URL - все как надо. Только вместо контента нужной страницы, сервер выдает мне 404.
cURL со включенным CURLOPT_FOLLOWLOCATION и точно теми же параметрами (url, login, password) выдает правильный результат. Почему-то на том конкретном сайте спотыкается только эмулятор.
Я пытаюсь понять, чем работа эмулятора может отличаться от CURLOPT_FOLLOWLOCATION? Что в нем может быть не учтено?
http://openweathermap.org/api - чем плох?
А еще не надо пользоваться левыми плагинами и темами, скаченными с варезных сайтов.
В любом текстовом редакторе, кроме ноутпада. Например: http://www.pnotepad.org/