Curl - это библиотека для работы с URL. Умеет она получить на вход URL и дополнительные параметры, произвести запрос и вернуть ответ. Работает CURL с множеством протоколов, таких как http, ftp и другие. Интегрирован CURL во множество языков, в том числе и в PHP. Работа с cURL осуществляется в 4 основных вызова:

$curl = curl_init($url);
curl_setopt($curl, опция, значение); //для настройки дополнительных опций
$response = curl_exec($curl);
curl_close($curl);

Список возможных опций довольно большой, но есть так же и необходимые для ежедневной работы опции:

  • curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); //чтобы получить ответ сервера в переменную $response
  • curl_setopt($curl, CURLOPT_HEADER, true); //чтобы получить в нее же еще и заголовки ответа
  • curl_setopt($curl, CURLOPT_TIMEOUT, 30); //таймаут выполнения запроса. 30 секунд - величина большая. Рекомендуется выставлять это число в значение 15 или менее.
  • curl_setopt($curl, CURLOPT_CONNECTTIMEOUT_MS, 1000); //время открытия соединения. Для локальной сети может быть выставленно от 100 до 3000 милисекунд, большие значения бессмысленны. Для удаленного сервера, доступного через сеть Интернет, от 3000 до 10000.
  • curl_setopt($curl, CURLOPT_HTTPHEADER, [ 'X-Client-Header: value' ]); //заголовки запроса, передаются в виде массива

На что следует обратить внимание?

  • на содержимое curl_error()
  • на код HTTP-ответа
  • на содержимое заголовка ответа Location. Даже клиенты API, неспособные обработать редирект, убоги: неудобны и бывает, что внезапно ломаются (угадайте, когда)

Мы написали готовый trait для работы с http/https ссылками с помощью cURL:


namespace app\features;

trait Curl
{

    protected function __curl(array $headers, $url, $method, $body='', $config=[])
    {
        $ch = curl_init();
        if ($method == 'POST') {
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
        }

        $default_config = [
            'connect_timeout' => 3,
            'dns_cache_timeout' => 3,
            'full_timeout' => 30,
            'UA' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36',
        ];
        $config = array_merge($default_config, $config);

        curl_setopt($ch, CURLOPT_HEADER, 1);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_USERAGENT, $config['UA']);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $config['connect_timeout']);
        curl_setopt($ch, CURLOPT_DNS_CACHE_TIMEOUT, $config['dns_cache_timeout']);
        curl_setopt($ch, CURLOPT_TIMEOUT, $config['full_timeout']);
        $response = curl_exec($ch);

        $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
        $header = substr($response, 0, $header_size);
        $body = substr($response, $header_size);
	$errors = curl_error($ch);
        curl_close($ch);
        $headers_raw = explode("\r\n", $header);
	$status_row = array_shift($headers_raw);
	$status = explode(' ', $status_row)[1];
        $headers = [];
        foreach ($headers_raw as $header) {
            @list($k, $v) = explode(': ', $header);
            $headers[$k] = $v;
        }
        return [$errors, $status, $headers, $body];
    }

}

И, собственно, пример использования на основе Yii2. Для начала создаем директорию features и кладем в нее файл Curl.php. В разделе конфигурации params создаем вхождение для настройки curl:

    ...
    'curl' => [
        'connect_timeout' => 3,
        'dns_cache_timeout' => 3,
        'full_timeout' => 45,
        'UA' => 'MyApplication/1.0 Curl/X.X', //можно вписать свой, удобный User-Agent
    ],
    ...

В нужном нам классе подключаем его:

use \app\features\Curl; //Оставляю полный путь к namespace для простоты

и используем в нужном нам методе:

list($errors, $status, $headers, $body) = $this->__curl([], 'http://example.com/', 'GET', '', \Yii::$app->params['curl']);

В итоге получился удобный для использования в одну строчку клиент, с минимальным набором функций для работы с http/https. Кстати, его можно использовать и с basic-авторизацией:

$auth_header = 'Authorization: Basic ' . base64_encode($user . ":" . $password);
list($errors, $status, $headers, $body) = $this->__curl([ $auth_header ], 'http://example.com/', 'GET', '', \Yii::$app->params['curl']);

Использовать для получения ответов из json API его тоже просто:

list($errors, $status, $headers, $body) = $this->__curl([ $auth_header ], 'http://example.com/', 'GET', '', \Yii::$app->params['curl']);
if (empty($errors) && ($status == '200')) {
     $json = json_decode($body, true);
}

Так сложилось, что иногда проще написать статью и дать на нее ссылку, чем пояснять в чате новым коллегам, что и почему. Это была очередная статья из цикла "в помощь разработчику", она претендует на уклон в удобство кода и учет мелочей, но ни коим образом не на  роль универсального мопеда с крыльями. Таких статей здесь будет всё больше и больше, разного уровня и разной направленности.