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.
1 | <?php |
||||
2 | |||||
3 | declare(strict_types=1); |
||||
4 | |||||
5 | namespace QB\Generic\Statement; |
||||
6 | |||||
7 | use QB\Generic\Clause\Column; |
||||
8 | use QB\Generic\Clause\IColumn; |
||||
9 | use QB\Generic\Clause\IJoin; |
||||
10 | use QB\Generic\Clause\ITable; |
||||
11 | use QB\Generic\Clause\Join; |
||||
12 | use QB\Generic\Clause\Table; |
||||
13 | use QB\Generic\Expr\Expr; |
||||
14 | use QB\Generic\IQueryPart; |
||||
15 | use RuntimeException; |
||||
16 | |||||
17 | /** |
||||
18 | * @SuppressWarnings(PHPMD.TooManyPublicMethods) |
||||
19 | * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) |
||||
20 | * SuppressWarnings("complexity") |
||||
21 | */ |
||||
22 | class Select implements ISelect |
||||
23 | { |
||||
24 | public const ALL = 'ALL'; |
||||
25 | public const DISTINCT = 'DISTINCT'; |
||||
26 | |||||
27 | /** @var array<int,Table|string> */ |
||||
28 | protected array $tables = []; |
||||
29 | |||||
30 | /** @var string[] */ |
||||
31 | protected array $modifiers = []; |
||||
32 | |||||
33 | /** @var IColumn[] */ |
||||
34 | protected array $columns = []; |
||||
35 | |||||
36 | /** @var IJoin[] */ |
||||
37 | protected array $joins = []; |
||||
38 | |||||
39 | /** @var IQueryPart[] */ |
||||
40 | protected array $whereParts = []; |
||||
41 | |||||
42 | /** @var IQueryPart[] */ |
||||
43 | protected array $groupByParts = []; |
||||
44 | |||||
45 | /** @var IQueryPart[] */ |
||||
46 | protected array $havingParts = []; |
||||
47 | |||||
48 | /** @var array<string,string> */ |
||||
49 | protected array $orderBy = []; |
||||
50 | |||||
51 | protected ?int $offset = null; |
||||
52 | |||||
53 | protected ?int $limit = null; |
||||
54 | |||||
55 | /** |
||||
56 | * Select constructor. |
||||
57 | * |
||||
58 | * @param IColumn|string ...$columns |
||||
59 | */ |
||||
60 | 69 | public function __construct(IColumn|string ...$columns) |
|||
61 | { |
||||
62 | 69 | $this->columns(...$columns); |
|||
63 | 69 | } |
|||
64 | |||||
65 | /** |
||||
66 | * @param ITable|string ...$tables |
||||
67 | * |
||||
68 | * @return $this |
||||
69 | */ |
||||
70 | 51 | public function from(ITable|string ...$tables): static |
|||
71 | { |
||||
72 | 51 | $this->tables = array_merge($this->tables, $tables); |
|||
73 | |||||
74 | 51 | return $this; |
|||
75 | } |
||||
76 | |||||
77 | /** |
||||
78 | * @param string ...$modifiers |
||||
79 | * |
||||
80 | * @return $this |
||||
81 | */ |
||||
82 | 5 | public function modifier(string ...$modifiers): static |
|||
83 | { |
||||
84 | 5 | $this->modifiers = array_merge($this->modifiers, $modifiers); |
|||
85 | |||||
86 | 5 | return $this; |
|||
87 | } |
||||
88 | |||||
89 | /** |
||||
90 | * @param IColumn|string ...$columns |
||||
91 | * |
||||
92 | * @return $this |
||||
93 | */ |
||||
94 | 69 | public function columns(IColumn|string ...$columns): static |
|||
95 | { |
||||
96 | 69 | foreach ($columns as $column) { |
|||
97 | 42 | if ($column instanceof IColumn) { |
|||
98 | 13 | $this->columns[] = $column; |
|||
99 | 13 | continue; |
|||
100 | } |
||||
101 | |||||
102 | 33 | if (strpos($column, ' AS ')) { |
|||
103 | 5 | $parts = explode(' AS ', $column); |
|||
104 | |||||
105 | 5 | $this->columns[] = new Column($parts[0], $parts[1]); |
|||
106 | } else { |
||||
107 | 33 | $this->columns[] = new Column($column, null); |
|||
108 | } |
||||
109 | } |
||||
110 | |||||
111 | 69 | return $this; |
|||
112 | } |
||||
113 | |||||
114 | /** |
||||
115 | * @param ITable|string $table |
||||
116 | * @param IQueryPart|string|null $on |
||||
117 | * |
||||
118 | * @return $this |
||||
119 | */ |
||||
120 | 8 | public function innerJoin(ITable|string $table, IQueryPart|string|null $on = null): static |
|||
0 ignored issues
–
show
|
|||||
121 | { |
||||
122 | 8 | $this->joins[] = new Join(IJoin::TYPE_INNER_JOIN, $table, $on); |
|||
0 ignored issues
–
show
It seems like
$on can also be of type null ; however, parameter $on of QB\Generic\Clause\Join::__construct() does only seem to accept QB\Generic\Clause\null|Q...neric\IQueryPart|string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
123 | |||||
124 | 8 | return $this; |
|||
125 | } |
||||
126 | |||||
127 | /** |
||||
128 | * @param ITable|string $table |
||||
129 | * @param IQueryPart|string|null $on |
||||
130 | * |
||||
131 | * @return $this |
||||
132 | */ |
||||
133 | 6 | public function leftJoin(ITable|string $table, IQueryPart|string|null $on = null): static |
|||
134 | { |
||||
135 | 6 | $this->joins[] = new Join(IJoin::TYPE_LEFT_JOIN, $table, $on); |
|||
0 ignored issues
–
show
It seems like
$on can also be of type null ; however, parameter $on of QB\Generic\Clause\Join::__construct() does only seem to accept QB\Generic\Clause\null|Q...neric\IQueryPart|string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
136 | |||||
137 | 6 | return $this; |
|||
138 | } |
||||
139 | |||||
140 | /** |
||||
141 | * @param ITable|string $table |
||||
142 | * @param IQueryPart|string|null $on |
||||
143 | * |
||||
144 | * @return $this |
||||
145 | */ |
||||
146 | 3 | public function rightJoin(ITable|string $table, IQueryPart|string|null $on = null): static |
|||
147 | { |
||||
148 | 3 | $this->joins[] = new Join(IJoin::TYPE_RIGHT_JOIN, $table, $on); |
|||
0 ignored issues
–
show
It seems like
$on can also be of type null ; however, parameter $on of QB\Generic\Clause\Join::__construct() does only seem to accept QB\Generic\Clause\null|Q...neric\IQueryPart|string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
149 | |||||
150 | 3 | return $this; |
|||
151 | } |
||||
152 | |||||
153 | /** |
||||
154 | * @param ITable|string $table |
||||
155 | * @param IQueryPart|string|null $on |
||||
156 | * |
||||
157 | * @return $this |
||||
158 | */ |
||||
159 | 3 | public function fullJoin(ITable|string $table, IQueryPart|string|null $on = null): static |
|||
160 | { |
||||
161 | 3 | $this->joins[] = new Join(IJoin::TYPE_FULL_JOIN, $table, $on); |
|||
0 ignored issues
–
show
It seems like
$on can also be of type null ; however, parameter $on of QB\Generic\Clause\Join::__construct() does only seem to accept QB\Generic\Clause\null|Q...neric\IQueryPart|string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
162 | |||||
163 | 3 | return $this; |
|||
164 | } |
||||
165 | |||||
166 | /** |
||||
167 | * @param IJoin ...$joins |
||||
168 | * |
||||
169 | * @return $this |
||||
170 | */ |
||||
171 | 3 | public function join(IJoin ...$joins): static |
|||
172 | { |
||||
173 | 3 | $this->joins = array_merge($this->joins, $joins); |
|||
174 | |||||
175 | 3 | return $this; |
|||
176 | } |
||||
177 | |||||
178 | /** |
||||
179 | * @param IQueryPart|string ...$whereParts |
||||
180 | * |
||||
181 | * @return $this |
||||
182 | */ |
||||
183 | 8 | public function where(IQueryPart|string ...$whereParts): static |
|||
184 | { |
||||
185 | 8 | foreach ($whereParts as $wherePart) { |
|||
186 | 8 | $wherePart = is_string($wherePart) ? new Expr($wherePart) : $wherePart; |
|||
187 | |||||
188 | 8 | $this->whereParts[] = $wherePart; |
|||
189 | } |
||||
190 | |||||
191 | 8 | return $this; |
|||
192 | } |
||||
193 | |||||
194 | /** |
||||
195 | * @param IQueryPart|string ...$groupByParts |
||||
196 | * |
||||
197 | * @return $this |
||||
198 | */ |
||||
199 | 8 | public function groupBy(IQueryPart|string ...$groupByParts): static |
|||
200 | { |
||||
201 | 8 | foreach ($groupByParts as $groupByPart) { |
|||
202 | 8 | $groupByPart = is_string($groupByPart) ? new Expr($groupByPart) : $groupByPart; |
|||
203 | |||||
204 | 8 | $this->groupByParts[] = $groupByPart; |
|||
205 | } |
||||
206 | |||||
207 | 8 | return $this; |
|||
208 | } |
||||
209 | |||||
210 | /** |
||||
211 | * @param IQueryPart|string ...$havingParts |
||||
212 | * |
||||
213 | * @return $this |
||||
214 | */ |
||||
215 | 8 | public function having(IQueryPart|string ...$havingParts): static |
|||
216 | { |
||||
217 | 8 | foreach ($havingParts as $havingPart) { |
|||
218 | 8 | $havingPart = is_string($havingPart) ? new Expr($havingPart) : $havingPart; |
|||
219 | |||||
220 | 8 | $this->havingParts[] = $havingPart; |
|||
221 | } |
||||
222 | |||||
223 | 8 | return $this; |
|||
224 | } |
||||
225 | |||||
226 | /** |
||||
227 | * @param string $column |
||||
228 | * @param string $direction |
||||
229 | * |
||||
230 | * @return $this |
||||
231 | */ |
||||
232 | 5 | public function orderBy(string $column, string $direction = self::DIRECTION_ASC): static |
|||
233 | { |
||||
234 | 5 | $this->orderBy[$column] = $direction; |
|||
235 | |||||
236 | 5 | return $this; |
|||
237 | } |
||||
238 | |||||
239 | /** |
||||
240 | * @param int|null $offset |
||||
241 | * |
||||
242 | * @return $this |
||||
243 | */ |
||||
244 | 5 | public function offset(?int $offset): static |
|||
245 | { |
||||
246 | 5 | $this->offset = $offset; |
|||
247 | |||||
248 | 5 | return $this; |
|||
249 | } |
||||
250 | |||||
251 | /** |
||||
252 | * @param int|null $limit |
||||
253 | * |
||||
254 | * @return $this |
||||
255 | */ |
||||
256 | 6 | public function limit(?int $limit): static |
|||
257 | { |
||||
258 | 6 | $this->limit = $limit; |
|||
259 | |||||
260 | 6 | return $this; |
|||
261 | } |
||||
262 | |||||
263 | /** |
||||
264 | * @return string |
||||
265 | */ |
||||
266 | 61 | public function __toString(): string |
|||
267 | { |
||||
268 | 61 | if (!$this->isValid()) { |
|||
269 | 3 | throw new RuntimeException('under-initialized SELECT query'); |
|||
270 | } |
||||
271 | |||||
272 | 58 | $select = $this->getSelect(); |
|||
273 | |||||
274 | 58 | if (count($this->tables) === 0) { |
|||
275 | 19 | return $select; |
|||
276 | } |
||||
277 | |||||
278 | 39 | $parts = array_merge( |
|||
279 | 39 | [$select], |
|||
280 | 39 | $this->getFrom(), |
|||
281 | 39 | $this->getJoin(), |
|||
282 | 39 | $this->getWhere(), |
|||
283 | 39 | $this->getGroupBy(), |
|||
284 | 39 | $this->getHaving(), |
|||
285 | 39 | $this->getOrderBy(), |
|||
286 | 39 | $this->getLimit(), |
|||
287 | ); |
||||
288 | |||||
289 | 39 | $parts = array_filter($parts); |
|||
290 | |||||
291 | 39 | return implode(PHP_EOL, $parts); |
|||
292 | } |
||||
293 | |||||
294 | 61 | public function isValid(): bool |
|||
295 | { |
||||
296 | 61 | return count($this->columns) > 0 || count($this->tables) > 0; |
|||
297 | } |
||||
298 | |||||
299 | 58 | protected function getSelect(): string |
|||
300 | { |
||||
301 | 58 | $sql = []; |
|||
302 | 58 | $sql[] = 'SELECT'; |
|||
303 | 58 | $sql[] = $this->getModifiers(); |
|||
304 | |||||
305 | 58 | $sql = array_filter($sql); |
|||
306 | |||||
307 | 58 | $sql = implode(' ', $sql); |
|||
308 | |||||
309 | 58 | return $sql . ' ' . $this->getColumns(); |
|||
310 | } |
||||
311 | |||||
312 | 58 | protected function getColumns(): string |
|||
313 | { |
||||
314 | 58 | if (empty($this->columns)) { |
|||
315 | 24 | return '*'; |
|||
316 | } |
||||
317 | |||||
318 | 34 | $parts = []; |
|||
319 | 34 | foreach ($this->columns as $column) { |
|||
320 | 34 | $parts[] = (string)$column; |
|||
321 | } |
||||
322 | |||||
323 | 34 | return implode(', ', $parts); |
|||
324 | } |
||||
325 | |||||
326 | 58 | protected function getModifiers(): string |
|||
327 | { |
||||
328 | 58 | if (empty($this->modifiers)) { |
|||
329 | 55 | return ''; |
|||
330 | } |
||||
331 | |||||
332 | 7 | return implode(' ', $this->modifiers); |
|||
333 | } |
||||
334 | |||||
335 | 39 | protected function getFrom(): array |
|||
336 | { |
||||
337 | 39 | return ['FROM ' . implode(', ', $this->tables)]; |
|||
338 | } |
||||
339 | |||||
340 | /** |
||||
341 | * @return string[] |
||||
342 | */ |
||||
343 | 39 | protected function getJoin(): array |
|||
344 | { |
||||
345 | 39 | if (count($this->joins) === 0) { |
|||
346 | 23 | return []; |
|||
347 | } |
||||
348 | |||||
349 | 20 | $parts = []; |
|||
350 | 20 | foreach ($this->joins as $join) { |
|||
351 | 20 | $parts[] = (string)$join; |
|||
352 | } |
||||
353 | |||||
354 | 20 | return $parts; |
|||
355 | } |
||||
356 | |||||
357 | 39 | protected function getWhere(): array |
|||
358 | { |
||||
359 | 39 | if (count($this->whereParts) === 0) { |
|||
360 | 38 | return []; |
|||
361 | } |
||||
362 | |||||
363 | 5 | $parts = []; |
|||
364 | 5 | foreach ($this->whereParts as $wherePart) { |
|||
365 | 5 | $parts[] = (string)$wherePart; |
|||
366 | } |
||||
367 | |||||
368 | 5 | return ['WHERE ' . implode(' AND ', $parts)]; |
|||
369 | } |
||||
370 | |||||
371 | 39 | protected function getGroupBy(): array |
|||
372 | { |
||||
373 | 39 | if (count($this->groupByParts) === 0) { |
|||
374 | 38 | return []; |
|||
375 | } |
||||
376 | |||||
377 | 5 | $parts = []; |
|||
378 | 5 | foreach ($this->groupByParts as $groupByPart) { |
|||
379 | 5 | $parts[] = (string)$groupByPart; |
|||
380 | } |
||||
381 | |||||
382 | 5 | return ['GROUP BY ' . implode(', ', $parts)]; |
|||
383 | } |
||||
384 | |||||
385 | 39 | protected function getHaving(): array |
|||
386 | { |
||||
387 | 39 | if (count($this->havingParts) === 0) { |
|||
388 | 38 | return []; |
|||
389 | } |
||||
390 | |||||
391 | 5 | $parts = []; |
|||
392 | 5 | foreach ($this->havingParts as $havingPart) { |
|||
393 | 5 | $parts[] = (string)$havingPart; |
|||
394 | } |
||||
395 | |||||
396 | 5 | return ['HAVING ' . implode(' AND ', $parts)]; |
|||
397 | } |
||||
398 | |||||
399 | 39 | protected function getOrderBy(): array |
|||
400 | { |
||||
401 | 39 | if (count($this->orderBy) === 0) { |
|||
402 | 38 | return []; |
|||
403 | } |
||||
404 | |||||
405 | 5 | $parts = []; |
|||
406 | 5 | foreach ($this->orderBy as $column => $direction) { |
|||
407 | 5 | $parts[] = "$column $direction"; |
|||
408 | } |
||||
409 | |||||
410 | 5 | return ['ORDER BY ' . implode(', ', $parts)]; |
|||
411 | } |
||||
412 | |||||
413 | 24 | protected function getLimit(): array |
|||
414 | { |
||||
415 | 24 | $parts = []; |
|||
416 | 24 | if ($this->offset !== null) { |
|||
417 | 4 | $parts[] = sprintf('OFFSET %d ROWS', $this->offset); |
|||
418 | } |
||||
419 | 24 | if ($this->limit !== null) { |
|||
420 | 4 | $parts[] = sprintf('FETCH FIRST %d ROWS ONLY', $this->limit); |
|||
421 | } |
||||
422 | |||||
423 | 24 | return $parts; |
|||
424 | } |
||||
425 | |||||
426 | /** |
||||
427 | * @return array |
||||
428 | */ |
||||
429 | 6 | public function getParams(): array |
|||
430 | { |
||||
431 | 6 | $params = []; |
|||
432 | |||||
433 | 6 | foreach ($this->columns as $column) { |
|||
434 | 6 | $params = array_merge($params, $column->getParams()); |
|||
435 | } |
||||
436 | |||||
437 | 6 | foreach ($this->joins as $join) { |
|||
438 | 3 | $params = array_merge($params, $join->getParams()); |
|||
439 | } |
||||
440 | |||||
441 | 6 | foreach ($this->whereParts as $wherePart) { |
|||
442 | 3 | $params = array_merge($params, $wherePart->getParams()); |
|||
443 | } |
||||
444 | |||||
445 | 6 | foreach ($this->groupByParts as $groupByPart) { |
|||
446 | 3 | $params = array_merge($params, $groupByPart->getParams()); |
|||
447 | } |
||||
448 | |||||
449 | 6 | foreach ($this->havingParts as $havingPart) { |
|||
450 | 3 | $params = array_merge($params, $havingPart->getParams()); |
|||
451 | } |
||||
452 | |||||
453 | 6 | return $params; |
|||
454 | } |
||||
455 | } |
||||
456 |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"]
, you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths