cURL es una herramienta que utiliza la sintaxis de URL para transferir archivos y datos. Admite muchos protocolos, como HTTP, FTP, TELNET, etc. Lo mejor es que PHP también soporta la biblioteca cURL. Este artículo presentará algunas características avanzadas de cURL y cómo usarlo en PHP.
¿Por qué utilizar cURL?
Sí, podemos obtener contenido web a través de otros métodos. La mayoría de las veces, como quiero ser vago, solo uso una función PHP simple:
$contenido = file_get_contents(" http://www.bizhicool.com ");
// o
$líneas = archivo(" http://www.bizhicool.com ");
// o
readfile( http://www.bizhicool.com ); Sin embargo, este enfoque carece de flexibilidad y manejo efectivo de errores. Además, no puede utilizarlo para completar algunas tareas difíciles, como manejar cookies, validación, envío de formularios, carga de archivos, etc.
cURL es una biblioteca poderosa que admite muchos protocolos y opciones diferentes y puede proporcionar varios detalles relacionados con las solicitudes de URL.
Estructura básica Antes de aprender sobre funciones más complejas, echemos un vistazo a los pasos básicos para configurar una solicitud cURL en PHP:
Inicializar, establecer variables, ejecutar y obtener resultados, liberar el controlador cURL
// 1. Inicialización
$ch = curl_init();
// 2. Establecer opciones, incluida la URL
curl_setopt($ch, CURLOPT_URL, " http://www.bizhicool.com ");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
// 3. Ejecutar y obtener el contenido del documento HTML
$salida = curl_exec($ch);
// 4. Suelte el controlador de rizo
curl_close($ch); El segundo paso (es decir, curl_setopt()) es el más importante y todo el misterio radica aquí. Hay una larga lista de parámetros de cURL que se pueden configurar y que especifican varios detalles de la solicitud de URL. Puede resultar difícil leerlos y comprenderlos todos a la vez, por lo que hoy solo probaremos las opciones más comunes y útiles.
Comprobación de errores Puede agregar una declaración para comprobar si hay errores (aunque esto no es obligatorio):
//...
$salida = curl_exec($ch);
si ($salida === FALSO) {
echo "Error de rizo: " . curl_error($ch);
}
// ...Tenga en cuenta que utilizamos "=== FALSE" en lugar de "== FALSE" al comparar. Porque tenemos que distinguir entre salida vacía y el valor booleano FALSO, que es el verdadero error.
Obtener información Esta es otra configuración opcional que puede obtener información sobre esta solicitud después de ejecutar cURL:
//...
curl_exec($ch);
$info = curl_getinfo($ch);
echo 'Obtener'. $info['url'] 'Consume tiempo'. $info['total_time'] 'Segundos';
// ...la matriz devuelta incluye la siguiente información:
"url" //Dirección de red de recursos
"content_type" //Codificación de contenido
"http_code" //Código de estado HTTP
"header_size" //El tamaño del encabezado
"request_size" //Tamaño de la solicitud
"filetime" //Hora de creación del archivo
"ssl_verify_result" //Resultado de la verificación SSL
"redirect_count" //Tecnología de salto
"total_time" //Tiempo total empleado
"namelookup_time" //hora de consulta DNS
"connect_time" //Esperando el tiempo de conexión
"pretransfer_time" //El tiempo de preparación antes de la transmisión
"size_upload" //El tamaño de los datos cargados
"size_download" //El tamaño de los datos descargados
"speed_download" //Velocidad de descarga
"speed_upload" //Velocidad de carga
"download_content_length" //La duración del contenido descargado
"upload_content_length" //La longitud del contenido subido
"starttransfer_time" //Hora de iniciar la transferencia
"redirect_time" //La redirección lleva tiempo Redirección basada en navegador En el primer ejemplo, proporcionaremos un fragmento de código que detecta si el servidor tiene una redirección basada en navegador. Por ejemplo, algunos sitios web redirigirán las páginas web en función de si se trata de un navegador móvil o incluso del país de origen del usuario.
Usamos la opción CURLOPT_HTTPHEADER para configurar los encabezados de solicitud HTTP que enviamos (encabezados http), incluida la información del agente de usuario y el idioma predeterminado. Luego veremos si estos sitios web específicos nos redireccionan a URL diferentes.
// URL para probar
$url = matriz(
" http://www.cnn.com ",
" http://www.mozilla.com ",
" http://www.facebook.com "
);
// Información del navegador para pruebas
$navegadores = matriz(
"estándar" => matriz (
"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)",
"idioma" => "en-us,en;q=0.5"
),
"iphone" => matriz (
"user_agent" => "Mozilla/5.0 (iPhone; U; CPU como Mac OS X; en) AppleWebKit/420+ (KHTML, como Gecko) Version/3.0 Mobile/1A537a Safari/419.3",
"idioma" => "es"
),
"francés" => matriz (
"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 ($url como $url) {
echo "URL: $urln";
foreach ($navegadores como $test_name => $navegador) {
$ch = curl_init();
//Establecer URL
curl_setopt($ch, CURLOPT_URL, $url);
//Establecer encabezados específicos del navegador
curl_setopt($ch, CURLOPT_HTTPHEADER, matriz(
"Agente de usuario: {$browser['user_agent']}",
"Aceptar-Idioma: {$ navegador['idioma']}"
));
// No necesitamos el contenido de la página
curl_setopt($ch, CURLOPT_NOBODY, 1);
// Simplemente devuelve el encabezado HTTP
curl_setopt($ch, CURLOPT_HEADER, 1);
// Devuelve el resultado en lugar de imprimirlo
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$salida = curl_exec($ch);
curl_close($ch);
// ¿Existe alguna información de encabezado HTTP para la redirección?
if (preg_match("!Ubicación: (.*)!", $salida, $matches)) {
echo "$test_name: redirige a $matches[1]n";
} demás {
echo "$test_name: sin redirecciónn";
}
}
eco "nn";
} Primero, creamos un conjunto de URL que deben probarse y luego especificamos un conjunto de información del navegador que debe probarse. Finalmente, se utiliza un bucle para probar varias situaciones de coincidencia de URL y navegador que pueden ocurrir.
Debido a que especificamos la opción cURL, la salida devuelta solo incluye información del encabezado HTTP (almacenada en $output). Usando una regla regular simple, verificamos si la información del encabezado contiene la palabra "Ubicación:".
La ejecución de este código debería devolver los siguientes resultados:
Envío de datos mediante el método POST Al realizar una solicitud GET, los datos se pueden pasar a una URL a través de una "cadena de consulta". Por ejemplo, cuando se realiza una búsqueda en Google, la clave de búsqueda forma parte de la cadena de consulta de la URL:
http://www.google.com/search?q=nettuts En este caso probablemente no necesite cURL para simular. Lanzar esta URL a "file_get_contents()" obtendrá el mismo resultado.
Sin embargo, algunos formularios HTML se envían mediante el método POST. Cuando se envía este formulario, los datos se envían a través del cuerpo de la solicitud HTTP (cuerpo de la solicitud) en lugar de la cadena de consulta. Por ejemplo, cuando utilice el formulario del foro CodeIgniter, no importa qué palabras clave ingrese, siempre será PUBLICADO en la siguiente página:
http://codeigniter.com/forums/do_search/ Puede utilizar un script PHP para simular esta solicitud de URL. Primero, cree un nuevo archivo que pueda aceptar y mostrar datos POST. Lo llamamos post_output.php:
print_r($_POST); A continuación, escriba un script PHP para realizar la solicitud cURL:
$url = " http://localhost/post_output.php ";
$post_data = matriz (
"foo" => "barra",
"consulta" => "Nettuts",
"acción" => "Enviar"
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// ¡Estamos PUBLICANDO datos!
curl_setopt($ch, CURLOPT_POST, 1);
//Añadir la variable de publicación
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
$salida = curl_exec($ch);
curl_close($ch);
echo $output;Después de ejecutar el código, debería obtener los siguientes resultados:
Este script envía una solicitud POST a post_output.php, la variable $_POST de la página y la devuelve. Capturamos esta salida usando cURL.
Carga de archivos La carga de archivos es muy similar al POST anterior. Porque todos los formularios de carga de archivos se envían mediante el método POST.
Primero, cree una nueva página para recibir archivos, llamada upload_output.php:
print_r($_FILES);El siguiente es el script que realmente realiza la tarea de carga del archivo:
$url = " http://localhost/upload_output.php ";
$post_data = matriz (
"foo" => "barra",
//La dirección del archivo local que se cargará
"cargar" => "@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);
$salida = curl_exec($ch);
curl_close($ch);
echo $output; Si necesita cargar un archivo, simplemente pase la ruta del archivo como una variable de publicación, pero recuerde agregar el símbolo @ al frente. La ejecución de este script debería generar el siguiente resultado:
Procesamiento por lotes de cURL (multicURL)
cURL también tiene una función avanzada: identificadores por lotes. Esta función le permite abrir múltiples conexiones URL de forma simultánea o asincrónica.
Aquí hay un código de muestra de php.net:
//Crea dos recursos cURL
$ch1 = curl_init();
$ch2 = curl_init();
//Especifique la URL y los parámetros apropiados
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 identificador por lotes de cURL
$mh = curl_multi_init();
//Añadir los dos primeros identificadores de recursos
curl_multi_add_handle($mh,$ch1);
curl_multi_add_handle($mh,$ch2);
// Predefinir una variable de estado
$activo = nulo;
//Ejecutar procesamiento por lotes
hacer {
$mrc = curl_multi_exec($mh, $activo);
} mientras ($mrc == CURLM_CALL_MULTI_PERFORM);
mientras ($activo && $mrc == CURLM_OK) {
si (curl_multi_select($mh) != -1) {
hacer {
$mrc = curl_multi_exec($mh, $activo);
} mientras ($mrc == CURLM_CALL_MULTI_PERFORM);
}
}
//Cierra cada identificador
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
curl_multi_close($mh); lo que debe hacer aquí es abrir varios identificadores de cURL y asignarlos a un identificador por lotes. Luego simplemente espera un bucle while hasta que se complete.
Hay dos bucles principales en este ejemplo. El primer bucle do- while llama a curl_multi_exec() repetidamente. Esta función no es bloqueante pero se ejecutará lo menos posible. Devuelve un valor de estado, siempre que este valor sea igual a la constante CURLM_CALL_MULTI_PERFORM, significa que todavía queda trabajo urgente por hacer (por ejemplo, enviar la información del encabezado http correspondiente a la URL). Es decir, debemos seguir llamando a esta función hasta que cambie el valor de retorno.
El siguiente bucle while solo continuará cuando la variable $active sea verdadera. Esta variable se pasó previamente a curl_multi_exec() como segundo parámetro y representa si todavía hay conexiones activas en el identificador por lotes. A continuación, llamamos a curl_multi_select(), que se "bloquea" hasta que se produce una conexión activa (como recibir una respuesta del servidor). Después de que esta función se ejecute correctamente, ingresaremos otro bucle do- while y continuaremos con la siguiente URL.
Echemos un vistazo a cómo poner esta característica en práctica:
Comprobador de conexión de WordPress Imagine que tiene un blog con una gran cantidad de artículos que contienen una gran cantidad de enlaces a sitios web externos. Después de un tiempo, un buen número de estos enlaces dejaron de ser válidos por una razón u otra. O se ha armonizado o todo el sitio ha sido pirateado...
Creemos un script a continuación para analizar todos estos enlaces, descubrir los sitios web/páginas web que no se pueden abrir o tienen 404 y generar un informe.
Tenga en cuenta que lo siguiente no es un complemento de WordPress que funcione realmente, es solo un script con funciones independientes, solo para demostración, gracias.
Bien, comencemos. Primero, lea todos estos enlaces de la base de datos:
//CONFIGURAR
$db_host = 'localhost';
$db_user = 'raíz';
$db_pass = '';
$db_name = 'wordpress';
$dominios_excluidos = matriz(
'localhost', 'www.midominio.com');
$max_conexiones = 10;
//Inicializa algunas variables
$lista_url = matriz();
$working_urls = matriz();
$urls_muertos = matriz();
$not_found_urls = matriz();
$activo = nulo;
// Conéctate a MySQL
si (!mysql_connect($db_host, $db_user, $db_pass)) {
die('No se pudo conectar: ' . mysql_error());
}
si (!mysql_select_db($db_name)) {
die('No se pudo seleccionar db: ' . mysql_error());
}
// Encuentra todos los artículos con enlaces
$q = "SELECCIONAR post_content DE wp_posts
DONDE post_content COMO '%href=%'
Y post_status = 'publicar'
AND post_type = 'publicación'";
$r = mysql_query($q) o morir(mysql_error());
mientras ($d = mysql_fetch_assoc($r)) {
// Utilice enlaces coincidentes regulares
if (preg_match_all("!href="(.*?)"!", $d['post_content'], $matches)) {
foreach ($coincide con [1] como $url) {
// excluir algunos dominios
$tmp = parse_url($url);
if (in_array($tmp['host'], $dominios_excluidos)) {
continuar;
}
// almacena la URL
$lista_url []= $url;
}
}
}
// Eliminar enlaces duplicados
$lista_url = valores_array(array_unique($lista_url));
si (!$url_list) {
die('No hay URL para verificar');
}Primero configuramos la base de datos, una serie de nombres de dominio a excluir ($excluded_domains) y el número máximo de conexiones simultáneas ($max_connections). Luego, conéctese a la base de datos, obtenga los artículos y los enlaces incluidos y recopilelos en una matriz ($url_list).
El siguiente código es un poco complicado, así que lo explicaré en detalle paso a paso:
// 1. Procesador por lotes
$mh = curl_multi_init();
// 2. Agregue las URL que deben procesarse en lotes
para ($i = 0; $i < $max_conexiones; $i++) {
add_url_to_multi_handle($mh, $url_list);
}
// 3. Procesamiento inicial
hacer {
$mrc = curl_multi_exec($mh, $activo);
} mientras ($mrc == CURLM_CALL_MULTI_PERFORM);
// 4. Bucle principal
mientras ($activo && $mrc == CURLM_OK) {
// 5. Hay una conexión activa
si (curl_multi_select($mh) != -1) {
// 6. Trabajo
hacer {
$mrc = curl_multi_exec($mh, $activo);
} mientras ($mrc == CURLM_CALL_MULTI_PERFORM);
// 7. ¿Tienes alguna información?
si ($mhinfo = curl_multi_info_read($mh)) {
//Significa que la conexión finalizó normalmente
// 8. Obtener información del identificador curl
$chinfo = curl_getinfo($mhinfo['handle']);
// 9. ¿Enlace muerto?
si (!$chinfo['http_code']) {
$dead_urls []= $chinfo['url'];
// 10.404?
} si no ($chinfo['http_code'] == 404) {
$not_found_urls []= $chinfo['url'];
// 11. Aún disponible
} demás {
$working_urls []= $chinfo['url'];
}
// 12. Quitar el asa
curl_multi_remove_handle($mh, $mhinfo['mango']);
curl_close($mhinfo['manejar']);
// 13. Agrega una nueva URL y haz el trabajo
si (add_url_to_multi_handle($mh, $url_list)) {
hacer {
$mrc = curl_multi_exec($mh, $activo);
} mientras ($mrc == CURLM_CALL_MULTI_PERFORM);
}
}
}
}
// 14. Terminado
curl_multi_close($mh);
echo "==URL inactivas==n";
echo implosión("n",$dead_urls) "nn";
echo "==404 URL==n";
echo implode("n",$not_found_urls) "nn";
echo "==URL de trabajo==n";
echo implode("n",$working_urls);
// 15. Agregar URL al procesador por lotes
función add_url_to_multi_handle($mh, $url_list) {
índice $ estático = 0;
// Si se deja la URL, es inútil
si ($lista_url[$índice]) {
//Crear un nuevo identificador de rizo
$ch = curl_init();
//Configurar URL
curl_setopt($ch, CURLOPT_URL, $url_list[$index]);
// No quiero generar el contenido devuelto
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// Iremos a donde nos lleve la redirección
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
// No se requiere ningún cuerpo de contenido, lo que puede ahorrar ancho de banda y tiempo
curl_setopt($ch, CURLOPT_NOBODY, 1);
//Agregar al procesador por lotes
curl_multi_add_handle($mh, $ch);
// Marque el contador y podrá agregar la siguiente URL la próxima vez que llame a esta función.
$índice++;
devolver verdadero;
} demás {
// No es necesario procesar nuevas URL
devolver falso;
}
}El código anterior se explica a continuación. Los números de serie de la lista corresponden a los números secuenciales de los comentarios del código.
Cree un nuevo procesador por lotes. Creó un mango múltiple.
Posteriormente crearemos una función add_url_to_multi_handle() que agrega URL al controlador por lotes. Cada vez que se llama a esta función, se agrega una nueva URL al procesador por lotes. Inicialmente, agregamos 10 URL al procesador por lotes (este número está determinado por $max_connections).
Es necesario ejecutar curl_multi_exec() para realizar el trabajo de inicialización, mientras devuelva CURLM_CALL_MULTI_PERFORM todavía hay algo por hacer. Esto se hace principalmente para crear la conexión, no espera la respuesta URL completa.
El bucle principal continúa mientras haya conexiones activas en el lote.
curl_multi_select() espera hasta que una consulta de URL dé como resultado una conexión activa.
El trabajo de cURL está aquí nuevamente, principalmente para obtener datos de respuesta.
Consulta información diversa. Cuando se completa una solicitud de URL, se devuelve una matriz.
Hay un identificador de cURL en la matriz devuelta. Lo usamos para obtener la información correspondiente para una única solicitud cURL.
Si se trata de un enlace inactivo o la solicitud se agota, no se devolverá ningún código de estado http.
Si no se puede encontrar esta página, se devolverá un código de estado 404.
En otros casos, asumimos que este enlace está disponible (por supuesto, también puedes comprobar si hay errores 500 y similares...).
Elimine este identificador cURL del lote porque ya no sirve, ¡ciérrelo!
Genial, ahora puedes agregar otra URL. Una vez más, el trabajo de inicialización comienza de nuevo...
Bueno, todo lo que hay que hacer, está hecho. Cierre el procesador por lotes y genere el informe.
Volvamos a la función que agrega una nueva URL al procesador por lotes. Cada vez que se llama a esta función, la variable estática $index se incrementa para que podamos saber cuántas URL quedan por procesar.
Ejecuté este script en mi blog (es necesario realizar pruebas, se agregaron algunos enlaces incorrectos intencionalmente) y los resultados son los siguientes:
Se comprobaron un total de unas 40 URL y tardó menos de dos segundos. Cuando necesites comprobar una mayor cantidad de URL, ¡puedes imaginar el efecto que te ahorrará preocupaciones! Si abres 10 conexiones al mismo tiempo, ¡será 10 veces más rápido! Además, también puede aprovechar la función sin bloqueo del procesamiento por lotes de cURL para manejar una gran cantidad de solicitudes de URL sin bloquear sus scripts web.
Algunas otras opciones útiles de cURL
Autenticación HTTP Si una solicitud de URL requiere autenticación basada en HTTP, puede utilizar el siguiente código:
$url = " http://www.somesite.com/members/ ";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
//Enviar usuario y contraseña
curl_setopt($ch, CURLOPT_USERPWD, "minombredeusuario:micontraseña");
// Puedes permitir que redirija
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
// Las siguientes opciones permiten que cURL
// También puede enviar nombre de usuario y contraseña
curl_setopt($ch, CURLOPT_UNRESTRICTED_AUTH, 1);
$salida = curl_exec($ch);
curl_close($ch);carga FTP
PHP viene con su propia biblioteca FTP, pero también puedes usar cURL:
//Abrir un puntero de archivo
$archivo = fopen("/ruta/al/archivo", "r");
// La URL contiene la mayor parte de la información requerida.
$url = " ftp://nombre de usuario:contraseñ[email protected]:21/ruta/al/nuevo/archivo ";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
//Subir opciones relacionadas
curl_setopt($ch, CURLOPT_UPLOAD, 1);
curl_setopt($ch, CURLOPT_INFILE, $fp);
curl_setopt($ch, CURLOPT_INFILESIZE, tamaño de archivo("/ruta/al/archivo"));
// Si se habilita el modo ASCII (útil al cargar archivos de texto)
curl_setopt($ch, CURLOPT_FTPASCII, 1);
$salida = curl_exec($ch);
curl_close($ch); Para eludir el muro, puede utilizar un proxy para iniciar una solicitud cURL:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,'http://www.example.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
//Especificar dirección de proxy
curl_setopt($ch, CURLOPT_PROXY, '11.11.11.11:8080');
// Proporcione nombre de usuario y contraseña si es necesario
curl_setopt($ch, CURLOPT_PROXYUSERPWD,'usuario:contraseña');
$salida = curl_exec($ch);
curl_close ($ch); la función de devolución de llamada permite a cURL llamar a una función de devolución de llamada específica durante una solicitud de URL. Por ejemplo, comience a utilizar datos tan pronto como se descargue el contenido o la respuesta, en lugar de esperar hasta que se descargue por completo.
$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);
función progreso_función($ch,$cadena) {
eco $cadena;
devolver cadena($cadena);
}Esta función de devolución de llamada debe devolver la longitud de la cadena; de lo contrario, esta función no funcionará correctamente.
Durante el proceso de recepción de la respuesta URL, se llamará a esta función siempre que se reciba un paquete de datos.
Resumen Hoy aprendimos sobre las potentes funciones y la escalabilidad flexible de la biblioteca cURL. Espero que te guste. La próxima vez que quieras realizar una solicitud de URL, ¡considera cURL!
¡Gracias!
Texto original: Inicio rápido con cURL basado en PHP
Texto original en inglés: http://net.tutsplus.com/tutorials/php/techniques-and-resources-for-mastering-curl/
Autor original: Burak Guzel
Se debe conservar la fuente para la reimpresión.