matomo
/
app
/
vendor
/
prefixed
/
maxmind
/
web-service-common
/
src
/
WebService
/
Http
/
CurlRequest.php
matomo
/
app
/
vendor
/
prefixed
/
maxmind
/
web-service-common
/
src
/
WebService
/
Http
Last commit date
CurlRequest.php
1 year ago
Request.php
2 years ago
RequestFactory.php
2 years ago
CurlRequest.php
109 lines
| 1 | <?php |
| 2 | |
| 3 | declare (strict_types=1); |
| 4 | namespace Matomo\Dependencies\MaxMind\WebService\Http; |
| 5 | |
| 6 | use Matomo\Dependencies\MaxMind\Exception\HttpException; |
| 7 | /** |
| 8 | * This class is for internal use only. Semantic versioning does not not apply. |
| 9 | * |
| 10 | * @internal |
| 11 | */ |
| 12 | class CurlRequest implements Request |
| 13 | { |
| 14 | /** |
| 15 | * @var \CurlHandle |
| 16 | */ |
| 17 | private $ch; |
| 18 | /** |
| 19 | * @var string |
| 20 | */ |
| 21 | private $url; |
| 22 | /** |
| 23 | * @var array |
| 24 | */ |
| 25 | private $options; |
| 26 | public function __construct(string $url, array $options) |
| 27 | { |
| 28 | $this->url = $url; |
| 29 | $this->options = $options; |
| 30 | $this->ch = $options['curlHandle']; |
| 31 | } |
| 32 | /** |
| 33 | * @throws HttpException |
| 34 | */ |
| 35 | public function post(string $body) : array |
| 36 | { |
| 37 | $curl = $this->createCurl(); |
| 38 | curl_setopt($curl, \CURLOPT_POST, \true); |
| 39 | curl_setopt($curl, \CURLOPT_POSTFIELDS, $body); |
| 40 | return $this->execute($curl); |
| 41 | } |
| 42 | public function get() : array |
| 43 | { |
| 44 | $curl = $this->createCurl(); |
| 45 | curl_setopt($curl, \CURLOPT_HTTPGET, \true); |
| 46 | return $this->execute($curl); |
| 47 | } |
| 48 | /** |
| 49 | * @return \CurlHandle |
| 50 | */ |
| 51 | private function createCurl() |
| 52 | { |
| 53 | curl_reset($this->ch); |
| 54 | $opts = []; |
| 55 | $opts[\CURLOPT_URL] = $this->url; |
| 56 | if (!empty($this->options['caBundle'])) { |
| 57 | $opts[\CURLOPT_CAINFO] = $this->options['caBundle']; |
| 58 | } |
| 59 | $opts[\CURLOPT_ENCODING] = ''; |
| 60 | $opts[\CURLOPT_SSL_VERIFYHOST] = 2; |
| 61 | $opts[\CURLOPT_FOLLOWLOCATION] = \false; |
| 62 | $opts[\CURLOPT_SSL_VERIFYPEER] = \true; |
| 63 | $opts[\CURLOPT_RETURNTRANSFER] = \true; |
| 64 | $opts[\CURLOPT_HTTPHEADER] = $this->options['headers']; |
| 65 | $opts[\CURLOPT_USERAGENT] = $this->options['userAgent']; |
| 66 | $opts[\CURLOPT_PROXY] = $this->options['proxy']; |
| 67 | // The defined()s are here as the *_MS opts are not available on older |
| 68 | // cURL versions |
| 69 | $connectTimeout = $this->options['connectTimeout']; |
| 70 | if (\defined('CURLOPT_CONNECTTIMEOUT_MS')) { |
| 71 | $opts[\CURLOPT_CONNECTTIMEOUT_MS] = ceil($connectTimeout * 1000); |
| 72 | } else { |
| 73 | $opts[\CURLOPT_CONNECTTIMEOUT] = ceil($connectTimeout); |
| 74 | } |
| 75 | $timeout = $this->options['timeout']; |
| 76 | if (\defined('CURLOPT_TIMEOUT_MS')) { |
| 77 | $opts[\CURLOPT_TIMEOUT_MS] = ceil($timeout * 1000); |
| 78 | } else { |
| 79 | $opts[\CURLOPT_TIMEOUT] = ceil($timeout); |
| 80 | } |
| 81 | curl_setopt_array($this->ch, $opts); |
| 82 | return $this->ch; |
| 83 | } |
| 84 | /** |
| 85 | * @param \CurlHandle $curl |
| 86 | * |
| 87 | * @throws HttpException |
| 88 | */ |
| 89 | private function execute($curl) : array |
| 90 | { |
| 91 | $body = curl_exec($curl); |
| 92 | if ($errno = curl_errno($curl)) { |
| 93 | $errorMessage = curl_error($curl); |
| 94 | throw new HttpException("cURL error ({$errno}): {$errorMessage}", 0, $this->url); |
| 95 | } |
| 96 | $statusCode = curl_getinfo($curl, \CURLINFO_HTTP_CODE); |
| 97 | $contentType = curl_getinfo($curl, \CURLINFO_CONTENT_TYPE); |
| 98 | return [ |
| 99 | $statusCode, |
| 100 | // The PHP docs say "Content-Type: of the requested document. NULL |
| 101 | // indicates server did not send valid Content-Type: header" for |
| 102 | // CURLINFO_CONTENT_TYPE. However, it will return FALSE if no header |
| 103 | // is set. To keep our types simple, we return null in this case. |
| 104 | $contentType === \false ? null : $contentType, |
| 105 | $body, |
| 106 | ]; |
| 107 | } |
| 108 | } |
| 109 |