Completed
Push — master ( da6718...a32414 )
by dotzero
01:52
created

Request::request()   B

Complexity

Conditions 6
Paths 24

Size

Total Lines 50
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 50
ccs 0
cts 38
cp 0
rs 8.6315
cc 6
eloc 32
nc 24
nop 2
crap 42
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 130
    public function __construct(ParamsBag $parameters)
45
    {
46 130
        if (!function_exists('curl_init')) {
47
            throw new NetworkException('The cURL PHP extension was not loaded');
48
        }
49
50 130
        $this->parameters = $parameters;
51 130
    }
52
53
    /**
54
     * Установка флага вывода отладочной информации
55
     *
56
     * @param bool $flag Значение флага
57
     * @return $this
58
     */
59 1
    public function debug($flag = false)
60
    {
61 1
        $this->debug = (bool)$flag;
62
63 1
        return $this;
64
    }
65
66
    /**
67
     * Выполнить HTTP GET запрос и вернуть тело ответа
68
     *
69
     * @param string $url Запрашиваемый URL
70
     * @param array $parameters Список GET параметров
71
     * @param null|string $modified Значение заголовка IF-MODIFIED-SINCE
72
     * @return mixed
73
     * @throws Exception
74
     * @throws NetworkException
75
     */
76 1
    protected function getRequest($url, $parameters = [], $modified = null)
77
    {
78 1
        if (!empty($parameters)) {
79 1
            $this->parameters->addGet($parameters);
80 1
        }
81
82 1
        return $this->request($url, $modified);
83
    }
84
85
    /**
86
     * Выполнить HTTP POST запрос и вернуть тело ответа
87
     *
88
     * @param string $url Запрашиваемый URL
89
     * @param array $parameters Список POST параметров
90
     * @return mixed
91
     * @throws Exception
92
     * @throws NetworkException
93
     */
94 1
    protected function postRequest($url, $parameters = [])
95
    {
96 1
        if (!empty($parameters)) {
97 1
            $this->parameters->addPost($parameters);
98 1
        }
99
100 1
        return $this->request($url);
101
    }
102
103
    /**
104
     * Подготавливает список заголовков HTTP
105
     *
106
     * @param null|string $modified Значение заголовка IF-MODIFIED-SINCE
107
     * @return array
108
     */
109 2
    protected function prepareHeaders($modified = null)
110
    {
111 2
        $headers = ['Content-Type: application/json'];
112
113 2
        if ($modified !== null) {
114 2
            $headers[] = 'IF-MODIFIED-SINCE: ' . (new \DateTime($modified))->format(\DateTime::RFC1123);
115 1
        }
116
117 1
        return $headers;
118
    }
119
120
    /**
121
     * Подготавливает URL для HTTP запроса
122
     *
123
     * @param string $url Запрашиваемый URL
124
     * @return string
125
     */
126 2
    protected function prepareEndpoint($url)
127
    {
128 2
        if ($this->v1 === false) {
129 1
            $query = http_build_query(array_merge($this->parameters->getGet(), [
130 1
                'USER_LOGIN' => $this->parameters->getAuth('login'),
131 1
                'USER_HASH' => $this->parameters->getAuth('apikey'),
132 1
            ]));
133 1
        } else {
134 1
            $query = http_build_query(array_merge($this->parameters->getGet(), [
135 1
                'login' => $this->parameters->getAuth('login'),
136 1
                'api_key' => $this->parameters->getAuth('apikey'),
137 1
            ]));
138
        }
139
140 2
        return sprintf('https://%s.amocrm.ru%s?%s', $this->parameters->getAuth('domain'), $url, $query);
141
    }
142
143
    /**
144
     * Выполнить HTTP запрос и вернуть тело ответа
145
     *
146
     * @param string $url Запрашиваемый URL
147
     * @param null|string $modified Значение заголовка IF-MODIFIED-SINCE
148
     * @return mixed
149
     * @throws Exception
150
     * @throws NetworkException
151
     */
152
    protected function request($url, $modified = null)
153
    {
154
        $headers = $this->prepareHeaders($modified);
155
        $endpoint = $this->prepareEndpoint($url);
156
157
        if ($this->debug) {
158
            printf('[DEBUG] url: %s' . PHP_EOL, $endpoint);
159
            printf('[DEBUG] headers: %s' . PHP_EOL, print_r($headers, 1));
160
            if ($this->parameters->hasPost()) {
161
                printf('[DEBUG] post: %s' . PHP_EOL, json_encode([
162
                    'request' => $this->parameters->getPost(),
163
                ]));
164
            }
165
        }
166
167
        $ch = curl_init();
168
169
        curl_setopt($ch, CURLOPT_URL, $endpoint);
170
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
171
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
172
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
173
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
174
175
        if ($this->parameters->hasPost()) {
176
            curl_setopt($ch, CURLOPT_POST, true);
177
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
178
                'request' => $this->parameters->getPost(),
179
            ]));
180
        }
181
182
        $result = curl_exec($ch);
183
        $info = curl_getinfo($ch);
184
        $error = curl_error($ch);
185
        $errno = curl_errno($ch);
186
187
        curl_close($ch);
188
189
        if ($this->debug) {
190
            printf('[DEBUG] curl_exec: %s' . PHP_EOL, $result);
191
            printf('[DEBUG] curl_getinfo: %s' . PHP_EOL, print_r($info, 1));
192
            printf('[DEBUG] curl_error: %s' . PHP_EOL, $error);
193
            printf('[DEBUG] curl_errno: %s' . PHP_EOL, $errno);
194
        }
195
196
        if ($error) {
197
            throw new NetworkException($error, $errno);
198
        }
199
200
        return $this->parseResponse($result, $info);
201
    }
202
203
    /**
204
     * Парсит HTTP ответ, валидирует и возвращает тело
205
     *
206
     * @param string $response HTTP ответ
207
     * @param array $info Результат функции curl_getinfo
208
     * @return mixed
209
     * @throws Exception
210
     */
211 4
    protected function parseResponse($response, $info)
212
    {
213 4
        $result = json_decode($response, true);
214
215 4
        if (!isset($result['response'])) {
216 1
            return false;
217 3
        } elseif (floor($info['http_code'] / 100) >= 3) {
218 3
            $code = 0;
219 3
            if (isset($result['response']['error_code']) && $result['response']['error_code'] > 0) {
220 1
                $code = $result['response']['error_code'];
221 1
            }
222 3
            if ($this->v1 === false) {
223 2
                throw new Exception($result['response']['error'], $code);
224
            } else {
225 1
                throw new Exception(json_encode($result['response']));
226
            }
227
        }
228
229
        return $result['response'];
230
    }
231
}
232