Issues (3)

Security Analysis    no request data  

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

  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.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  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.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  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.
  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.
  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.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
  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.
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  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.
  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.
  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.
  Header Injection
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/QueryBuilder/Query.php (1 issue)

Labels
Severity
1
<?php
2
3
namespace Xsolve\SalesforceClient\QueryBuilder;
4
5
use Xsolve\SalesforceClient\QueryBuilder\Expr\Compare\AbstractCompare;
6
use Xsolve\SalesforceClient\QueryBuilder\Expr\ExprInterface;
7
use Xsolve\SalesforceClient\QueryBuilder\Expr\From\AbstractFrom;
8
use Xsolve\SalesforceClient\QueryBuilder\Expr\GroupBy\AbstractGroupBy;
9
use Xsolve\SalesforceClient\QueryBuilder\Expr\OrderBy\AbstractOrderBy;
10
use Xsolve\SalesforceClient\QueryBuilder\Expr\Select\AbstractSelect;
11
use Xsolve\SalesforceClient\QueryBuilder\Visitor\Parameters\ParametersReplacingVisitor;
12
use Xsolve\SalesforceClient\QueryBuilder\Visitor\VisiteeInterface;
13
use Xsolve\SalesforceClient\QueryBuilder\Visitor\VisitorInterface;
14
15
class Query
16
{
17
    /**
18
     * @var AbstractSelect[]
19
     */
20
    private $selects = [];
21
22
    /**
23
     * @var AbstractFrom|null
24
     */
25
    private $from;
26
27
    /**
28
     * @var AbstractCompare|null
29
     */
30
    private $where;
31
32
    /**
33
     * @var AbstractGroupBy|null
34
     */
35
    private $groupBy;
36
37
    /**
38
     * @var AbstractCompare|null
39
     */
40
    private $having;
41
42
    /**
43
     * @var AbstractOrderBy|null
44
     */
45
    private $orderBy;
46
47
    /**
48
     * @var int|null
49
     */
50
    private $limit;
51
52
    /**
53
     * @var int|null
54
     */
55
    private $offset;
56
57
    /**
58
     * @var VisitorInterface[]
59
     */
60
    private $visitors;
61
62
    /**
63
     * @param VisitorInterface[] $visitors
64
     */
65 53
    public function __construct(array $visitors = [])
66
    {
67 53
        $this->visitors = $visitors;
68 53
    }
69
70 53
    public function addSelect(AbstractSelect $select)
71
    {
72 53
        $this->selects[] = $select;
73 53
    }
74
75 53
    public function setFrom(AbstractFrom $from)
76
    {
77 53
        $this->from = $from;
78 53
    }
79
80 19
    public function setWhere(AbstractCompare $where)
81
    {
82 19
        $this->where = $where;
83 19
    }
84
85 4
    public function setGroupBy(AbstractGroupBy $groupBy)
86
    {
87 4
        $this->groupBy = $groupBy;
88 4
    }
89
90 19
    public function setHaving(AbstractCompare $having)
91
    {
92 19
        $this->having = $having;
93 19
    }
94
95
    /**
96
     * @return AbstractCompare|null
97
     */
98 1
    public function getWhere()
99
    {
100 1
        return $this->where;
101
    }
102
103
    /**
104
     * @return AbstractCompare|null
105
     */
106 1
    public function getHaving()
107
    {
108 1
        return $this->having;
109
    }
110
111 4
    public function setOrderBy(AbstractOrderBy $orderBy)
112
    {
113 4
        $this->orderBy = $orderBy;
114 4
    }
115
116 2
    public function setLimit(int $limit)
117
    {
118 2
        $this->limit = $limit;
119 2
    }
120
121 2
    public function setOffset(int $offset)
122
    {
123 2
        $this->offset = $offset;
124 2
    }
125
126 19
    public function setParameters(array $parameters)
127
    {
128 19
        $this->visitors[] = new ParametersReplacingVisitor($parameters);
129 19
    }
130
131 53
    public function parse(): string
132
    {
133 53
        $this->validate();
134 53
        $this->visitQueryParts();
135
136 53
        return $this->parseSelect()
137 53
            .$this->parseWhere()
138 53
            .$this->parseGroupBy()
139 53
            .$this->parseHaving()
140 53
            .$this->parseOrderBy()
141 53
            .$this->parseLimit()
142 53
            .$this->parseOffset();
143
    }
144
145 53
    private function validate()
146
    {
147 53
        if (empty($this->selects) || null === $this->from) {
148
            throw new \LogicException('At least SELECT and FROM must be defined');
149
        }
150 53
    }
151
152 53
    private function visitQueryParts()
153
    {
154 53
        foreach ($this->visitors as $visitor) {
155 19
            foreach ($this->getQueryParts() as $queryPart) {
156 19
                if ($queryPart instanceof VisiteeInterface) {
157 19
                    $queryPart->accept($visitor);
158
                }
159
            }
160
        }
161 53
    }
162
163
    /**
164
     * @return ExprInterface[]
165
     */
166 19
    private function getQueryParts(): array
167
    {
168 19
        return array_merge(
169 19
            $this->selects,
170 19
            [$this->from],
171 19
            [$this->where],
172 19
            [$this->groupBy],
173 19
            [$this->having],
174 19
            [$this->orderBy]
175
        );
176
    }
177
178 53
    private function parseSelect(): string
179
    {
180 53
        $selects = implode(', ', array_map(
181 53
            function (AbstractSelect $select): string {
182 53
                return $select->asSOQL();
183 53
            },
184 53
            $this->selects
185
        ));
186
187 53
        return sprintf('SELECT %s FROM %s', $selects, $this->from->asSOQL());
0 ignored issues
show
The method asSOQL() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

187
        return sprintf('SELECT %s FROM %s', $selects, $this->from->/** @scrutinizer ignore-call */ asSOQL());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
188
    }
189
190 53
    private function parseWhere(): string
191
    {
192 53
        if (!$this->where) {
193 35
            return '';
194
        }
195
196 19
        return sprintf(' WHERE %s', $this->where->asSOQL());
197
    }
198
199 53
    private function parseGroupBy(): string
200
    {
201 53
        if (!$this->groupBy) {
202 50
            return '';
203
        }
204
205 4
        return sprintf(' GROUP BY %s', $this->groupBy->asSOQL());
206
    }
207
208 53
    private function parseHaving(): string
209
    {
210 53
        if (!$this->having) {
211 35
            return '';
212
        }
213
214 19
        return sprintf(' HAVING %s', $this->having->asSOQL());
215
    }
216
217 53
    private function parseOrderBy(): string
218
    {
219 53
        if (!$this->orderBy) {
220 50
            return '';
221
        }
222
223 4
        return sprintf(' ORDER BY %s', $this->orderBy->asSOQL());
224
    }
225
226 53
    private function parseLimit(): string
227
    {
228 53
        if (!is_int($this->limit)) {
229 52
            return '';
230
        }
231
232 2
        return sprintf(' LIMIT %d', $this->limit);
233
    }
234
235 53
    private function parseOffset(): string
236
    {
237 53
        if (!is_int($this->offset)) {
238 52
            return '';
239
        }
240
241 2
        return sprintf(' OFFSET %d', $this->offset);
242
    }
243
}
244