Completed
Push — master ( 9f9778...4d38ee )
by dotzero
02:38
created

Request::request()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 43
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

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