Completed
Pull Request — master (#72)
by
unknown
02:34
created

Request::getLastHttpCode()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
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 237
    public function __construct(ParamsBag $parameters, CurlHandle $curlHandle = null)
61
    {
62 237
        $this->parameters = $parameters;
63 237
        $this->curlHandle = $curlHandle !== null ? $curlHandle : new CurlHandle();
64 237
    }
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->logRequest($endpoint, 'REQUEST');
208
209
        $this->printDebug('url', $endpoint);
210
        $this->printDebug('headers', $headers);
211
212
        $ch = $this->curlHandle->open();
213
214
        curl_setopt($ch, CURLOPT_URL, $endpoint);
215
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
216
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
217
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
218
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
219
        curl_setopt($ch, CURLOPT_ENCODING, '');
220
221
        if ($this->parameters->hasPost()) {
222
            $fields = json_encode([
223
                'request' => $this->parameters->getPost(),
224
            ]);
225
            curl_setopt($ch, CURLOPT_POST, true);
226
            curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
227
            $this->printDebug('post params', $fields);
228
        }
229
230
        if ($this->parameters->hasProxy()) {
231
            curl_setopt($ch, CURLOPT_PROXY, $this->parameters->getProxy());
232
        }
233
234
        $result = curl_exec($ch);
235
        $info = curl_getinfo($ch);
236
        $error = curl_error($ch);
237
        $errno = curl_errno($ch);
238
239
        $this->curlHandle->close();
240
241
        $this->lastHttpCode = $info['http_code'];
242
        $this->lastHttpResponse = $result;
243
244
        $this->printDebug('curl_exec', $result);
245
        $this->printDebug('curl_getinfo', $info);
246
        $this->printDebug('curl_error', $error);
247
        $this->printDebug('curl_errno', $errno);
248
249
        if ($result === false && !empty($error)) {
250
            throw new NetworkException($error, $errno);
251
        }
252
253
        return $this->parseResponse($result, $info);
254
    }
255
256
    /**
257
     * Парсит HTTP ответ, проверяет на наличие ошибок и возвращает тело ответа
258
     *
259
     * @param string $response HTTP ответ
260
     * @param array $info Результат функции curl_getinfo
261
     * @return mixed
262
     * @throws Exception
263
     */
264 7
    protected function parseResponse($response, $info)
265
    {
266 7
        $result = json_decode($response, true);
267
268 7
        if (floor($info['http_code'] / 100) >= 3) {
269 5
            if (isset($result['response']['error_code']) && $result['response']['error_code'] > 0) {
270 1
                $code = $result['response']['error_code'];
271 5
            } elseif ($result !== null) {
272 2
                $code = 0;
273 2
            } else {
274 2
                $code = $info['http_code'];
275
            }
276 5
            if ($this->v1 === false && isset($result['response']['error'])) {
277 2
                throw new Exception($result['response']['error'], $code);
278 3
            } elseif (isset($result['response'])) {
279 1
                throw new Exception(json_encode($result['response']));
280
            } else {
281 2
                throw new Exception('Invalid response body.', $code);
282
            }
283 2
        } elseif (!isset($result['response'])) {
284 1
            return false;
285
        }
286
287 1
        return $result['response'];
288
    }
289
290
    /**
291
     * Вывода отладочной информации
292
     *
293
     * @param string $key Заголовок отладочной информации
294
     * @param mixed $value Значение отладочной информации
295
     * @param bool $return Возврат строки вместо вывода
296
     * @return mixed
297
     */
298 2
    protected function printDebug($key = '', $value = null, $return = false)
299
    {
300 2
        if ($this->debug !== true) {
301 1
            return false;
302
        }
303
304 1
        if (!is_string($value)) {
305 1
            $value = print_r($value, true);
306 1
        }
307
308 1
        $line = sprintf('[DEBUG] %s: %s', $key, $value);
309
310 1
        if ($return === false) {
311
            return print_r($line . PHP_EOL);
312
        }
313
314 1
        return $line;
315
    }
316
317
    protected function logRequest($value, $entity=""){
318
        $timestamp = gmdate("Y-m-d H:i:s", time());
319
        $log_dir = defined('LOG_DIR')?LOG_DIR:sys_get_temp_dir();
320
        if(!is_dir($log_dir)) {
321
            mkdir($log_dir);
322
        }
323
        file_put_contents($log_dir."/amo_requests.log","[".$timestamp."] ".microtime(true)." | ".strtoupper($entity)." ".$value. PHP_EOL, FILE_APPEND | LOCK_EX);
324
    }
325
}
326