cURL is een hulpmiddel voor het overbrengen van bestanden en gegevens met URL-syntaxis en ondersteunt vele protocollen, waaronder HTTP, FTP, TELNET en meer. Aanvankelijk was cURL ontworpen als een hulpmiddel voor de opdrachtregel. Gelukkig voor ons, de cURL-bibliotheek wordt ook ondersteund door PHP. In dit artikel zullen we kijken naar enkele van de geavanceerde functies van cURL en hoe we ze kunnen gebruiken in onze PHP-scripts.
Het klopt dat er andere manieren zijn om de inhoud van een webpagina op te halen. Vele malen, voornamelijk vanwege luiheid, heb ik zojuist eenvoudige PHP-functies gebruikt in plaats van CURL:
$ content = file_get_contents ("http://www.nettuts.com"); // of $ lines = bestand ("http://www.nettuts.com"); // of readfile ("http://www.nettuts.com");
Ze hebben echter vrijwel geen flexibiliteit en missen voldoende foutafhandeling. Er zijn ook bepaalde taken die je simpelweg niet kunt doen, zoals omgaan met cookies, authenticatie, formulierberichten, bestandsuploads enz.
cURL is een krachtige bibliotheek die vele verschillende protocollen en opties ondersteunt en die gedetailleerde informatie biedt over de URL-verzoeken.
Voordat we verder gaan met meer gecompliceerde voorbeelden, laten we de basisstructuur van een cURL-verzoek in PHP bekijken. Er zijn vier hoofdstappen:
// 1. initialiseer $ ch = curl_init (); // 2. stel de opties in, inclusief de URL curl_setopt ($ ch, CURLOPT_URL, "http://www.nettuts.com"); curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt ($ ch, CURLOPT_HEADER, 0); // 3. voer de resulterende HTML-uitvoer uit en haal deze op $ output = curl_exec ($ ch); // 4. maak de krulhendel vrij curl_close ($ ch);
Stap # 2 (dat wil zeggen curl_setopt () aanroepen) wordt een groot deel van dit artikel, omdat dat is waar alle magie gebeurt. Er is een lange lijst met cURL-opties die kunnen worden ingesteld, waarmee het URL-verzoek in detail kan worden geconfigureerd. Het is misschien moeilijk om de hele lijst door te nemen en alles tegelijk te verwerken. Dus vandaag gaan we enkele van de meer gebruikelijke en nuttige opties gebruiken in verschillende codevoorbeelden.
Optioneel kunt u ook foutcontrole toevoegen:
// ... $ output = curl_exec ($ ch); if ($ output === FALSE) echo "cURL Error:". curl_error ($ ch); // ...
Let op: we moeten "=== FALSE" gebruiken ter vergelijking in plaats van "== FALSE". Omdat we onderscheid moeten maken tussen lege uitvoer en de Booleaanse waarde ONWAAR, die een fout aangeeft.
Een andere optionele stap is om informatie te krijgen over de cURL-aanvraag, nadat deze is uitgevoerd.
// ... curl_exec ($ ch); $ info = curl_getinfo ($ ch); echo 'nam'. $ info ['total_time']. 'seconden voor url'. $ Info [ 'url']; // ...
De volgende informatie is opgenomen in de geretourneerde array:
In dit eerste voorbeeld zullen we een script schrijven dat URL-omleidingen detecteert op basis van verschillende browserinstellingen. Sommige websites verwijzen bijvoorbeeld naar browsers van mobiele telefoons of zelfs naar surfers uit verschillende landen.
We gaan de optie CURLOPT_HTTPHEADER gebruiken om onze uitgaande HTTP-headers in te stellen, inclusief de user-agentstring en de geaccepteerde talen. Ten slotte zullen we controleren of deze websites ons proberen om te leiden naar verschillende URL's.
// test-URL's $ urls = array ("http://www.cnn.com", "http://www.mozilla.com", "http://www.facebook.com"); // testbrowsers $ browsers = array ("standaard" => array ("user_agent" => "Mozilla / 5.0 (Windows; U; Windows NT 6.1; nl-VS; rv: 1.9.1.6) Gecko / 20091201 Firefox / 3.5 .6 (.NET CLR 3.5.30729) "," language "=>" en-us, en; q = 0.5 ")," iphone "=> array (" user_agent "=>" Mozilla / 5.0 (iPhone; U ; CPU zoals Mac OS X; en) AppleWebKit / 420 + (KHTML, zoals Gecko) Versie / 3.0 Mobile / 1A537a Safari / 419.3 "," taal "=>" en ")," french "=> array (" user_agent " => "Mozilla / 4.0 (compatibel; MSIE 7.0; Windows NT 5.1; GTB6; .NET CLR 2.0.50727)", "taal" => "fr, fr-FR; q = 0.5")); foreach ($ urls als $ url) echo "URL: $ url \ n"; foreach ($ browsers als $ test_name => $ browser) $ ch = curl_init (); // set url curl_setopt ($ ch, CURLOPT_URL, $ url); // stel browser-specifieke headers in curl_setopt ($ ch, CURLOPT_HTTPHEADER, array ("User-Agent: $ browser ['user_agent']", "Accept-Language: $ browser ['taal']")); // we willen niet dat de pagina-inhoud curl_setopt ($ ch, CURLOPT_NOBODY, 1); // we hebben de HTTP Header geretourneerd curl_setopt ($ ch, CURLOPT_HEADER, 1) nodig; // de resultaten retourneren in plaats van deze af te geven curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); $ output = curl_exec ($ ch); curl_close ($ ch); // was er een redirectie HTTP-header? if (preg_match ("! Location: (. *)!", $ output, $ matches)) echo "$ test_name: verwijst naar $ overeenkomsten [1] \ n"; else echo "$ test_name: no redirection \ n"; echo "\ n \ n";
Eerst moeten we een reeks URL's testen, gevolgd door een reeks browserinstellingen om elk van deze URL's te testen. Vervolgens doorlopen we deze testcases en maken een cURL-verzoek voor elk.
Vanwege de manier waarop de cURL-opties worden ingesteld, bevat de geretourneerde uitvoer alleen de HTTP-headers (opgeslagen in $ uitvoer). Met een eenvoudige regex kunnen we zien of er een "Locatie:" header was opgenomen.
Wanneer u dit script uitvoert, zou u een dergelijke uitvoer moeten krijgen:
Op een GET-verzoek kunnen gegevens via de "queryreeks" naar een URL worden verzonden. Wanneer u bijvoorbeeld op Google zoekt, bevindt de zoekterm zich in het gedeelte met de queryreeks van de URL:
http://www.google.com/search?q=nettuts
Mogelijk hebt u CURL niet nodig om dit in een webscript te simuleren. Je kunt gewoon lui zijn en die URL raken met "file_get_contents ()" om de resultaten te ontvangen.
Maar sommige HTML-formulieren zijn ingesteld op de POST-methode. Wanneer deze formulieren via de browser worden verzonden, worden de gegevens verzonden via de instantie van het HTTP-verzoek in plaats van de queryreeks. Als u bijvoorbeeld een zoekopdracht uitvoert op de CodeIgniter-forums, POST u uw zoekopdracht naar:
http://codeigniter.com/forums/do_search/
We kunnen een PHP-script schrijven om dit soort URL-verzoeken te simuleren. Laten we eerst een eenvoudig bestand maken voor het accepteren en weergeven van de POST-gegevens. Laten we het post_output.php noemen:
print_r ($ _ POST);
Vervolgens maken we een PHP-script om een cURL-verzoek uit te voeren:
$ url = "http: //localhost/post_output.php"; $ post_data = array ("foo" => "bar", "query" => "Nettuts", "action" => "Submit"); $ ch = curl_init (); curl_setopt ($ ch, CURLOPT_URL, $ url); curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); // we doen een POST-aanvraag curl_setopt ($ ch, CURLOPT_POST, 1); // de postvariabelen toevoegen aan het verzoek curl_setopt ($ ch, CURLOPT_POSTFIELDS, $ post_data); $ output = curl_exec ($ ch); curl_close ($ ch); echo $ output;
Wanneer u dit script uitvoert, zou u een dergelijke uitvoer moeten krijgen:
Het stuurde een POST naar het script post_output.php, dat de variabele $ _POST heeft gedumpt en we hebben die uitvoer vastgelegd via cURL.
Het uploaden van bestanden werkt op dezelfde manier als het vorige POST-voorbeeld, omdat alle bestandsuploads de POST-methode hebben.
Laten we eerst een bestand maken voor het ontvangen van het verzoek en dit uploaden upload_output.php:
print_r ($ _ FILES);
En hier is het daadwerkelijke script dat de bestandsupload uitvoert:
$ url = "http: //localhost/upload_output.php"; $ post_data = array ("foo" => "bar", // bestand om te uploaden "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); $ output = curl_exec ($ ch); curl_close ($ ch); echo $ output;
Wanneer u een bestand wilt uploaden, hoeft u alleen het bestandspad door te geven, net als een postvariabele, en plaatst u het @ -symbool ervoor. Wanneer je dit script uitvoert, zou je een uitvoer zoals deze moeten krijgen:
Een van de meer geavanceerde functies van cURL is de mogelijkheid om een "multi" cURL-greep te maken. Hiermee kunt u tegelijkertijd en asynchroon verbindingen met meerdere URL's openen.
Bij een normale cURL-aanvraag stopt de uitvoering van het script en wacht het totdat het URL-verzoek wordt voltooid voordat het kan doorgaan. Als u van plan bent meerdere URL's te raken, kan dit lang duren, omdat u slechts één URL tegelijk kunt aanvragen. We kunnen deze beperking overwinnen door de multi-hendel te gebruiken.
Laten we eens kijken naar deze voorbeeldcode van php.net:
// maak beide cURL-bronnen $ ch1 = curl_init (); $ ch2 = curl_init (); // stel URL en andere geschikte opties in 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); // maak de meerdere cURL-handle $ mh = curl_multi_init (); // voeg de twee handvatten toe curl_multi_add_handle ($ mh, $ ch1); curl_multi_add_handle ($ mh, $ CH2); $ active = null; / / voer de handvatten uit doe $ mrc = curl_multi_exec ($ mh, $ active); while ($ mrc == CURLM_CALL_MULTI_PERFORM); while ($ active && $ mrc == CURLM_OK) if (curl_multi_select ($ mh)! = -1) do $ mrc = curl_multi_exec ($ mh, $ active); while ($ mrc == CURLM_CALL_MULTI_PERFORM); // sluit de handvatten curl_multi_remove_handle ($ mh, $ ch1); curl_multi_remove_handle ($ mh, $ ch2); curl_multi_close ($ mh);
Het idee is dat u meerdere cURL-handles kunt openen en ze aan één multigreep kunt toewijzen. Dan kunt u wachten tot ze klaar zijn met het uitvoeren in een lus.
Er zijn twee hoofdlussen in dit voorbeeld. De eerste do-while-lus roept herhaaldelijk curl_multi_exec () aan. Deze functie is niet-blokkerend. Het wordt zo weinig mogelijk uitgevoerd en retourneert een statuswaarde. Zolang de geretourneerde waarde de constante 'CURLM_CALL_MULTI_PERFORM' is, betekent dit dat er nog meer direct werk moet worden uitgevoerd (bijvoorbeeld http-headers naar de URL's sturen.) Daarom blijven we het bellen totdat de retourwaarde iets anders is.
In de volgende while-lus gaan we door zolang de $ actieve variabele 'waar' is. Dit werd doorgegeven als het tweede argument voor de aanroep curl_multi_exec (). Het is ingesteld op 'true' zolang er actieve verbindingen zijn met de multi-handle. Het volgende dat we doen is om curl_multi_select () aan te roepen. Deze functie blokkeert totdat er enige verbindingsactiviteit is, zoals het ontvangen van een antwoord. Wanneer dat gebeurt, gaan we naar nog een andere do-while-lus om door te gaan met het uitvoeren.
Laten we eens kijken of we zelf een werkend voorbeeld kunnen maken, dat een praktisch doel heeft.
Stel je een blog voor met veel berichten met links naar externe websites. Sommige van deze links kunnen om verschillende redenen na een tijdje dood zijn. Misschien is de pagina langer, of is de hele website verdwenen.
We gaan een script maken dat alle links analyseert en niet-ladende websites en 404 pagina's vindt en een rapport aan ons retourneert.
Merk op dat dit geen echte WordPress plug-in zal zijn. Het is slechts een zelfstandig hulpprogramma-script en het is alleen voor demonstratiedoeleinden.
Dus laten we beginnen. Eerst moeten we de links uit de database ophalen:
// CONFIG $ db_host = 'localhost'; $ db_user = 'root'; $ db_pass = "; $ db_name = 'wordpress'; $ excluded_domains = array ('localhost', 'www.mydomain.com'); $ max_connections = 10; // initialiseer een aantal variabelen $ url_list = array (); $ work_urls = array (); $ dead_urls = array (); $ not_found_urls = array (); $ active = null; // verbinding maken met MySQL if (! mysql_connect ($ db_host, $ db_user, $ db_pass)) die ('Kon geen verbinding maken : '. mysql_error ()); if (! mysql_select_db ($ db_name)) die (' Could not select db: '. mysql_error ()); // krijg alle gepubliceerde berichten met links $ q = "SELECT post_content FROM wp_posts WHERE post_content LIKE '% href =%' AND post_status = 'publish' AND post_type = 'post' "; $ r = mysql_query ($ q) of die (mysql_error ()); while ($ d = mysql_fetch_assoc ($ r )) // ontvang alle links via regex if (preg_match_all ("! href = \" (. *?) \ "!", $ d ['post_content'], $ matches)) foreach ($ matches [1] als $ url) // sluit sommige domeinen uit $ tmp = parse_url ($ url); if (in_array ($ tmp ['host'], $ excluded_domains)) continue; // sla de URL op $ url_list [] = $ url; // re verplaats duplicaten $ url_list = array_values (array_unique ($ url_list)); if (! $ url_list) die ('Geen URL om te controleren');
Eerst hebben we wat databaseconfiguratie, gevolgd door een reeks domeinnamen die we zullen negeren ($ excluded_domains). We stellen ook een nummer in voor maximale gelijktijdige verbindingen die we later zullen gebruiken ($ max_connections). Vervolgens maken we verbinding met de database, halen we berichten op die koppelingen bevatten en verzamelen ze in een array ($ url_list).
De volgende code kan een beetje ingewikkeld zijn, dus ik zal het in kleine stapjes proberen uit te leggen.
// 1. multi-handle $ mh = curl_multi_init (); // 2. voeg meerdere URL's toe aan de multi-handle voor ($ 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;
En hier is de verklaring voor de bovenstaande code. Nummers in de lijst komen overeen met de cijfers in de opmerkingen bij de code.
Ik heb het script op mijn blog uitgevoerd (met enkele kapotte links die expres zijn toegevoegd, om te testen) en hier is hoe het eruit zag:
Het duurde slechts minder dan 2 seconden om ongeveer 40 URL's door te nemen. De prestatiewinst is aanzienlijk als het gaat om nog grotere reeksen URL's. Als u tegelijkertijd tien verbindingen opent, kan deze tot tien keer sneller lopen. U kunt ook gewoon het niet-blokkerende karakter van de multi-curl-ingang gebruiken om URL-verzoeken te doen zonder uw webscript te blokkeren.
Als er HTTP-gebaseerde verificatie op een URL is, kunt u dit gebruiken:
$ url = "http://www.somesite.com/members/"; $ ch = curl_init (); curl_setopt ($ ch, CURLOPT_URL, $ url); curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); // stuur de gebruikersnaam en het wachtwoord curl_setopt ($ ch, CURLOPT_USERPWD, "myusername: mypassword"); // als u omleidingen curl_setopt ($ ch, CURLOPT_FOLLOWLOCATION, 1) toestaat; // hierdoor kan cURL de gebruikersnaam en het wachtwoord blijven verzenden // na omgeleide curl_setopt ($ ch, CURLOPT_UNRESTRICTED_AUTH, 1); $ output = curl_exec ($ ch); curl_close ($ ch);
PHP heeft wel een FTP-bibliotheek, maar je kunt ook cURL gebruiken:
// open een bestandsaanwijzer $ file = fopen ("/ path / to / file", "r"); // de URL bevat de meeste benodigde info $ url = "ftp: // gebruikersnaam: [email protected]: 21 / pad / naar / nieuw / bestand"; $ ch = curl_init (); curl_setopt ($ ch, CURLOPT_URL, $ url); curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); // upload gerelateerde opties curl_setopt ($ ch, CURLOPT_UPLOAD, 1); curl_setopt ($ ch, CURLOPT_INFILE, $ fp); curl_setopt ($ ch, CURLOPT_INFILESIZE, bestandsgrootte ("/ path / to / file")); // set voor ASCII-modus (bijvoorbeeld tekstbestanden) curl_setopt ($ ch, CURLOPT_FTPASCII, 1); $ output = curl_exec ($ ch); curl_close ($ ch);
U kunt uw URL-aanvraag uitvoeren via een proxy:
$ ch = curl_init (); curl_setopt ($ ch, CURLOPT_URL, 'http: //www.example.com'); curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); // stel het proxy-adres in om curl_setopt ($ ch, CURLOPT_PROXY, '11 .11.11.11: 8080 ') te gebruiken; // als de proxy een gebruikersnaam en wachtwoord vereist curl_setopt ($ ch, CURLOPT_PROXYUSERPWD, 'user: pass'); $ output = curl_exec ($ ch); curl_close ($ ch);
Het is mogelijk om de cURL-call de callback-functies te geven tijdens de URL-aanvraag, voordat deze is voltooid. Als de inhoud van het antwoord bijvoorbeeld wordt gedownload, kunt u beginnen met het gebruik van de gegevens, zonder te wachten tot de hele download is voltooid.
$ 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); function progress_function ($ ch, $ str) echo $ str; return strlen ($ str);
De callback-functie MOET de lengte van de string retourneren, wat een vereiste is om dit goed te laten werken.
Terwijl het URL-antwoord wordt opgehaald, wordt elke keer dat een gegevenspakket wordt ontvangen de callback-functie opgeroepen.
We hebben vandaag de kracht en de flexibiliteit van de cURL-bibliotheek verkend. Ik hoop dat je het leuk vond en geleerd van dit artikel. Probeer de volgende keer dat u een URL-aanvraag in uw webtoepassing moet doen, cURL.
Dank je en heb een fijne dag!
Wist je dat je tot $ 600 kunt verdienen voor het schrijven van een PLUS tutorial en / of screencast voor ons?? We zijn op zoek naar diepgaande en goed geschreven tutorials over HTML, CSS, PHP en JavaScript. Als je van het vermogen bent, neem dan contact op met Jeffrey via [email protected].
Houd er rekening mee dat de daadwerkelijke compensatie afhankelijk is van de kwaliteit van de laatste zelfstudie en screencast.