Issues (24)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/classes/Collection.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Class BookCollection
4
 *
5
 * @author       Denis Shestakov <[email protected]>
6
 * @copyright    Copyright (c) 2017, Lan Publishing
7
 * @license      MIT
8
 */
9
10
namespace Lan\Ebs\Sdk\Classes;
11
12
use ArrayObject;
13
use Exception;
14
use Lan\Ebs\Sdk\Client;
15
use Lan\Ebs\Sdk\Collection\ArticleCollection;
16
use Lan\Ebs\Sdk\Collection\IssueCollection;
17
use Lan\Ebs\Sdk\Common;
18
use ReflectionClass;
19
20
/**
21
 * Абстрактный класс для всех коллекций (+ итерируемый)
22
 *
23
 * @package      Lan\Ebs
24
 * @subpackage   Sdk
25
 * @category     Classes
26
 */
27
abstract class Collection extends ArrayObject implements Common
28
{
29
    /**
30
     * Инстанс клиента API
31
     *
32
     * @var Client
33
     */
34
    private $client;
35
36
    /**
37
     * Флаг, сигнализирующий что коллекция загружена
38
     *
39
     * @var int
40
     */
41
    private $loadStatus = 0;
42
43
    /**
44
     * Имена полей, подлежаших получению через API
45
     *
46
     * @var array
47
     */
48
    private $fields = array();
49
50
    /**
51
     * Класс модели
52
     *
53
     * @var Model|string
54
     */
55
    private $class = null;
56
57
    /**
58
     * Лимит получаемых моделей коллекции через API
59
     *
60
     * @var int
61
     */
62
    private $limit = null;
63
64
    /**
65
     * Смещение выборки моделей через API
66
     *
67
     * @var int
68
     */
69
    private $offset = null;
70
71
    /**
72
     * Всего элементов без учета лимита
73
     *
74
     * @var int
75
     */
76
    private $fullCount = null;
77
78
    /**
79
     * Конструктор коллекции
80
     *
81
     * @param Client $client Инстанс клиента
82
     * @param array $fields Поля для выборки
83
     * @param string $class Класс модели
84
     * @param int $limit Лимит выборки
85
     * @param int $offset Смещение выборки
86
     *
87
     * Пример:
88
     * ```php
89
     *      $token = '7c0c2193d27108a509abd8ea84a8750c82b3a520'; // токен для тестового подписчика
90
     *
91
     *      $client = new Client($token); // инициализация клиента
92
     *
93
     *      $bookCollection = new BookCollection($client, [], '\Lan\Ebs\Sdk\Model\Book', 5, 10); // инициализация коллекции книг
94
     * ```
95
     *
96
     * @throws Exception
97
     *
98
     * @see ArticleCollection::__construct
99
     * @see BookCollection::__construct
100
     * @see IssueCollection::__construct
101
     * @see JournalCollection::__construct
102
     * @see UserCollection::__construct
103
     */
104 3
    public function __construct(Client $client, array $fields, $class, $limit, $offset)
105
    {
106 3
        if (!$client) {
107
            throw new Exception('Клиент не инициализирован');
108
        }
109
110 3
        if (!is_array($fields)) {
111
            throw new Exception('Fields for model of collection mast be array');
112
        }
113
114 3
        $reflectionClass = new ReflectionClass($class);
115
116 3
        if (!$reflectionClass->isSubclassOf(Model::class)) {
117
            throw new Exception('Class of model collection not subclass for Model');
118
        }
119
120 3
        $this->client = $client;
121 3
        $this->fields = $fields;
122 3
        $this->class = $class;
123
124 3
        $this->setLimit($limit);
125 3
        $this->setOffset($offset);
126 3
    }
127
128
    /**
129
     * Установка лимита выборки
130
     *
131
     * Установка/изменение лимита выборки коллекции. Вызывет перезагрузку коллекции если значение лимита изменилось
132
     *
133
     * @param int $limit Значение лимита выборки
134
     *
135
     * Пример:
136
     * ```php
137
     *      $token = '7c0c2193d27108a509abd8ea84a8750c82b3a520'; // токен для тестового подписчика
138
     *
139
     *      $client = new Client($token); // инициализация клиента
140
     *
141
     *      $bookCollection = new BookCollection($client, [], '\Lan\Ebs\Sdk\Model\Book', 5, 100); // инициализация коллекции книг
142
     *
143
     *      $bookCollection->setLimit(100); // изменение лимита с 5 до 100
144
     * ```
145
     *
146
     * @return $this
147
     *
148
     * Пример:
149
     * ```php
150
     *      echo $bookCollection->setLimit(100)->count(); // Выведет количество элементов коллекции
151
     * ```
152
     *
153
     * @throws Exception
154
     */
155 3 View Code Duplication
    public function setLimit($limit)
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
156
    {
157 3
        $isChanged = $this->limit != $limit;
158
159 3
        $this->limit = $limit;
160
161 3
        if ($isChanged && $this->loadStatus == 200) {
162
            $this->load(true);
163
        }
164
165 3
        return $this;
166
    }
167
168
    /**
169
     * Загрузка коллекции
170
     *
171
     * Загрузка осуществляется только после вызова зависимого метода (ленивая загрузка)
172
     *
173
     * @param bool $force Заново загружать коллекцию даже если она загружена ранее
174
     *
175
     * Пример:
176
     * ```php
177
     *      $token = '7c0c2193d27108a509abd8ea84a8750c82b3a520'; // токен для тестового подписчика
178
     *
179
     *      $client = new Client($token); // инициализация клиента
180
     *
181
     *      $bookCollection = new BookCollection($client, [], '\Lan\Ebs\Sdk\Model\Book', 5, 100); // инициализация коллекции книг
182
     *
183
     *      // Вызова метода загрузки еще небыло.. коллекция пустая
184
     *      $bookCollection->load(); // загрузка коллекции данными
185
     *      // Запрос к API выполнен.. коллекция загружена
186
     * ```
187
     *
188
     * @return $this Вернет текущую коллекцию
189
     *
190
     * Пример:
191
     * ```php
192
     *       echo $bookCollection->load()->count(); // Выведет количество элементов коллекции
193
     * ```
194
     *
195
     * @throws Exception
196
     *
197
     * @see Collection::setLimit()
198
     * @see Collection::setOffset()
199
     * @see Collection::getFullCount()
200
     * @see Collection::getCount()
201
     * @see Collection::getData()
202
     * @see Collection::reset()
203
     * @see Collection::end()
204
     * @see CollectionIterator::rewind()
205
     */
206 3
    public function load($force = false)
207
    {
208 3
        if ($this->loadStatus == 200 && !$force) {
209
            return $this;
210
        }
211
212
        $params = array(
213 3
            'limit' => $this->limit,
214 3
            'offset' => $this->offset
215
        );
216
217 3
        if (!empty($this->fields)) {
218
            $params['fields'] = implode(',', (array)$this->fields);
219
        }
220
221 3
        $response = $this->client->getResponse($this->getUrl(__FUNCTION__), $params);
222
223
        $this->exchangeArray($response['data']);
224
225
        $this->loadStatus = $response['status'];
226
227
        $this->fullCount = $response['count'];
228
229
        unset($response);
230
231
        return $this;
232
    }
233
234
    /**
235
     * Установка смещения выборки
236
     *
237
     * Установка/изменение смещения выборки коллекции. Вызывет перезагрузку коллекции если значение смещения изменилось
238
     *
239
     * @param int $offset Значение смещения выборки
240
     *
241
     * Пример:
242
     * ```php
243
     *      $token = '7c0c2193d27108a509abd8ea84a8750c82b3a520'; // токен для тестового подписчика
244
     *
245
     *      $client = new Client($token); // инициализация клиента
246
     *
247
     *      $bookCollection = new BookCollection($client, [], '\Lan\Ebs\Sdk\Model\Book', 5, 100); // инициализация коллекции книг
248
     *
249
     *      $bookCollection->setOffset(1000); // изменение смещения со 100 до 1000
250
     * ```
251
     *
252
     * @return $this Вернет текущую коллекцию
253
     *
254
     * Пример:
255
     * ```php
256
     *      echo $bookCollection->setOffset(1000)->count(); // Выведет количество элементов коллекции
257
     * ```
258
     *
259
     * @throws Exception
260
     */
261 3 View Code Duplication
    public function setOffset($offset)
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
262
    {
263 3
        $isChanged = $this->offset != $offset;
264
265 3
        $this->offset = $offset;
266
267 3
        if ($isChanged && $this->loadStatus == 200) {
268
            $this->load(true);
269
        }
270
271 3
        return $this;
272
    }
273
274
    /**
275
     * Получение количества всех элементов без учета лимита
276
     *
277
     * Вернет общее количество элементов необходимое, например, для вычисления постраничной выборки
278
     *
279
     * Пример:
280
     * ```php
281
     *      $token = '7c0c2193d27108a509abd8ea84a8750c82b3a520'; // токен для тестового подписчика
282
     *
283
     *      $client = new Client($token); // инициализация клиента
284
     *
285
     *      $bookCollection = new BookCollection($client, [], '\Lan\Ebs\Sdk\Model\Book', 5, 100); // инициализация коллекции книг
286
     *
287
     *      echo $bookCollection->getFullCount(); // Вернет количество элементов без учета лимита
288
     * ```
289
     *
290
     * @return int
291
     *
292
     * Пример:
293
     * ```php
294
     *      echo $bookCollection>getFullCount(); // Вернет, например, 286
295
     *      echo $bookCollection->сount(); // Вернет, например, 5
296
     *      // Итого получаем ceil($bookCollection>getFullCount() /  $bookCollection>getLimit()) = 58 страниц
297
     * ```
298
     *
299
     * @throws Exception
300
     */
301
    public function getFullCount()
302
    {
303
        $this->load();
304
305
        return $this->fullCount;
306
    }
307
308
    /**
309
     * Получение нового инстанса итератора коллекции
310
     *
311
     * Итератор для реализации итерируемой коллекции
312
     *
313
     * @return CollectionIterator Вернет экзепляря итератора текущей коллекции
314
     */
315
    public function getIterator()
316
    {
317
        return new CollectionIterator($this);
318
    }
319
320
    /**
321
     * Количество моделей в коллекции
322
     *
323
     * Фактическое число моделей в коллекции
324
     *
325
     * Пример:
326
     * ```php
327
     *      $token = '7c0c2193d27108a509abd8ea84a8750c82b3a520'; // токен для тестового подписчика
328
     *
329
     *      $client = new Client($token); // инициализация клиента
330
     *
331
     *      $bookCollection = new BookCollection($client, [], '\Lan\Ebs\Sdk\Model\Book', 5, 100); // инициализация коллекции книг
332
     *
333
     *      echo $bookCollection>getFullCount(); // Вернет количество элементов без учета лимита
334
     * ```
335
     *
336
     * @return int
337
     *
338
     * Пример:
339
     * ```php
340
     *      echo $bookCollection->сount(); // Вернет, например, 5 (но не больше 5 - фактическое количество)
341
     * ```
342
     *
343
     * @throws Exception
344
     */
345 2
    public function count()
346
    {
347 2
        $this->load();
348
349
        return parent::count();
350
    }
351
352
    /**
353
     * Получение коллекции в виде массива
354
     *
355
     * Выгрузка коллекции в массив
356
     *
357
     * Пример:
358
     * ```php
359
     *      $token = '7c0c2193d27108a509abd8ea84a8750c82b3a520'; // токен для тестового подписчика
360
     *
361
     *      $client = new Client($token); // инициализация клиента
362
     *
363
     *      $bookCollection = new BookCollection($client, [], '\Lan\Ebs\Sdk\Model\Book', 1, 10); // инициализация коллекции книг
364
     *
365
     *      print_r($bookCollection->getData()); // Вернет количество элементов без учета лимита
366
     * ```
367
     *
368
     * @return array
369
     *
370
     * Пример:
371
     * ```
372
     * [
373
     *      'id' => 22445,
374
     *      'name' => 'Свадьба. Сцена в одном действии',
375
     *      'authors' => 'Чехов А.П.'
376
     * ]
377
     * ```
378
     *
379
     * @throws Exception
380
     */
381
    public function getData()
382
    {
383
        $this->load();
384
385
        return $this->getArrayCopy();
386
    }
387
388
    /**
389
     * Получение первой модели в коллекции
390
     *
391
     * Вернет первую модель коллекции.
392
     *
393
     * @return Model
394
     *
395
     * @throws Exception
396
     */
397 1
    public function reset()
398
    {
399 1
        $this->load();
400
401
        $data = reset($this);
402
403
        return $data ? $this->createModel($data) : null;
404
    }
405
406
    /**
407
     * Создание модели по переданным данным
408
     *
409
     * Создает модель по ее данным
410
     *
411
     * Пример:
412
     * ```php
413
     *      $token = '7c0c2193d27108a509abd8ea84a8750c82b3a520'; // токен для тестового подписчика
414
     *
415
     *      $client = new Client($token); // инициализация клиента
416
     *
417
     *      $bookCollection = new BookCollection($client, [], '\Lan\Ebs\Sdk\Model\Book', 1, 10); // инициализация коллекции книг
418
     *
419
     *      $bookData = [
420
     *          'id' => 22445,
421
     *          'name' => 'Свадьба. Сцена в одном действии',
422
     *          'authors' => 'Чехов А.П.'
423
     *      ];
424
     *
425
     *      $book = $bookCollection->createModel($bookData);
426
     * ```
427
     *
428
     * @param array $data Данные для создания модели
429
     *
430
     * @return Model Вернет модель на основе данных
431
     *
432
     * @throws Exception
433
     */
434
    public function createModel(array $data = null)
435
    {
436
        $class = $this->class;
437
438
        /**
439
         * @var Model $model
440
         */
441
        $model = new $class($this->client, $this->fields);
442
443
        $model->set($data === null ? current($this) : $data);
444
445
        return $model;
446
    }
447
448
    /**
449
     * Получение последней модели в коллекции
450
     *
451
     * Вернет полделнюю модель коллекции.
452
     *
453
     * @return Model
454
     *
455
     * @throws Exception
456
     */
457
    public function end()
458
    {
459
        $this->load();
460
461
        $data = end($this);
462
463
        return $data ? $this->createModel($data) : null;
464
    }
465
466
    /**
467
     * Получение инстанса клиента
468
     *
469
     * @return Client
470
     */
471
    protected function getClient()
472
    {
473
        return $this->client;
474
    }
475
476
    /**
477
     * Получение текущего лимита коллекции
478
     *
479
     * @return int
480
     */
481
    public function getLimit()
482
    {
483
        return $this->limit;
484
    }
485
486
    /**
487
     *
488
     * Получение текущего смещения коллекции
489
     *
490
     * @return int
491
     */
492
    public function getOffset()
493
    {
494
        return $this->offset;
495
    }
496
497
    /**
498
     * Общее количество страниц при заданом лимиите на страницу
499
     *
500
     * @return float
501
     * @throws Exception
502
     */
503
    public function getPages() {
504
        return ceil($this->getFullCount() /  $this->getLimit());
505
    }
506
}