Issues (75)

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.

Migration/MigrationExecutor.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 RDV\Bundle\MigrationBundle\Migration;
4
5
use Doctrine\DBAL\Platforms\AbstractPlatform;
6
use Doctrine\DBAL\Platforms\MySqlPlatform;
7
use Doctrine\DBAL\Schema\Column;
8
use Doctrine\DBAL\Schema\ColumnDiff;
9
use Doctrine\DBAL\Schema\Comparator;
10
use Doctrine\DBAL\Schema\Index;
11
use Doctrine\DBAL\Schema\Schema;
12
use Doctrine\DBAL\Schema\SchemaConfig;
13
use Doctrine\DBAL\Schema\SchemaDiff;
14
use Doctrine\DBAL\Schema\Sequence;
15
use Doctrine\DBAL\Schema\Table;
16
use Doctrine\DBAL\Schema\TableDiff;
17
use Psr\Log\LoggerInterface;
18
use RDV\Bundle\MigrationBundle\Exception\InvalidNameException;
19
20
class MigrationExecutor
21
{
22
    /**
23
     * @var MigrationQueryExecutor
24
     */
25
    protected $queryExecutor;
26
27
    /**
28
     * @var LoggerInterface
29
     */
30
    protected $logger;
31
32
    /**
33
     * @var MigrationExtensionManager
34
     */
35
    protected $extensionManager;
36
37
    /**
38
     * @param MigrationQueryExecutor $queryExecutor
39
     */
40
    public function __construct(MigrationQueryExecutor $queryExecutor)
41
    {
42
        $this->queryExecutor = $queryExecutor;
43
    }
44
45
    /**
46
     * Sets a logger
47
     *
48
     * @param LoggerInterface $logger
49
     */
50
    public function setLogger(LoggerInterface $logger)
51
    {
52
        $this->logger = $logger;
53
    }
54
55
    /**
56
     * Gets a query executor object this migration executor works with
57
     *
58
     * @return MigrationQueryExecutor
59
     */
60
    public function getQueryExecutor()
61
    {
62
        return $this->queryExecutor;
63
    }
64
65
    /**
66
     * Sets extension manager
67
     *
68
     * @param MigrationExtensionManager $extensionManager
69
     */
70
    public function setExtensionManager(MigrationExtensionManager $extensionManager)
71
    {
72
        $this->extensionManager = $extensionManager;
73
        $this->extensionManager->setDatabasePlatform(
74
            $this->queryExecutor->getConnection()->getDatabasePlatform()
75
        );
76
    }
77
78
    /**
79
     * Executes UP method for the given migrations
80
     *
81
     * @param MigrationState[] $migrations
82
     * @param bool             $dryRun
83
     *
84
     * @throws \RuntimeException if at lease one migration failed
85
     */
86
    public function executeUp(array $migrations, $dryRun = false)
87
    {
88
        $platform    = $this->queryExecutor->getConnection()->getDatabasePlatform();
89
        $sm          = $this->queryExecutor->getConnection()->getSchemaManager();
90
        $schema      = $this->createSchemaObject(
91
            $sm->listTables(),
92
            $platform->supportsSequences() ? $sm->listSequences() : [],
93
            $sm->createSchemaConfig()
94
        );
95
        $failedMigrations = false;
96
        foreach ($migrations as $item) {
97
            $migration = $item->getMigration();
98
            if (!empty($failedMigrations) && !$migration instanceof FailIndependentMigration) {
99
                $this->logger->notice(sprintf('> %s - skipped', get_class($migration)));
100
                continue;
101
            }
102
103
            if ($this->executeUpMigration($schema, $platform, $migration, $dryRun)) {
104
                $item->setSuccessful();
105
            } else {
106
                $item->setFailed();
107
                $failedMigrations[] = get_class($migration);
108
            }
109
        }
110
        if (!empty($failedMigrations)) {
111
            throw new \RuntimeException(sprintf('Failed migrations: %s.', implode(', ', $failedMigrations)));
112
        }
113
    }
114
115
    /**
116
     * @param Schema           $schema
117
     * @param AbstractPlatform $platform
118
     * @param Migration        $migration
119
     * @param bool             $dryRun
120
     *
121
     * @return bool
122
     */
123
    public function executeUpMigration(
124
        Schema &$schema,
125
        AbstractPlatform $platform,
126
        Migration $migration,
127
        $dryRun = false
128
    ) {
129
        $result = true;
130
131
        $this->logger->notice(sprintf('> %s', get_class($migration)));
132
        $toSchema = clone $schema;
133
        $this->setExtensions($migration);
134
        try {
135
            $queryBag = new QueryBag();
136
            $migration->up($toSchema, $queryBag);
137
138
            $comparator = new Comparator();
139
            $schemaDiff = $comparator->compare($schema, $toSchema);
140
141
            $this->checkTables($schemaDiff, $migration);
142
            $this->checkIndexes($schemaDiff, $migration);
143
144
            $queries = array_merge(
145
                $queryBag->getPreQueries(),
146
                $schemaDiff->toSql($platform),
147
                $queryBag->getPostQueries()
148
            );
149
150
            $schema = $toSchema;
151
152
            foreach ($queries as $query) {
153
                $this->queryExecutor->execute($query, $dryRun);
154
            }
155
        } catch (\Exception $ex) {
156
            $result = false;
157
            $this->logger->error(sprintf('  ERROR: %s', $ex->getMessage()));
158
        }
159
160
        return $result;
161
    }
162
163
    /**
164
     * Creates a database schema object
165
     *
166
     * @param Table[]           $tables
167
     * @param Sequence[]        $sequences
168
     * @param SchemaConfig|null $schemaConfig
169
     *
170
     * @return Schema
171
     */
172
    protected function createSchemaObject(array $tables = [], array $sequences = [], $schemaConfig = null)
173
    {
174
        return new Schema($tables, $sequences, $schemaConfig);
175
    }
176
177
    /**
178
     * Sets extensions for the given migration
179
     *
180
     * @param Migration $migration
181
     */
182
    protected function setExtensions(Migration $migration)
183
    {
184
        if ($this->extensionManager) {
185
            $this->extensionManager->applyExtensions($migration);
186
        }
187
    }
188
189
    /**
190
     * Validates the given tables from SchemaDiff
191
     *
192
     * @param SchemaDiff $schemaDiff
193
     * @param Migration  $migration
194
     *
195
     * @throws InvalidNameException if invalid table or column name is detected
196
     */
197 View Code Duplication
    protected function checkTables(SchemaDiff $schemaDiff, Migration $migration)
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
198
    {
199
        foreach ($schemaDiff->newTables as $table) {
200
            $this->checkTableName($table->getName(), $migration);
201
            $this->checkColumnNames($table->getName(), $table->getColumns(), $migration);
202
        }
203
204
        foreach ($schemaDiff->changedTables as $tableName => $diff) {
205
            $this->checkColumnNames(
206
                $tableName,
207
                array_values($diff->addedColumns),
208
                $migration
209
            );
210
        }
211
    }
212
213
    /**
214
     * Validates the given columns
215
     *
216
     * @param string    $tableName
217
     * @param Column[]  $columns
218
     * @param Migration $migration
219
     *
220
     * @throws InvalidNameException if invalid column name is detected
221
     */
222
    protected function checkColumnNames($tableName, $columns, Migration $migration)
223
    {
224
        foreach ($columns as $column) {
225
            $this->checkColumnName($tableName, $column->getName(), $migration);
226
        }
227
    }
228
229
    /**
230
     * Validates table name
231
     *
232
     * @param string    $tableName
233
     * @param Migration $migration
234
     *
235
     * @throws InvalidNameException if table name is invalid
236
     */
237
    protected function checkTableName($tableName, Migration $migration)
238
    {
239
    }
240
241
    /**
242
     * Validates column name
243
     *
244
     * @param string    $tableName
245
     * @param string    $columnName
246
     * @param Migration $migration
247
     *
248
     * @throws InvalidNameException if column name is invalid
249
     */
250
    protected function checkColumnName($tableName, $columnName, Migration $migration)
251
    {
252
    }
253
254
    /**
255
     * @param SchemaDiff $schemaDiff
256
     * @param Migration  $migration
257
     */
258 View Code Duplication
    protected function checkIndexes(SchemaDiff $schemaDiff, Migration $migration)
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
259
    {
260
        foreach ($schemaDiff->newTables as $table) {
261
            foreach ($table->getIndexes() as $index) {
262
                $this->checkIndex($table, $index, $migration);
263
            }
264
        }
265
266
        foreach ($schemaDiff->changedTables as $tableDiff) {
267
            foreach (array_values($tableDiff->addedIndexes) as $index) {
268
                $this->checkIndex(
269
                    $this->getTableFromDiff($tableDiff),
270
                    $index,
271
                    $migration
272
                );
273
            }
274
        }
275
    }
276
277
    /**
278
     * @param Table     $table
279
     * @param Index     $index
280
     * @param Migration $migration
281
     *
282
     * @throws InvalidNameException
283
     */
284
    protected function checkIndex(Table $table, Index $index, Migration $migration)
285
    {
286
        $columns = $index->getColumns();
287
        foreach ($columns as $columnName) {
288
            if ($table->getColumn($columnName)->getLength() > MySqlPlatform::LENGTH_LIMIT_TINYTEXT) {
289
                throw new InvalidNameException(
290
                    sprintf(
291
                        'Could not create index for column with length more than %s. ' .
292
                        'Please correct "%s" column length "%s" in table in "%s" migration',
293
                        MySqlPlatform::LENGTH_LIMIT_TINYTEXT,
294
                        $columnName,
295
                        $table->getName(),
296
                        get_class($migration)
297
                    )
298
                );
299
            }
300
        }
301
    }
302
303
    /**
304
     * @param TableDiff $diff
305
     *
306
     * @return Table
307
     */
308
    protected function getTableFromDiff(TableDiff $diff)
309
    {
310
        $changedColumns = array_map(
311
            function (ColumnDiff $columnDiff) {
312
                return $columnDiff->column;
313
            },
314
            $diff->changedColumns
315
        );
316
317
        $table = new Table(
318
            $diff->fromTable->getName(),
319
            array_merge($diff->fromTable->getColumns(), $diff->addedColumns, $changedColumns)
320
        );
321
322
        return $table;
323
    }
324
}
325