cURL é uma ferramenta que usa sintaxe de URL para transferir arquivos e dados. Suporta vários protocolos, como HTTP, FTP, TELNET, etc. A melhor coisa é que o php também suporta a biblioteca cURL. Este artigo apresentará alguns recursos avançados do cURL e como usá-lo em PHP.
Por que usar cURL?
Sim, podemos obter conteúdo da web através de outros métodos. Na maioria das vezes, porque quero ser preguiçoso, apenas uso uma função php simples:
$content = file_get_contents(" http://www.bizhicool.com ");
// ou
$linhas = arquivo(" http://www.bizhicool.com ");
// ou
readfile( http://www.bizhicool.com ); No entanto, esta abordagem carece de flexibilidade e tratamento eficaz de erros. Além disso, você não pode usá-lo para realizar algumas tarefas difíceis – como manipulação de cookies, validação, envio de formulários, upload de arquivos, etc.
cURL é uma biblioteca poderosa que suporta muitos protocolos e opções diferentes e pode fornecer vários detalhes relacionados a solicitações de URL.
Estrutura Básica Antes de aprender sobre funções mais complexas, vamos dar uma olhada nas etapas básicas de configuração de uma solicitação cURL em PHP:
Inicialize, defina variáveis, execute e obtenha resultados, libere o identificador cURL
// 1. Inicialização
$ch = curl_init();
// 2. Defina opções, incluindo URL
curl_setopt($ch, CURLOPT_URL, " http://www.bizhicool.com ");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
// 3. Execute e obtenha o conteúdo do documento HTML
$saída = curl_exec($ch);
// 4. Solte a alça de curvatura
curl_close($ch); O segundo passo (ou seja, curl_setopt()) é o mais importante, e todo o mistério está aqui. Há uma longa lista de parâmetros cURL que podem ser definidos e especificam vários detalhes da solicitação de URL. Pode ser difícil lê-los e compreendê-los todos de uma vez, por isso hoje tentaremos apenas as opções mais comuns e úteis.
Verificando erros Você pode adicionar uma instrução para verificar erros (embora isso não seja obrigatório):
// ...
$saída = curl_exec($ch);
if ($saída === FALSO) {
echo "Erro cURL: ". curl_error($ch);
}
// ...Observe que usamos "=== FALSE" em vez de "== FALSE" ao comparar. Porque temos que distinguir entre a saída vazia e o valor booleano FALSE, que é o erro real.
Obter informações Esta é outra configuração opcional que pode obter informações sobre esta solicitação após a execução do cURL:
// ...
curl_exec($ch);
$info = curl_getinfo($ch);
echo 'Obter'. $info['url'] . 'Demora' $info['total_time'] .
// ...o array retornado inclui as seguintes informações:
"url" //Endereço de rede do recurso
"content_type" //Codificação de conteúdo
"http_code" //Código de status HTTP
"header_size" //O tamanho do cabeçalho
"request_size" //Tamanho da solicitação
"filetime" //Hora de criação do arquivo
"ssl_verify_result" //resultado da verificação SSL
"redirect_count" //Tecnologia de salto
"total_time" //Tempo total gasto
"namelookup_time" //Tempo de consulta DNS
"connect_time" //Aguardando tempo de conexão
"pretransfer_time" //O tempo de preparação antes da transmissão
"size_upload" //O tamanho dos dados enviados
"size_download" //O tamanho dos dados baixados
"speed_download" //Velocidade de download
"speed_upload" //Velocidade de upload
"download_content_length" //A duração do conteúdo do download
"upload_content_length" //O comprimento do conteúdo enviado
"starttransfer_time" //Hora de iniciar a transferência
"redirect_time" //O redirecionamento leva tempo Redirecionamento baseado em navegador No primeiro exemplo, forneceremos um trecho de código que detecta se o servidor possui um redirecionamento baseado em navegador. Por exemplo, alguns sites redirecionam páginas da web com base no navegador móvel ou mesmo no país de origem do usuário.
Usamos a opção CURLOPT_HTTPHEADER para definir os cabeçalhos de solicitação HTTP que enviamos (cabeçalhos http), incluindo informações do agente do usuário e idioma padrão. Então veremos se esses sites específicos nos redirecionam para URLs diferentes.
//URL para teste
$urls = array(
" http://www.cnn.com ",
" http://www.mozilla.com ",
" http://www.facebook.com "
);
//Informações do navegador para teste
$navegadores = array(
"padrão" => 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) Versão/3.0 Mobile/1A537a Safari/419.3",
"idioma" => "pt"
),
"francês" => matriz (
"user_agent" => "Mozilla/4.0 (compatível; MSIE 7.0; Windows NT 5.1; GTB6; .NET CLR 2.0.50727)",
"idioma" => "fr,fr-FR;q=0,5"
)
);
foreach ($urls como $url){
echo "URL: $urln";
foreach ($navegadores as $test_name => $navegador) {
$ch = curl_init();
//Definir url
curl_setopt($ch, CURLOPT_URL, $url);
//Definir cabeçalhos específicos do navegador
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"User-Agent: {$browser['user_agent']}",
"Aceitar-Idioma: {$browser['idioma']}"
));
// Não precisamos do conteúdo da página
curl_setopt($ch, CURLOPT_NOBODY, 1);
// Apenas retorne o cabeçalho HTTP
curl_setopt($ch, CURLOPT_HEADER, 1);
// Retorna o resultado em vez de imprimi-lo
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$saída = curl_exec($ch);
curl_close($ch);
// Existe alguma informação de cabeçalho HTTP para redirecionamento?
if (preg_match("!Local: (.*)!", $output, $matches)) {
echo "$test_name: redireciona para $matches[1]n";
} outro {
echo "$test_name: sem redirecionamenton";
}
}
eco "nn";
}Primeiro, criamos um conjunto de URLs que precisam ser testados e, em seguida, especificamos um conjunto de informações do navegador que precisam ser testadas. Finalmente, um loop é usado para testar várias situações de correspondência de URL e navegador que podem ocorrer.
Como especificamos a opção cURL, a saída retornada inclui apenas informações do cabeçalho HTTP (armazenadas em $output). Usando uma regra regular simples, verificamos se as informações do cabeçalho contêm a palavra "Local:".
A execução deste código deve retornar os seguintes resultados:
Envio de dados usando o método POST Ao fazer uma solicitação GET, os dados podem ser passados para uma URL por meio de uma "query string". Por exemplo, ao pesquisar no Google, a chave de pesquisa faz parte da string de consulta do URL:
http://www.google.com/search?q=nettuts Nesse caso, você provavelmente não precisa de cURL para simular. Jogar este URL para "file_get_contents()" obterá o mesmo resultado.
No entanto, alguns formulários HTML são enviados usando o método POST. Quando este formulário é enviado, os dados são enviados por meio do corpo da solicitação HTTP (corpo da solicitação) em vez da string de consulta. Por exemplo, ao usar o formulário do fórum CodeIgniter, não importa quais palavras-chave você inserir, você sempre será POSTado na seguinte página:
http://codeigniter.com/forums/do_search/ Você pode usar um script PHP para simular esta solicitação de URL. Primeiro, crie um novo arquivo que possa aceitar e exibir dados POST. Chamamos-lhe post_output.php:
print_r($_POST); Em seguida, escreva um script PHP para realizar a solicitação cURL:
$url = " http://localhost/post_output.php ";
$post_data = array (
"foo" => "barra",
"consulta" => "Nettuts",
"ação" => "Enviar"
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// Estamos POSTANDO dados!
curl_setopt($ch, CURLOPT_POST, 1);
//Adiciona a variável de postagem
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
$saída = curl_exec($ch);
curl_close($ch);
echo $output;Após executar o código, você deverá obter os seguintes resultados:
Este script envia uma solicitação POST para post_output.php, a variável $_POST da página e a retorna. Capturamos essa saída usando cURL.
Upload de arquivos O upload de arquivos é muito semelhante ao POST anterior. Porque todos os formulários de upload de arquivos são enviados através do método POST.
Primeiro, crie uma nova página para receber arquivos, chamada upload_output.php:
print_r($_FILES);A seguir está o script que realmente executa a tarefa de upload do arquivo:
$url = " http://localhost/upload_output.php ";
$post_data = array (
"foo" => "barra",
//O endereço do arquivo local a ser carregado
"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);
$saída = curl_exec($ch);
curl_close($ch);
echo $output; Se você precisar fazer upload de um arquivo, basta passar o caminho do arquivo como uma variável post, mas lembre-se de adicionar o símbolo @ na frente. A execução deste script deve resultar na seguinte saída:
Processamento em lote cURL (multi cURL)
cURL também possui um recurso avançado - identificadores de lote. Este recurso permite abrir várias conexões URL simultaneamente ou de forma assíncrona.
Aqui está um exemplo de código do php.net:
//Cria dois recursos cURL
$ch1 = curl_init();
$ch2 = curl_init();
//Especifique URL e parâmetros apropriados
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);
//Cria identificador de lote cURL
$mh = curl_multi_init();
//Adiciona os dois primeiros identificadores de recursos
curl_multi_add_handle($mh,$ch1);
curl_multi_add_handle($mh,$ch2);
// Predefine uma variável de estado
$ativo = nulo;
//Executa processamento em lote
fazer {
$mrc = curl_multi_exec($mh, $ativo);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
while ($ativo && $mrc == CURLM_OK) {
if (curl_multi_select($mh) != -1) {
fazer {
$mrc = curl_multi_exec($mh, $ativo);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
}
}
//Fecha cada alça
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
curl_multi_close($mh); O que você precisa fazer aqui é abrir vários identificadores cURL e atribuí-los a um identificador de lote. Então você apenas espera um loop while para que ele seja concluído.
Existem dois loops principais neste exemplo. O primeiro loop do-while chama curl_multi_exec() repetidamente. Esta função não bloqueia, mas será executada o menos possível. Retorna um valor de status. Desde que esse valor seja igual à constante CURLM_CALL_MULTI_PERFORM, significa que ainda há algum trabalho urgente a ser feito (por exemplo, enviar as informações do cabeçalho http correspondente à URL). Ou seja, precisamos continuar chamando essa função até que o valor de retorno mude.
O loop while seguinte só continuará quando a variável $active for verdadeira. Esta variável foi passada anteriormente para curl_multi_exec() como segundo parâmetro e representa se ainda existem conexões ativas no identificador de lote. Em seguida, chamamos curl_multi_select(), que é "bloqueado" até que ocorra uma conexão ativa (como o recebimento de uma resposta do servidor). Depois que esta função for executada com sucesso, entraremos em outro loop do-while e continuaremos para a próxima URL.
Vamos dar uma olhada em como colocar esse recurso em uso prático:
Verificador de conexão WordPress Imagine que você tem um blog com um grande número de artigos que contém um grande número de links para sites externos. Depois de um tempo, um bom número desses links tornou-se inválido por um motivo ou outro. Ou foi harmonizado ou todo o site foi hackeado...
Vamos criar um script abaixo para analisar todos esses links, descobrir os sites/páginas que não podem ser abertos ou possuem 404 e gerar um relatório.
Observe que o seguinte não é um plug-in WordPress real e funcional, é apenas um script com funções independentes, apenas para demonstração, obrigado.
OK, vamos começar. Primeiro, leia todos estes links do banco de dados:
//CONFIGURAÇÃO
$db_host = 'localhost';
$db_user = 'raiz';
$db_pass = '';
$db_name = 'wordpress';
$excluded_domains = array(
'localhost', 'www.meudominio.com');
$max_conexões = 10;
//Inicializa algumas variáveis
$url_list = array();
$working_urls = array();
$dead_urls=array();
$not_found_urls = array();
$ativo = nulo;
//Conecta ao MySQL
if (!mysql_connect($db_host, $db_user, $db_pass)) {
die('Não foi possível conectar: '. mysql_error());
}
if (!mysql_select_db($db_name)) {
die('Não foi possível selecionar o banco de dados: '. mysql_error());
}
// Encontre todos os artigos com links
$q = "SELECIONE post_content DE wp_posts
ONDE post_content LIKE '%href=%'
E post_status = 'publicar'
AND post_type = 'post'";
$r = mysql_query($q) ou morrer(mysql_error());
enquanto ($d = mysql_fetch_assoc($r)) {
// Use links de correspondência regulares
if (preg_match_all("!href="(.*?)"!", $d['post_content'], $matches)) {
foreach ($correspondências[1] como $url) {
//exclui alguns domínios
$tmp = parse_url($url);
if (in_array($tmp['host'], $excluded_domains)) {
continuar;
}
//armazena a URL
$url_list[]= $url;
}
}
}
//Remove links duplicados
$url_list = array_values(array_unique($url_list));
if (!$url_list){
die('Nenhuma URL para verificar');
}Primeiro configuramos o banco de dados, uma série de nomes de domínio a serem excluídos ($excluded_domains) e o número máximo de conexões simultâneas ($max_connections). Em seguida, conecte-se ao banco de dados, obtenha os artigos e links incluídos e reúna-os em um array ($url_list).
O código abaixo é um pouco complicado, então vou explicá-lo detalhadamente passo a passo:
// 1. Processador em lote
$mh = curl_multi_init();
// 2. Adicione URLs que precisam ser processados em lotes
for ($i = 0; $i < $max_connections; $i++) {
add_url_to_multi_handle($mh, $url_list);
}
// 3. Processamento inicial
fazer {
$mrc = curl_multi_exec($mh, $ativo);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
// 4. Loop principal
while ($ativo && $mrc == CURLM_OK) {
// 5. Existe uma conexão ativa
if (curl_multi_select($mh) != -1) {
// 6. Trabalho
fazer {
$mrc = curl_multi_exec($mh, $ativo);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
// 7. Você tem alguma informação?
if ($mhinfo = curl_multi_info_read($mh)) {
//Significa que a conexão terminou normalmente
// 8. Obtenha informações do identificador curl
$chinfo = curl_getinfo($mhinfo['handle']);
// 9. Link morto?
if (!$chinfo['http_code']) {
$dead_urls[]= $chinfo['url'];
//10.404?
} else if ($chinfo['http_code'] == 404) {
$not_found_urls []= $chinfo['url'];
// 11. Ainda disponível
} outro {
$working_urls []= $chinfo['url'];
}
// 12. Remova o identificador
curl_multi_remove_handle($mh, $mhinfo['handle']);
curl_close($mhinfo['handle']);
// 13. Adicione um novo URL e faça o trabalho
if (add_url_to_multi_handle($mh, $url_list)) {
fazer {
$mrc = curl_multi_exec($mh, $ativo);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
}
}
}
}
// 14. Concluído
curl_multi_close($mh);
echo "==URLs inoperantes==n";
echo implode("n",$dead_urls) "nn";
echo "==404 URLs==n";
echo implode("n",$not_found_urls) "nn";
echo "==URLs funcionais==n";
echo implode("n",$working_urls);
// 15. Adicionar URL ao processador em lote
função add_url_to_multi_handle($mh, $url_list) {
índice estático $ = 0;
// Se a url for deixada, é inútil
if ($url_list[$index]) {
//Cria um novo identificador de curl
$ch = curl_init();
//Configurar url
curl_setopt($ch, CURLOPT_URL, $url_list[$index]);
//Não quero exibir o conteúdo retornado
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// Iremos aonde o redirecionamento nos levar
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
// Nenhum corpo de conteúdo é necessário, o que pode economizar largura de banda e tempo
curl_setopt($ch, CURLOPT_NOBODY, 1);
//Adiciona ao processador em lote
curl_multi_add_handle($mh, $ch);
// Disque o contador e você poderá adicionar a próxima URL na próxima vez que chamar esta função.
$índice++;
retornar verdadeiro;
} outro {
// Nenhum novo URL precisa ser processado
retornar falso;
}
}O código acima é explicado abaixo. Os números de série na lista correspondem aos números sequenciais nos comentários do código.
Crie um novo processador em lote. Criou uma alça múltipla.
Posteriormente criaremos uma função add_url_to_multi_handle() que adiciona URLs ao manipulador de lote. Sempre que esta função é chamada, uma nova URL é adicionada ao processador em lote. Inicialmente, adicionamos 10 URLs ao processador em lote (esse número é determinado por $max_connections).
É necessário executar curl_multi_exec() para fazer o trabalho de inicialização, desde que retorne CURLM_CALL_MULTI_PERFORM ainda há algo a fazer. Isso é feito principalmente para criar a conexão, não espera pela resposta completa do URL.
O loop principal continua enquanto houver conexões ativas no lote.
curl_multi_select() espera até que uma consulta de URL resulte em uma conexão ativa.
O trabalho do cURL está aqui novamente, principalmente para obter dados de resposta.
Confira diversas informações. Quando uma solicitação de URL é concluída, um array é retornado.
Há um identificador cURL na matriz retornada. Nós o usamos para obter as informações correspondentes para uma única solicitação cURL.
Se este for um link inativo ou se a solicitação expirar, nenhum código de status http será retornado.
Se esta página não puder ser encontrada, um código de status 404 será retornado.
Em outros casos, assumimos que este link está disponível (claro, você também pode verificar 500 erros e similares...).
Remova este identificador cURL do lote porque ele não é mais útil, feche-o!
Ótimo, agora você pode adicionar outro URL. Mais uma vez, o trabalho de inicialização começa novamente...
Bem, tudo o que precisa ser feito está feito. Feche o processador em lote e gere o relatório.
Voltemos à função que adiciona uma nova URL ao processador em lote. Cada vez que esta função é chamada, a variável estática $index é incrementada para que possamos saber quantas URLs faltam para serem processadas.
Executei este script no meu blog (preciso de testes, alguns links errados foram adicionados intencionalmente) e os resultados são os seguintes:
Um total de cerca de 40 URLs foram verificados e demorou menos de dois segundos. Quando você precisa verificar um número maior de URLs, o efeito que evita preocupações pode ser imaginado! Se você abrir 10 conexões ao mesmo tempo, será 10 vezes mais rápido! Além disso, você também pode aproveitar o recurso de não bloqueio do processamento em lote cURL para lidar com um grande número de solicitações de URL sem bloquear seus scripts da web.
Algumas outras opções úteis de cURL
Autenticação HTTP Se uma solicitação de URL exigir autenticação baseada em HTTP, você poderá usar o seguinte código:
$url = " http://www.somesite.com/members/ ";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
//Envia usuário e senha
curl_setopt($ch, CURLOPT_USERPWD, "meunomedeusuario:minhasenha");
// Você pode permitir o redirecionamento
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
// As opções a seguir permitem que cURL
// Também pode enviar nome de usuário e senha
curl_setopt($ch, CURLOPT_UNRESTRICTED_AUTH, 1);
$saída = curl_exec($ch);
curl_close($ch);Envio FTP
PHP vem com sua própria biblioteca FTP, mas você também pode usar cURL:
//Abre um ponteiro de arquivo
$arquivo = fopen("/caminho/para/arquivo", "r");
// O URL contém a maioria das informações necessárias
$url = " ftp://nomedeusuário:[email protected]:21/caminho/para/novo/arquivo ";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
//Carregar opções relacionadas
curl_setopt($ch, CURLOPT_UPLOAD, 1);
curl_setopt($ch, CURLOPT_INFILE, $fp);
curl_setopt($ch, CURLOPT_INFILESIZE, filesize("/caminho/para/arquivo"));
// Habilita ou não o modo ASCII (útil ao enviar arquivos de texto)
curl_setopt($ch, CURLOPT_FTPASCII, 1);
$saída = curl_exec($ch);
curl_close($ch); Para contornar o muro, você pode usar um proxy para iniciar uma solicitação cURL:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,'http://www.example.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
//Especifique o endereço do proxy
curl_setopt($ch, CURLOPT_PROXY, '11.11.11.11:8080');
// Forneça nome de usuário e senha se necessário
curl_setopt($ch, CURLOPT_PROXYUSERPWD,'usuário:pass');
$saída = curl_exec($ch);
curl_close ($ch); A função de retorno de chamada permite que cURL chame uma função de retorno de chamada especificada durante uma solicitação de URL. Por exemplo, comece a utilizar os dados assim que o conteúdo ou a resposta for baixado, em vez de esperar até que o download seja 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);
função progress_function($ch,$str) {
eco $str;
retornar strlen($str);
}Esta função de retorno de chamada deve retornar o comprimento da string, caso contrário esta função não funcionará corretamente.
Durante o processo de recepção da resposta URL, esta função será chamada enquanto um pacote de dados for recebido.
Resumo Hoje aprendemos sobre as funções poderosas e a escalabilidade flexível da biblioteca cURL. Espero que você goste. Na próxima vez que você quiser fazer uma solicitação de URL, considere cURL!
Obrigado!
Texto original: Início rápido com cURL baseado em PHP
Texto original em inglês: http://net.tutsplus.com/tutorials/php/techniques-and-resources-for-mastering-curl/
Autor original: Burak Guzel
A fonte deve ser mantida para reimpressão.