PHP Curl Class упрощает отправку HTTP-запросов и интеграцию с веб-API.

https://github.com/php-curl-class/php-curl-class

Установка

Чтобы установить класс PHP Curl, просто:

$ composer require php-curl-class/php-curl-class

Для последней версии фиксации:

$ composer require php-curl-class/php-curl-class @dev

Требования

PHP Curl Class работает с PHP 5.3, 5.4, 5.5, 5.6, 7.0, 7.1, 7.2 и HHVM.

Быстрый старт и примеры

Дополнительные примеры доступны в /примерах.

require __DIR__ . '/vendor/autoload.php';

use \Curl\Curl;

$curl = new Curl();
$curl->get('https://www.example.com/');

if ($curl->error) {
    echo 'Error: ' . $curl->errorCode . ': ' . $curl->errorMessage . "\n";
} else {
    echo 'Response:' . "\n";
    var_dump($curl->response);
}
// https://www.example.com/search?q=keyword
$curl = new Curl();
$curl->get('https://www.example.com/search', array(
    'q' => 'keyword',
));
$curl = new Curl();
$curl->post('https://www.example.com/login/', array(
    'username' => 'myusername',
    'password' => 'mypassword',
));
$curl = new Curl();
$curl->setBasicAuthentication('username', 'password');
$curl->setUserAgent('MyUserAgent/0.0.1 (+https://www.example.com/bot.html)');
$curl->setReferrer('https://www.example.com/url?url=https%3A%2F%2Fwww.example.com%2F');
$curl->setHeader('X-Requested-With', 'XMLHttpRequest');
$curl->setCookie('key', 'value');
$curl->get('https://www.example.com/');

if ($curl->error) {
    echo 'Error: ' . $curl->errorCode . ': ' . $curl->errorMessage . "\n";
} else {
    echo 'Response:' . "\n";
    var_dump($curl->response);
}

var_dump($curl->requestHeaders);
var_dump($curl->responseHeaders);
$curl = new Curl();
$curl->setOpt(CURLOPT_FOLLOWLOCATION, true);
$curl->get('https://shortn.example.com/bHbVsP');
$curl = new Curl();
$curl->put('https://api.example.com/user/', array(
    'first_name' => 'Zach',
    'last_name' => 'Borboa',
));
$curl = new Curl();
$curl->patch('https://api.example.com/profile/', array(
    'image' => '@path/to/file.jpg',
));
$curl = new Curl();
$curl->patch('https://api.example.com/profile/', array(
    'image' => new CURLFile('path/to/file.jpg'),
));
$curl = new Curl();
$curl->delete('https://api.example.com/user/', array(
    'id' => '1234',
));
// Включить все поддерживаемые типы кодировки и загрузите файл.
$curl = new Curl();
$curl->setOpt(CURLOPT_ENCODING , '');
$curl->download('https://www.example.com/file.bin', '/tmp/myfile.bin');
// Нечувствительный к регистру доступ к заголовкам.
$curl = new Curl();
$curl->download('https://www.example.com/image.png', '/tmp/myimage.png');
echo $curl->responseHeaders['Content-Type'] . "\n"; // image/png
echo $curl->responseHeaders['CoNTeNT-TyPE'] . "\n"; // image/png
// Очистить.
$curl->close();
// Пример доступа к объекту curl.
curl_set_opt($curl->curl, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1');
curl_close($curl->curl);
require __DIR__ . '/vendor/autoload.php';

use \Curl\MultiCurl;

// Запросы параллельно с функциями обратного вызова.
$multi_curl = new MultiCurl();

$multi_curl->success(function($instance) {
    echo 'вызов "' . $instance->url . '"был удачный.' . "\n";
    echo 'ответ:' . "\n";
    var_dump($instance->response);
});
$multi_curl->error(function($instance) {
    echo 'call to "' . $instance->url . '" was unsuccessful.' . "\n";
    echo 'код ошибки: ' . $instance->errorCode . "\n";
    echo 'сообщение об ошибке: ' . $instance->errorMessage . "\n";
});
$multi_curl->complete(function($instance) {
    echo 'вызов завершен' . "\n";
});

$multi_curl->addGet('https://www.google.com/search', array(
    'q' => 'hello world',
));
$multi_curl->addGet('https://duckduckgo.com/', array(
    'q' => 'hello world',
));
$multi_curl->addGet('https://www.bing.com/search', array(
    'q' => 'hello world',
));

$multi_curl->start(); // Blocks until all items in the queue have been processed.

Дополнительные примеры доступны в разделе /образцы.

Имеющиеся методы

Curl::__construct($base_url = null)
Curl::__destruct()
Curl::__get($name)
Curl::attemptRetry()
Curl::beforeSend($callback)
Curl::buildPostData($data)
Curl::call()
Curl::close()
Curl::complete($callback)
Curl::delete($url, $query_parameters = array(), $data = array())
Curl::download($url, $mixed_filename)
Curl::error($callback)
Curl::exec($ch = null)
Curl::execDone()
Curl::get($url, $data = array())
Curl::getAttempts()
Curl::getBeforeSendCallback()
Curl::getCompleteCallback()
Curl::getCookie($key)
Curl::getCurl()
Curl::getCurlErrorCode()
Curl::getCurlErrorMessage()
Curl::getDownloadCompleteCallback()
Curl::getDownloadFileName()
Curl::getErrorCallback()
Curl::getErrorCode()
Curl::getErrorMessage()
Curl::getFileHandle()
Curl::getHttpErrorMessage()
Curl::getHttpStatusCode()
Curl::getId()
Curl::getInfo($opt = null)
Curl::getJsonDecoder()
Curl::getOpt($option)
Curl::getRawResponse()
Curl::getRawResponseHeaders()
Curl::getRemainingRetries()
Curl::getRequestHeaders()
Curl::getResponse()
Curl::getResponseCookie($key)
Curl::getResponseCookies()
Curl::getResponseHeaders()
Curl::getRetries()
Curl::getRetryDecider()
Curl::getSuccessCallback()
Curl::getUrl()
Curl::getXmlDecoder()
Curl::head($url, $data = array())
Curl::isChildOfMultiCurl()
Curl::isCurlError()
Curl::isError()
Curl::isHttpError()
Curl::options($url, $data = array())
Curl::patch($url, $data = array())
Curl::post($url, $data = '', $follow_303_with_post = false)
Curl::progress($callback)
Curl::put($url, $data = array())
Curl::removeHeader($key)
Curl::reset()
Curl::search($url, $data = array())
Curl::setBasicAuthentication($username, $password = '')
Curl::setConnectTimeout($seconds)
Curl::setCookie($key, $value)
Curl::setCookieFile($cookie_file)
Curl::setCookieJar($cookie_jar)
Curl::setCookieString($string)
Curl::setCookies($cookies)
Curl::setDefaultDecoder($mixed = 'json')
Curl::setDefaultJsonDecoder()
Curl::setDefaultTimeout()
Curl::setDefaultUserAgent()
Curl::setDefaultXmlDecoder()
Curl::setDigestAuthentication($username, $password = '')
Curl::setHeader($key, $value)
Curl::setHeaders($headers)
Curl::setJsonDecoder($mixed)
Curl::setMaxFilesize($bytes)
Curl::setOpt($option, $value)
Curl::setOpts($options)
Curl::setPort($port)
Curl::setProxy($proxy, $port = null, $username = null, $password = null)
Curl::setProxyAuth($auth)
Curl::setProxyTunnel($tunnel = true)
Curl::setProxyType($type)
Curl::setReferer($referer)
Curl::setReferrer($referrer)
Curl::setRetry($mixed)
Curl::setTimeout($seconds)
Curl::setUrl($url, $mixed_data = '')
Curl::setUserAgent($user_agent)
Curl::setXmlDecoder($mixed)
Curl::success($callback)
Curl::unsetHeader($key)
Curl::unsetProxy()
Curl::verbose($on = true, $output = STDERR)
MultiCurl::__construct($base_url = null)
MultiCurl::__destruct()
MultiCurl::addCurl(Curl $curl)
MultiCurl::addDelete($url, $query_parameters = array(), $data = array())
MultiCurl::addDownload($url, $mixed_filename)
MultiCurl::addGet($url, $data = array())
MultiCurl::addHead($url, $data = array())
MultiCurl::addOptions($url, $data = array())
MultiCurl::addPatch($url, $data = array())
MultiCurl::addPost($url, $data = '', $follow_303_with_post = false)
MultiCurl::addPut($url, $data = array())
MultiCurl::addSearch($url, $data = array())
MultiCurl::beforeSend($callback)
MultiCurl::close()
MultiCurl::complete($callback)
MultiCurl::error($callback)
MultiCurl::getOpt($option)
MultiCurl::removeHeader($key)
MultiCurl::setBasicAuthentication($username, $password = '')
MultiCurl::setConcurrency($concurrency)
MultiCurl::setConnectTimeout($seconds)
MultiCurl::setCookie($key, $value)
MultiCurl::setCookieFile($cookie_file)
MultiCurl::setCookieJar($cookie_jar)
MultiCurl::setCookieString($string)
MultiCurl::setCookies($cookies)
MultiCurl::setDigestAuthentication($username, $password = '')
MultiCurl::setHeader($key, $value)
MultiCurl::setHeaders($headers)
MultiCurl::setJsonDecoder($mixed)
MultiCurl::setOpt($option, $value)
MultiCurl::setOpts($options)
MultiCurl::setPort($port)
MultiCurl::setReferer($referer)
MultiCurl::setReferrer($referrer)
MultiCurl::setRetry($mixed)
MultiCurl::setTimeout($seconds)
MultiCurl::setUrl($url)
MultiCurl::setUserAgent($user_agent)
MultiCurl::setXmlDecoder($mixed)
MultiCurl::start()
MultiCurl::success($callback)
MultiCurl::unsetHeader($key)
MultiCurl::verbose($on = true, $output = STDERR)

Соображения безопасности.

Url может указывать на системные файлы.

  • Слепо не принимать ссылки от пользователей, поскольку они могут указывать на системные файлы. Curl поддерживает множество протоколов, включая FILE. Ниже показано содержимое файла file:///etc/passwd
# Атакующий.
$ curl https://www.example.com/display_webpage.php?url=file%3A%2F%2F%2Fetc%2Fpasswd
// display_webpage.php
$url = $_GET['url']; // DANGER!
$curl = new Curl();
$curl->get($url);
echo $curl->response;

Более безопасный:

function is_allowed_url($url, $allowed_url_schemes = array('http', 'https')) {
    $valid_url = filter_var($url, FILTER_VALIDATE_URL, FILTER_FLAG_SCHEME_REQUIRED | FILTER_FLAG_HOST_REQUIRED) !== false;
    if ($valid_url) {
        $scheme = parse_url($url, PHP_URL_SCHEME);
        return in_array($scheme, $allowed_url_schemes, true);
    }
    $valid_ip = filter_var($url, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false;
    return $valid_ip;
}

$url = $_GET['url'];
if (!is_allowed_url($url)) {
    die('Unsafe url detected.');
}

URL-адрес может указывать на внутренние URL-адреса.

  • Url-адрес может указывать на внутренние URL-адреса, в том числе за брандмауэром (например http://192.168.0.1 / или ftp://192.168.0.1/). Используйте белый список, чтобы разрешить определенные URL, а не черный список.

Данные запроса могут относиться к системным файлам.

  • Данные запроса с префиксом @ могут иметь специальную интерпретацию и считываться из системных файлов.
# Атакующий.
$ curl https://www.example.com/upload_photo.php --data "photo=@/etc/passwd"
// upload_photo.php
$curl = new Curl();
$curl->post('http://www.anotherwebsite.com/', array(
    'photo' => $_POST['photo'], // DANGER!
));

Небезопасный ответ с включенным перенаправлением.

  • Запросы с включенным перенаправлением могут возвращать ответы из неожиданных источников. Загрузка https://www.example.com/image.png может редирект и скачать https://www.evil.com/virus.exe
$curl = new Curl();
$curl->setOpt(CURLOPT_FOLLOWLOCATION, true); // DANGER!
$curl->download('https://www.example.com/image.png', 'my_image.png');
$curl = new Curl();
$curl->setOpt(CURLOPT_FOLLOWLOCATION, true); // DANGER!
$curl->get('https://www.example.com/image.png');

Держите SSL защита включеной.

  • Не отключайте защиту SSL.
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // DANGER!
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // DANGER!

Предотвращение внедрения внешней сущности XML.

  • Задайте следующие параметры при использовании парсера PHP XML по умолчанию, чтобы предотвратить внедрение внешних XML-объектов.
libxml_disable_entity_loader(true);

Выполнить тесты.

Для запуска тестов:

$ git clone https://github.com/php-curl-class/php-curl-class.git
$ cd php-curl-class/
$ composer update
$ ./tests/run.sh

Чтобы проверить все версии PHP в контейнерах:

$ git clone https://github.com/php-curl-class/php-curl-class.git
$ cd php-curl-class/
$ ./tests/test_all.sh