Técnicas para dominar el CURSO

cURL es una herramienta para transferir archivos y datos con sintaxis de URL, que admite muchos protocolos, incluidos HTTP, FTP, TELNET y más. Inicialmente, cURL fue diseñado para ser una herramienta de línea de comandos. Por suerte para nosotros, la biblioteca cURL también es compatible con PHP. En este artículo, veremos algunas de las funciones avanzadas de cURL y cómo podemos usarlas en nuestros scripts de PHP..

Por que cURL?

Es cierto que hay otras formas de obtener el contenido de una página web. Muchas veces, principalmente debido a la pereza, acabo de usar funciones simples de PHP en lugar de cURL:

 $ content = file_get_contents ("http://www.nettuts.com"); // o $ líneas = archivo ("http://www.nettuts.com"); // o readfile ("http://www.nettuts.com");

Sin embargo, no tienen virtualmente ninguna flexibilidad y carecen de suficiente manejo de errores Además, hay ciertas tareas que simplemente no puede hacer, como tratar con cookies, autenticación, envío de formularios, carga de archivos, etc..

cURL es una biblioteca potente que admite muchos protocolos, opciones y proporciona información detallada sobre las solicitudes de URL.

Estructura basica

Antes de pasar a ejemplos más complicados, revisemos la estructura básica de una solicitud de cURL en PHP. Hay cuatro pasos principales:

  1. Inicializar
  2. Establecer opciones
  3. Ejecutar y obtener el resultado
  4. Libera el mango cURL
 // 1. inicializar $ ch = curl_init (); // 2. establezca las opciones, incluida la url curl_setopt ($ ch, CURLOPT_URL, "http://www.nettuts.com"); curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt ($ ch, CURLOPT_HEADER, 0); // 3. ejecutar y obtener la salida HTML resultante $ output = curl_exec ($ ch); // 4. libere la manija de enrollamiento curl_close ($ ch);

El paso # 2 (es decir, las llamadas a curl_setopt ()) será una gran parte de este artículo, porque ahí es donde ocurre toda la magia. Existe una larga lista de opciones de cURL que se pueden configurar, que pueden configurar la solicitud de URL en detalle. Puede ser difícil repasar toda la lista y digerirla de una vez. Así que hoy, solo vamos a utilizar algunas de las opciones más comunes y útiles en varios ejemplos de código..

Comprobación de errores

Opcionalmente, también puede agregar la comprobación de errores:

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

Tenga en cuenta que necesitamos usar "=== FALSO" para la comparación en lugar de "== FALSO". Porque debemos distinguir entre la salida vacía y el valor booleano FALSE, que indica un error.

Consiguiendo información

Otro paso opcional es obtener información sobre la solicitud de cURL, después de que se haya ejecutado.

 //… curl_exec ($ ch); $ info = curl_getinfo ($ ch); echo 'Took'. $ info ['total_time']. 'segundos para url'. $ info ['url']; //… 

La siguiente información se incluye en la matriz devuelta:

  • "url"
  • "tipo de contenido"
  • "http_code"
  • "header_size"
  • "request_size"
  • "filetime"
  • "ssl_verify_result"
  • "redirect_count"
  • "Tiempo Total"
  • "namelookup_time"
  • "tiempo de conexión"
  • "pretransfer_time"
  • "size_upload"
  • "size_download"
  • "speed_download"
  • "speed_upload"
  • "download_content_length"
  • "upload_content_length"
  • "starttransfer_time"
  • "redirect_time"

Detectar la redirección basada en el navegador

En este primer ejemplo, escribiremos un script que puede detectar redirecciones de URL en función de diferentes configuraciones del navegador. Por ejemplo, algunos sitios web redireccionan los navegadores de teléfonos celulares o incluso los usuarios de diferentes países..

Vamos a utilizar la opción CURLOPT_HTTPHEADER para configurar nuestros encabezados HTTP salientes, incluida la cadena de agente de usuario y los idiomas aceptados. Finalmente, comprobaremos si estos sitios web intentan redirigirnos a diferentes URL..

 // URL de prueba $ urls = array ("http://www.cnn.com", "http://www.mozilla.com", "http://www.facebook.com"); // probar navegadores $ 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 "=>" es-es, en; q = 0.5 ")," iphone "=> array (" user_agent "=>" Mozilla / 5.0 (iPhone; U ; CPU como Mac OS X; es) AppleWebKit / 420 + (KHTML, como Gecko) Versión / 3.0 Mobile / 1A537a Safari / 419.3 "," language "=>" en ")," french "=> array (" user_agent " => "Mozilla / 4.0 (compatible; MSIE 7.0; Windows NT 5.1; GTB6; .NET CLR 2.0.50727)", "idioma" => "fr, fr-FR; q = 0.5")); foreach ($ urls as $ url) echo "URL: $ url \ n"; foreach ($ browser como $ test_name => $ browser) $ ch = curl_init (); // establece url curl_setopt ($ ch, CURLOPT_URL, $ url); // establecer los encabezados específicos del navegador curl_setopt ($ ch, CURLOPT_HTTPHEADER, array ("User-Agent: $ browser ['user_agent']", "Accept-Language: $ browser ['language']")); // no queremos los contenidos de la página curl_setopt ($ ch, CURLOPT_NOBODY, 1); // necesitamos el encabezado HTTP devuelto curl_setopt ($ ch, CURLOPT_HEADER, 1); // devuelve los resultados en lugar de generarlos curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); $ output = curl_exec ($ ch); curl_close ($ ch); // ¿Hubo un encabezado HTTP de redireccionamiento? if (preg_match ("! Location: (. *)!", $ output, $ matches)) echo "$ test_name: redirige a $ matches [1] \ n";  else echo "$ test_name: no hay redirección \ n";  echo "\ n \ n"; 

Primero tenemos un conjunto de URL para probar, seguido de un conjunto de configuraciones del navegador para probar cada una de estas URL. Luego hacemos un bucle a través de estos casos de prueba y hacemos una solicitud cURL para cada uno.

Debido a la forma en que se configuran las opciones de cURL, la salida devuelta solo contendrá los encabezados HTTP (guardados en $ output). Con una expresión regular simple, podemos ver si había un encabezado "Ubicación:" incluido.

Cuando ejecute este script, debería obtener una salida como esta:

POSTING a una URL

En una solicitud GET, los datos pueden enviarse a una URL a través de la "cadena de consulta". Por ejemplo, cuando realiza una búsqueda en Google, el término de búsqueda se encuentra en la parte de la cadena de consulta de la URL:

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

Es posible que no necesite cURL para simular esto en un script web. Solo puedes ser perezoso y golpear esa url con "file_get_contents ()" para recibir los resultados.

Pero algunos formularios HTML están configurados para el método POST. Cuando estos formularios se envían a través del navegador, los datos se envían a través del cuerpo de Solicitud HTTP, en lugar de la cadena de consulta. Por ejemplo, si realiza una búsqueda en los foros de CodeIgniter, enviará su consulta de búsqueda a:

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

Podemos escribir un script PHP para simular este tipo de solicitud de URL. Primero vamos a crear un archivo simple para aceptar y mostrar los datos POST. Llamémoslo post_output.php:

 print_r ($ _ POST);

A continuación creamos un script PHP para realizar una solicitud de 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); // estamos haciendo una solicitud POST curl_setopt ($ ch, CURLOPT_POST, 1); // añadiendo las variables post a la solicitud curl_setopt ($ ch, CURLOPT_POSTFIELDS, $ post_data); $ output = curl_exec ($ ch); curl_close ($ ch); echo $ output;

Cuando ejecute este script, debería obtener una salida como esta:

Envió un POST al script post_output.php, que descargó la variable $ _POST, y capturamos ese resultado a través de cURL.

Subir archivo

La carga de archivos funciona de manera muy similar al ejemplo anterior de POST, ya que todos los formularios de carga de archivos tienen el método POST.

Primero vamos a crear un archivo para recibir la solicitud y llamarlo upload_output.php:

 print_r ($ _ FILES);

Y aquí está el script real que realiza la carga del archivo:

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

Cuando desee cargar un archivo, todo lo que tiene que hacer es pasar su ruta de archivo como una variable de publicación y colocar el símbolo @ delante de él. Ahora, cuando ejecute este script, debería obtener una salida como esta:

Multi cURL

Una de las características más avanzadas de cURL es la capacidad de crear un identificador "multi" de cURL. Esto le permite abrir conexiones a múltiples URL de forma simultánea y asíncrona.

En una solicitud de cURL regular, la ejecución del script se detiene y espera a que finalice la solicitud de URL antes de que pueda continuar. Si pretende acceder a varias URL, esto puede llevar mucho tiempo, ya que solo puede solicitar una URL a la vez. Podemos superar esta limitación utilizando el multi manejador..

Veamos este código de ejemplo de php.net:

 // crea los dos recursos de cURL $ ch1 = curl_init (); $ ch2 = curl_init (); // establecer la URL y otras opciones apropiadas 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); // crear el identificador de varias CURSAS $ mh = curl_multi_init (); // agrega los dos manejadores curl_multi_add_handle ($ mh, $ ch1); curl_multi_add_handle ($ mh, $ ch2); $ activo = nulo; // ejecuta los manejadores 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, $ activo);  while ($ mrc == CURLM_CALL_MULTI_PERFORM);  // cierra los controles curl_multi_remove_handle ($ mh, $ ch1); curl_multi_remove_handle ($ mh, $ ch2); curl_multi_close ($ mh);

La idea es que puede abrir varios manejadores cURL y asignarlos a un solo manejador múltiple. Luego puedes esperar a que terminen de ejecutarse mientras están en un bucle.

Hay dos bucles principales en este ejemplo. El primer bucle do-while llama repetidamente a curl_multi_exec (). Esta función es no bloqueante. Se ejecuta lo menos posible y devuelve un valor de estado. Siempre que el valor devuelto sea la constante 'CURLM_CALL_MULTI_PERFORM', significa que todavía hay más trabajo inmediato que hacer (por ejemplo, enviar encabezados http a las URL). Por eso seguimos llamando hasta que el valor de retorno sea otra cosa..

En el siguiente bucle while, continuamos siempre y cuando la variable $ activa sea 'verdadera'. Esto se pasó como el segundo argumento de la llamada curl_multi_exec (). Se establece en 'verdadero' siempre que haya conexiones activas dentro del controlador múltiple. Lo siguiente que hacemos es llamar a curl_multi_select (). Esta función está 'bloqueando' hasta que haya alguna actividad de conexión, como recibir una respuesta. Cuando eso sucede, entramos en otro bucle do-while para continuar ejecutando.

Veamos si podemos crear un ejemplo de trabajo nosotros mismos, que tenga un propósito práctico..

Wordpress Link Checker

Imagina un blog con muchas publicaciones que contengan enlaces a sitios web externos. Algunos de estos enlaces pueden terminar muertos después de un tiempo por varias razones. Tal vez la página sea más larga allí, o el sitio web completo haya desaparecido..

Vamos a construir un script que analice todos los enlaces y encuentre sitios web sin carga y páginas 404 y nos devuelva un informe..

Tenga en cuenta que este no será un complemento real de Wordpress. Es solo un script de utilidad independiente, y es solo para fines de demostración.

Entonces empecemos. Primero necesitamos obtener los enlaces de la base de datos:

 // CONFIG $ db_host = 'localhost'; $ db_user = 'root'; $ db_pass = "; $ db_name = 'wordpress'; $ excluded_domains = array ('localhost', 'www.mydomain.com'); $ max_connections = 10; // inicialice algunas variables $ url_list = array (); $ working_urls = array (); $ dead_urls = array (); $ not_found_urls = array (); $ active = null; // conectarse a MySQL si (! mysql_connect ($ db_host, $ db_user, $ db_pass)) die ('No se pudo conectar : '. mysql_error ()); if (! mysql_select_db ($ db_name)) die (' No se pudo seleccionar db: '. mysql_error ()); // obtener todas las publicaciones publicadas que tengan enlaces $ q = "SELECT post_content FROM wp_posts WHERE post_content LIKE '% href =%' AND post_status = 'publish' AND post_type = 'post' "; $ r = mysql_query ($ q) o die (mysql_error ()); while ($ d = mysql_fetch_assoc ($ r )) // obtener todos los enlaces a través de expresiones regulares si (preg_match_all ("! href = \" (. *?) \ "!", $ d ['post_content'], $ coincidencias)) foreach ($ coincidencias [1] como $ url) // excluye algunos dominios $ tmp = parse_url ($ url); if (in_array ($ tmp ['host'], $ excluded_domains)) continue; // almacena la url $ url_list [] = $ url; // re mover duplicados $ url_list = array_values ​​(array_unique ($ url_list)); if (! $ url_list) die ('No URL to check'); 

Primero tenemos una configuración de base de datos, seguida de una matriz de nombres de dominio que ignoraremos ($ excluded_domains). También establecemos un número para el máximo de conexiones simultáneas que usaremos más adelante ($ max_connections). Luego nos conectamos a la base de datos, recuperamos publicaciones que contienen enlaces y las reunimos en una matriz ($ url_list).

El siguiente código puede ser un poco complejo, así que intentaré explicarlo en pequeños pasos.

 // 1. multi handle $ mh = curl_multi_init (); // 2. agregue múltiples URL al controlador múltiple para ($ 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;  

Y aquí está la explicación para el código anterior. Los números en la lista corresponden a los números en el código de comentarios.

  1. Creado un mango múltiple.
  2. Vamos a crear la función add_url_to_multi_handle () más adelante. Cada vez que se llama, se agregará una url al controlador múltiple. Inicialmente, agregamos 10 (basadas en $ max_connections) URLs a los múltiples manejadores.
  3. Debemos ejecutar curl_multi_exec () para el trabajo inicial. Mientras se devuelva CURLM_CALL_MULTI_PERFORM, queda trabajo por hacer. Esto es principalmente para crear las conexiones. No espera la respuesta completa de la URL..
  4. Este bucle principal se ejecuta siempre que haya alguna actividad en el controlador múltiple.
  5. curl_multi_select () espera la secuencia de comandos hasta que ocurra una actividad con cualquiera de las búsquedas de URL.
  6. Una vez más, debemos dejar que cURL haga un poco de trabajo, principalmente para obtener datos de respuesta.
  7. Verificamos la información. Se devuelve una matriz si se completó una solicitud de URL.
  8. Hay un identificador cURL en la matriz devuelta. Usamos eso para obtener información sobre la solicitud de cURL individual.
  9. Si el enlace estaba muerto o agotado, no habrá ningún código http.
  10. Si el enlace era una página 404, el código http se establecerá en 404.
  11. De lo contrario, suponemos que era un enlace de trabajo. (Puede agregar cheques adicionales para 500 códigos de error, etc.)
  12. Quitamos el identificador cURL del identificador múltiple porque ya no es necesario y lo cerramos.
  13. Ahora podemos agregar otra url al controlador múltiple y, nuevamente, hacer el trabajo inicial antes de continuar..
  14. Todo está terminado. Podemos cerrar el identificador múltiple e imprimir un informe..
  15. Esta es la función que agrega una nueva url al controlador múltiple. La variable estática $ index se incrementa cada vez que se llama a esta función, por lo que podemos hacer un seguimiento de dónde lo dejamos.

Ejecuté el script en mi blog (con algunos enlaces rotos agregados a propósito, para pruebas), y esto es lo que parecía:

Solo tomó menos de 2 segundos pasar por cerca de 40 URL. Las mejoras en el rendimiento son significativas cuando se trata de conjuntos de URL aún más grandes. Si abre diez conexiones al mismo tiempo, puede funcionar hasta diez veces más rápido. También puede utilizar la naturaleza no bloqueante del identificador de múltiples rizos para realizar solicitudes de URL sin detener su script web.

Algunas otras opciones útiles cURL

Autenticación HTTP

Si hay una autenticación basada en HTTP en una URL, puede usar esto:

 $ url = "http://www.somesite.com/members/"; $ ch = curl_init (); curl_setopt ($ ch, CURLOPT_URL, $ url); curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); // enviar el nombre de usuario y la contraseña curl_setopt ($ ch, CURLOPT_USERPWD, "myusername: mypassword"); // si permite redirecciones curl_setopt ($ ch, CURLOPT_FOLLOWLOCATION, 1); // esto permite a cURL continuar enviando el nombre de usuario y la contraseña // después de ser redirigido curl_setopt ($ ch, CURLOPT_UNRESTRICTED_AUTH, 1); $ output = curl_exec ($ ch); curl_close ($ ch);

Subir FTP

PHP tiene una biblioteca FTP, pero también puedes usar cURL:

 // abrir un puntero a archivo $ archivo = fopen ("/ ruta / a / archivo", "r"); // la url contiene la mayor parte de la información necesaria $ 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); // cargar las opciones relacionadas curl_setopt ($ ch, CURLOPT_UPLOAD, 1); curl_setopt ($ ch, CURLOPT_INFILE, $ fp); curl_setopt ($ ch, CURLOPT_INFILESIZE, tamaño de archivo ("/ path / to / file")); // configurado para el modo ASCII (por ejemplo, archivos de texto) curl_setopt ($ ch, CURLOPT_FTPASCII, 1); $ output = curl_exec ($ ch); curl_close ($ ch);

Usando un proxy

Puede realizar su solicitud de URL a través de un proxy:

 $ ch = curl_init (); curl_setopt ($ ch, CURLOPT_URL, 'http: //www.example.com'); curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); // configura la dirección proxy para usar curl_setopt ($ ch, CURLOPT_PROXY, '11 .11.11.11: 8080 '); // si el proxy requiere un nombre de usuario y contraseña curl_setopt ($ ch, CURLOPT_PROXYUSERPWD, 'user: pass'); $ output = curl_exec ($ ch); curl_close ($ ch);

Funciones de devolución de llamada

Es posible tener las funciones de devolución de llamada de cURL call durante la solicitud de URL, antes de que finalice. Por ejemplo, a medida que se descarga el contenido de la respuesta, puede comenzar a usar los datos, sin esperar a que se complete la descarga completa..

 $ 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 función de devolución de llamada DEBE devolver la longitud de la cadena, que es un requisito para que esto funcione correctamente.

A medida que se recupera la respuesta URL, cada vez que se recibe un paquete de datos, se llama a la función de devolución de llamada.

Conclusión

Hemos explorado el poder y la flexibilidad de la biblioteca cURL en la actualidad. Espero que hayan disfrutado y aprendido de este artículo. La próxima vez que necesite realizar una solicitud de URL en su aplicación web, considere usar cURL.

Gracias y que tengas un buen día!

Escribe un Tutorial Plus

¿Sabía que puede ganar hasta $ 600 por escribir un tutorial PLUS y / o un screencast para nosotros?? Estamos buscando tutoriales detallados y bien escritos sobre HTML, CSS, PHP y JavaScript. Si tiene la habilidad, contacte a Jeffrey en [email protected].

Tenga en cuenta que la compensación real dependerá de la calidad del tutorial final y del screencast.

  • Síganos en Twitter o suscríbase a Nettuts + RSS Feed para obtener los mejores tutoriales de desarrollo web en la web..