Issues (3885)

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.

lib/Doctrine/DBAL/Schema/OracleSchemaManager.php (4 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
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\DBAL\Schema;
21
22
use Doctrine\DBAL\DBALException;
23
use Doctrine\DBAL\Driver\DriverException;
24
use Doctrine\DBAL\Platforms\OraclePlatform;
25
use Doctrine\DBAL\Types\Type;
26
use const CASE_LOWER;
27
use function array_change_key_case;
28
use function array_values;
29
use function assert;
30
use function is_null;
31
use function preg_match;
32
use function sprintf;
33
use function strpos;
34
use function strtolower;
35
use function strtoupper;
36
use function trim;
37
38
/**
39
 * Oracle Schema Manager.
40
 *
41
 * @author Konsta Vesterinen <[email protected]>
42
 * @author Lukas Smith <[email protected]> (PEAR MDB2 library)
43
 * @author Benjamin Eberlei <[email protected]>
44
 * @since  2.0
45
 */
46
class OracleSchemaManager extends AbstractSchemaManager
47
{
48
    /**
49
     * {@inheritdoc}
50
     */
51 View Code Duplication
    public function dropDatabase($database)
52
    {
53
        try {
54
            parent::dropDatabase($database);
55
        } catch (DBALException $exception) {
56
            $exception = $exception->getPrevious();
57
58
            if (! $exception instanceof DriverException) {
59
                throw $exception;
60
            }
61
62
            // If we have a error code 1940 (ORA-01940), the drop database operation failed
63
            // because of active connections on the database.
64
            // To force dropping the database, we first have to close all active connections
65
            // on that database and issue the drop database operation again.
66
            if ($exception->getErrorCode() !== 1940) {
67
                throw $exception;
68
            }
69
70
            $this->killUserSessions($database);
71
72
            parent::dropDatabase($database);
73
        }
74
    }
75
76
    /**
77
     * {@inheritdoc}
78
     */
79
    protected function _getPortableViewDefinition($view)
80
    {
81
        $view = \array_change_key_case($view, CASE_LOWER);
82
83
        return new View($this->getQuotedIdentifierName($view['view_name']), $view['text']);
84
    }
85
86
    /**
87
     * {@inheritdoc}
88
     */
89
    protected function _getPortableUserDefinition($user)
90
    {
91
        $user = \array_change_key_case($user, CASE_LOWER);
92
93
        return [
94
            'user' => $user['username'],
95
        ];
96
    }
97
98
    /**
99
     * {@inheritdoc}
100
     */
101
    protected function _getPortableTableDefinition($table)
102
    {
103
        $table = \array_change_key_case($table, CASE_LOWER);
104
105
        return $this->getQuotedIdentifierName($table['table_name']);
106
    }
107
108
    /**
109
     * {@inheritdoc}
110
     *
111
     * @license New BSD License
112
     * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html
113
     */
114
    protected function _getPortableTableIndexesList($tableIndexes, $tableName=null)
115
    {
116
        $indexBuffer = [];
117
        foreach ($tableIndexes as $tableIndex) {
118
            $tableIndex = \array_change_key_case($tableIndex, CASE_LOWER);
119
120
            $keyName = strtolower($tableIndex['name']);
121
            $buffer  = [];
122
123
            if (strtolower($tableIndex['is_primary']) == "p") {
124
                $keyName = 'primary';
125
                $buffer['primary'] = true;
126
                $buffer['non_unique'] = false;
127
            } else {
128
                $buffer['primary'] = false;
129
                $buffer['non_unique'] = ! $tableIndex['is_unique'];
130
            }
131
            $buffer['key_name'] = $keyName;
132
            $buffer['column_name'] = $this->getQuotedIdentifierName($tableIndex['column_name']);
133
            $indexBuffer[] = $buffer;
134
        }
135
136
        return parent::_getPortableTableIndexesList($indexBuffer, $tableName);
137
    }
138
139
    /**
140
     * {@inheritdoc}
141
     */
142
    protected function _getPortableTableColumnDefinition($tableColumn)
143
    {
144
        $tableColumn = \array_change_key_case($tableColumn, CASE_LOWER);
145
146
        $dbType = strtolower($tableColumn['data_type']);
147
        if (strpos($dbType, "timestamp(") === 0) {
148
            if (strpos($dbType, "with time zone")) {
149
                $dbType = "timestamptz";
150
            } else {
151
                $dbType = "timestamp";
152
            }
153
        }
154
155
        $unsigned = $fixed = null;
156
157
        if ( ! isset($tableColumn['column_name'])) {
158
            $tableColumn['column_name'] = '';
159
        }
160
161
        // Default values returned from database sometimes have trailing spaces.
162
        $tableColumn['data_default'] = trim($tableColumn['data_default']);
163
164 View Code Duplication
        if ($tableColumn['data_default'] === '' || $tableColumn['data_default'] === 'NULL') {
165
            $tableColumn['data_default'] = null;
166
        }
167
168 View Code Duplication
        if (null !== $tableColumn['data_default']) {
169
            // Default values returned from database are enclosed in single quotes.
170
            $tableColumn['data_default'] = trim($tableColumn['data_default'], "'");
171
        }
172
173
        $precision = null;
174
        $scale = null;
175
176
        $type = $this->_platform->getDoctrineTypeMapping($dbType);
177
        $type = $this->extractDoctrineTypeFromComment($tableColumn['comments'], $type);
178
        $tableColumn['comments'] = $this->removeDoctrineTypeFromComment($tableColumn['comments'], $type);
179
180
        switch ($dbType) {
181
            case 'number':
182
                if ($tableColumn['data_precision'] == 20 && $tableColumn['data_scale'] == 0) {
183
                    $precision = 20;
184
                    $scale = 0;
185
                    $type = 'bigint';
186
                } elseif ($tableColumn['data_precision'] == 5 && $tableColumn['data_scale'] == 0) {
187
                    $type = 'smallint';
188
                    $precision = 5;
189
                    $scale = 0;
190
                } elseif ($tableColumn['data_precision'] == 1 && $tableColumn['data_scale'] == 0) {
191
                    $precision = 1;
192
                    $scale = 0;
193
                    $type = 'boolean';
194
                } elseif ($tableColumn['data_scale'] > 0) {
195
                    $precision = $tableColumn['data_precision'];
196
                    $scale = $tableColumn['data_scale'];
197
                    $type = 'decimal';
198
                }
199
                $length = null;
200
                break;
201
            case 'pls_integer':
202
            case 'binary_integer':
203
                $length = null;
204
                break;
205
            case 'varchar':
206
            case 'varchar2':
207
            case 'nvarchar2':
208
                $length = $tableColumn['char_length'];
209
                $fixed = false;
210
                break;
211
            case 'char':
212
            case 'nchar':
213
                $length = $tableColumn['char_length'];
214
                $fixed = true;
215
                break;
216
            case 'date':
217
            case 'timestamp':
218
                $length = null;
219
                break;
220
            case 'float':
221
            case 'binary_float':
222
            case 'binary_double':
223
                $precision = $tableColumn['data_precision'];
224
                $scale = $tableColumn['data_scale'];
225
                $length = null;
226
                break;
227
            case 'clob':
228
            case 'nclob':
229
                $length = null;
230
                break;
231
            case 'blob':
232
            case 'raw':
233
            case 'long raw':
234
            case 'bfile':
235
                $length = null;
236
                break;
237
            case 'rowid':
238
            case 'urowid':
239
            default:
240
                $length = null;
241
        }
242
243
        $options = [
244
            'notnull'    => (bool) ($tableColumn['nullable'] === 'N'),
245
            'fixed'      => (bool) $fixed,
246
            'unsigned'   => (bool) $unsigned,
247
            'default'    => $tableColumn['data_default'],
248
            'length'     => $length,
249
            'precision'  => $precision,
250
            'scale'      => $scale,
251
            'comment'    => isset($tableColumn['comments']) && '' !== $tableColumn['comments']
252
                ? $tableColumn['comments']
253
                : null,
254
        ];
255
256
        return new Column($this->getQuotedIdentifierName($tableColumn['column_name']), Type::getType($type), $options);
257
    }
258
259
    /**
260
     * {@inheritdoc}
261
     */
262
    protected function _getPortableTableForeignKeysList($tableForeignKeys)
263
    {
264
        $list = [];
265
        foreach ($tableForeignKeys as $value) {
266
            $value = \array_change_key_case($value, CASE_LOWER);
267
            if (!isset($list[$value['constraint_name']])) {
268
                if ($value['delete_rule'] == "NO ACTION") {
269
                    $value['delete_rule'] = null;
270
                }
271
272
                $list[$value['constraint_name']] = [
273
                    'name' => $this->getQuotedIdentifierName($value['constraint_name']),
274
                    'local' => [],
275
                    'foreign' => [],
276
                    'foreignTable' => $value['references_table'],
277
                    'onDelete' => $value['delete_rule'],
278
                ];
279
            }
280
281
            $localColumn = $this->getQuotedIdentifierName($value['local_column']);
282
            $foreignColumn = $this->getQuotedIdentifierName($value['foreign_column']);
283
284
            $list[$value['constraint_name']]['local'][$value['position']] = $localColumn;
285
            $list[$value['constraint_name']]['foreign'][$value['position']] = $foreignColumn;
286
        }
287
288
        $result = [];
289
        foreach ($list as $constraint) {
290
            $result[] = new ForeignKeyConstraint(
291
                array_values($constraint['local']), $this->getQuotedIdentifierName($constraint['foreignTable']),
292
                array_values($constraint['foreign']), $this->getQuotedIdentifierName($constraint['name']),
293
                ['onDelete' => $constraint['onDelete']]
294
            );
295
        }
296
297
        return $result;
298
    }
299
300
    /**
301
     * {@inheritdoc}
302
     */
303
    protected function _getPortableSequenceDefinition($sequence)
304
    {
305
        $sequence = \array_change_key_case($sequence, CASE_LOWER);
306
307
        return new Sequence(
308
            $this->getQuotedIdentifierName($sequence['sequence_name']),
309
            (int) $sequence['increment_by'],
310
            (int) $sequence['min_value']
311
        );
312
    }
313
314
    /**
315
     * {@inheritdoc}
316
     */
317
    protected function _getPortableFunctionDefinition($function)
0 ignored issues
show
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
318
    {
319
        $function = \array_change_key_case($function, CASE_LOWER);
320
321
        return $function['name'];
322
    }
323
324
    /**
325
     * {@inheritdoc}
326
     */
327
    protected function _getPortableDatabaseDefinition($database)
0 ignored issues
show
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
328
    {
329
        $database = \array_change_key_case($database, CASE_LOWER);
330
331
        return $database['username'];
332
    }
333
334
    /**
335
     * {@inheritdoc}
336
     */
337
    public function createDatabase($database = null)
338
    {
339
        if ($database === null) {
340
            $database = $this->_conn->getDatabase();
341
        }
342
343
        $params = $this->_conn->getParams();
344
        $username   = $database;
345
        $password   = $params['password'];
346
347
        $query  = 'CREATE USER ' . $username . ' IDENTIFIED BY ' . $password;
0 ignored issues
show
'CREATE USER ' . $userna...TIFIED BY ' . $password is used as a query on line 348. If $password can contain user-input, it is usually preferable to use a parameter placeholder like :paramName and pass the dynamic input as second argument array('param' => $password).

Instead of embedding dynamic parameters in SQL, Doctrine also allows you to pass them separately and insert a placeholder instead:

function findUser(Doctrine\DBAL\Connection $con, $email) {
    // Unsafe
    $con->executeQuery("SELECT * FROM users WHERE email = '".$email."'");

    // Safe
    $con->executeQuery(
        "SELECT * FROM users WHERE email = :email",
        array('email' => $email)
    );
}
Loading history...
348
        $this->_conn->executeUpdate($query);
349
350
        $query = 'GRANT DBA TO ' . $username;
0 ignored issues
show
'GRANT DBA TO ' . $username is used as a query on line 351. If $username can contain user-input, it is usually preferable to use a parameter placeholder like :paramName and pass the dynamic input as second argument array('param' => $username).

Instead of embedding dynamic parameters in SQL, Doctrine also allows you to pass them separately and insert a placeholder instead:

function findUser(Doctrine\DBAL\Connection $con, $email) {
    // Unsafe
    $con->executeQuery("SELECT * FROM users WHERE email = '".$email."'");

    // Safe
    $con->executeQuery(
        "SELECT * FROM users WHERE email = :email",
        array('email' => $email)
    );
}
Loading history...
351
        $this->_conn->executeUpdate($query);
352
    }
353
354
    /**
355
     * @param string $table
356
     *
357
     * @return bool
358
     */
359
    public function dropAutoincrement($table)
360
    {
361
        assert($this->_platform instanceof OraclePlatform);
362
363
        $sql = $this->_platform->getDropAutoincrementSql($table);
364
        foreach ($sql as $query) {
365
            $this->_conn->executeUpdate($query);
366
        }
367
368
        return true;
369
    }
370
371
    /**
372
     * {@inheritdoc}
373
     */
374
    public function dropTable($name)
375
    {
376
        $this->tryMethod('dropAutoincrement', $name);
377
378
        parent::dropTable($name);
379
    }
380
381
    /**
382
     * Returns the quoted representation of the given identifier name.
383
     *
384
     * Quotes non-uppercase identifiers explicitly to preserve case
385
     * and thus make references to the particular identifier work.
386
     *
387
     * @param string $identifier The identifier to quote.
388
     *
389
     * @return string The quoted identifier.
390
     */
391
    private function getQuotedIdentifierName($identifier)
392
    {
393
        if (preg_match('/[a-z]/', $identifier)) {
394
            return $this->_platform->quoteIdentifier($identifier);
395
        }
396
397
        return $identifier;
398
    }
399
400
    /**
401
     * Kills sessions connected with the given user.
402
     *
403
     * This is useful to force DROP USER operations which could fail because of active user sessions.
404
     *
405
     * @param string $user The name of the user to kill sessions for.
406
     *
407
     * @return void
408
     */
409
    private function killUserSessions($user)
410
    {
411
        $sql = <<<SQL
412
SELECT
413
    s.sid,
414
    s.serial#
415
FROM
416
    gv\$session s,
417
    gv\$process p
418
WHERE
419
    s.username = ?
420
    AND p.addr(+) = s.paddr
421
SQL;
422
423
        $activeUserSessions = $this->_conn->fetchAll($sql, [strtoupper($user)]);
424
425
        foreach ($activeUserSessions as $activeUserSession) {
426
            $activeUserSession = array_change_key_case($activeUserSession, \CASE_LOWER);
427
428
            $this->_execSql(
429
                sprintf(
430
                    "ALTER SYSTEM KILL SESSION '%s, %s' IMMEDIATE",
431
                    $activeUserSession['sid'],
432
                    $activeUserSession['serial#']
433
                )
434
            );
435
        }
436
    }
437
}
438