1<?php
2
3namespace MaxMind\WebService\Http;
4
5use MaxMind\Exception\HttpException;
6
7/**
8 * This class is for internal use only. Semantic versioning does not not apply.
9 *
10 * @internal
11 */
12class CurlRequest implements Request
13{
14    private $url;
15    private $options;
16
17    /**
18     * @param $url
19     * @param $options
20     */
21    public function __construct($url, $options)
22    {
23        $this->url = $url;
24        $this->options = $options;
25    }
26
27    /**
28     * @param $body
29     *
30     * @return array
31     */
32    public function post($body)
33    {
34        $curl = $this->createCurl();
35
36        curl_setopt($curl, CURLOPT_POST, true);
37        curl_setopt($curl, CURLOPT_POSTFIELDS, $body);
38
39        return $this->execute($curl);
40    }
41
42    public function get()
43    {
44        $curl = $this->createCurl();
45
46        curl_setopt($curl, CURLOPT_HTTPGET, true);
47
48        return $this->execute($curl);
49    }
50
51    /**
52     * @return resource
53     */
54    private function createCurl()
55    {
56        $curl = curl_init($this->url);
57
58        if (!empty($this->options['caBundle'])) {
59            $opts[CURLOPT_CAINFO] = $this->options['caBundle'];
60        }
61        $opts[CURLOPT_SSL_VERIFYHOST] = 2;
62        $opts[CURLOPT_FOLLOWLOCATION] = false;
63        $opts[CURLOPT_SSL_VERIFYPEER] = true;
64        $opts[CURLOPT_RETURNTRANSFER] = true;
65
66        $opts[CURLOPT_HTTPHEADER] = $this->options['headers'];
67        $opts[CURLOPT_USERAGENT] = $this->options['userAgent'];
68        $opts[CURLOPT_PROXY] = $this->options['proxy'];
69
70        // The defined()s are here as the *_MS opts are not available on older
71        // cURL versions
72        $connectTimeout = $this->options['connectTimeout'];
73        if (defined('CURLOPT_CONNECTTIMEOUT_MS')) {
74            $opts[CURLOPT_CONNECTTIMEOUT_MS] = ceil($connectTimeout * 1000);
75        } else {
76            $opts[CURLOPT_CONNECTTIMEOUT] = ceil($connectTimeout);
77        }
78
79        $timeout = $this->options['timeout'];
80        if (defined('CURLOPT_TIMEOUT_MS')) {
81            $opts[CURLOPT_TIMEOUT_MS] = ceil($timeout * 1000);
82        } else {
83            $opts[CURLOPT_TIMEOUT] = ceil($timeout);
84        }
85
86        curl_setopt_array($curl, $opts);
87
88        return $curl;
89    }
90
91    private function execute($curl)
92    {
93        $body = curl_exec($curl);
94        if ($errno = curl_errno($curl)) {
95            $errorMessage = curl_error($curl);
96
97            throw new HttpException(
98                "cURL error ({$errno}): {$errorMessage}",
99                0,
100                $this->url
101            );
102        }
103
104        $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
105        $contentType = curl_getinfo($curl, CURLINFO_CONTENT_TYPE);
106        curl_close($curl);
107
108        return [$statusCode, $contentType, $body];
109    }
110}
111