cURL este un instrument pentru transferul fișierelor și datelor cu sintaxa URL, susținând multe protocoale, inclusiv HTTP, FTP, TELNET și multe altele. Inițial, cURL a fost proiectat să fie un instrument de linie de comandă. Norocos pentru noi, biblioteca cURL este de asemenea sprijinită de PHP. În acest articol, vom analiza unele dintre caracteristicile avansate ale cURL și cum le putem folosi în script-urile noastre PHP.
Este adevărat că există și alte modalități de a prelua conținutul unei pagini web. De multe ori, mai ales din cauza lenei, am folosit doar funcții simple PHP în loc de cURL:
$ content = file_get_contents ("http://www.nettuts.com"); // sau $ lines = fișier ("http://www.nettuts.com"); // sau readfile ("http://www.nettuts.com");
Cu toate acestea, ele nu au practic nici o flexibilitate și nu dispun de o manevrare suficientă a erorilor. De asemenea, există anumite sarcini pe care pur și simplu nu le puteți face, cum ar fi tratarea cookie-urilor, autentificării, posturilor de formular, încărcărilor de fișiere etc..
cURL este o bibliotecă puternică care acceptă multe protocoale, opțiuni diferite și oferă informații detaliate despre solicitările de adrese URL.
Înainte de a trece la exemple mai complicate, să examinăm structura de bază a unei cereri cURL în PHP. Există patru pași principali:
// 1. inițializați $ ch = curl_init (); // 2. setați opțiunile, inclusiv url curl_setopt ($ ch, CURLOPT_URL, "http://www.nettuts.com"); curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt ($ ch, CURLOPT_HEADER, 0); // 3. executați și preluați rezultatul HTML rezultant $ output = curl_exec ($ ch); // 4. eliberați mânerul curl curl_close ($ ch);
Pasul 2 (adică apelurile curl_setopt () va fi o mare parte a acestui articol, pentru că acolo se petrece toată magia. Există o listă lungă de opțiuni cURL care pot fi setate, care pot configura în detaliu solicitarea adresei URL. S-ar putea să fie dificil să treceți prin toată lista și să o digerați pe rând. Așadar, astăzi, vom folosi doar câteva dintre cele mai comune și mai utile opțiuni în diferite exemple de cod.
Opțional, puteți adăuga și verificarea erorilor:
// ... $ output = curl_exec ($ ch); dacă ($ output === FALSE) echo "Eroare cURL:". curl_error ($ ch); // ...
Rețineți că trebuie să folosim "=== FALSE" pentru comparație în loc de "== FALSE". Pentru că trebuie să distingem între ieșirea goală și valoarea booleană FALSE, care indică o eroare.
Un alt pas opțional este de a obține informații despre cererea cURL, după ce a fost executată.
// ... curl_exec ($ ch); $ info = curl_getinfo ($ ch); echo "a luat". $ info ['total_time']. "secunde pentru url". $ Info [ 'url']; // ...
Următoarele informații sunt incluse în matricea returnată:
În acest prim exemplu, vom scrie un script care să detecteze redirecționările adreselor URL bazate pe diferite setări ale browserului. De exemplu, unele site-uri web redirecționează browsere de telefonie mobilă sau chiar surferi din diferite țări.
Vom utiliza opțiunea CURLOPT_HTTPHEADER pentru a seta antetele HTTP de ieșire, inclusiv șirul de agent utilizator și limbile acceptate. În cele din urmă, vom verifica dacă aceste site-uri încearcă să ne redirecționeze către diferite adrese URL.
// URL-uri de test $ urls = array ("http://www.cnn.com", "http://www.mozilla.com", "http://www.facebook.com"); // browsere de test $ browsers = array ("standard" => array ("user_agent" => "Mozilla / 5.0 (Windows; .6 (.NET CLR 3.5.30729), "language" => "en-us, en; q = 0.5"), "iphone" => array ("user_agent" => ; CPU ca Mac OS X; ro) AppleWebKit / 420 + (KHTML, ca Gecko) Versiune / 3.0 Mobile / 1A537a Safari / 419.3 "," language "=> => "Mozilla / 4.0 (compatibil; MSIE 7.0; Windows NT 5.1; GTB6; .NET CLR 2.0.50727)"; "limbă" => "fr, fr; foreach ($ urls ca $ url) echo "URL: $ url \ n"; foreach ($ browsere ca $ test_name => $ browser) $ ch = curl_init (); // set url curl_setopt ($ ch, CURLOPT_URL, $ url); // setați anteturile browserului curl_setopt ($ ch, CURLOPT_HTTPHEADER, array ("User-Agent: $ browser ['user_agent']", Accept-Language: $ browser ['language'])); // nu vrem conținutul paginii curl_setopt ($ ch, CURLOPT_NOBODY, 1); // avem nevoie de Header-ul HTTP returnat curl_setopt ($ ch, CURLOPT_HEADER, 1); // returnați rezultatele în loc să le expediați curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); $ ieșire = curl_exec ($ ch); curl_close ($ ch); // a existat un antet HTTP de redirecționare? dacă (preg_match ("! Location: (. *)!", $ output, $ matches)) echo "$ test_name: redirecționează la $ meciuri [1] \ n"; altceva echo "$ test_name: nici o redirecționare \ n"; echo "\ n \ n";
Mai întâi avem un set de adrese URL de testat, urmat de un set de setări de browser pentru a testa fiecare dintre aceste adrese URL. Apoi buclele prin aceste cazuri de testare și de a face o cerere cURL pentru fiecare.
Din cauza modului de configurare a opțiunilor cURL, ieșirea returnată va conține numai anteturile HTTP (salvate în $ output). Cu un simplu regex, putem vedea dacă a fost inclus un antet "Location:".
Când executați acest script, ar trebui să obțineți o ieșire astfel:
În cazul unei solicitări GET, datele pot fi trimise către o adresă URL prin intermediul "șirului de interogare". De exemplu, atunci când efectuați o căutare pe Google, termenul de căutare este localizat în partea de șir de interogări a adresei URL:
http://www.google.com/search?q=nettuts
Este posibil să nu aveți nevoie de cURL pentru a simula acest lucru într-un script web. Puteți fi doar leneș și ați lovit acea url cu "file_get_contents ()" pentru a primi rezultatele.
Dar unele formulare HTML sunt setate la metoda POST. Atunci când aceste formulare sunt trimise prin browser, datele sunt trimise prin intermediul organismului de solicitare HTTP, mai degrabă decât șirul de interogare. De exemplu, dacă efectuați o căutare în forumurile CodeIgniter, veți efectua o căutare după interogarea dvs. de căutare la:
http://codeigniter.com/forums/do_search/
Putem scrie un script PHP pentru a simula acest tip de solicitare de adrese URL. Mai întâi, să creăm un fișier simplu pentru acceptarea și afișarea datelor POST. Să o numim post_output.php:
print_r ($ _ POST);
Apoi vom crea un script PHP pentru a efectua o solicitare cURL:
$ url = "http: //localhost/post_output.php"; $ post_data = array ("foo" => "bar", "interogare" => "Nettuts", "acțiune" => "Trimiteți"); $ ch = curl_init (); curl_setopt ($ ch, CURLOPT_URL, $ url); curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); // facem o cerere POST curl_setopt ($ ch, CURLOPT_POST, 1); // adăugarea variabilelor post la cererea curl_setopt ($ ch, CURLOPT_POSTFIELDS, $ post_data); $ ieșire = curl_exec ($ ch); curl_close ($ ch); echo $ output;
Când executați acest script, ar trebui să obțineți o ieșire astfel:
A trimis un POST la scriptul post_output.php, care a aruncat valiza variabilei $ _POST și am capturat acea ieșire prin cURL.
Încărcarea fișierelor funcționează foarte similar cu exemplul POST anterior, deoarece toate fișierele de încărcare a fișierelor au metoda POST.
Mai întâi, să creăm un fișier pentru primirea solicitării și să îl sunăm upload_output.php:
print_r ($ _ FILES);
Iată scriptul real care efectuează încărcarea fișierului:
$ url = "http: //localhost/upload_output.php"; $ post_data = array ("foo" => "bar", // fișier pentru a fi încărcat "upload" => "@C: /wamp/www/test.zip"); $ ch = curl_init (); curl_setopt ($ ch, CURLOPT_URL, $ url); curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt ($ ch, CURLOPT_POST, 1); curl_setopt ($ ch, CURLOPT_POSTFIELDS, $ post_data); $ ieșire = curl_exec ($ ch); curl_close ($ ch); echo $ output;
Când doriți să încărcați un fișier, tot ce trebuie să faceți este să treceți calea fișierului la fel ca o variabilă post și puneți simbolul @ în fața acestuia. Acum, când executați acest script, trebuie să obțineți o ieșire astfel:
Una dintre caracteristicile mai avansate ale cURL este abilitatea de a crea un mâner "multi" cURL. Aceasta vă permite să deschideți simultan și asincron conexiuni la mai multe adrese URL.
Într-o solicitare cURL obișnuită, executarea script-ului se oprește și așteaptă ca cererea URL să se termine înainte de a putea continua. Dacă intenționați să atingeți mai multe adrese URL, aceasta poate dura mult timp, deoarece puteți solicita doar o adresă URL la un moment dat. Putem depăși această limitare utilizând mânerul multiplu.
Să ne uităm la acest exemplu de cod din php.net:
// creați ambele resurse cURL $ ch1 = curl_init (); $ ch2 = curl_init (); // setați adresa URL și alte opțiuni corespunzătoare curl_setopt ($ ch1, CURLOPT_URL, "http://lxr.php.net/"); curl_setopt ($ ch1, CURLOPT_HEADER, 0); curl_setopt ($ ch2, CURLOPT_URL, "http://www.php.net/"); curl_setopt ($ ch2, CURLOPT_HEADER, 0); // a crea mânerul multiplu cURL $ mh = curl_multi_init (); // adăugați cele două mânere curl_multi_add_handle ($ mh, $ ch1); curl_multi_add_handle ($ mh, $ CH2); $ active = null; // executați mânerele nu $ mrc = curl_multi_exec ($ mh, $ active); în timp ce ($ mrc == CURLM_CALL_MULTI_PERFORM); în timp ce ($ active && $ mrc == CURLM_OK) dacă curl_multi_select ($ mh)! = -1) do $ mrc = curl_multi_exec ($ mh, $ active); în timp ce ($ mrc == CURLM_CALL_MULTI_PERFORM); // închideți mânerele curl_multi_remove_handle ($ mh, $ ch1); curl_multi_remove_handle ($ mh, $ ch2); curl_multi_close ($ mh);
Ideea este că puteți deschide mai multe mânere cURL și le puteți atribui unui singur mâner multi. Apoi, puteți aștepta ca aceștia să termine executarea în timp ce se află într-o buclă.
Există două bucle principale în acest exemplu. Prima buclă do-while solicită în mod repetat curl_multi_exec (). Această funcție nu este blocată. Efectuează cât mai puțin posibil și returnează o valoare de stare. Atâta timp cât valoarea returnată este constanta "CURLM_CALL_MULTI_PERFORM", înseamnă că există încă o activitate mai imediată de făcut (de exemplu, trimiterea antetelor http la adresele URL). De aceea continuăm să o numim până când valoarea returnată este altceva.
În următoarea buclă, vom continua atâta timp cât variabila activă $ este "adevărată". Acesta a fost trecut ca al doilea argument pentru apelul curl_multi_exec (). Este setat la "adevărat" atâta timp cât există legături active cu mânerul multiplu. Următorul lucru pe care îl facem este să sunăm curl_multi_select (). Această funcție este "blocarea" până când nu există nicio activitate de conexiune, cum ar fi primirea unui răspuns. Când se întâmplă acest lucru, intrăm într-o altă buclă în care să continuăm executarea.
Să vedem dacă noi putem crea un exemplu de lucru, care are un scop practic.
Imaginați-vă un blog cu multe postări care conțin linkuri către site-uri externe. Unele dintre aceste legături s-ar putea sfârși după câteva momente din diferite motive. Poate că pagina este mai lungă acolo sau întregul site a dispărut.
Vom construi un script care analizează toate legăturile și găsește site-uri non-încărcare și 404 de pagini și ne întoarce un raport.
Rețineți că acest lucru nu va fi un plug-in real Wordpress. Este doar un script de utilitate autonom și este doar pentru scopuri demonstrative.
Deci sa începem. Mai întâi trebuie să preluăm linkurile din baza de date:
// CONFIG $ db_host = 'localhost'; $ db_user = 'rădăcină'; $ max_connections = 10; // inițializați unele variabile $ url_list = array (); $ work_urls = $ db_pass = "; $ db_name = 'wordpress'; $ excluded_domains = array ('localhost', 'www.mydomain.com' ($ db_host, $ db_user, $ db_pass)) die ('Nu s-a putut conecta ($ db_host, $ db_user, $ db_pass) : mysql_error ()); if (mysql_select_db ($ db_name)) die ('Nu a putut fi selectat db:' mysql_error () FROM wp_posts WHERE post_content LIKE '% href =%' ȘI post_status = 'publica' și post_type = 'post' "; $ r = mysql_query ($ q) sau die (mysql_error )) // obțineți toate linkurile prin regex if (preg_match_all ("! href = \" (. *?) \ "!", $ d ['post_content'], $ matches)) foreach ca $ url) // excludeți unele domenii $ tmp = parse_url ($ url); dacă (in_array ($ tmp ['host'], $ excluded_domains)) continue; // stoca url $ url_list [ url; // re mutați duplicate $ url_list = array_values (array_unique ($ url_list)); dacă (! $ url_list) die ("Nu se verifică URL-ul");
Mai întâi avem o configurație a bazei de date, urmată de o serie de nume de domenii pe care le vom ignora ($ excluded_domains). De asemenea, stabilim un număr pentru conexiunile maxime simultane pe care le vom folosi mai târziu ($ max_connections). Apoi ne conectam la baza de date, preluam mesaje care contin link-uri si le colectam intr-un tablou ($ url_list).
Codul următor ar putea fi un complex mic, așa că voi încerca să-l explic în pași mici.
// 1. mâner multi $ mh = curl_multi_init (); // 2. adăugați mai multe adrese URL la mânerul multi pentru ($ i = 0; $ i < $max_connections; $i++) add_url_to_multi_handle($mh, $url_list); // 3. initial execution do $mrc = curl_multi_exec($mh, $active); while ($mrc == CURLM_CALL_MULTI_PERFORM); // 4. main loop while ($active && $mrc == CURLM_OK) // 5. there is activity if (curl_multi_select($mh) != -1) // 6. do work do $mrc = curl_multi_exec($mh, $active); while ($mrc == CURLM_CALL_MULTI_PERFORM); // 7. is there info? if ($mhinfo = curl_multi_info_read($mh)) // this means one of the requests were finished // 8. get the info on the curl handle $chinfo = curl_getinfo($mhinfo['handle']); // 9. dead link? if (!$chinfo['http_code']) $dead_urls []= $chinfo['url']; // 10. 404? else if ($chinfo['http_code'] == 404) $not_found_urls []= $chinfo['url']; // 11. working else $working_urls []= $chinfo['url']; // 12. remove the handle curl_multi_remove_handle($mh, $mhinfo['handle']); curl_close($mhinfo['handle']); // 13. add a new url and do work if (add_url_to_multi_handle($mh, $url_list)) do $mrc = curl_multi_exec($mh, $active); while ($mrc == CURLM_CALL_MULTI_PERFORM); // 14. finished curl_multi_close($mh); echo "==Dead URLs==\n"; echo implode("\n",$dead_urls) . "\n\n"; echo "==404 URLs==\n"; echo implode("\n",$not_found_urls) . "\n\n"; echo "==Working URLs==\n"; echo implode("\n",$working_urls); // 15. adds a url to the multi handle function add_url_to_multi_handle($mh, $url_list) static $index = 0; // if we have another url to get if ($url_list[$index]) // new curl handle $ch = curl_init(); // set the url curl_setopt($ch, CURLOPT_URL, $url_list[$index]); // to prevent the response from being outputted curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // follow redirections curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // do not need the body. this saves bandwidth and time curl_setopt($ch, CURLOPT_NOBODY, 1); // add it to the multi handle curl_multi_add_handle($mh, $ch); // increment so next url is used next time $index++; return true; else // we are done adding new URLs return false;
Iată explicația codului de mai sus. Numerele din listă corespund numerelor din comentariile codului.
Am rulat scriptul pe blogul meu (cu unele link-uri rupte adăugate în scop, pentru testare), și aici este cum arăta:
Au fost necesare doar mai puțin de 2 secunde pentru a trece prin aproximativ 40 de adrese URL. Câștigurile de performanță sunt semnificative atunci când se ocupă cu seturi chiar mai mari de adrese URL. Dacă deschideți zece conexiuni în același timp, poate dura până la zece ori mai rapid. De asemenea, puteți folosi doar caracterul non-blocant al mânerului multi-curl pentru a face solicitări de adrese URL fără a vă împiedica script-ul web.
Dacă există autentificare bazată pe HTTP pe o adresă URL, puteți folosi aceasta:
$ url = "http://www.somesite.com/members/"; $ ch = curl_init (); curl_setopt ($ ch, CURLOPT_URL, $ url); curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); // trimite numele de utilizator și parola curl_setopt ($ ch, CURLOPT_USERPWD, "myusername: mypassword"); // dacă permiteți redirecționări curl_setopt ($ ch, CURLOPT_FOLLOWLOCATION, 1); // aceasta permite cURL să păstreze în continuare numele de utilizator și parola // după ce a fost redirecționat curl_setopt ($ ch, CURLOPT_UNRESTRICTED_AUTH, 1); $ ieșire = curl_exec ($ ch); curl_close ($ ch);
PHP are o bibliotecă FTP, dar puteți utiliza și cURL:
// deschideți un fișier pointer $ file = fopen ("/ path / to / file", "r"); // URL-ul conține majoritatea informațiilor necesare $ url = "ftp: // username: [email protected]: 21 / path / to / new / file"; $ ch = curl_init (); curl_setopt ($ ch, CURLOPT_URL, $ url); curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); // încărcați opțiunile corespunzătoare curl_setopt ($ ch, CURLOPT_UPLOAD, 1); curl_setopt ($ ch, CURLOPT_INFILE, $ fp); curl_setopt ($ ch, CURLOPT_INFILESIZE, dimensiunea fișierului ("/ path / to / file")); // setat pentru modul ASCII (de ex. fișiere text) curl_setopt ($ ch, CURLOPT_FTPASCII, 1); $ ieșire = curl_exec ($ ch); curl_close ($ ch);
Puteți efectua solicitarea adresei URL printr-un proxy:
$ ch = curl_init (); curl_setopt ($ ch, CURLOPT_URL, 'http: //www.example.com'); curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); // setați adresa proxy pentru a utiliza curl_setopt ($ ch, CURLOPT_PROXY, '11 .11.11.11: 8080 '); // dacă proxy-ul necesită un nume de utilizator și o parolă curl_setopt ($ ch, CURLOPT_PROXYUSERPWD, 'user: pass'); $ ieșire = curl_exec ($ ch); curl_close ($ ch);
Este posibil să aveți funcții de apel invers apel cURL în timpul solicitării adresei URL, înainte de a fi terminat. De exemplu, deoarece conținutul răspunsului este descărcat, puteți începe să utilizați datele, fără a aștepta terminarea întregii descărcări.
$ ch = curl_init (); curl_setopt ($ ch, CURLOPT_URL, "http: //net.tutsplus.com"); curl_setopt ($ ch, CURLOPT_WRITEFUNCTION, "progress_function"); curl_exec ($ ch); curl_close ($ ch); funcția funcției progress_function ($ ch, $ str) echo $ str; retur strlen ($ str);
Funcția de apel invers TREBUIE să returneze lungimea șirului, care este o cerință pentru ca aceasta să funcționeze corect.
Odată ce răspunsul URL este preluat, de fiecare dată când este recepționat un pachet de date, este apelată funcția de apel invers.
Am explorat astăzi puterea și flexibilitatea bibliotecii cURL. Sper că v-ați bucurat și ați învățat din acest articol. Data viitoare când trebuie să faceți o solicitare de adresă URL în aplicația dvs. web, luați în considerare utilizarea cURL.
Multumesc si sa ai o zi buna!
Știați că puteți câștiga până la 600 USD pentru a scrie un tutorial PLUS și / sau pentru noi? Căutăm tutoriale detaliate și bine scrise despre HTML, CSS, PHP și JavaScript. Dacă sunteți în măsură, contactați Jeffrey la [email protected].
Rețineți că o compensație reală va depinde de calitatea tutorialului final și a scenariului.