Tecniche per padroneggiare cURL

cURL è uno strumento per il trasferimento di file e dati con la sintassi dell'URL, che supporta molti protocolli tra cui HTTP, FTP, TELNET e altro. Inizialmente, cURL è stato progettato per essere uno strumento da riga di comando. Fortunatamente per noi, la libreria cURL è supportata anche da PHP. In questo articolo, vedremo alcune delle funzionalità avanzate di cURL e come possiamo usarle nei nostri script PHP.

Perché cURL?

È vero che ci sono altri modi per recuperare il contenuto di una pagina web. Molte volte, principalmente a causa della pigrizia, ho appena usato semplici funzioni PHP invece di cURL:

 $ content = file_get_contents ("http://www.nettuts.com"); // o $ lines = file ("http://www.nettuts.com"); // o readfile ("http://www.nettuts.com");

Tuttavia, non hanno praticamente alcuna flessibilità e mancano di una gestione degli errori sufficiente. Inoltre, ci sono alcuni compiti che semplicemente non puoi fare, come trattare con i cookie, l'autenticazione, i messaggi di moduli, i caricamenti di file ecc.

cURL è una potente libreria che supporta molti protocolli, opzioni e fornisce informazioni dettagliate sulle richieste di URL.

Struttura basilare

Prima di passare a esempi più complicati, esaminiamo la struttura di base di una richiesta CURL in PHP. Ci sono quattro passaggi principali:

  1. Inizializzare
  2. Imposta opzioni
  3. Esegui e recupera risultato
  4. Liberare l'handle di cURL
 // 1. inizializza $ ch = curl_init (); // 2. imposta le opzioni, incluso l'url curl_setopt ($ ch, CURLOPT_URL, "http://www.nettuts.com"); curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt ($ ch, CURLOPT_HEADER, 0); // 3. esegue e recupera l'output HTML risultante $ output = curl_exec ($ ch); // 4. libera la maniglia del curl curl_close ($ ch);

Il passo 2 (cioè le chiamate a curl_setopt ()) sarà una parte importante di questo articolo, perché è lì che avviene tutta la magia. Esiste una lunga lista di opzioni cURL che possono essere impostate, che possono configurare la richiesta URL in dettaglio. Potrebbe essere difficile esaminare l'intera lista e digerirla tutto in una volta. Quindi oggi useremo solo alcune delle opzioni più comuni e utili in vari esempi di codice.

Controllo degli errori

Facoltativamente, puoi anche aggiungere il controllo degli errori:

 // ... $ output = curl_exec ($ ch); if ($ output === FALSE) echo "errore cURL:". curl_error ($ ch);  // ... 

Si noti che è necessario utilizzare "=== FALSE" per il confronto anziché "== FALSE". Perché è necessario distinguere tra output vuoto e valore booleano FALSE, che indica un errore.

Ottenere informazioni

Un altro passaggio facoltativo è ottenere informazioni sulla richiesta cURL, dopo che è stata eseguita.

 // ... curl_exec ($ ch); $ info = curl_getinfo ($ ch); echo "Took". $ info ['total_time']. "secondi per url". $ Info [ 'url']; // ... 

Le seguenti informazioni sono incluse nell'array restituito:

  • "Url"
  • "tipo di contenuto"
  • "HTTP_CODE"
  • "Header_size"
  • "Request_size"
  • "FILETIME"
  • "Ssl_verify_result"
  • "Redirect_count"
  • "tempo totale"
  • "Namelookup_time"
  • "Connect_time"
  • "Pretransfer_time"
  • "Size_upload"
  • "Size_download"
  • "Speed_download"
  • "Speed_upload"
  • "Download_content_length"
  • "Upload_content_length"
  • "Starttransfer_time"
  • "Redirect_time"

Rileva il reindirizzamento in base al browser

In questo primo esempio, scriveremo uno script in grado di rilevare i reindirizzamenti URL in base alle diverse impostazioni del browser. Ad esempio, alcuni siti Web reindirizzano i browser dei cellulari o anche i navigatori di paesi diversi.

Stiamo per utilizzare l'opzione CURLOPT_HTTPHEADER per impostare le nostre intestazioni HTTP in uscita, compresa la stringa dell'agente utente e le lingue accettate. Infine controlleremo se questi siti web stanno tentando di reindirizzare a URL diversi.

 // test URL $ urls = array ("http://www.cnn.com", "http://www.mozilla.com", "http://www.facebook.com"); // test browser $ browsers = array ("standard" => array ("user_agent" => "Mozilla / 5.0 (Windows; U; Windows NT 6.1; en-US; 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 come Mac OS X; en) AppleWebKit / 420 + (KHTML, come Gecko) Versione / 3.0 Mobile / 1A537a Safari / 419.3 "," lingua "=>" en ")," francese "=> array (" user_agent " => "Mozilla / 4.0 (compatibile; MSIE 7.0; Windows NT 5.1; GTB6; .NET CLR 2.0.50727)", "lingua" => "fr, fr-FR; q = 0.5")); foreach ($ urls as $ url) echo "URL: $ url \ n"; foreach ($ browser come $ test_name => $ browser) $ ch = curl_init (); // imposta url curl_setopt ($ ch, CURLOPT_URL, $ url); // imposta intestazioni specifiche del browser curl_setopt ($ ch, CURLOPT_HTTPHEADER, array ("User-Agent: $ browser ['user_agent']", "Accept-Language: $ browser ['language']")); // non vogliamo i contenuti della pagina curl_setopt ($ ch, CURLOPT_NOBODY, 1); // abbiamo bisogno dell'header HTTP restituito da curl_setopt ($ ch, CURLOPT_HEADER, 1); // restituisce i risultati invece di emetterli curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); $ output = curl_exec ($ ch); curl_close ($ ch); // c'era un'intestazione HTTP di reindirizzamento? if (preg_match ("! Location: (. *)!", $ output, $ corrisponde)) echo "$ test_name: reindirizza a $ matches [1] \ n";  else echo "$ test_name: nessun reindirizzamento \ n";  echo "\ n \ n"; 

Per prima cosa abbiamo una serie di URL da testare, seguita da una serie di impostazioni del browser per testare ciascuno di questi URL. Quindi passiamo in rassegna questi casi di test e facciamo una richiesta cURL per ciascuno.

A causa del modo in cui vengono impostate le opzioni cURL, l'output restituito conterrà solo le intestazioni HTTP (salvate in $ output). Con una semplice regex, possiamo vedere se c'era un'intestazione "Location:" inclusa.

Quando esegui questo script, dovresti ottenere un risultato come questo:

POSTING a un URL

Su una richiesta GET, i dati possono essere inviati a un URL tramite la "stringa di query". Ad esempio, quando esegui una ricerca su Google, il termine di ricerca si trova nella parte della stringa di query dell'URL:

http://www.google.com/search?q=nettuts

Potrebbe non essere necessario CURL per simulare questo in uno script web. Puoi semplicemente essere pigro e premere l'url con "file_get_contents ()" per ricevere i risultati.

Ma alcuni moduli HTML sono impostati sul metodo POST. Quando questi moduli vengono inviati tramite il browser, i dati vengono inviati tramite il corpo della richiesta HTTP, anziché dalla stringa di query. Ad esempio, se esegui una ricerca nei forum CodeIgniter, esegui il POST della query di ricerca per:

http://codeigniter.com/forums/do_search/

Possiamo scrivere uno script PHP per simulare questo tipo di richiesta URL. Per prima cosa creiamo un semplice file per accettare e visualizzare i dati POST. Chiamiamolo post_output.php:

 print_r ($ _ POST);

Quindi creiamo uno script PHP per eseguire una richiesta CURL:

 $ url = "http: //localhost/post_output.php"; $ post_data = array ("foo" => "bar", "query" => "Netsuts", "action" => "Submit"); $ ch = curl_init (); curl_setopt ($ ch, CURLOPT_URL, $ url); curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); // stiamo facendo una richiesta POST curl_setopt ($ ch, CURLOPT_POST, 1); // aggiungendo le variabili post alla richiesta curl_setopt ($ ch, CURLOPT_POSTFIELDS, $ post_data); $ output = curl_exec ($ ch); curl_close ($ ch); echo $ output;

Quando esegui questo script, dovresti ottenere un risultato come questo:

Ha inviato un post allo script post_output.php, che ha scaricato la variabile $ _POST e abbiamo catturato quell'output tramite cURL.

Upload di file

Il caricamento dei file funziona in modo molto simile all'esempio POST precedente, poiché tutti i moduli di caricamento dei file hanno il metodo POST.

Per prima cosa creiamo un file per ricevere la richiesta e chiamiamolo upload_output.php:

 print_r ($ _ FILES);

Ed ecco lo script che esegue il caricamento del file:

 $ url = "http: //localhost/upload_output.php"; $ post_data = array ("foo" => "bar", // file da caricare "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;

Quando vuoi caricare un file, tutto quello che devi fare è passare il suo percorso file proprio come una variabile post, e mettere il simbolo @ davanti ad esso. Ora quando esegui questo script dovresti ottenere un output come questo:

Multi cURL

Una delle funzionalità più avanzate di cURL è la possibilità di creare un handle "multi" cURL. Ciò consente di aprire connessioni a più URL contemporaneamente e in modo asincrono.

Su una richiesta CURL regolare, l'esecuzione dello script si interrompe e attende la fine della richiesta URL prima che possa continuare. Se intendi colpire più URL, questo può richiedere molto tempo, poiché puoi richiedere solo un URL alla volta. Possiamo superare questa limitazione usando il multi handle.

Diamo un'occhiata a questo codice di esempio da php.net:

 // crea entrambe le risorse cURL $ ch1 = curl_init (); $ ch2 = curl_init (); // imposta URL e altre opzioni appropriate 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); // crea l'handle di cURL multiple $ mh = curl_multi_init (); // aggiungi i due handle curl_multi_add_handle ($ mh, $ ch1); curl_multi_add_handle ($ mh, $ CH2); $ attivo = null; // esegue gli handle do $ 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);  // chiudi le maniglie curl_multi_remove_handle ($ mh, $ ch1); curl_multi_remove_handle ($ mh, $ ch2); curl_multi_close ($ mh);

L'idea è che puoi aprire più maniglie di cURL e assegnarle a un unico multi handle. Quindi puoi aspettare che finiscano di eseguire mentre si è in loop.

Ci sono due anelli principali in questo esempio. Il primo ciclo di do-while chiama ripetutamente curl_multi_exec (). Questa funzione è non bloccante. Esegue il minor numero possibile e restituisce un valore di stato. Finché il valore restituito è la costante "CURLM_CALL_MULTI_PERFORM", significa che c'è ancora un lavoro più immediato da fare (ad esempio, l'invio di intestazioni HTTP agli URL). Ecco perché continuiamo a chiamarlo finché il valore restituito è un'altra cosa.

Nel ciclo while successivo, continuiamo finché la variabile $ $ è 'true'. Questo è stato passato come secondo argomento della chiamata a curl_multi_exec (). È impostato su "true" finché ci sono connessioni attive con il multi handle. La prossima cosa da fare è chiamare curl_multi_select (). Questa funzione è 'bloccante' fino a quando non vi è alcuna attività di connessione, come ricevere una risposta. Quando ciò accade, entriamo in un altro ciclo do-while per continuare l'esecuzione.

Vediamo se possiamo creare noi stessi un esempio funzionante, che ha uno scopo pratico.

Link Checker di Wordpress

Immagina un blog con molti post contenenti collegamenti a siti Web esterni. Alcuni di questi link potrebbero finire morti dopo un po 'per vari motivi. Forse la pagina è più lunga lì, o l'intero sito web è sparito.

Stiamo costruendo uno script che analizza tutti i link e trova siti Web non caricati e 404 pagine e ci restituisce un rapporto.

Si noti che questo non sarà un vero plug-in di Wordpress. È solo uno script di utilità standalone ed è solo a scopo dimostrativo.

Quindi iniziamo. Per prima cosa dobbiamo recuperare i link dal database:

 // CONFIG $ db_host = 'localhost'; $ db_user = 'root'; $ db_pass = "; $ db_name = 'wordpress'; $ escluso_domains = array ('localhost', 'www.mydomain.com'); $ max_connections = 10; // inizializza alcune variabili $ url_list = array (); $ working_urls = array (); $ dead_urls = array (); $ not_found_urls = array (); $ active = null; // si connette a MySQL if (! mysql_connect ($ db_host, $ db_user, $ db_pass)) die ('Impossibile connettersi : '. mysql_error ()); if (! mysql_select_db ($ db_name)) die (' Impossibile selezionare db: '. mysql_error ()); // ottiene tutti i post pubblicati che hanno collegamenti $ q = "SELECT post_content FROM wp_posts WHERE post_content LIKE '% href =%' AND post_status = 'pubblica' AND post_type = 'post' "; $ r = mysql_query ($ q) o muore (mysql_error ()); while ($ d = mysql_fetch_assoc ($ r )) // ottieni tutti i collegamenti tramite regex se (preg_match_all ("! href = \" (. *?) \ "!", $ d ['post_content'], $ corrisponde)) foreach ($ matches [1] come $ url) // esclude alcuni domini $ tmp = parse_url ($ url); if (in_array ($ tmp ['host'], $ excluded_domains)) continua; // memorizza l'url $ url_list [] = $ url; // re sposta i duplicati $ url_list = array_values ​​(array_unique ($ url_list)); if (! $ url_list) die ('Nessun URL da verificare'); 

Per prima cosa abbiamo una configurazione del database, seguita da una serie di nomi di dominio che ignoreremo ($ excluded_domains). Inoltre impostiamo un numero per le connessioni simultanee massime che useremo in seguito ($ max_connections). Quindi ci colleghiamo al database, recuperiamo i post che contengono collegamenti e li raccogliamo in un array ($ url_list).

Seguire il codice potrebbe essere un po 'complesso, quindi cercherò di spiegarlo a piccoli passi.

 // 1. multi handle $ mh = curl_multi_init (); // 2. aggiungi più URL al multi handle per ($ 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;  

Ed ecco la spiegazione per il codice sopra. I numeri nell'elenco corrispondono ai numeri nei commenti del codice.

  1. Creato un multi-handle.
  2. Creeremo la funzione add_url_to_multi_handle () in seguito. Ogni volta che viene chiamato, aggiungerà un url al multi handle. Inizialmente, aggiungiamo 10 (in base a $ max_connections) URL al multi handle.
  3. Dobbiamo eseguire curl_multi_exec () per il lavoro iniziale. Finché restituisce CURLM_CALL_MULTI_PERFORM, c'è del lavoro da fare. Questo è principalmente per creare le connessioni. Non aspetta la risposta completa all'URL.
  4. Questo ciclo principale viene eseguito fintantoché vi è una certa attività nell'impugnatura multipla.
  5. curl_multi_select () attende lo script fino a quando non si verifica un'attività con una delle ricerche di URL.
  6. Ancora una volta dobbiamo lasciare che cURL faccia del lavoro, principalmente per recuperare i dati di risposta.
  7. Controlliamo per informazioni. C'è una matrice restituita se una richiesta URL è stata completata.
  8. C'è un handle cURL nell'array restituito. Lo usiamo per recuperare informazioni sulla singola richiesta cURL.
  9. Se il link era morto o scaduto, non ci sarà alcun codice http.
  10. Se il link era una pagina 404, il codice http sarà impostato su 404.
  11. Altrimenti supponiamo che fosse un collegamento funzionante. (Puoi aggiungere ulteriori controlli per 500 codici di errore ecc ...)
  12. Rimuoviamo l'handle cURL dal multi handle poiché non è più necessario e lo chiudiamo.
  13. Ora possiamo aggiungere un altro url al multi handle, e di nuovo fare il lavoro iniziale prima di proseguire.
  14. Tutto è finito. Possiamo chiudere il multi handle e stampare un report.
  15. Questa è la funzione che aggiunge un nuovo URL al multi handle. La variabile statica $ index viene incrementata ogni volta che viene chiamata questa funzione, così possiamo tenere traccia di dove abbiamo lasciato.

Ho eseguito la sceneggiatura sul mio blog (con alcuni collegamenti interrotti aggiunti di proposito, per test), ed ecco come appariva:

Sono bastati meno di 2 secondi per esaminare circa 40 URL. I guadagni in termini di prestazioni sono significativi quando si gestiscono insiemi di URL ancora più grandi. Se apri dieci connessioni allo stesso tempo, puoi eseguire fino a dieci volte più velocemente. Inoltre puoi semplicemente utilizzare la natura non bloccante dell'handle multi curl per eseguire richieste URL senza arrestare lo script web.

Alcune altre opzioni cURL utili

Autenticazione HTTP

Se c'è un'autenticazione basata su HTTP su un URL, puoi usare questo:

 $ url = "http://www.somesite.com/members/"; $ ch = curl_init (); curl_setopt ($ ch, CURLOPT_URL, $ url); curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); // invia nome utente e password curl_setopt ($ ch, CURLOPT_USERPWD, "myusername: mypassword"); // se permetti i reindirizzamenti curl_setopt ($ ch, CURLOPT_FOLLOWLOCATION, 1); // questo consente a cURL di continuare a inviare nome utente e password // dopo essere stato reindirizzato a curl_setopt ($ ch, CURLOPT_UNRESTRICTED_AUTH, 1); $ output = curl_exec ($ ch); curl_close ($ ch);

Upload FTP

PHP ha una libreria FTP, ma puoi anche usare cURL:

 // apre un puntatore file $ file = fopen ("/ percorso / su / file", "r"); // l'url contiene la maggior parte delle informazioni necessarie $ 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); // carica le opzioni correlate curl_setopt ($ ch, CURLOPT_UPLOAD, 1); curl_setopt ($ ch, CURLOPT_INFILE, $ fp); curl_setopt ($ ch, CURLOPT_INFILESIZE, filesize ("/ percorso / a / file")); // imposta la modalità ASCII (ad es. file di testo) curl_setopt ($ ch, CURLOPT_FTPASCII, 1); $ output = curl_exec ($ ch); curl_close ($ ch);

Utilizzo di un proxy

Puoi eseguire la tua richiesta di URL tramite un proxy:

 $ ch = curl_init (); curl_setopt ($ ch, CURLOPT_URL, 'http: //www.example.com'); curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); // imposta l'indirizzo proxy per usare curl_setopt ($ ch, CURLOPT_PROXY, '11 .11.11.11: 8080 '); // se il proxy richiede un nome utente e una password curl_setopt ($ ch, CURLOPT_PROXYUSERPWD, 'user: pass'); $ output = curl_exec ($ ch); curl_close ($ ch);

Funzioni di callback

È possibile avere chiamate cURL fornite funzioni di callback durante la richiesta URL, prima che sia terminata. Ad esempio, mentre viene scaricato il contenuto della risposta, è possibile iniziare a utilizzare i dati, senza attendere il completamento dell'intero download.

 $ 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); 

La funzione di callback DEVE restituire la lunghezza della stringa, che è un requisito che funzioni correttamente.

Poiché la risposta URL viene recuperata, ogni volta che viene ricevuto un pacchetto di dati, viene richiamata la funzione di callback.

Conclusione

Oggi abbiamo esplorato la potenza e la flessibilità della biblioteca di cURL. Spero vi sia piaciuto e imparato da questo articolo. La prossima volta che devi fare una richiesta URL nella tua applicazione web, considera l'utilizzo di cURL.

Grazie e buona giornata!

Scrivi un tutorial Plus

Sapevi che puoi guadagnare fino a $ 600 per scrivere un tutorial PLUS e / o screencast per noi? Stiamo cercando tutorial dettagliati e ben scritti su HTML, CSS, PHP e JavaScript. Se sei dell'abilità, contatta Jeffrey a [email protected].

Si prega di notare che il risarcimento effettivo dipenderà dalla qualità del tutorial finale e screencast.

  • Seguici su Twitter o iscriviti al feed Nettuts + RSS per i migliori tutorial di sviluppo web sul web.