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.
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.