Completed
Push — master ( 7cb621...ebe87d )
by dotzero
11s
created

Request::debug()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 6
rs 9.4285
c 1
b 0
f 0
ccs 3
cts 3
cp 1
cc 1
eloc 3
nc 1
nop 1
crap 1
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
     * @var CurlHandle Экземпляр CurlHandle
41
     */
42
    private $curlHandle;
43
44
    /**
45
     * @var int|null Последний полученный HTTP код
46
     */
47
    private $lastHttpCode = null;
48
49
    /**
50
     * @var string|null Последний полученный HTTP ответ
51
     */
52
    private $lastHttpResponse = null;
53
54
    /**
55
     * Request constructor
56
     *
57
     * @param ParamsBag       $parameters Экземпляр ParamsBag для хранения аргументов
58
     * @param CurlHandle|null $curlHandle Экземпляр CurlHandle для повторного использования
59
     */
60 236
    public function __construct(ParamsBag $parameters, CurlHandle $curlHandle = null)
61
    {
62 236
        $this->parameters = $parameters;
63 236
        $this->curlHandle = $curlHandle !== null ? $curlHandle : new CurlHandle();
64 236
    }
65
66
    /**
67
     * Установка флага вывода отладочной информации
68
     *
69
     * @param bool $flag Значение флага
70
     * @return $this
71
     */
72 2
    public function debug($flag = false)
73
    {
74 2
        $this->debug = (bool)$flag;
75
76 2
        return $this;
77
    }
78
79
    /**
80
     * Возвращает последний полученный HTTP код
81
     *
82
     * @return int|null
83
     */
84 1
    public function getLastHttpCode()
85
    {
86 1
        return $this->lastHttpCode;
87
    }
88
89
    /**
90
     * Возвращает последний полученный HTTP ответ
91
     *
92
     * @return null|string
93
     */
94 1
    public function getLastHttpResponse()
95
    {
96 1
        return $this->lastHttpResponse;
97
    }
98
99
    /**
100
     * Возвращает экземпляр ParamsBag для хранения аргументов
101
     *
102
     * @return ParamsBag|null
103
     */
104 3
    protected function getParameters()
105
    {
106 3
        return $this->parameters;
107
    }
108
109
    /**
110
     * Выполнить HTTP GET запрос и вернуть тело ответа
111
     *
112
     * @param string $url Запрашиваемый URL
113
     * @param array $parameters Список GET параметров
114
     * @param null|string $modified Значение заголовка IF-MODIFIED-SINCE
115
     * @return mixed
116
     * @throws Exception
117
     * @throws NetworkException
118
     */
119 1
    protected function getRequest($url, $parameters = [], $modified = null)
120
    {
121 1
        if (!empty($parameters)) {
122 1
            $this->parameters->addGet($parameters);
123 1
        }
124
125 1
        return $this->request($url, $modified);
126
    }
127
128
    /**
129
     * Выполнить HTTP POST запрос и вернуть тело ответа
130
     *
131
     * @param string $url Запрашиваемый URL
132
     * @param array $parameters Список POST параметров
133
     * @return mixed
134
     * @throws Exception
135
     * @throws NetworkException
136
     */
137 1
    protected function postRequest($url, $parameters = [])
138
    {
139 1
        if (!empty($parameters)) {
140 1
            $this->parameters->addPost($parameters);
141 1
        }
142
143 1
        return $this->request($url);
144
    }
145
146
    /**
147
     * Подготавливает список заголовков HTTP
148
     *
149
     * @param mixed $modified Значение заголовка IF-MODIFIED-SINCE
150
     * @return array
151
     */
152 2
    protected function prepareHeaders($modified = null)
153
    {
154
        $headers = [
155 2
            'Connection: keep-alive',
156 2
            'Content-Type: application/json',
157 2
        ];
158
159 2
        if ($modified !== null) {
160 2
            if (is_int($modified)) {
161 1
                $headers[] = 'IF-MODIFIED-SINCE: ' . $modified;
162 1
            } else {
163 2
                $headers[] = 'IF-MODIFIED-SINCE: ' . (new DateTime($modified))->format(DateTime::RFC1123);
164
            }
165 1
        }
166
167 1
        return $headers;
168
    }
169
170
    /**
171
     * Подготавливает URL для HTTP запроса
172
     *
173
     * @param string $url Запрашиваемый URL
174
     * @return string
175
     */
176 2
    protected function prepareEndpoint($url)
177
    {
178 2
        if ($this->v1 === false) {
179 1
            $query = http_build_query(array_merge($this->parameters->getGet(), [
180 1
                'USER_LOGIN' => $this->parameters->getAuth('login'),
181 1
                'USER_HASH' => $this->parameters->getAuth('apikey'),
182 1
            ]), null, '&');
183 1
        } else {
184 1
            $query = http_build_query(array_merge($this->parameters->getGet(), [
185 1
                'login' => $this->parameters->getAuth('login'),
186 1
                'api_key' => $this->parameters->getAuth('apikey'),
187 1
            ]), null, '&');
188
        }
189
190 2
        return sprintf('https://%s%s?%s', $this->parameters->getAuth('domain'), $url, $query);
191
    }
192
193
    /**
194
     * Выполнить HTTP запрос и вернуть тело ответа
195
     *
196
     * @param string $url Запрашиваемый URL
197
     * @param null|string $modified Значение заголовка IF-MODIFIED-SINCE
198
     * @return mixed
199
     * @throws Exception
200
     * @throws NetworkException
201
     */
202
    protected function request($url, $modified = null)
203
    {
204
        $headers = $this->prepareHeaders($modified);
205
        $endpoint = $this->prepareEndpoint($url);
206
207
        $this->printDebug('url', $endpoint);
208
        $this->printDebug('headers', $headers);
209
210
        $ch = $this->curlHandle->open();
211
212
        curl_setopt($ch, CURLOPT_URL, $endpoint);
213
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
214
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
215
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
216
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
217
        curl_setopt($ch, CURLOPT_ENCODING, '');
218
219
        if ($this->parameters->hasPost()) {
220
            $fields = json_encode([
221
                'request' => $this->parameters->getPost(),
222
            ]);
223
            curl_setopt($ch, CURLOPT_POST, true);
224
            curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
225
            $this->printDebug('post params', $fields);
226
        }
227
228
        if ($this->parameters->hasProxy()) {
229
            curl_setopt($ch, CURLOPT_PROXY, $this->parameters->getProxy());
230
        }
231
232
        $result = curl_exec($ch);
233
        $info = curl_getinfo($ch);
234
        $error = curl_error($ch);
235
        $errno = curl_errno($ch);
236
237
        $this->curlHandle->close();
238
239
        $this->lastHttpCode = $info['http_code'];
240
        $this->lastHttpResponse = $result;
241
242
        $this->printDebug('curl_exec', $result);
243
        $this->printDebug('curl_getinfo', $info);
244
        $this->printDebug('curl_error', $error);
245
        $this->printDebug('curl_errno', $errno);
246
247
        if ($result === false && !empty($error)) {
248
            throw new NetworkException($error, $errno);
249
        }
250
251
        return $this->parseResponse($result, $info);
252
    }
253
254
    /**
255
     * Парсит HTTP ответ, проверяет на наличие ошибок и возвращает тело ответа
256
     *
257
     * @param string $response HTTP ответ
258
     * @param array $info Результат функции curl_getinfo
259
     * @return mixed
260
     * @throws Exception
261
     */
262 7
    protected function parseResponse($response, $info)
263
    {
264 7
        $result = json_decode($response, true);
265
266 7
        if (floor($info['http_code'] / 100) >= 3) {
267 5
            if (isset($result['response']['error_code']) && $result['response']['error_code'] > 0) {
268 1
                $code = $result['response']['error_code'];
269 5
            } elseif ($result !== null) {
270 2
                $code = 0;
271 2
            } else {
272 2
                $code = $info['http_code'];
273
            }
274 5
            if ($this->v1 === false && isset($result['response']['error'])) {
275 2
                throw new Exception($result['response']['error'], $code);
276 3
            } elseif (isset($result['response'])) {
277 1
                throw new Exception(json_encode($result['response']));
278
            } else {
279 2
                throw new Exception('Invalid response body.', $code);
280
            }
281 2
        } elseif (!isset($result['response'])) {
282 1
            return false;
283
        }
284
285 1
        return $result['response'];
286
    }
287
288
    /**
289
     * Вывода отладочной информации
290
     *
291
     * @param string $key Заголовок отладочной информации
292
     * @param mixed $value Значение отладочной информации
293
     * @param bool $return Возврат строки вместо вывода
294
     * @return mixed
295
     */
296 2
    protected function printDebug($key = '', $value = null, $return = false)
297
    {
298 2
        if ($this->debug !== true) {
299 1
            return false;
300
        }
301
302 1
        if (!is_string($value)) {
303 1
            $value = print_r($value, true);
304 1
        }
305
306 1
        $line = sprintf('[DEBUG] %s: %s', $key, $value);
307
308 1
        if ($return === false) {
309
            return print_r($line . PHP_EOL);
310
        }
311
312 1
        return $line;
313
    }
314
}
315