Issues (3887)

Security Analysis    not enabled

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.

ORM/Query/BufferedQueryResultIterator.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
namespace Oro\Bundle\BatchBundle\ORM\Query;
4
5
use Doctrine\ORM\QueryBuilder;
6
use Doctrine\ORM\Query;
7
8
/**
9
 * Iterates results of Query using buffer, allows to iterate large query
10
 * results without risk of getting out of memory error
11
 */
12
class BufferedQueryResultIterator implements \Iterator, \Countable
13
{
14
    /**
15
     * Count of records that will be loaded on each page during iterations
16
     */
17
    const DEFAULT_BUFFER_SIZE = 200;
18
19
    /**
20
     * Count of records that will be loaded on each page during iterations
21
     * This is just recommended buffer size because the real size can be differed
22
     * in case when MaxResults of source query is specified
23
     *
24
     * @var int
25
     */
26
    private $requestedBufferSize = self::DEFAULT_BUFFER_SIZE;
27
28
    /**
29
     * Defines the processing mode to be used during hydration / result set transformation
30
     * This is just recommended hydration mode because the real mode can be calculated automatically
31
     * in case when the requested hydration mode is not specified
32
     *
33
     * @var integer
34
     */
35
    private $requestedHydrationMode;
36
37
    /**
38
     * The source Query or QueryBuilder
39
     *
40
     * @var mixed
41
     */
42
    private $source;
43
44
    /**
45
     * Query to iterate
46
     *
47
     * @var Query
48
     */
49
    private $query;
50
51
    /**
52
     * Total count of records in query
53
     *
54
     * @var int
55
     */
56
    private $totalCount;
57
58
    /**
59
     * Index of current page
60
     *
61
     * @var int
62
     */
63
    private $page = -1;
64
65
    /**
66
     * Offset of current record in current page
67
     *
68
     * @var int
69
     */
70
    private $offset = -1;
71
72
    /**
73
     * A position of a current record within the current page
74
     *
75
     * @var int
76
     */
77
    private $position = -1;
78
79
    /**
80
     * Rows that where loaded for current page
81
     *
82
     * @var array
83
     */
84
    private $rows;
85
86
    /**
87
     * Current record, populated from query result row
88
     *
89
     * @var mixed
90
     */
91
    private $current;
92
93
    /**
94
     * @var int
95
     */
96
    protected $firstResult;
97
98
    /**
99
     * The maximum number of results the original query object was set to retrieve
100
     *
101
     * @var int
102
     */
103
    protected $maxResults;
104
105
    /**
106
     * @var bool|null
107
     */
108
    private $useCountWalker;
109
110
    /**
111
     * Walk through results in reverse order
112
     * Useful when selected records are being updated in between page load
113
     *
114
     * @var bool
115
     */
116
    private $reverse = false;
117
118
    /**
119
     * @var callable|null
120
     */
121
    protected $pageCallback;
122
123
    /**
124
     * @var callable|null
125
     */
126
    protected $pageLoadedCallback;
127
128
    /**
129
     * Constructor
130
     *
131
     * @param Query|QueryBuilder $source
132
     * @param null|bool $useCountWalker
133
     */
134
    public function __construct($source, $useCountWalker = null)
135
    {
136
        if (null === $source) {
137
            throw new \InvalidArgumentException('The $source must not be null');
138
        } elseif (!($source instanceof Query) && !($source instanceof QueryBuilder)) {
139
            throw new \InvalidArgumentException(
140
                sprintf(
141
                    'The $source must be instance of "%s" or "%s", but "%s" given',
142
                    is_object($this->source) ? get_class($this->source) : gettype($this->source),
143
                    'Doctrine\ORM\Query',
144
                    'Doctrine\ORM\QueryBuilder'
145
                )
146
            );
147
        }
148
        $this->source = $source;
149
        $this->useCountWalker = $useCountWalker;
150
    }
151
152
    /**
153
     * Sets size of buffer that is queried from storage to iterate results
154
     *
155
     * @param int $bufferSize
156
     * @return BufferedQueryResultIterator
157
     * @throws \InvalidArgumentException If buffer size is not greater than 0
158
     */
159
    public function setBufferSize($bufferSize)
160
    {
161
        $this->assertQueryWasNotExecuted('buffer size');
162
        if ($bufferSize <= 0) {
163
            throw new \InvalidArgumentException('$bufferSize must be greater than 0');
164
        }
165
        $this->requestedBufferSize = (int)$bufferSize;
166
167
        return $this;
168
    }
169
170
    /**
171
     * Sets callback to be called after page iteration was finished
172
     *
173
     * @param callable|null $callback
174
     *
175
     * @return $this
176
     */
177
    public function setPageCallback(callable $callback = null)
178
    {
179
        $this->pageCallback = $callback;
180
181
        return $this;
182
    }
183
184
    /**
185
     * Sets callback to be called after page is loaded
186
     *
187
     * @param callable|null $callback (array $rows): array $rows
188
     *
189
     * @return $this
190
     */
191
    public function setPageLoadedCallback(callable $callback = null)
192
    {
193
        $this->pageLoadedCallback = $callback;
194
195
        return $this;
196
    }
197
198
    /**
199
     * Sets query hydration mode to be used to iterate results
200
     *
201
     * @param integer $hydrationMode Processing mode to be used during the hydration process.
202
     * @return BufferedQueryResultIterator
203
     */
204
    public function setHydrationMode($hydrationMode)
205
    {
206
        $this->assertQueryWasNotExecuted('hydration mode');
207
        $this->requestedHydrationMode = $hydrationMode;
208
209
        return $this;
210
    }
211
212
    /**
213
     * Sets iteration order
214
     *
215
     * @param bool $reverse Determines the iteration order
216
     * @return BufferedQueryResultIterator
217
     */
218
    public function setReverse($reverse)
219
    {
220
        $this->assertQueryWasNotExecuted('reverse mode');
221
        $this->reverse = $reverse;
222
223
        return $this;
224
    }
225
226
    /**
227
     * {@inheritDoc}
228
     */
229
    public function current()
230
    {
231
        return $this->current;
232
    }
233
234
    /**
235
     * {@inheritDoc}
236
     */
237
    public function next()
238
    {
239
        $this->offset++;
240
241
        if (!isset($this->rows[$this->offset]) && !$this->loadNextPage()) {
242
            $this->current = null;
243
        } else {
244
            $this->current  = $this->rows[$this->offset];
245
            $this->position = $this->offset + $this->getQuery()->getMaxResults() * $this->page;
246
        }
247
    }
248
249
    /**
250
     * {@inheritDoc}
251
     */
252
    public function key()
253
    {
254
        return $this->position;
255
    }
256
257
    /**
258
     * {@inheritDoc}
259
     */
260
    public function valid()
261
    {
262
        return null !== $this->current;
263
    }
264
265
    /**
266
     * {@inheritDoc}
267
     */
268
    public function rewind()
269
    {
270
        // reset total count only if at least one item was loaded by this iterator
271
        // for example if we call count method and then start iteration the total count must be calculated once
272
        if (null !== $this->totalCount && $this->offset != -1) {
273
            $this->totalCount = null;
274
        }
275
        $this->offset     = -1;
276
        $this->page       = -1;
277
        $this->position   = -1;
278
        $this->current    = null;
279
280
        $this->next();
281
    }
282
283
    /**
284
     * {@inheritDoc}
285
     */
286
    public function count()
287
    {
288
        if (null === $this->totalCount) {
289
            $query = $this->cloneQuery($this->getQuery());
290
            // restore original max results
291
            $query->setMaxResults($this->maxResults);
292
293
            $this->totalCount = QueryCountCalculator::calculateCount($query, $this->useCountWalker);
294
        }
295
296
        return $this->totalCount;
297
    }
298
299
    /**
300
     * Asserts that query was not executed, otherwise raise an exception
301
     *
302
     * @param string $optionLabel
303
     * @throws \LogicException
304
     */
305
    protected function assertQueryWasNotExecuted($optionLabel)
306
    {
307
        if (!$this->source) {
308
            throw new \LogicException(sprintf('Cannot set %s object as query was already executed.', $optionLabel));
309
        }
310
    }
311
312
    /**
313
     * @return Query
314
     * @throws \LogicException If source of a query is not valid
315
     */
316
    protected function getQuery()
317
    {
318
        if (null === $this->query) {
319
            if ($this->source instanceof Query) {
320
                $this->query = $this->cloneQuery($this->source);
321
            } elseif ($this->source instanceof QueryBuilder) {
322
                $this->query = $this->source->getQuery();
323
            } else {
324
                throw new \LogicException('Unexpected source');
325
            }
326
            unset($this->source);
327
328
            // initialize cloned query
329
            $this->maxResults = $this->query->getMaxResults();
330
            if (!$this->maxResults || $this->requestedBufferSize < $this->maxResults) {
331
                $this->query->setMaxResults($this->requestedBufferSize);
332
            }
333
            if (null !== $this->requestedHydrationMode) {
334
                $this->query->setHydrationMode($this->requestedHydrationMode);
335
            }
336
            $this->firstResult = (int)$this->query->getFirstResult();
337
        }
338
339
        return $this->query;
340
    }
341
342
    /**
343
     * Makes full clone of the given query, including its parameters and hints
344
     *
345
     * @param Query $query
346
     * @return Query
347
     */
348 View Code Duplication
    protected function cloneQuery(Query $query)
349
    {
350
        $result = clone $query;
351
352
        // clone parameters
353
        $result->setParameters(clone $query->getParameters());
354
355
        // clone hints
356
        foreach ($query->getHints() as $name => $value) {
357
            $result->setHint($name, $value);
358
        }
359
360
        return $result;
361
    }
362
363
    /**
364
     * Attempts to load next page
365
     *
366
     * @return bool If page loaded successfully
367
     */
368
    protected function loadNextPage()
369
    {
370
        if ($this->pageCallback && $this->page !== -1) {
371
            call_user_func($this->pageCallback);
372
        }
373
374
        $query = $this->getQuery();
375
376
        $totalPages = ceil($this->count() / $query->getMaxResults());
377
        if ($this->reverse) {
378
            if ($this->page == -1) {
379
                $this->page = $totalPages;
380
            }
381
            if ($this->page < 1) {
382
                unset($this->rows);
383
384
                return false;
385
            }
386
            $this->page--;
387
        } else {
388
            if (!$totalPages || $totalPages <= $this->page + 1) {
389
                unset($this->rows);
390
391
                return false;
392
            }
393
            $this->page++;
394
        }
395
396
        $this->offset = 0;
397
398
        $this->prepareQueryToExecute($query);
399
        $this->rows = $query->execute();
0 ignored issues
show
Documentation Bug introduced by
It seems like $query->execute() of type * is incompatible with the declared type array of property $rows.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
400
401
        if ($this->pageLoadedCallback) {
402
            $this->rows = call_user_func($this->pageLoadedCallback, $this->rows);
0 ignored issues
show
Documentation Bug introduced by
It seems like call_user_func($this->pa...dCallback, $this->rows) of type * is incompatible with the declared type array of property $rows.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
403
        }
404
405
        return count($this->rows) > 0;
406
    }
407
408
    /**
409
     * Makes final preparation of a query object before its execute method will be called.
410
     *
411
     * @param Query $query
412
     */
413
    protected function prepareQueryToExecute(Query $query)
414
    {
415
        $query->setFirstResult($this->firstResult + $query->getMaxResults() * $this->page);
416
    }
417
}
418