curl vs url_fopen

U jednom od prethodnih postova pisao sam o najčešćim problemima s php-om. Jedan od njih je bio problem s url_fopenom koji je iz sigurnosnih razloga ugašen na našim serverima. Zbog sve češćih upita odlučio sam napraviti ovaj post koji će se osvrnuti i na drugu stranu problematike url_fopena.

Zašto curl a ne fopen?

Jedan od osnovnih razloga je sigurnost, fopenom dozvoljavate da se u vaš site includa remote maliciozni php kod i time riskirate defaceanje stranice.

Osim samih sigurnosnih razloga povlači se i pitanje performansi. U nastavku možete pronaći opis problematike kao i skriptu za riješenje ovog problema.

Prvi problem je nepotrebni promet i sporo učitavanje vašeg sitea.

Vrlo često velik broj webmastera međusobno razmjenjuju sadržaje ili rss feedovima ili direktnim parsanjem sadržaja. U 90% slučajeva se koristi fopen za pristupanje remote contentu. Najčešće takva razmjena sadržaja nije prethodno dogovorena nego se uzima zdravo za gotovo.

Koristeći fopen prilikom svakog učitavanja vašeg sitea, za svakog posjetitelja server mora napraviti request na remote server, pritom se oslanjajući na brzinu veze, dns lookupe, zagušenje veza između dva servera i na koncu samu brzinu i opterećenje remote servera. Naravno bilo kakvo usporenje ili prekid funkcionalnosti na bilo kojem od ovih segmenta, se direktno osjeti na vašem siteu jer on s fopenom ovisi o remote site-u. U najgorim slučajevima zbog prekida rada remote sitea i vaš može prestat radit.

Čak i u slučajevima kad sve funkcionira normalno, stvara se overhead od barem 1-2 sekunde po posjetitelju, naravno i promet se nepotrebno povećava, a to osjete i webmasteri remote sitea koji mogu s vremenom odlučiti zabranit pristup serveru na kojem se nalazi vaš site.

Elegantno riješenje ovog problema je povremeno downloadanje remote sadržaja lokalno, te posluživanje lokalno spremljenog file-a. Ovo se može izvest ili programiranjem php skripte ili kroz cron jobove u cpanelu na linux hosting paketima.

Drugi problem je relativno usko vezan uz prvi, a radi se o ovisnosti vašeg sitea o remote sadržajima.

Fopen nažalost nema mogćnost provjere dostupnosti sadržaja. Pa tako ukoliko je sadržaj na remote serveru uklonjen fopen će i dalje uredno downloadati 404 (file not found) page. Curl s druge strane ima mogćnost provjere http headera i filtiranja downloada po istima.

Da skratim priču, pripremili smo dio koda koji bi zamjenio dosadašnje fopen funkcije. Kod vam omogućava jednostavno downloadanje remote sadržaja i periodičke update tog sadržaja ukoliko je lokalni sadržaj stariji od definiranog vremena.

Isto tako skripta provjerava dali je remote sadržaj uistinu dostupan, ako nije nastavlja se koristiti zadnji validni lokalni sadržaj.

Znači dosadašnji kod:

$handle = fopen(“http://www.example.com/”, “r”);

je potrebno zamjeniti sa:


// variables to set
$remoteurl = "http://plus.hr"; //Url koji zelite downloadati
$chtime = "2"; //lokalni sadrzaj nece biti stariji od koliko sati?
$timeout = "10"; //Koliko se dugo u sekundama ceka remote server? //ne editirati $localfile = preg_replace("/[^A-Za-z0-9_\.]/", "_", $remoteurl); if (file_exists($localfile)){ $localfile_stat = stat($localfile); if ($localfile_stat['mtime'] < strtotime("-$chtime hours")){ $chresponse = curl_init($remoteurl); $ret = curl_setopt($chresponse, CURLOPT_HEADER, 1); $ret = curl_setopt($chresponse, CURLOPT_FOLLOWLOCATION,1); $ret = curl_setopt($chresponse, CURLOPT_TIMEOUT,$timeout); $ret = curl_setopt($chresponse, CURLOPT_RETURNTRANSFER, 1); $ret = curl_exec($chresponse); if (empty($ret)) { die(curl_error($chresponse)); curl_close($chresponse); } else { $info = curl_getinfo($chresponse); curl_close($chresponse); if ($info['http_code'] == "200") { $ch = curl_init($remoteurl); $fp = fopen($localfile, "w"); curl_setopt($ch, CURLOPT_FILE, $fp); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); curl_exec($ch); curl_close($ch); fclose($fp); }else{ touch($localfile); } } } }else{ $ch = curl_init($remoteurl); $fp = fopen($localfile, "w"); curl_setopt($ch, CURLOPT_FILE, $fp); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); curl_exec($ch); curl_close($ch); fclose($fp); } $handle = fopen($localfile, "r");

Za intezivnije uporabe kod se može vrlo jednostavno konvertirati u funkciju koja bi se nalazila u nekom global include fileu, pa bi se umjesto fopena pozivala ta funkcija.

Povezani članci

Odgovori