cURL to biblioteka, tak zwany klient HTTP, z ogromnymi możliwościami. Jedną z nich jest możliwość podążania za przekierowaniami zawartymi w nagłówkach odpowiedzi serwera.
Służy do tego opcja CURLOPT_FOLLOWLOCATION, włącza się ja w następujący sposób:
curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, true);
Niestety, jeśli na serwerze włączone są elementy zabezpieczeń serwera PHP: safe_mode lub open_basedir opcja ta jest niedostępna.
Próba jej użycia kończy się komunikatem:
PHP Warning: curl_setopt() [function.curl-setopt]: CURLOPT_FOLLOWLOCATION cannot be activated when in safe_mode or an open_basedir is set
PHP pozwala manipulować opcjami w trakcie działania skryptu poprzez funkcję ini_set, jednak ani ustawienia safe_mode ani open_basedir nie mogą być w ten sposób zmieniane.
W sieci znalazłem kilka przykładów rozwiązania problemu, ale żaden nie spełniał moich oczekiwań. Napisałem więc własną funkcję, tzw. wrapper funkcji curl_exec, która realizuje zadanie. Funkcja zachowuje się dokładnie tak, jak curl_exec, tzn. zwraca to samo przy tych samych parametrach.
/**
* @param cURL $ch - uchwyt do cURL
* @param int $redirects - przekierowania
* @param bool $curlopt_returntransfer - CURLOPT_RETURNTRANSFER
* @param int $curlopt_maxredirs - CURLOPT_MAXREDIRS
* @param bool $curlopt_header - CURLOPT_HEADER
* @return mixed
*/
function curl_redirect_exec($ch, &$redirects, $curlopt_returntransfer = false, $curlopt_maxredirs = 10, $curlopt_header = false) {
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$data = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$exceeded_max_redirects = $curlopt_maxredirs > $redirects;
$exist_more_redirects = false;
if ($http_code == 301 || $http_code == 302) {
if ($exceeded_max_redirects) {
list($header) = explode("\r\n\r\n", $data, 2);
$matches = array();
preg_match('/(Location:|URI:)(.*?)\n/', $header, $matches);
$url = trim(array_pop($matches));
$url_parsed = parse_url($url);
if (isset($url_parsed)) {
curl_setopt($ch, CURLOPT_URL, $url);
$redirects++;
return curl_redirect_exec($ch, $redirects, $curlopt_returntransfer, $curlopt_maxredirs, $curlopt_header);
}
}
else {
$exist_more_redirects = true;
}
}
if ($data !== false) {
if (!$curlopt_header)
list(,$data) = explode("\r\n\r\n", $data, 2);
if ($exist_more_redirects) return false;
if ($curlopt_returntransfer) {
return $data;
}
else {
echo $data;
if (curl_errno($ch) === 0) return true;
else return false;
}
}
else {
return false;
}
}
Przykłady użycia
Przedstawię dwa przykłady użycia funkcji. Pierwszy prosty, drugi pokazujący wszystkie możliwości.
Standardowe użycie cURL z opcją CURLOPT_FOLLOWLOCATION:
$ch = curl_init("http://08r.utnij.net");
curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, true);
curl_exec($ch);
$info = curl_getinfo($ch);
echo "Aktualny adres: ".$info['url'].", wykonanych przekierowań: {$info['redirect_count']}\n";
curl_close($ch);
to samo zrealizowane z użyciem funkcji curl_redirect_exec:
$ch = curl_init("http://08r.utnij.net");
// deklarujemy i inicjujemy zmienną którą funkcja
// zwiększy o ilość wykonanych przekierowań
$redirects = 0;
// wykonujemy funckję curl_redirect_exec
// zamiast oryginalnej curl_exec
curl_redirect_exec($ch, $redirects);
$info = curl_getinfo($ch);
echo "Aktualny adres: ".$info['url'].", wykonanych przekierowań: $redirects\n";
curl_close($ch);
Użycie cURL z opcjami CURLOPT_FOLLOWLOCATION, CURLOPT_MAXREDIRS i CURLOPT_HEADER:
$ch = curl_init("http://08r.utnij.net");
curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt ($ch, CURLOPT_MAXREDIRS, 5);
curl_setopt ($ch, CURLOPT_HEADER, true);
curl_exec($ch);
$info = curl_getinfo($ch);
echo "Aktualny adres: {$info['url']}, wykonanych przekierowań: {$info['redirect_count']}\n";
if(curl_errno($ch)) echo "Error: ".curl_error($ch);
curl_close($ch);
to samo zrealizowane z użyciem funkcji curl_redirect_exec:
$ch = curl_init("http://08r.utnij.net");
$redirects = 0;
curl_redirect_exec($ch, $redirects, true, 5, true);
$info = curl_getinfo($ch);
echo "Aktualny adres: {$info['url']}, wykonanych przekierowań: $redirects\n";
if(curl_errno($ch)) echo "Error: ".curl_error($ch);
curl_close($ch);
Jeśli chcemy użyć któreś z opcji: CURLOPT_FOLLOWLOCATION, CURLOPT_MAXREDIRS lub CURLOPT_HEADER, podajemy je jako parametry funkcji curl_redirect_exec.
Znane ograniczenia
Ponieważ cURL nie jest natywną częścią języka PHP, nie na wszystko programista ma wpływ.
Ograniczenia:
- Przy włączonej opcji CURLOPT_HEADER curl_exec zwróci nagłówki wszystkich przekierowujących stron, curl_redirect_exec zwróci tylko nagłówek ostatniej.
- curl_redirect_exec nie wywoła błędu CURLE_TOO_MANY_REDIRECTS (47), ale tak jak curl_exec zwróci false.
Pliki oraz przykłady do pobrania: http://antczak.org/source/curl/curl_redirect_exec.zip
„cURL to biblioteka, tak zwany klient HTTP”
sory ale skoro to jest PHP to ta nazwa bardziej się kojarzy z deczko innym „klijentem” (którego też nie testowałem ale sam link za siebie mówi – choć w sumie klasą 😉 ):
http://pl.php.net/manual/en/book.http.php
„…z ogromnymi możliwościami. …”
to zależy, jak się klasę/funkcję napisze – curl jest kompromisem między oop i procedurą bym rzekł – aczkolwiek dla początkujących jest łatwiejszy niż inne rozwiązania 😉
„…Jedną z nich jest możliwość podążania za przekierowaniami zawartymi w nagłówkach odpowiedzi serwera…”
jestem bardziej hobbistą niż programistą 😉 – aczkolwiek z forum może mnie kojarzysz 😉 to jest i plus i moim zdaniem baardzo duży minus, gdyż wielu nie prubuje pomyśleć, a wystarczy zrobić podobne narzędzie do Twojego… inaczej, pasuje wiedzieć, jakie są odpowiedzi serwera chcący parsować bardziej skomplikowane strony/połaczenia… problem sprowadziłeś w tym temacie do kwestii choćby surowego i samego fsockpen – a wystarczy go obudować odpowiednią klasą 😉 – i cóż, jeśli w odpowiedzi przeparsujesz inną funkcj/klasą odpowiedź (same nagłówki w pierw) to wiesz co zrobić dalej, czy zdekompresować zawartość czy falow location… czy inne „pierdoły”… a w zasadzie Tutaj curl’a obudowałeś funkcją – więc równie dobrze mogłeś skorzystać z prostszych funkcji w sensie może uboższych aczkolwiek w „surowym transferze danych”
„Przy włączonej opcji CURLOPT_HEADER curl_exec zwróci nagłówki wszystkich przekierowujących stron, curl_redirect_exec zwróci tylko nagłówek ostatniej”
już nie pamiętam jak to dokładnie wygląda – zapewne to się „skumuluje” to wyświetlanie nagłówków – jak już wspomniałem nie jestem programistą a hobbistą i czasami grywam w różne gierki, jak utrudnić wykrycie korzystania z własnych pseudo programów – trzeba wysyłać odpowiednie nagłówki w zależności od sytuacji 😉 – tak więc liczenie n automatyczne FOLLOWLOCATION jest zgubne
przepraszam, za komentarz który chyba nic nie wnosi do tematu gdyż jestem pod wpływem %-ów 😉 – są święta w końcu – miałem coś jeszcze napisać aczkolwiek mi z głowy wyleciało… przypomnę tylko jeszcze raz, że sam curl jest tylko kompromisem miedzy oop a procedurą i jest tylko więcej artykułów na jego temat ale w sumie on nie daje nic więcej niż fsockpen – a sama ta funkcja daje tylko tyle, że na strumieniu danych operuje się tak jak na pliku + troszku wiedzy, bo do samego strumienia sa też inne odpowiednie funkcje w php 😉
ps. skoro masz utf-8 na stronie i zamieniane cytowanie to może zamień cytaty na polski otwierający i zamykający ;)?? – raczej mało pracy…
Witam,
Nie wiem co źle robię ale niestety usunięcie
powoduje że mój skrypt nie loguje się do pewnego serwisu.
$a = curl_init('site'); curl_setopt($a, CURLOPT_COOKIEFILE, 'cookie.txt'); curl_setopt($a, CURLOPT_COOKIEJAR, 'cookie.txt'); curl_setopt($a, CURLOPT_USERAGENT, 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3'); curl_setopt($a, CURLOPT_POST, 1); curl_setopt($a, CURLOPT_POSTFIELDS, '__submit__=1&email='.$login.'&pass='.$pass.'&remember=1'); $redirects = 0; curl_redirect_exec($a, $redirects);Witam.
Zamiast ręcznie ustawiać
zmień wywołanie z
na
W zaawansowanym przykładzie jest to użyte.
Odnośnie komentarza zegarka84:
1. Na czym polega kompromis pomiędzy OOP, a *INNYM* paradygmatem programowania w CURL-u? Wybacz, ale jakoś nie rzuca się to w oczy.
2. Nie znam powodu wywodu, ale CURL ogólnie nie jest praktyczny – gdy przychodzi zastosować go w bardziej wymagających projektach ( + zawiera bugi ), wystarczyło krótko podsumować i nie marnować nikomu czasu na czytanie tego wszystkiego.
3. Follow location to jedna z niewielu rzeczy która działa tam poprawnie. Za to korzystanie z hostingu który ustawia safe mode, już jest pograniczu zdrowego rozsądku.
Pozdrawiam autora 😉
A co w sytuacji gdy ktoś używa multi_curl, Jak przerobić dany skrypt
A co w sytuacji jeżeli strona nie używa przekierowań za pomocą absolutnych URL-i (http://www.example.com/blog/) tylko relatywnych url-i (/blog/)
Dzięki, za zajebista funkcje, dizeki niej zrozumialem dzialanie tego shitu.
Thanks again sir
niby działa, w sensie że po zmianie skrypt działa dalej, jednak przy użyciu fallow location w moim skrypcie (parser) dostaje ponad 1000 wyników, przy użyciu tej funkcji dostaje ich niecałe 200, i akurat niecałe 200 nie wymaga przekierowania, co za tym idzie wnioskuję że przekierowania w funkcji nie działają..
Podaj przykład adresu, dla którego nie działa przekierowanie.
Pzdr.