This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace SimaLand\API\Rest; |
||
4 | |||
5 | use GuzzleHttp\ClientInterface; |
||
6 | use GuzzleHttp\RequestOptions; |
||
7 | use GuzzleHttp\Psr7\Response; |
||
8 | use SimaLand\API\Object; |
||
9 | |||
10 | /** |
||
11 | * SimaLand клиент. |
||
12 | * |
||
13 | * @link https://www.sima-land.ru/api/v3/help/ |
||
14 | */ |
||
15 | class Client extends Object |
||
16 | { |
||
17 | /** |
||
18 | * Базовый url API sima-land.ru. |
||
19 | * |
||
20 | * @var string |
||
21 | */ |
||
22 | public $baseUrl = 'https://www.sima-land.ru/api/v5'; |
||
23 | |||
24 | /** |
||
25 | * @var string |
||
26 | */ |
||
27 | public $login; |
||
28 | |||
29 | /** |
||
30 | * @var string |
||
31 | */ |
||
32 | public $password; |
||
33 | |||
34 | /** |
||
35 | * @var bool |
||
36 | */ |
||
37 | public $regulation = false; |
||
38 | |||
39 | /** |
||
40 | * Путь до токена. |
||
41 | * |
||
42 | * @var string |
||
43 | */ |
||
44 | public $tokenPath; |
||
45 | |||
46 | /** |
||
47 | * @var \GuzzleHttp\ClientInterface |
||
48 | */ |
||
49 | private $httpClient; |
||
50 | |||
51 | /** |
||
52 | * @var string |
||
53 | */ |
||
54 | private $token; |
||
55 | |||
56 | /** |
||
57 | * Базовые опции http запроса к API |
||
58 | * |
||
59 | * @var array |
||
60 | */ |
||
61 | private $options = [ |
||
62 | 'http_errors' => false, |
||
63 | 'headers' => [ |
||
64 | 'User-Agent' => 'Sima-land api-php-client/5.0', |
||
65 | 'Content-Type' => 'application/json', |
||
66 | ], |
||
67 | ]; |
||
68 | |||
69 | /** |
||
70 | * @param array $options |
||
71 | * @throws \Exception |
||
72 | */ |
||
73 | public function __construct(array $options = []) |
||
74 | { |
||
75 | if (!isset($options['login'])) { |
||
76 | throw new \Exception('Login can`t be empty'); |
||
77 | } |
||
78 | if (!isset($options['password'])) { |
||
79 | throw new \Exception('Password can`t be empty'); |
||
80 | } |
||
81 | parent::__construct($options); |
||
82 | } |
||
83 | |||
84 | /** |
||
85 | * Получить http клиент. |
||
86 | * |
||
87 | * @return \GuzzleHttp\ClientInterface |
||
88 | */ |
||
89 | public function getHttpClient() |
||
90 | { |
||
91 | if (is_null($this->httpClient)) { |
||
92 | $this->httpClient = new \GuzzleHttp\Client(); |
||
93 | } |
||
94 | return $this->httpClient; |
||
95 | } |
||
96 | |||
97 | /** |
||
98 | * Установить http клиент. |
||
99 | * |
||
100 | * @param \GuzzleHttp\ClientInterface $httpClient |
||
101 | * @return Client |
||
102 | */ |
||
103 | public function setHttpClient(ClientInterface $httpClient) |
||
104 | { |
||
105 | $this->httpClient = $httpClient; |
||
106 | return $this; |
||
107 | } |
||
108 | |||
109 | /** |
||
110 | * Групповой запрос к API. |
||
111 | * |
||
112 | * @param array $requests |
||
113 | * @return Response[] |
||
114 | * @throws \Exception |
||
115 | */ |
||
116 | public function batchQuery(array $requests) |
||
117 | { |
||
118 | $client = $this->getHttpClient(); |
||
119 | $promises = []; |
||
120 | foreach ($requests as $name => $request) { |
||
121 | if (!($request instanceof Request)) { |
||
122 | throw new \Exception('Request must be implement "\SimaLand\API\Rest\Request"'); |
||
123 | } |
||
124 | $url = $this->createUrl($request->entity); |
||
125 | $this->getLogger()->info( |
||
126 | "Send request {$url}", |
||
127 | [ |
||
128 | 'getParams' => $request->getParams, |
||
129 | ] |
||
130 | ); |
||
131 | $promises[$name] = $client->requestAsync($request->method, $url, $this->getOptions($request)); |
||
132 | } |
||
133 | /** @var \GuzzleHttp\Psr7\Response[] $responses */ |
||
134 | $responses = \GuzzleHttp\Promise\unwrap($promises); |
||
135 | foreach ($responses as $key => $response) { |
||
136 | if ($response->getStatusCode() == 401) { |
||
137 | $this->deleteToken(); |
||
138 | return $this->batchQuery($requests); |
||
139 | } |
||
140 | } |
||
141 | return $responses; |
||
142 | } |
||
143 | |||
144 | /** |
||
145 | * Запрос к API. |
||
146 | * |
||
147 | * @param string $method |
||
148 | * @param string $entity |
||
149 | * @param array $getParams |
||
150 | * @return Response |
||
151 | * @throws \Exception |
||
152 | */ |
||
153 | public function query($method, $entity, array $getParams = []) |
||
154 | { |
||
155 | $response = $this->batchQuery([ |
||
156 | new Request([ |
||
157 | 'entity' => $entity, |
||
158 | 'method' => $method, |
||
159 | 'getParams' => $getParams, |
||
160 | ]) |
||
161 | ]); |
||
162 | return reset($response); |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
![]() |
|||
163 | } |
||
164 | |||
165 | /** |
||
166 | * GET запрос к API. |
||
167 | * |
||
168 | * @param string $entity |
||
169 | * @param array $getParams |
||
170 | * @return Response |
||
171 | */ |
||
172 | public function get($entity, array $getParams = []) |
||
173 | { |
||
174 | return $this->query('GET', $entity, $getParams); |
||
175 | } |
||
176 | |||
177 | /** |
||
178 | * Удалить файл с токеном. |
||
179 | * |
||
180 | * @return Client |
||
181 | * @throws \Exception |
||
182 | */ |
||
183 | public function deleteToken() |
||
184 | { |
||
185 | $this->token = null; |
||
186 | $filename = $this->getTokenFilename(); |
||
187 | if (file_exists($filename)) { |
||
188 | unlink($filename); |
||
189 | } |
||
190 | return $this; |
||
191 | } |
||
192 | |||
193 | /** |
||
194 | * Получить опции для http клиента. |
||
195 | * |
||
196 | * @param Request|null $request |
||
197 | * @return array |
||
198 | */ |
||
199 | public function getOptions(Request $request = null) |
||
200 | { |
||
201 | $options = []; |
||
202 | if (!is_null($request)) { |
||
203 | if (!empty($request->getParams)) { |
||
204 | $options[RequestOptions::QUERY] = $request->getParams; |
||
205 | } |
||
206 | } |
||
207 | $options = array_merge($this->options, $options); |
||
208 | $options['headers']['Authorization'] = $this->getToken(); |
||
209 | return $options; |
||
210 | } |
||
211 | |||
212 | /** |
||
213 | * Аутентификация пользователя. |
||
214 | * |
||
215 | * @throws \Exception |
||
216 | */ |
||
217 | private function auth() |
||
218 | { |
||
219 | $client = $this->getHttpClient(); |
||
220 | $options = $this->options; |
||
221 | $options[RequestOptions::JSON] = [ |
||
222 | "email" => $this->login, |
||
223 | "password" => $this->password, |
||
224 | "regulation" => $this->regulation |
||
225 | ]; |
||
226 | $response = $client->request('POST', $this->createUrl('signin'), $options); |
||
227 | if ($response->getStatusCode() != 204) { |
||
228 | throw new \Exception($response->getReasonPhrase(), $response->getStatusCode()); |
||
229 | } |
||
230 | $headerAuth = $response->getHeader("Authorization"); |
||
231 | $this->token = reset($headerAuth); |
||
0 ignored issues
–
show
It seems like
reset($headerAuth) can also be of type false . However, the property $token is declared as type string . Maybe add an additional type check?
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly. For example, imagine you have a variable Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
![]() |
|||
232 | file_put_contents($this->getTokenFilename(), $this->token); |
||
233 | } |
||
234 | |||
235 | /** |
||
236 | * Создания url к сущности. |
||
237 | * |
||
238 | * @param string $entity |
||
239 | * @return string |
||
240 | */ |
||
241 | private function createUrl($entity) |
||
242 | { |
||
243 | $url = $this->baseUrl; |
||
244 | $urlLen = strlen($url); |
||
245 | if ($url[$urlLen - 1] != '/' && $entity[0] != '/') { |
||
246 | $url .= "/"; |
||
247 | } |
||
248 | return $url . $entity; |
||
249 | } |
||
250 | |||
251 | /** |
||
252 | * Получить полный путь до токена. |
||
253 | * |
||
254 | * @return string |
||
255 | * @throws \Exception |
||
256 | */ |
||
257 | private function getTokenFilename() |
||
258 | { |
||
259 | if (is_null($this->tokenPath)) { |
||
260 | $this->tokenPath = sys_get_temp_dir(); |
||
261 | } |
||
262 | if (!file_exists($this->tokenPath)) { |
||
263 | throw new \Exception("Path {$this->tokenPath} not found"); |
||
264 | } |
||
265 | if (substr($this->tokenPath, -1) != '/') { |
||
266 | $this->tokenPath .= '/'; |
||
267 | } |
||
268 | return $this->tokenPath . 'token.txt'; |
||
269 | } |
||
270 | |||
271 | /** |
||
272 | * Получить токен. |
||
273 | * |
||
274 | * @return string |
||
275 | * @throws \Exception |
||
276 | */ |
||
277 | private function getToken() |
||
278 | { |
||
279 | if (is_null($this->token)) { |
||
280 | $filename = $this->getTokenFilename(); |
||
281 | if (file_exists($filename)) { |
||
282 | $this->token = file_get_contents($filename); |
||
283 | } else { |
||
284 | $this->auth(); |
||
285 | } |
||
286 | } |
||
287 | return $this->token; |
||
288 | } |
||
289 | } |
||
290 |