PHP cURL: GET и POST запросы, JSON и загрузка файлов (понятное руководство)
Запросы к внешним сервисам — повседневная задача в PHP. Да, можно пользоваться file_get_contents, но для реальной разработки лучше применять cURL: он управляет заголовками, таймаутами, SSL, редиректами, позволяет отправлять JSON и файлы, а также выполнять запросы параллельно.
Проверка и быстрый старт
<?php
if (!extension_loaded('curl')) {
die('Расширение cURL не установлено');
}
$ch = curl_init('https://httpbin.org/get?hello=world');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true, // вернуть ответ как строку
CURLOPT_TIMEOUT => 10, // общий таймаут (сек)
CURLOPT_CONNECTTIMEOUT => 5, // таймаут соединения (сек)
]);
$response = curl_exec($ch);
if ($response === false) {
throw new RuntimeException('cURL error: ' . curl_error($ch));
}
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) {
throw new RuntimeException("HTTP статус: {$httpCode}");
}
$data = json_decode($response, true);
print_r($data);
Так вы выполняете простой GET-запрос и безопасно обрабатываете ошибки и HTTP-статус.
POST запрос: форма (application/x-www-form-urlencoded)
<?php
$url = 'https://httpbin.org/post';
$post = [
'email' => 'user@example.com',
'name' => 'Ivan',
];
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($post),
CURLOPT_HTTPHEADER => [
'Content-Type: application/x-www-form-urlencoded; charset=UTF-8'
],
CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
if ($response === false) {
throw new RuntimeException('cURL error: ' . curl_error($ch));
}
curl_close($ch);
echo $response;
Совет: всегда используйте http_build_query — он корректно кодирует данные и спецсимволы.
Отправка и приём JSON
<?php
$url = 'https://httpbin.org/post';
$payload = [
'title' => 'Привет, мир',
'tags' => ['php', 'curl']
];
$json = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $json,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Accept: application/json',
'User-Agent: MyApp/1.0'
],
CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
if ($response === false) {
throw new RuntimeException('cURL error: ' . curl_error($ch));
}
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($http < 200 || $http >= 300) {
throw new RuntimeException("HTTP статус: {$http}, тело: {$response}");
}
$data = json_decode($response, true, 512, JSON_THROW_ON_ERROR);
print_r($data);
Важно: задавайте правильные заголовки Content-Type и Accept. Для Unicode используйте JSON_UNESCAPED_UNICODE, а для строгой обработки — JSON_THROW_ON_ERROR.
Чтение ответа: заголовки, код статуса, редиректы
<?php
$url = 'https://httpbin.org/redirect-to?url=https%3A%2F%2Fexample.com';
$headers = [];
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_FOLLOWLOCATION => true, // идти за редиректами
CURLOPT_MAXREDIRS => 5,
CURLOPT_HEADERFUNCTION => function($ch, $headerLine) use (&$headers) {
$len = strlen($headerLine);
$parts = explode(':', $headerLine, 2);
if (count($parts) === 2) {
$headers[trim($parts[0])] = trim($parts[1]);
}
return $len; // важно вернуть длину
},
CURLOPT_RETURNTRANSFER => true,
]);
$body = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$finalUrl = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
curl_close($ch);
echo "HTTP: {$httpCode}\nURL: {$finalUrl}\n";
print_r($headers);
Так вы получите конечный URL после редиректов, заголовки и статус.
SSL: безопасность по умолчанию
По умолчанию cURL проверяет SSL-сертификат. Не отключайте проверку без необходимости!
<?php
$ch = curl_init('https://example.com');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
// Не делайте так в продакшене, только для диагностики:
// CURLOPT_SSL_VERIFYPEER => false,
// CURLOPT_SSL_VERIFYHOST => 0,
]);
$response = curl_exec($ch);
if ($response === false) {
throw new RuntimeException(curl_error($ch));
}
curl_close($ch);
Если возникает ошибка сертификации, проверьте корневые сертификаты на сервере (CA bundle).
Загрузка файлов (multipart/form-data)
<?php
$url = 'https://httpbin.org/post';
$filePath = __DIR__ . '/logo.png';
if (!file_exists($filePath)) {
throw new RuntimeException('Файл не найден');
}
$fields = [
'file' => new CURLFile($filePath, 'image/png', 'logo.png'),
'title' => 'Логотип'
];
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $fields, // cURL сам выставит multipart
CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
if ($response === false) {
throw new RuntimeException(curl_error($ch));
}
curl_close($ch);
echo $response;
Используйте класс CURLFile — это безопаснее и чище, чем префикс @ в старых версиях.
Таймауты и повторные попытки (retry с бэкоффом)
<?php
function http_get_with_retry(string $url, int $retries = 3): string {
$delay = 200; // миллисекунды
for ($i = 0; $i <= $retries; $i++) {
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT_MS => 1500,
CURLOPT_TIMEOUT_MS => 3000,
]);
$body = curl_exec($ch);
$err = curl_error($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($body !== false && $code >= 200 && $code < 500) {
return $body; // для 2xx и 3xx возвращаем ответ
}
// 5xx, timeouts, network — ждём и повторяем
usleep($delay * 1000);
$delay = min($delay * 2, 3000);
}
throw new RuntimeException('Не удалось получить ответ: ' . ($err ?: 'unknown'));
}
Не забывайте ставить разумные таймауты и ограничение на количество повторов.
Отладка cURL
<?php
$ch = curl_init('https://httpbin.org/get');
$stream = fopen('php://temp', 'w+');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_VERBOSE => true, // включает подробный лог
CURLOPT_STDERR => $stream, // куда писать лог
]);
curl_exec($ch);
rewind($stream);
$debug = stream_get_contents($stream);
fclose($stream);
curl_close($ch);
echo "DEBUG:\n" . $debug;
CURLOPT_VERBOSE покажет низкоуровневый обмен, что удобно при диагностике SSL и заголовков.
Параллельные запросы: curl_multi
<?php
$urls = [
'https://httpbin.org/delay/1',
'https://httpbin.org/delay/2',
];
$multi = curl_multi_init();
$chs = [];
foreach ($urls as $u) {
$ch = curl_init($u);
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 5]);
curl_multi_add_handle($multi, $ch);
$chs[] = $ch;
}
do {
$status = curl_multi_exec($multi, $running);
curl_multi_select($multi);
} while ($running && $status == CURLM_OK);
foreach ($chs as $ch) {
echo curl_getinfo($ch, CURLINFO_EFFECTIVE_URL) . " - HTTP " . curl_getinfo($ch, CURLINFO_HTTP_CODE) . "\n";
curl_multi_remove_handle($multi, $ch);
curl_close($ch);
}
curl_multi_close($multi);
curl_multi позволяет существенно ускорить работу при большом числе независимых запросов.
Типичные ошибки и рекомендации
- Не забывайте CURLOPT_RETURNTRANSFER, иначе echo перехватит ответ и смешает его с HTML.
- Для форм — http_build_query, для JSON — json_encode + корректные заголовки.
- Используйте таймауты и ретраи; логируйте код ответа и URL.
- Не отключайте SSL-проверку в продакшене. Исправляйте корневые сертификаты.
- Закрывайте ресурсы: curl_close и curl_multi_close.
Что дальше?
Освоили основы cURL — сделайте следующий шаг: подключение к БД, авторизация, работа с файлами и деплой. Посмотрите практический курс с проектами и домашками — Прокачать PHP и MySQL на практике →.
Теперь у вас есть рабочий набор приёмов: GET и POST запросы, JSON, загрузка файлов, заголовки, SSL, таймауты, отладка и параллельные вызовы. Этого достаточно, чтобы уверенно интегрировать внешние API в ваши PHP‑проекты.
-
Создано 24.04.2026 17:01:08
-
Михаил Русаков

Комментарии (0):
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.