Issues (82)

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/Storage/Db/DBALMysqlResource.php (3 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 Maketok\DataMigration\Storage\Db;
4
5
use Doctrine\DBAL\Driver as DriverInterface;
6
use Doctrine\DBAL\Driver\PDOMySql\Driver;
7
use Doctrine\DBAL\Schema\Schema;
8
use Maketok\DataMigration\Storage\Exception\ParsingException;
9
10
class DBALMysqlResource extends AbstractDBALResource
11
{
12
    /**
13
     * @var DriverInterface
14
     */
15
    private $driver;
16
17
    /**
18
     * {@inheritdoc}
19
     */
20 31
    protected function getDriverOptions()
21
    {
22
        return [
23 31
            \PDO::MYSQL_ATTR_LOCAL_INFILE => true,
24 31
            \PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'
25 31
        ];
26
    }
27
28
    /**
29
     * {@inheritdoc}
30
     */
31 2
    public function deleteUsingTempPK($deleteTable, $tmpTable, $primaryKey = 'id')
32
    {
33 2
        $sql = $this->getDeleteUsingTempPkSql($deleteTable, $tmpTable, $primaryKey);
34 2
        return $this->connection->executeUpdate($sql);
35
    }
36
37
    /**
38
     * @param string $deleteTable
39
     * @param string $tmpTable
40
     * @param string|string[] $primaryKey
41
     * @return string
42
     */
43 3
    public function getDeleteUsingTempPkSql($deleteTable, $tmpTable, $primaryKey)
44
    {
45 3
        $deleteTable = $this->connection->quoteIdentifier($deleteTable);
46 3
        $tmpTable = $this->connection->quoteIdentifier($tmpTable);
47 3
        if (!is_array($primaryKey)) {
48 2
            $primaryKey = [$primaryKey];
49 2
        }
50 3
        $primaryKey = array_map([$this->connection, 'quoteIdentifier'], $primaryKey);
51 3
        $conditionParts = [];
52 3
        foreach ($primaryKey as $key) {
53 3
            $conditionParts[] = "`main_table`.$key=`tmp_table`.$key";
54 3
        }
55 3
        $condition = implode('AND', $conditionParts);
56
        return <<<MYSQL
57
DELETE main_table FROM $deleteTable AS main_table
58 3
JOIN $tmpTable AS tmp_table ON $condition
59 3
MYSQL;
60
    }
61
62
    /**
63
     * {@inheritdoc}
64
     * @param string $delimiter
65
     * @param string $enclosure
66
     * @param string $escape
67
     * @param string $termination
68
     * @param bool $optionallyEnclosed
69
     */
70 6
    public function loadData(
0 ignored issues
show
This method has 10 parameters which exceeds the configured maximum of 10.

A high number of parameters is generally an indication that you should consider creating a dedicated object for the parameters.

Let’s take a look at an example:

<?php

class SomeClass
{
    public function doSomething(A $a, B $b, C $c, D $d, E $e, F $f)
    {
        // ..
    }
}

class AnotherClass
{
    public function doSomething(A $a, B $b, C $c, D $d, E $e, F $f)
    {
        // ...
    }
}

could be refactored to:

class Context
{
    private $a;
    private $b;
    private $c;
    private $d;
    private $e;
    private $f;

    public function __construct(A $a, B $b, C $c, D $d, E $e, F $f)
    {
        // ...
    }
}

class SomeClass
{
    public function doSomething(Context $context)
    {
        // ...
    }
}

class AnotherClass
{
    public function doSomething(Context $context)
    {
        // ...
    }
}
Loading history...
71
        $table,
72
        $file,
73
        $local = false,
74
        array $columns = [],
75
        array $set = [],
76
        $delimiter = ",",
77
        $enclosure = '"',
78
        $escape = '\\',
79
        $termination = '\n',
80
        $optionallyEnclosed = true
81
    ) {
82 6
        $sql = $this->getLoadDataSql($table, $file, $local, $columns, $set, $delimiter, $enclosure,
83 6
            $escape, $termination, $optionallyEnclosed);
84 6
        return $this->connection->executeUpdate($sql);
85
    }
86
87
    /**
88
     * @param string $table
89
     * @param string $file
90
     * @param bool|false $local
91
     * @param array $columns
92
     * @param array $set
93
     * @param string $delimiter
94
     * @param string $enclosure
95
     * @param string $escape
96
     * @param string $termination
97
     * @param bool|true $optionallyEnclosed
98
     * @return string
99
     */
100 7
    public function getLoadDataSql(
0 ignored issues
show
This method has 10 parameters which exceeds the configured maximum of 10.

A high number of parameters is generally an indication that you should consider creating a dedicated object for the parameters.

Let’s take a look at an example:

<?php

class SomeClass
{
    public function doSomething(A $a, B $b, C $c, D $d, E $e, F $f)
    {
        // ..
    }
}

class AnotherClass
{
    public function doSomething(A $a, B $b, C $c, D $d, E $e, F $f)
    {
        // ...
    }
}

could be refactored to:

class Context
{
    private $a;
    private $b;
    private $c;
    private $d;
    private $e;
    private $f;

    public function __construct(A $a, B $b, C $c, D $d, E $e, F $f)
    {
        // ...
    }
}

class SomeClass
{
    public function doSomething(Context $context)
    {
        // ...
    }
}

class AnotherClass
{
    public function doSomething(Context $context)
    {
        // ...
    }
}
Loading history...
101
        $table,
102
        $file,
103
        $local = false,
104
        array $columns = [],
105
        array $set = [],
106
        $delimiter = ",",
107
        $enclosure = '"',
108
        $escape = "\\",
109
        $termination = '\n',
110
        $optionallyEnclosed = true
111
    ) {
112 7
        $localKey = $local ? 'LOCAL' : '';
113 7
        $table = $this->connection->quoteIdentifier($table);
114 7
        $optionalKey = $optionallyEnclosed ? 'OPTIONALLY' : '';
115 7
        if (!empty($columns)) {
116 1
            $columns = '(' . implode(',', $columns) . ')';
117 1
        } else {
118 6
            $columns = '';
119
        }
120 7
        if (!empty($set)) {
121 1
            $setParts = [];
122 1
            foreach ($set as $key => $val) {
123 1
                $setParts[] = "$key=$val";
124 1
            }
125 1
            $set = 'SET ' . implode(',', $setParts);
126 1
        } else {
127 6
            $set = '';
128
        }
129 7
        $escape = $this->connection->quote($escape);
130
        return <<<MYSQL
131 7
LOAD DATA $localKey INFILE '$file'
132 7
INTO TABLE $table
133
CHARACTER SET UTF8
134
FIELDS
135 7
    TERMINATED BY '$delimiter'
136 7
    $optionalKey ENCLOSED BY '$enclosure'
137 7
    ESCAPED BY $escape
138
LINES
139 7
    TERMINATED BY '$termination'
140 7
$columns
141 7
$set
142 7
MYSQL;
143
    }
144
145
    /**
146
     * {@inheritdoc}
147
     */
148 9
    public function move(
149
        $fromTable,
150
        $toTable,
151
        array $columns = [],
152
        array $conditions = [],
153
        array $orderBy = [],
154
        $dir = 'ASC'
155
    ) {
156 9
        $sql = $this->getMoveSql($fromTable, $toTable, $columns, $conditions, $orderBy, $dir);
157 9
        return $this->connection->executeUpdate($sql);
158
    }
159
160
    /**
161
     * @param string $fromTable
162
     * @param string $toTable
163
     * @param array $columns
164
     * @param array $conditions
165
     * @param array $orderBy
166
     * @param string $dir
167
     * @return string
168
     */
169 18
    public function getMoveSql(
170
        $fromTable,
171
        $toTable,
172
        array $columns = [],
173
        array $conditions = [],
174
        array $orderBy = [],
175
        $dir = 'ASC'
176
    ) {
177 18
        $selectColumns = '*';
178 18
        $onDuplicate = '';
179 18
        $fromTable = $this->connection->quoteIdentifier($fromTable);
180 18
        $toTable = $this->connection->quoteIdentifier($toTable);
181 18
        if (!empty($columns)) {
182 18
            $columns = array_map([$this->connection, 'quoteIdentifier'], $columns);
183 18
            $selectColumns = implode(',', $columns);
184 18
            $duplicateParts = array_map(function ($var) {
185 18
                return "$var=VALUES($var)";
186 18
            }, $columns);
187 18
            $columns = '(' . $selectColumns . ')';
188 18
            $onDuplicate = 'ON DUPLICATE KEY UPDATE ' . implode(',', $duplicateParts);
189 18
        } else {
190
            $columns = '';
191
        }
192 18
        if (!empty($conditions)) {
193 10
            $conditionParts = [];
194 10
            foreach ($conditions as $key => $val) {
195 10
                $key = $this->connection->quoteIdentifier($key);
196 10
                if (is_array($val)) {
197 9
                    $conditionParts[] = $this->getParsedCondition("$fromTable.$key", $val);
198 5
                } else {
199 1
                    $val = $this->connection->quote($val);
200 1
                    $conditionParts[] = "$fromTable.$key=$val";
201
                }
202 6
            }
203 6
            $conditions = 'WHERE ' . implode('AND', $conditionParts);
204 6
        } else {
205 8
            $conditions = '';
206
        }
207 14
        if (!empty($orderBy)) {
208 8
            $orderBy = array_map([$this->connection, 'quoteIdentifier'], $orderBy);
209 8
            $orderBy = implode(',', $orderBy);
210 8
        } else {
211 6
            $orderBy = 'NULL';
212
        }
213
        return <<<MYSQL
214 14
INSERT INTO $toTable $columns
215 14
SELECT $selectColumns FROM $fromTable
216 14
$conditions
217 14
ORDER BY $orderBy $dir
218 14
$onDuplicate
219 14
MYSQL;
220
    }
221
222
    /**
223
     * Return valid condition
224
     * @param $column
225
     * @param array $value
226
     * @throws ParsingException
227
     * @return string
228
     */
229 9
    protected function getParsedCondition($column, array $value)
230
    {
231 9
        if (count($value) > 1) {
232 1
            throw new ParsingException("Condition should contain only 1 element");
233
        }
234 8
        $operation = key($value);
235 8
        $actualValue = current($value);
236
        switch ($operation) {
237 8
            case 'neq':
238 1
                $string = "$column<>{$this->connection->quote($actualValue)}";
239 1
                break;
240 7
            case 'eq':
241 1
                $string = "$column={$this->connection->quote($actualValue)}";
242 1
                break;
243 6
            case 'in':
244 2
                if (!is_array($actualValue)) {
245 1
                    throw new ParsingException("Can not use 'in' operation with non array.");
246
                }
247 1
                $actualValue = array_map([$this->connection, 'quote'], $actualValue);
248 1
                $glued = implode(',', $actualValue);
249 1
                $string = "$column in ($glued)";
250 1
                break;
251 4
            case 'nin':
252 3
                if (!is_array($actualValue)) {
253 1
                    throw new ParsingException("Can not use 'nin' operation with non array.");
254
                }
255 2
                $actualValue = array_map([$this->connection, 'quote'], $actualValue);
256 2
                $glued = implode(',', $actualValue);
257 2
                $string = "$column not in ($glued)";
258 2
                break;
259 1
            default:
260 1
                throw new ParsingException(sprintf("Could not resolve condition operation %s.", $operation));
261 1
        }
262 5
        return $string;
263
    }
264
265
    /**
266
     * {@inheritdoc}
267
     */
268 3
    public function dumpData($table, array $columns = [], $limit = 1000, $offset = 0)
269
    {
270 3
        $sql = $this->getDumpDataSql($table, $columns);
271 3
        $stmt = $this->connection->prepare($sql);
272 3
        $stmt->bindValue(1, $limit, \PDO::PARAM_INT);
273 3
        $stmt->bindValue(2, $offset, \PDO::PARAM_INT);
274 3
        $res = $stmt->execute();
275 3
        if ($res === false) {
276
            return false;
277
        }
278 3
        return $stmt->fetchAll(\PDO::FETCH_ASSOC);
279
    }
280
281
    /**
282
     * @param string $table
283
     * @param array $columns
284
     * @return string
285
     */
286 4
    public function getDumpDataSql($table, array $columns = [])
287
    {
288 4
        $table = $this->connection->quoteIdentifier($table);
289 4
        if (!empty($columns)) {
290 4
            $columns = array_map([$this->connection, 'quoteIdentifier'], $columns);
291 4
            $columns = implode(',', $columns);
292 4
        } else {
293 1
            $columns = '*';
294
        }
295
        return <<<MYSQL
296 4
SELECT $columns FROM $table
297 4
LIMIT ? OFFSET ?
298 4
MYSQL;
299
    }
300
301
    /**
302
     * {@inheritdoc}
303
     */
304 11
    public function createTmpTable($name, array $columns)
305
    {
306 11
        $sql = $this->getCreateTableSql($name, $columns);
307 11
        foreach ($sql as $directive) {
308 11
            $this->connection->executeUpdate($directive);
309 11
        }
310 11
        return true;
311
    }
312
313
    /**
314
     * @param string $name
315
     * @param array $columns
316
     * @return array
317
     * @throws \Doctrine\DBAL\DBALException
318
     */
319 12
    public function getCreateTableSql($name, array $columns)
320
    {
321 12
        $schema = new Schema();
322 12
        $table = $schema->createTable($name);
323 12
        foreach ($columns as $column => $definition) {
324 12
            if (is_array($definition)) {
325 8
                $type = array_shift($definition);
326 8
                $options = array_shift($definition);
327 8
            } else {
328 5
                $type = $definition;
329 5
                $options = [];
330
            }
331 12
            $table->addColumn($column, $type, $options);
332 12
        }
333 12
        if (!$this->config['db_debug']) {
334 12
            $table->addOption('temporary', true);
0 ignored issues
show
true is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
335 12
        }
336 12
        return $this->connection->getDatabasePlatform()->getCreateTableSQL($table);
337
    }
338
339
    /**
340
     * {@inheritdoc}
341
     */
342 31
    protected function getDriver()
343
    {
344 31
        if (is_null($this->driver)) {
345 31
            $driver = $this->config['db_driver'];
346 31
            if ($driver && $driver instanceof DriverInterface) {
347 13
                $this->driver = $driver;
348 13
            } else {
349 18
                $this->driver = new Driver();
350
            }
351 31
        }
352 31
        return $this->driver;
353
    }
354
}
355