cURL est un outil de transfert de fichiers et de données avec la syntaxe URL, prenant en charge de nombreux protocoles, notamment HTTP, FTP, TELNET, etc. Initialement, cURL a été conçu pour être un outil de ligne de commande. Heureusement pour nous, la bibliothèque cURL est également supportée par PHP. Dans cet article, nous allons examiner certaines des fonctionnalités avancées de cURL et voir comment nous pouvons les utiliser dans nos scripts PHP..
Il est vrai qu'il existe d'autres moyens de récupérer le contenu d'une page Web. Plusieurs fois, principalement à cause de la paresse, je viens d'utiliser des fonctions PHP simples au lieu de cURL:
$ content = file_get_contents ("http://www.nettuts.com"); // ou $ lines = file ("http://www.nettuts.com"); // ou readfile ("http://www.nettuts.com");
Cependant, ils n'ont pratiquement aucune flexibilité et manquent d'une gestion des erreurs suffisante. En outre, il y a certaines tâches que vous ne pouvez tout simplement pas faire, comme traiter avec les cookies, l'authentification, les publications de formulaires, les téléchargements de fichiers, etc..
cURL est une bibliothèque puissante qui prend en charge de nombreux protocoles et options différents et fournit des informations détaillées sur les requêtes d'URL..
Avant de passer à des exemples plus complexes, examinons la structure de base d’une requête cURL en PHP. Il y a quatre étapes principales:
// 1. initialise $ ch = curl_init (); // 2. définit les options, y compris l'url curl_setopt ($ ch, CURLOPT_URL, "http://www.nettuts.com"); curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt ($ ch, CURLOPT_HEADER, 0); // 3. exécute et récupère la sortie HTML résultante $ output = curl_exec ($ ch); // 4. libère le curl curl_close ($ ch);
L'étape 2 (par exemple, les appels curl_setopt ()) constituera une partie importante de cet article, car c'est là que toute la magie se produit. Il existe une longue liste d'options cURL pouvant être définies, permettant de configurer la demande d'URL en détail. Il peut être difficile de parcourir toute la liste et de la digérer en une seule fois. Donc, aujourd’hui, nous allons simplement utiliser certaines des options les plus courantes et les plus utiles dans divers exemples de code..
Facultativement, vous pouvez également ajouter une vérification d'erreur:
//… $ output = curl_exec ($ ch); if ($ output === FALSE) echo "Erreur cURL:". curl_error ($ ch); //…
Veuillez noter que nous devons utiliser "=== FAUX" pour la comparaison au lieu de "== FAUX". Parce qu'il faut distinguer la sortie vide de la valeur booléenne FALSE, ce qui indique une erreur.
Une autre étape optionnelle consiste à obtenir des informations sur la requête cURL après son exécution..
//… curl_exec ($ ch); $ info = curl_getinfo ($ ch); echo 'a pris'. $ info ['total_time']. 'secondes pour url'. $ info ['url']; //…
Les informations suivantes sont incluses dans le tableau renvoyé:
Dans ce premier exemple, nous allons écrire un script capable de détecter les redirections d’URL basées sur différents paramètres du navigateur. Par exemple, certains sites Web redirigent les navigateurs de téléphones portables, voire les internautes de différents pays..
Nous allons utiliser l'option CURLOPT_HTTPHEADER pour définir nos en-têtes HTTP sortants, y compris la chaîne de l'agent d'utilisateur et les langues acceptées. Enfin, nous vérifierons si ces sites Web essaient de nous rediriger vers des URL différentes..
// URL de test $ urls = array ("http://www.cnn.com", "http://www.mozilla.com", "http://www.facebook.com"); // test des navigateurs $ browsers = array ("standard" => array ("user_agent" => "Mozilla / 5.0 (Windows; U; Windows NT 6.1; en-US; version: 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 comme Mac OS X; en) AppleWebKit / 420 + (KHTML comme Gecko) Version / 3.0 Mobile / 1A537a Safari / 419.3 "," language "=>" en ")," français "=> array (" utilisateur_agent " => "Mozilla / 4.0 (compatible; MSIE 7.0; Windows NT 5.1; GTB6; .NET CLR 2.0.50727)", "langage" => "fr, fr-FR; q = 0,5")); foreach ($ urls as $ url) echo "URL: $ url \ n"; foreach ($ navigateurs en tant que $ test_name => $ browser) $ ch = curl_init (); // set url curl_setopt ($ ch, CURLOPT_URL, $ url); // définit des en-têtes spécifiques au navigateur curl_setopt ($ ch, CURLOPT_HTTPHEADER, array ("Agent utilisateur: $ browser ['user_agent']"), "Accept-Language: $ browser ['language']")); // nous ne voulons pas du contenu de la page curl_setopt ($ ch, CURLOPT_NOBODY, 1); // nous avons besoin de l'en-tête HTTP renvoyé curl_setopt ($ ch, CURLOPT_HEADER, 1); // retourne les résultats au lieu de les sortir curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); $ output = curl_exec ($ ch); curl_close ($ ch); // y avait-il un en-tête HTTP de redirection? if (preg_match ("! Emplacement: (. *)!", $ sortie, $ correspond)) echo "$ nom_test: redirige vers $ correspond [1] \ n"; else echo "$ nom_test: pas de redirection \ n"; echo "\ n \ n";
Nous avons d’abord un ensemble d’URL à tester, suivi d’un ensemble de paramètres de navigateur pour tester chacune de ces URL. Ensuite, nous parcourons ces cas de test et faisons une requête cURL pour chaque.
En raison de la manière dont les options cURL sont configurées, la sortie renvoyée ne contiendra que les en-têtes HTTP (enregistrés dans $ output). Avec une regex simple, nous pouvons voir s'il y avait un en-tête "Location:" inclus.
Lorsque vous exécutez ce script, vous devriez obtenir une sortie comme celle-ci:
Sur une requête GET, les données peuvent être envoyées à une URL via la "chaîne de requête". Par exemple, lorsque vous effectuez une recherche sur Google, le terme de recherche se trouve dans la partie chaîne de requête de l'URL:
http://www.google.com/search?q=nettuts
Vous n’avez peut-être pas besoin de cURL pour simuler cela dans un script Web. Vous pouvez simplement être paresseux et cliquer sur cette URL avec "file_get_contents ()" pour recevoir les résultats..
Mais certains formulaires HTML sont définis sur la méthode POST. Lorsque ces formulaires sont soumis via le navigateur, les données sont envoyées via le corps de la requête HTTP, plutôt que par la chaîne de requête. Par exemple, si vous effectuez une recherche sur les forums CodeIgniter, vous pourrez publier votre requête de recherche sur:
http://codeigniter.com/forums/do_search/
Nous pouvons écrire un script PHP pour simuler ce type de requête d’URL. Commençons par créer un fichier simple pour accepter et afficher les données POST. Appelons cela post_output.php:
print_r ($ _ POST);
Ensuite, nous créons un script PHP pour exécuter une requête cURL:
$ 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); // nous faisons une requête POST curl_setopt ($ ch, CURLOPT_POST, 1); // ajout des variables de publication à la requête curl_setopt ($ ch, CURLOPT_POSTFIELDS, $ post_data); $ output = curl_exec ($ ch); curl_close ($ ch); echo $ output;
Lorsque vous exécutez ce script, vous devriez obtenir une sortie comme celle-ci:
Il a envoyé un message POST au script post_output.php, qui a vidé la variable $ _POST, et nous avons capturé cette sortie via cURL..
Le téléchargement de fichiers fonctionne de manière très similaire à l'exemple POST précédent, car tous les formulaires de téléchargement de fichiers utilisent la méthode POST..
Commençons par créer un fichier pour recevoir la demande et appelons-le upload_output.php:
print_r ($ _FICHIERS);
Et voici le script qui effectue le téléchargement du fichier:
$ url = "http: //localhost/upload_output.php"; $ post_data = array ("foo" => "bar", // fichier à télécharger "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;
Lorsque vous souhaitez télécharger un fichier, il vous suffit de transmettre son chemin d'accès au fichier comme une variable de publication et de placer le symbole @ devant celui-ci. Maintenant, lorsque vous exécutez ce script, vous devriez obtenir une sortie comme celle-ci:
Une des fonctionnalités les plus avancées de cURL est la possibilité de créer une poignée "multi" cURL. Cela vous permet d’ouvrir des connexions à plusieurs URL simultanément et de manière asynchrone..
Sur une demande cURL normale, l'exécution du script s'arrête et attend que la demande d'URL se termine avant de pouvoir continuer. Si vous avez l'intention de saisir plusieurs URL, cela peut prendre un certain temps, car vous ne pouvez demander qu'une seule URL à la fois. Nous pouvons surmonter cette limitation en utilisant le multi handle.
Regardons cet exemple de code de php.net:
// crée les deux ressources cURL $ ch1 = curl_init (); $ ch2 = curl_init (); // set URL et autres options appropriées 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); // crée le handle de plusieurs cURL $ mh = curl_multi_init (); // ajoute les deux descripteurs curl_multi_add_handle ($ mh, $ ch1); curl_multi_add_handle ($ mh, $ ch2); $ actif = null; // exécuter les poignées 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, $ actif); while ($ mrc == CURLM_CALL_MULTI_PERFORM); // ferme les poignées curl_multi_remove_handle ($ mh, $ ch1); curl_multi_remove_handle ($ mh, $ ch2); curl_multi_close ($ mh);
L'idée est que vous pouvez ouvrir plusieurs poignées cURL et les affecter à une seule poignée multiple. Ensuite, vous pouvez attendre qu'ils aient fini de s'exécuter en boucle.
Il y a deux boucles principales dans cet exemple. La première boucle do-while appelle à plusieurs reprises curl_multi_exec (). Cette fonction est non bloquante. Il s'exécute le moins possible et renvoie une valeur de statut. Tant que la valeur renvoyée est la constante 'CURLM_CALL_MULTI_PERFORM', cela signifie qu'il reste encore du travail à faire immédiatement (par exemple, envoyer des en-têtes http aux URL). C'est pourquoi nous continuons à l'appeler jusqu'à ce que la valeur de retour soit différente.
Dans la boucle while suivante, nous continuons tant que la variable $ active est 'true'. Cela a été passé comme deuxième argument de l'appel curl_multi_exec (). Il est défini sur 'true' tant qu'il existe des connexions actives avec le multihandle. Nous allons ensuite appeler curl_multi_select (). Cette fonction «bloque» jusqu'à ce qu'il y ait une activité de connexion, telle que la réception d'une réponse. Lorsque cela se produit, nous entrons dans une autre boucle do-while pour continuer à exécuter.
Voyons si nous pouvons créer un exemple de travail nous-mêmes, qui a un but pratique.
Imaginez un blog avec de nombreux messages contenant des liens vers des sites Web externes. Certains de ces liens peuvent être morts au bout d'un moment pour diverses raisons. Peut-être que la page y est plus longue ou que tout le site Web a disparu.
Nous allons créer un script qui analyse tous les liens et trouve les sites Web non chargés et 404 pages et nous renvoie un rapport..
Notez que cela ne va pas être un plug-in Wordpress réel. Il s’agit uniquement d’un script d’utilitaire autonome, destiné uniquement à la démonstration..
Alors, commençons. Nous devons d’abord récupérer les liens dans la base de données:
// CONFIG $ db_host = 'localhost'; $ db_user = 'root'; $ db_pass = "; $ db_name = 'wordpress'; $ exclusive_domains = array ('localhost', 'www.mondomaine.com'); $ max_connections = 10; // initialise certaines variables $ url_list = array (); $ working_urls = array (); $ dead_urls = array (); $ not_found_urls = array (); $ active = null; // se connecte à MySQL si (! mysql_connect ($ db_host, $ db_user, $ db_pass)) die ('Connexion impossible : '. mysql_error ()); if (! mysql_select_db ($ nom_bdd)) die (' Impossible de sélectionner la base: '. mysql_error ()); // obtenir tous les articles publiés contenant des liens $ q = "SELECT post_content FROM wp_posts WHERE post_content LIKE '% href =%' AND post_status = 'publish' AND post_type = 'post' "; $ r = mysql_query ($ q) ou die (mysql_error ()); tandis que ($ d = mysql_fetch_assoc ($ r )) // récupère tous les liens via regex if (preg_match_all ("! href = \" (. *?) \ "!", $ d ['post_content'], $ correspond à)) foreach ($ correspond [1] as $ url) // exclut certains domaines $ tmp = parse_url ($ url); if (in_array ($ tmp ['hôte'], $ exclus_domaines)) continue; // stocke l'url $ url_list [] = $ url; // re déplacer les doublons $ url_list = array_values (array_unique ($ url_list)); if (! $ url_list) die ('Pas d'URL à vérifier');
Nous avons d’abord une configuration de base de données, suivie d’un tableau de noms de domaines que nous ignorerons ($ excluded_domains). Nous avons également défini un nombre maximal de connexions simultanées que nous utiliserons plus tard ($ max_connections). Ensuite, nous nous connectons à la base de données, récupérons les publications contenant des liens et les rassemblons dans un tableau ($ url_list)..
Le code suivant peut être un peu complexe, je vais donc essayer de l'expliquer par petites étapes..
// 1. poignée multiple $ mh = curl_multi_init (); // 2. ajouter plusieurs URL à la poignée multiple pour ($ 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;
Et voici l'explication du code ci-dessus. Les numéros dans la liste correspondent aux numéros dans les commentaires de code.
J'ai exécuté le script sur mon blog (avec des liens cassés ajoutés à dessein, à des fins de test), et voici à quoi il ressemble:
Il n'a fallu que moins de 2 secondes pour parcourir environ 40 URL. Les gains de performance sont significatifs lorsqu'il s'agit de gérer des ensembles d'URL encore plus vastes. Si vous ouvrez dix connexions en même temps, cela peut être dix fois plus rapide. De plus, vous pouvez simplement utiliser la nature non bloquante du multi-curl pour faire des requêtes d'URL sans bloquer votre script web.
S'il existe une authentification HTTP basée sur une URL, vous pouvez utiliser ceci:
$ url = "http://www.somesite.com/members/"; $ ch = curl_init (); curl_setopt ($ ch, CURLOPT_URL, $ url); curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); // envoie le nom d'utilisateur et le mot de passe curl_setopt ($ ch, CURLOPT_USERPWD, "myusername: mypassword"); // si vous autorisez les redirections curl_setopt ($ ch, CURLOPT_FOLLOWLOCATION, 1); // ceci permet à cURL de continuer à envoyer le nom d'utilisateur et le mot de passe // après avoir été redirigé curl_setopt ($ ch, CURLOPT_UNRESTRICTED_AUTH, 1); $ output = curl_exec ($ ch); curl_close ($ ch);
PHP a une bibliothèque FTP, mais vous pouvez aussi utiliser cURL:
// ouvre un pointeur de fichier $ file = fopen ("/ chemin / vers / fichier", "r"); // l'url contient la plupart des informations nécessaires $ url = "ftp: // nom d'utilisateur: [email protected]: 21 / chemin / vers / nouveau / fichier"; $ ch = curl_init (); curl_setopt ($ ch, CURLOPT_URL, $ url); curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); // upload les options liées curl_setopt ($ ch, CURLOPT_UPLOAD, 1); curl_setopt ($ ch, CURLOPT_INFILE, $ fp); curl_setopt ($ ch, CURLOPT_INFILESIZE, taille de fichier ("/ chemin / vers / fichier")); // défini pour le mode ASCII (par exemple, fichiers texte) curl_setopt ($ ch, CURLOPT_FTPASCII, 1); $ output = curl_exec ($ ch); curl_close ($ ch);
Vous pouvez effectuer votre demande d'URL via un proxy:
$ ch = curl_init (); curl_setopt ($ ch, CURLOPT_URL, 'http: //www.example.com'); curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); // définit l'adresse proxy pour qu'elle utilise curl_setopt ($ ch, CURLOPT_PROXY, '11.11.11.11: 8080'); // si le proxy requiert un nom d'utilisateur et un mot de passe curl_setopt ($ ch, CURLOPT_PROXYUSERPWD, 'user: pass'); $ output = curl_exec ($ ch); curl_close ($ ch);
Il est possible d’avoir des fonctions de rappel données aux appels cURL lors de la demande d’URL, avant que celle-ci ne soit terminée. Par exemple, pendant le téléchargement du contenu de la réponse, vous pouvez commencer à utiliser les données sans attendre la fin du téléchargement..
$ 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 fonction de rappel DOIT renvoyer la longueur de la chaîne, ce qui est indispensable pour que cela fonctionne correctement.
Lorsque la réponse de l'URL est extraite, chaque fois qu'un paquet de données est reçu, la fonction de rappel est appelée.
Nous avons exploré le pouvoir et la flexibilité de la bibliothèque cURL aujourd'hui. J'espère que vous avez apprécié et appris de cet article. La prochaine fois que vous devrez faire une demande d’URL dans votre application Web, envisagez d’utiliser cURL..
Merci et passez une bonne journée!
Saviez-vous que vous pouvez gagner jusqu'à 600 USD en écrivant un tutoriel et / ou un screencast PLUS pour nous?? Nous recherchons des didacticiels détaillés et bien écrits sur HTML, CSS, PHP et JavaScript. Si vous en avez la possibilité, veuillez contacter Jeffrey à l'adresse [email protected]..
Veuillez noter que la rémunération réelle dépendra de la qualité du didacticiel final et du screencast..