🔄 cURL em PHP
cURL (Client URL Library) é uma extensão do PHP que permite fazer pedidos HTTP de forma flexível e poderosa. É a escolha preferida para consumo profissional de APIs.
Vantagens do cURL
✅ Controlo Total
Controlo granular sobre todos os aspetos do pedido: timeouts, SSL, cookies, redirects, etc.
✅ Suporte Completo
Suporta HTTP, HTTPS, FTP, cookies, autenticação, proxies, uploads de ficheiros.
✅ Debug Detalhado
Informações detalhadas sobre o pedido e resposta para facilitar debugging.
✅ Performance
Mais eficiente e rápido que file_get_contents para múltiplos pedidos.
Verificar se cURL está Instalado
<?php
// Verificar se cURL está disponível
if (function_exists('curl_init')) {
echo "cURL está instalado!";
// Ver versão
$version = curl_version();
echo "Versão: " . $version['version'];
} else {
echo "cURL não está instalado. Instale a extensão php-curl.";
}
?>
📝 Uso Básico
O fluxo básico de cURL em PHP segue 4 passos:
Inicializar sessão
Configurar opções
Executar pedido
Fechar sessão
Exemplo Mínimo
<?php
// 1. Inicializar
$ch = curl_init();
// 2. Configurar opções
curl_setopt($ch, CURLOPT_URL, 'https://jsonplaceholder.typicode.com/posts/1');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// 3. Executar
$response = curl_exec($ch);
// 4. Fechar
curl_close($ch);
// Processar resposta
$data = json_decode($response, true);
print_r($data);
?>
⚙️ Opções do cURL
Opções Mais Usadas
| Opção | Descrição | Exemplo |
|---|---|---|
CURLOPT_URL |
URL do pedido | 'https://api.exemplo.com' |
CURLOPT_RETURNTRANSFER |
Retornar resposta em vez de imprimir | true |
CURLOPT_POST |
Definir método POST | true |
CURLOPT_POSTFIELDS |
Dados do body | json_encode($data) |
CURLOPT_HTTPHEADER |
Headers personalizados | ['Content-Type: application/json'] |
CURLOPT_TIMEOUT |
Timeout em segundos | 30 |
CURLOPT_CONNECTTIMEOUT |
Timeout de conexão | 10 |
CURLOPT_FOLLOWLOCATION |
Seguir redirects | true |
CURLOPT_SSL_VERIFYPEER |
Verificar SSL | true |
CURLOPT_USERAGENT |
User Agent | 'MeuApp/1.0' |
Configuração Completa
<?php
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => 'https://api.exemplo.com/endpoint',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 5,
CURLOPT_TIMEOUT => 30,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_SSL_VERIFYHOST => 2,
CURLOPT_USERAGENT => 'MeuApp/1.0',
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Accept: application/json'
]
]);
$response = curl_exec($ch);
curl_close($ch);
?>
🔍 Pedidos GET
GET com Parâmetros
<?php
// Construir URL com parâmetros
$baseUrl = 'https://jsonplaceholder.typicode.com/posts';
$params = [
'userId' => 1,
'_limit' => 5
];
$url = $baseUrl . '?' . http_build_query($params);
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true
]);
$response = curl_exec($ch);
curl_close($ch);
$posts = json_decode($response, true);
foreach ($posts as $post) {
echo $post['title'] . "\n";
}
?>
GET com Headers
<?php
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => 'https://api.exemplo.com/users',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer SEU_TOKEN_AQUI',
'Accept: application/json',
'X-API-Key: sua_api_key'
]
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
?>
📤 Pedidos POST
POST com JSON
<?php
$data = [
'title' => 'Novo Post',
'body' => 'Conteúdo do post',
'userId' => 1
];
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => 'https://jsonplaceholder.typicode.com/posts',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($data),
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Accept: application/json'
]
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 201) {
$result = json_decode($response, true);
echo "Post criado com ID: " . $result['id'];
}
?>
POST com Form Data
<?php
// Dados de formulário
$data = [
'nome' => 'João Silva',
'email' => 'joao@exemplo.com',
'mensagem' => 'Olá, mundo!'
];
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => 'https://api.exemplo.com/contact',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($data) // Converte para form data
]);
$response = curl_exec($ch);
curl_close($ch);
?>
Upload de Ficheiros
<?php
$filePath = '/caminho/para/ficheiro.jpg';
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => 'https://api.exemplo.com/upload',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => [
'file' => new CURLFile($filePath, 'image/jpeg', 'foto.jpg'),
'descricao' => 'Minha foto'
]
]);
$response = curl_exec($ch);
curl_close($ch);
?>
Para upload de ficheiros, usa a classe CURLFile. Não uses @ antes do caminho (deprecated desde PHP 5.5).
🔧 PUT e DELETE
Pedido PUT
<?php
$data = [
'id' => 1,
'title' => 'Título Atualizado',
'body' => 'Conteúdo atualizado',
'userId' => 1
];
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => 'https://jsonplaceholder.typicode.com/posts/1',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PUT', // Método personalizado
CURLOPT_POSTFIELDS => json_encode($data),
CURLOPT_HTTPHEADER => [
'Content-Type: application/json'
]
]);
$response = curl_exec($ch);
curl_close($ch);
?>
Pedido DELETE
<?php
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => 'https://jsonplaceholder.typicode.com/posts/1',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'DELETE'
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200 || $httpCode === 204) {
echo "Recurso eliminado com sucesso!";
}
?>
Pedido PATCH
<?php
// Apenas atualizar o título
$data = [
'title' => 'Novo Título'
];
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => 'https://jsonplaceholder.typicode.com/posts/1',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_POSTFIELDS => json_encode($data),
CURLOPT_HTTPHEADER => [
'Content-Type: application/json'
]
]);
$response = curl_exec($ch);
curl_close($ch);
?>
📋 Obter Headers de Resposta
<?php
$ch = curl_init();
// Variável para armazenar headers
$responseHeaders = [];
curl_setopt_array($ch, [
CURLOPT_URL => 'https://jsonplaceholder.typicode.com/posts',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => true, // Incluir headers na resposta
// Função para processar headers
CURLOPT_HEADERFUNCTION => function($curl, $header) use (&$responseHeaders) {
$len = strlen($header);
$header = explode(':', $header, 2);
if (count($header) < 2) {
return $len;
}
$responseHeaders[strtolower(trim($header[0]))] = trim($header[1]);
return $len;
}
]);
$response = curl_exec($ch);
curl_close($ch);
// Separar body dos headers
$body = substr($response, curl_getinfo($ch, CURLINFO_HEADER_SIZE));
// Headers disponíveis
print_r($responseHeaders);
// Exemplo: ['content-type' => 'application/json', 'x-ratelimit-limit' => '1000']
?>
Informações do Pedido
<?php
// Após curl_exec($ch)
$info = curl_getinfo($ch);
echo "Código HTTP: " . $info['http_code'] . "\n";
echo "Tempo total: " . $info['total_time'] . " segundos\n";
echo "Tamanho download: " . $info['size_download'] . " bytes\n";
echo "Velocidade: " . $info['speed_download'] . " bytes/s\n";
echo "URL final: " . $info['url'] . "\n";
echo "Content-Type: " . $info['content_type'] . "\n";
?>
🚨 Tratamento de Erros
<?php
function curlRequest(string $url, array $options = []) {
$ch = curl_init();
// Opções padrão
$defaultOptions = [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 5,
CURLOPT_SSL_VERIFYPEER => true
];
curl_setopt_array($ch, $defaultOptions + $options);
$response = curl_exec($ch);
// Verificar erros do cURL
if ($response === false) {
$errorCode = curl_errno($ch);
$errorMessage = curl_error($ch);
curl_close($ch);
return [
'success' => false,
'error_code' => $errorCode,
'error_message' => $errorMessage,
'http_code' => 0,
'data' => null
];
}
// Obter informações
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
// Verificar código HTTP
if ($httpCode >= 400) {
return [
'success' => false,
'error_code' => $httpCode,
'error_message' => "HTTP Error: $httpCode",
'http_code' => $httpCode,
'data' => json_decode($response, true)
];
}
return [
'success' => true,
'http_code' => $httpCode,
'data' => json_decode($response, true),
'raw' => $response
];
}
// Uso
$result = curlRequest('https://jsonplaceholder.typicode.com/posts/1');
if ($result['success']) {
echo "Título: " . $result['data']['title'];
} else {
echo "Erro: " . $result['error_message'];
}
?>
Códigos de Erro cURL Comuns
| Código | Constante | Descrição |
|---|---|---|
| 6 | CURLE_COULDNT_RESOLVE_HOST | Não conseguiu resolver o hostname (DNS) |
| 7 | CURLE_COULDNT_CONNECT | Falha ao conectar ao servidor |
| 28 | CURLE_OPERATION_TIMEDOUT | Timeout atingido |
| 35 | CURLE_SSL_CONNECT_ERROR | Erro de conexão SSL |
| 51 | CURLE_PEER_FAILED_VERIFICATION | Certificado SSL inválido |
📦 Classe Wrapper Reutilizável
<?php
class ApiClient {
private string $baseUrl;
private array $defaultHeaders = [];
private int $timeout = 30;
public function __construct(string $baseUrl = '') {
$this->baseUrl = $baseUrl;
}
public function setHeaders(array $headers): self {
$this->defaultHeaders = $headers;
return $this;
}
public function setTimeout(int $seconds): self {
$this->timeout = $seconds;
return $this;
}
public function get(string $endpoint, array $params = []): array {
$url = $this->baseUrl . $endpoint;
if (!empty($params)) {
$url .= '?' . http_build_query($params);
}
return $this->request('GET', $url);
}
public function post(string $endpoint, array $data = []): array {
return $this->request('POST', $this->baseUrl . $endpoint, $data);
}
public function put(string $endpoint, array $data = []): array {
return $this->request('PUT', $this->baseUrl . $endpoint, $data);
}
public function delete(string $endpoint): array {
return $this->request('DELETE', $this->baseUrl . $endpoint);
}
private function request(string $method, string $url, array $data = []): array {
$ch = curl_init();
$options = [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => $this->timeout,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => array_merge(
['Content-Type: application/json', 'Accept: application/json'],
$this->defaultHeaders
)
];
if (in_array($method, ['POST', 'PUT', 'PATCH']) && !empty($data)) {
$options[CURLOPT_POSTFIELDS] = json_encode($data);
}
curl_setopt_array($ch, $options);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
return [
'success' => $response !== false && $httpCode < 400,
'status' => $httpCode,
'data' => json_decode($response, true),
'error' => $error
];
}
}
// Uso
$api = new ApiClient('https://jsonplaceholder.typicode.com');
// GET
$result = $api->get('/posts/1');
print_r($result['data']);
// POST
$newPost = $api->post('/posts', [
'title' => 'Meu Post',
'body' => 'Conteúdo',
'userId' => 1
]);
?>
📝 Exercícios
Exercício 1: GET com cURL
Desafio: Usa cURL para obter todos os posts do utilizador ID 3 da API JSONPlaceholder.
<?php
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => 'https://jsonplaceholder.typicode.com/posts?userId=3',
CURLOPT_RETURNTRANSFER => true
]);
$response = curl_exec($ch);
curl_close($ch);
$posts = json_decode($response, true);
foreach ($posts as $post) {
echo $post['title'] . "\n";
}
?>
Exercício 2: POST com Tratamento de Erros
Desafio: Cria um pedido POST que trata erros de conexão e mostra o código HTTP.
<?php
$data = ['title' => 'Teste', 'body' => 'Conteúdo', 'userId' => 1];
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => 'https://jsonplaceholder.typicode.com/posts',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($data),
CURLOPT_HTTPHEADER => ['Content-Type: application/json']
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($response === false) {
echo "Erro cURL: " . curl_error($ch);
} elseif ($httpCode >= 400) {
echo "Erro HTTP: $httpCode";
} else {
$result = json_decode($response, true);
echo "Post criado! ID: " . $result['id'];
}
curl_close($ch);
?>