Completed
Push — master ( 3b9614...32a18f )
by dotzero
02:07
created

Request::prepareHeaders()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 14
ccs 9
cts 9
cp 1
rs 9.4285
cc 3
eloc 8
nc 3
nop 1
crap 3
1
<?php
2
3
namespace AmoCRM\Request;
4
5
use DateTime;
6
use AmoCRM\Exception;
7
use AmoCRM\NetworkException;
8
9
/**
10
 * Class Request
11
 *
12
 * Класс отправляющий запросы к API amoCRM используя cURL
13
 *
14
 * @package AmoCRM\Request
15
 * @author dotzero <[email protected]>
16
 * @link http://www.dotzero.ru/
17
 * @link https://github.com/dotzero/amocrm-php
18
 *
19
 * For the full copyright and license information, please view the LICENSE
20
 * file that was distributed with this source code.
21
 */
22
class Request
23
{
24
    /**
25
     * @var bool Использовать устаревшую схему авторизации
26
     */
27
    protected $v1 = false;
28
29
    /**
30
     * @var bool Флаг вывода отладочной информации
31
     */
32
    private $debug = false;
33
34
    /**
35
     * @var ParamsBag|null Экземпляр ParamsBag для хранения аргументов
36
     */
37
    private $parameters = null;
38
39
    /**
40
     * Request constructor
41
     *
42
     * @param ParamsBag $parameters Экземпляр ParamsBag для хранения аргументов
43
     * @throws NetworkException
44
     */
45 216
    public function __construct(ParamsBag $parameters)
46
    {
47 216
        if (!function_exists('curl_init')) {
48
            throw new NetworkException('The cURL PHP extension was not loaded');
49
        }
50
51 216
        $this->parameters = $parameters;
52 216
    }
53
54
    /**
55
     * Установка флага вывода отладочной информации
56
     *
57
     * @param bool $flag Значение флага
58
     * @return $this
59
     */
60 2
    public function debug($flag = false)
61
    {
62 2
        $this->debug = (bool)$flag;
63
64 2
        return $this;
65
    }
66
67
    /**
68
     * Возвращает экземпляр ParamsBag для хранения аргументов
69
     *
70
     * @return ParamsBag|null
71
     */
72 3
    protected function getParameters()
73
    {
74 3
        return $this->parameters;
75
    }
76
77
    /**
78
     * Выполнить HTTP GET запрос и вернуть тело ответа
79
     *
80
     * @param string $url Запрашиваемый URL
81
     * @param array $parameters Список GET параметров
82
     * @param null|string $modified Значение заголовка IF-MODIFIED-SINCE
83
     * @return mixed
84
     * @throws Exception
85
     * @throws NetworkException
86
     */
87 1
    protected function getRequest($url, $parameters = [], $modified = null)
88
    {
89 1
        if (!empty($parameters)) {
90 1
            $this->parameters->addGet($parameters);
91 1
        }
92
93 1
        return $this->request($url, $modified);
94
    }
95
96
    /**
97
     * Выполнить HTTP POST запрос и вернуть тело ответа
98
     *
99
     * @param string $url Запрашиваемый URL
100
     * @param array $parameters Список POST параметров
101
     * @return mixed
102
     * @throws Exception
103
     * @throws NetworkException
104
     */
105 1
    protected function postRequest($url, $parameters = [])
106
    {
107 1
        if (!empty($parameters)) {
108 1
            $this->parameters->addPost($parameters);
109 1
        }
110
111 1
        return $this->request($url);
112
    }
113
114
    /**
115
     * Подготавливает список заголовков HTTP
116
     *
117
     * @param mixed $modified Значение заголовка IF-MODIFIED-SINCE
118
     * @return array
119
     */
120 2
    protected function prepareHeaders($modified = null)
121
    {
122 2
        $headers = ['Content-Type: application/json'];
123
124 2
        if ($modified !== null) {
125 2
            if (is_int($modified)) {
126 1
                $headers[] = 'IF-MODIFIED-SINCE: ' . $modified;
127 1
            } else {
128 2
                $headers[] = 'IF-MODIFIED-SINCE: ' . (new DateTime($modified))->format(DateTime::RFC1123);
129
            }
130 1
        }
131
132 1
        return $headers;
133
    }
134
135
    /**
136
     * Подготавливает URL для HTTP запроса
137
     *
138
     * @param string $url Запрашиваемый URL
139
     * @return string
140
     */
141 2
    protected function prepareEndpoint($url)
142
    {
143 2
        if ($this->v1 === false) {
144 1
            $query = http_build_query(array_merge($this->parameters->getGet(), [
145 1
                'USER_LOGIN' => $this->parameters->getAuth('login'),
146 1
                'USER_HASH' => $this->parameters->getAuth('apikey'),
147 1
            ]));
148 1
        } else {
149 1
            $query = http_build_query(array_merge($this->parameters->getGet(), [
150 1
                'login' => $this->parameters->getAuth('login'),
151 1
                'api_key' => $this->parameters->getAuth('apikey'),
152 1
            ]));
153
        }
154
155 2
        return sprintf('https://%s%s?%s', $this->parameters->getAuth('domain'), $url, $query);
156
    }
157
158
    /**
159
     * Выполнить HTTP запрос и вернуть тело ответа
160
     *
161
     * @param string $url Запрашиваемый URL
162
     * @param null|string $modified Значение заголовка IF-MODIFIED-SINCE
163
     * @return mixed
164
     * @throws Exception
165
     * @throws NetworkException
166
     */
167
    protected function request($url, $modified = null)
168
    {
169
        $headers = $this->prepareHeaders($modified);
170
        $endpoint = $this->prepareEndpoint($url);
171
172
        $this->printDebug('url', $endpoint);
173
        $this->printDebug('headers', $headers);
174
175
        $ch = curl_init();
176
177
        curl_setopt($ch, CURLOPT_URL, $endpoint);
178
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
179
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
180
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
181
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
182
183
        if ($this->parameters->hasPost()) {
184
            $fields = json_encode([
185
                'request' => $this->parameters->getPost(),
186
            ]);
187
            curl_setopt($ch, CURLOPT_POST, true);
188
            curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
189
            $this->printDebug('post params', $fields);
190
        }
191
192
        $result = curl_exec($ch);
193
        $info = curl_getinfo($ch);
194
        $error = curl_error($ch);
195
        $errno = curl_errno($ch);
196
197
        curl_close($ch);
198
199
        $this->printDebug('curl_exec', $result);
200
        $this->printDebug('curl_getinfo', $info);
201
        $this->printDebug('curl_error', $error);
202
        $this->printDebug('curl_errno', $errno);
203
204
        if ($result === false && !empty($error)) {
205
            throw new NetworkException($error, $errno);
206
        }
207
208
        return $this->parseResponse($result, $info);
209
    }
210
211
    /**
212
     * Парсит HTTP ответ, проверяет на наличие ошибок и возвращает тело ответа
213
     *
214
     * @param string $response HTTP ответ
215
     * @param array $info Результат функции curl_getinfo
216
     * @return mixed
217
     * @throws Exception
218
     */
219 5
    protected function parseResponse($response, $info)
220
    {
221 5
        $result = json_decode($response, true);
222
223 5
        if (!isset($result['response'])) {
224 1
            return false;
225 4
        } elseif (floor($info['http_code'] / 100) >= 3) {
226 3
            $code = 0;
227 3
            if (isset($result['response']['error_code']) && $result['response']['error_code'] > 0) {
228 1
                $code = $result['response']['error_code'];
229 1
            }
230 3
            if ($this->v1 === false) {
231 2
                throw new Exception($result['response']['error'], $code);
232
            } else {
233 1
                throw new Exception(json_encode($result['response']));
234
            }
235
        }
236
237 1
        return $result['response'];
238
    }
239
240
    /**
241
     * Вывода отладочной информации
242
     *
243
     * @param string $key Заголовок отладочной информации
244
     * @param mixed $value Значение отладочной информации
245
     * @param bool $return Возврат строки вместо вывода
246
     * @return mixed
247
     */
248 2
    protected function printDebug($key = '', $value = null, $return = false)
249
    {
250 2
        if ($this->debug !== true) {
251 1
            return false;
252
        }
253
254 1
        if (!is_string($value)) {
255 1
            $value = print_r($value, true);
256 1
        }
257
258 1
        $line = sprintf('[DEBUG] %s: %s', $key, $value);
259
260 1
        if ($return === false) {
261
            return print_r($line . PHP_EOL);
262
        }
263
264 1
        return $line;
265
    }
266
}
267