Issues (91)

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/Database/Database.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 Anax\Database;
4
5
use \Anax\Database\Exception\Exception;
6
7
/**
8
 * Database wrapper, provides a database API on top of PHP PDO for
9
 * enhancing the API and dealing with error reporting and tracking.
10
 *
11
 *@SuppressWarnings(PHPMD.TooManyPublicMethods)
12
 */
13
class Database
14
{
15
    /**
16
     * @var array        $options used when creating the PDO object
17
     * @var PDO          $pdo     the PDO object
18
     * @var PDOStatement $stmt    the latest PDOStatement used
19
     */
20
    protected $options;
21
    private $pdo = null;
22
    private $stmt = null;
23
24
25
26
    /**
27
     * Constructor creating a PDO object connecting to a choosen database.
28
     *
29
     * @param array $options containing details for connecting to the database.
30
     */
31
    public function __construct($options = [])
32
    {
33
        $this->setOptions($options);
34
    }
35
36
37
38
    /**
39
     * Set options and connection details.
40
     *
41
     * @param array $options containing details for connecting to the database.
42
     *
43
     * @return void
44
     */
45
    public function setOptions($options = [])
46
    {
47
        $default = [
48
            'dsn'             => null,
49
            'username'        => null,
50
            'password'        => null,
51
            'driver_options'  => null,
52
            'table_prefix'    => null,
53
            'fetch_mode'      => \PDO::FETCH_OBJ,
54
            'session_key'     => 'Anax\Database',
55
            'verbose'         => null,
56
            'debug_connect'   => false,
57
        ];
58
        $this->options = array_merge($default, $options);
59
    }
60
61
62
63
    /**
64
     * Set a single option.
65
     *
66
     * @param string $option which to set.
67
     * @param mixed  $value  to set.
68
     *
69
     * @return self
70
     */
71
    public function setOption($option, $value)
72
    {
73
        $this->options[$option] = $value;
74
        return $this;
75
    }
76
77
78
79
    /**
80
     * Connect to the database, allow being called multiple times
81
     * but ignore when connection is already made.
82
     *
83
     * @return self
84
     *
85
     * @throws \Anax\Database\Exception
86
     */
87
    public function connect()
88
    {
89
        if ($this->pdo) {
90
            return $this;
91
        }
92
93
        if (!isset($this->options['dsn'])) {
94
            throw new Exception("You can not connect, missing dsn.");
95
        }
96
97
        try {
98
            $this->pdo = new \PDO(
99
                $this->options['dsn'],
100
                $this->options['username'],
101
                $this->options['password'],
102
                $this->options['driver_options']
103
            );
104
105
            $this->pdo->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, $this->options['fetch_mode']);
106
            $this->pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
107
        } catch (\PDOException $e) {
108
            if ($this->options['debug_connect']) {
109
                throw $e;
110
            }
111
            throw new Exception("Could not connect to database, hiding connection details.");
112
        }
113
114
        return $this;
115
    }
116
117
118
119
    public function next()
120
    {
121
        return $this->stmt->nextRowSet();
122
    }
123
124
125
126
    /**
127
     * Support arrays in params, extract array items and add to $params
128
     * and insert ? for each entry in the array.
129
     *
130
     * @param string $query  as the query to prepare.
131
     * @param array  $params the parameters that may contain arrays.
132
     *
133
     * @return array with query and params.
134
     */
135
    private function expandParamArray($query, $params)
136
    {
137
        $param = [];
138
        $offset = -1;
139
140
        foreach ($params as $val) {
141
            $offset = strpos($query, '?', $offset + 1);
142
143
            if (is_array($val)) {
144
                $nrOfItems = count($val);
145
146
                if ($nrOfItems) {
147
                    $query = substr($query, 0, $offset)
148
                        . str_repeat('?,', $nrOfItems  - 1)
149
                        . '?'
150
                        . substr($query, $offset + 1);
151
                    $param = array_merge($param, $val);
152
                } else {
153
                    $param[] = null;
154
                }
155
            } else {
156
                $param[] = $val;
157
            }
158
        }
159
160
        return [$query, $param];
161
    }
162
163
164
165
    /**
166
     * Execute a select-query with arguments and return the resultset.
167
     *
168
     * @param string $query  the SQL statement
169
     * @param array  $params the params array
170
     *
171
     * @return array with resultset
172
     */
173
    public function executeFetchAll($query, $params = [])
174
    {
175
        $this->execute($query, $params);
176
        return $this->stmt->fetchAll();
177
    }
178
179
180
181
    /**
182
     * Execute a select-query with arguments and return the first row
183
     * in the resultset.
184
     *
185
     * @param string $query  the SQL statement
186
     * @param array  $params the params array
187
     *
188
     * @return array with resultset
189
     */
190
    public function executeFetch($query, $params = [])
191
    {
192
        $this->execute($query, $params);
193
        return $this->stmt->fetch();
194
    }
195
196
197
198
    /**
199
     * Execute a select-query with arguments and insert the results into
200
     * a new object of the class.
201
     *
202
     * @param string $query  the SQL statement
203
     * @param array  $params the params array
204
     * @param string $class  the class to create an object of and insert into
205
     *
206
     * @return array with resultset
207
     */
208
    public function executeFetchClass($query, $params, $class)
209
    {
210
        $this->execute($query, $params);
211
        $this->stmt->setFetchMode(\PDO::FETCH_CLASS, $class);
212
        return $this->stmt->fetch();
213
    }
214
215
216
217
    /**
218
     * Execute a select-query with arguments and insert the results into
219
     * an existing object.
220
     *
221
     * @param string $query  the SQL statement
222
     * @param array  $params the params array
0 ignored issues
show
There is no parameter named $params. Did you maybe mean $param?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
223
     * @param string $object the existing object to insert into
224
     *
225
     * @return array with resultset
226
     */
227
    public function executeFetchInto($query, $param, $object = null)
228
    {
229
        if (!$object) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $object of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
230
            $object = $param;
231
            $param = [];
232
        }
233
        $this->execute($query, $param);
234
        $this->stmt->setFetchMode(\PDO::FETCH_INTO, $object);
235
        return $this->stmt->fetch();
236
    }
237
238
239
240
    /**
241
     * Fetch all resultset.
242
     *
243
     * @return array with resultset.
244
     */
245
    public function fetchAll()
246
    {
247
        return $this->stmt->fetchAll();
248
    }
249
250
251
252
    /**
253
     * Fetch one resultset.
254
     *
255
     * @return array with resultset.
256
     */
257
    public function fetch()
258
    {
259
        return $this->stmt->fetch();
260
    }
261
262
263
264
    /**
265
     * Fetch one resultset as a new object from this class.
266
     *
267
     * @param object $class which type of object to instantiate.
268
     *
269
     * @return array with resultset.
270
     */
271
    public function fetchClass($class)
272
    {
273
        $this->stmt->setFetchMode(\PDO::FETCH_CLASS, $class);
274
        return $this->stmt->fetch();
275
    }
276
277
278
279
    /**
280
     * Fetch full resultset as new objects from this class.
281
     *
282
     * @param object $class which type of object to instantiate.
283
     *
284
     * @return array with resultset.
285
     */
286
    public function fetchAllClass($class)
287
    {
288
        $this->stmt->setFetchMode(\PDO::FETCH_CLASS, $class);
289
        return $this->stmt->fetchAll();
290
    }
291
292
293
294
    /**
295
     * Fetch one resultset into an object.
296
     *
297
     * @param object $object to insert values into.
298
     *
299
     * @return array with resultset.
300
     */
301
    public function fetchInto($object)
302
    {
303
        $this->stmt->setFetchMode(\PDO::FETCH_INTO, $object);
304
        return $this->stmt->fetch();
305
    }
306
307
308
309
    /**
310
     * Execute a SQL-query and ignore the resultset.
311
     *
312
     * @param string $query  the SQL statement
313
     * @param array  $params the params array
314
     *
315
     * @return self
316
     *
317
     * @throws Exception when failing to prepare question.
318
     */
319
    public function execute($query, $params = [])
320
    {
321
        list($query, $params) = $this->expandParamArray($query, $params);
322
323
        $this->stmt = $this->pdo->prepare($query);
324
        if (!$this->stmt) {
325
            $this->pdoException($query, $params);
326
        }
327
328
        if ($this->options["verbose"]) {
329
            echo $query . "\n";
330
            print_r($params);
331
        }
332
333
        $res = $this->stmt->execute($params);
334
        if (!$res) {
335
            $this->statementException($query, $params);
336
        }
337
338
        return $this;
339
    }
340
341
342
343
    /**
344
     * Throw exception using detailed message.
345
     *
346
     * @param string       $msg     detailed error message from PDO
347
     * @param string       $query   query to execute
348
     * @param array        $param   to match ? in statement
349
     *
350
     * @return void
351
     *
352
     * @throws \Anax\Database\Exception
353
     */
354
    protected function createException($msg, $query, $param)
355
    {
356
        throw new Exception(
357
            $msg
358
            . "<br><br>SQL ("
359
            . substr_count($query, "?")
360
            . " params):<br><pre>$query</pre><br>PARAMS ("
361
            . count($param)
362
            . "):<br><pre>"
363
            . implode($param, "\n")
364
            . "</pre>"
365
            . ((count(array_filter(array_keys($param), 'is_string')) > 0)
366
                ? "WARNING your params array has keys, should only have values."
367
                : null)
368
        );
369
    }
370
371
372
373
    /**
374
     * Throw exception when pdo failed using detailed message.
375
     *
376
     * @param string       $query   query to execute
377
     * @param array        $param   to match ? in statement
378
     *
379
     * @return void
380
     *
381
     * @throws \Anax\Database\Exception
382
     */
383
    protected function pdoException($query, $param)
384
    {
385
        $this->createException($this->pdo->errorInfo()[2], $query, $param);
386
    }
387
388
389
390
    /**
391
     * Throw exception when statement failed using detailed message.
392
     *
393
     * @param string       $query   query to execute
394
     * @param array        $param   to match ? in statement
395
     *
396
     * @return void
397
     *
398
     * @throws \Anax\Database\Exception
399
     */
400
    protected function statementException($query, $param)
401
    {
402
        $this->createException($this->stmt->errorInfo()[2], $query, $param);
403
    }
404
405
406
407
    /**
408
     * Return last insert id from autoincremented key on INSERT.
409
     *
410
     * @return integer as last insert id.
411
     */
412
    public function lastInsertId()
413
    {
414
        return $this->pdo->lastInsertId();
415
    }
416
417
418
419
    /**
420
    * Return rows affected of last INSERT, UPDATE, DELETE
421
    *
422
    * @return integer as rows affected on last statement
423
    */
424
    public function rowCount()
425
    {
426
        return $this->stmt->rowCount();
427
    }
428
429
430
431
    /**
432
     * Fetch one resultset as an object from this class.
433
     * OBSOLETE replaced by fetchClass
434
     *
435
     * @param object $class which type of object to instantiate.
436
     *
437
     * @return array with resultset.
438
     */
439
    public function fetchObject($class)
440
    {
441
        return $this->stmt->fetchObject($class);
442
    }
443
444
445
446
    /**
447
     * Fetch one resultset. OBSOLETE replace by fetch()
448
     *
449
     * @return array with resultset.
450
     */
451
    public function fetchOne()
452
    {
453
        return $this->stmt->fetch();
454
    }
455
}
456