This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
0 ignored issues
–
show
|
|||
2 | /** |
||
3 | * CodeIgniter |
||
4 | * |
||
5 | * An open source application development framework for PHP |
||
6 | * |
||
7 | * This content is released under the MIT License (MIT) |
||
8 | * |
||
9 | * Copyright (c) 2014 - 2015, British Columbia Institute of Technology |
||
10 | * |
||
11 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
||
12 | * of this software and associated documentation files (the "Software"), to deal |
||
13 | * in the Software without restriction, including without limitation the rights |
||
14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||
15 | * copies of the Software, and to permit persons to whom the Software is |
||
16 | * furnished to do so, subject to the following conditions: |
||
17 | * |
||
18 | * The above copyright notice and this permission notice shall be included in |
||
19 | * all copies or substantial portions of the Software. |
||
20 | * |
||
21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||
22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||
23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||
24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||
25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||
26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
||
27 | * THE SOFTWARE. |
||
28 | * |
||
29 | * @package CodeIgniter |
||
30 | * @author EllisLab Dev Team |
||
31 | * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (http://ellislab.com/) |
||
32 | * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/) |
||
33 | * @license http://opensource.org/licenses/MIT MIT License |
||
34 | * @link http://codeigniter.com |
||
35 | * @since Version 3.0.0 |
||
36 | * @filesource |
||
37 | */ |
||
38 | defined('BASEPATH') OR exit('No direct script access allowed'); |
||
39 | |||
40 | /** |
||
41 | * Migration Class |
||
42 | * |
||
43 | * All migrations should implement this, forces up() and down() and gives |
||
44 | * access to the CI super-global. |
||
45 | * |
||
46 | * @package CodeIgniter |
||
47 | * @subpackage Libraries |
||
48 | * @category Libraries |
||
49 | * @author Reactor Engineers |
||
50 | * @link |
||
51 | */ |
||
52 | class CI_Migration { |
||
53 | |||
54 | /** |
||
55 | * Whether the library is enabled |
||
56 | * |
||
57 | * @var bool |
||
58 | */ |
||
59 | protected $_migration_enabled = FALSE; |
||
60 | |||
61 | /** |
||
62 | * Migration numbering type |
||
63 | * |
||
64 | * @var bool |
||
65 | */ |
||
66 | protected $_migration_type = 'sequential'; |
||
67 | |||
68 | /** |
||
69 | * Path to migration classes |
||
70 | * |
||
71 | * @var string |
||
72 | */ |
||
73 | protected $_migration_paths = NULL; |
||
74 | |||
75 | /** |
||
76 | * Current migration version |
||
77 | * |
||
78 | * @var mixed |
||
79 | */ |
||
80 | protected $_migration_version = 0; |
||
81 | |||
82 | /** |
||
83 | * Database table with migration info |
||
84 | * |
||
85 | * @var string |
||
86 | */ |
||
87 | protected $_migration_table = 'migrations'; |
||
88 | |||
89 | /** |
||
90 | * Whether to automatically run migrations |
||
91 | * |
||
92 | * @var bool |
||
93 | */ |
||
94 | protected $_migration_auto_latest = FALSE; |
||
95 | |||
96 | /** |
||
97 | * Migration basename regex |
||
98 | * |
||
99 | * @var bool |
||
100 | */ |
||
101 | protected $_migration_regex = NULL; |
||
102 | |||
103 | /** |
||
104 | * Error message |
||
105 | * |
||
106 | * @var string |
||
107 | */ |
||
108 | protected $_error_string = ''; |
||
109 | |||
110 | /** |
||
111 | * Initialize Migration Class |
||
112 | * |
||
113 | * @param array $config |
||
114 | * @return void |
||
115 | */ |
||
116 | public function __construct($config = array()) |
||
117 | { |
||
118 | // Only run this constructor on main library load |
||
119 | View Code Duplication | if ( ! in_array(get_class($this), array('CI_Migration', config_item('subclass_prefix').'Migration'), TRUE)) |
|
120 | { |
||
121 | return; |
||
122 | } |
||
123 | |||
124 | foreach ($config as $key => $val) |
||
125 | { |
||
126 | $this->{'_'.$key} = $val; |
||
127 | } |
||
128 | |||
129 | log_message('debug', 'Migrations class initialized'); |
||
130 | |||
131 | // Are they trying to use migrations while it is disabled? |
||
132 | if ($this->_migration_enabled !== TRUE) |
||
133 | { |
||
134 | show_error('Migrations has been loaded but is disabled or set up incorrectly.'); |
||
135 | } |
||
136 | |||
137 | // If not set, set it |
||
138 | count($this->_migration_paths) OR $this->_migration_paths = array(APPPATH.'database/migrations/'); |
||
139 | |||
140 | // Add trailing slash if not set |
||
141 | foreach ($this->_migration_paths as $alias => $path) { |
||
142 | $this->_migration_paths[$alias] = rtrim($this->_migration_paths[$alias], '/') . '/'; |
||
143 | } |
||
144 | |||
145 | // Load migration language |
||
146 | $this->lang->load('migration'); |
||
147 | |||
148 | // They'll probably be using dbforge |
||
149 | $this->load->dbforge(); |
||
150 | |||
151 | // Make sure the migration table name was set. |
||
152 | if (empty($this->_migration_table)) |
||
153 | { |
||
154 | show_error('Migrations configuration file (migration.php) must have "migration_table" set.'); |
||
155 | } |
||
156 | |||
157 | // Migration basename regex |
||
158 | $this->_migration_regex = ($this->_migration_type === 'timestamp') |
||
159 | ? '/^\d{14}_(\w+)$/' |
||
160 | : '/^\d{3}_(\w+)$/'; |
||
161 | |||
162 | // Make sure a valid migration numbering type was set. |
||
163 | View Code Duplication | if ( ! in_array($this->_migration_type, array('sequential', 'timestamp'))) |
|
164 | { |
||
165 | show_error('An invalid migration numbering type was specified: '.$this->_migration_type); |
||
166 | } |
||
167 | |||
168 | // If the migrations table is missing, make it |
||
169 | if ( ! $this->db->table_exists($this->_migration_table)) |
||
170 | { |
||
171 | $this->dbforge->add_field(array( |
||
172 | 'version' => array('type' => 'BIGINT', 'constraint' => 20), |
||
173 | 'alias' => array('type' => 'VARCHAR', 'constraint' => 255), |
||
174 | 'ondate' => array('type' => 'DATETIME') |
||
175 | )); |
||
176 | |||
177 | $this->dbforge->add_key('alias'); |
||
178 | |||
179 | $this->dbforge->create_table($this->_migration_table, TRUE); |
||
180 | } |
||
181 | |||
182 | // Do we auto migrate to the latest migration? |
||
183 | if ($this->_migration_auto_latest === TRUE && ! $this->latest()) |
||
184 | { |
||
185 | show_error($this->error_string()); |
||
186 | } |
||
187 | |||
188 | } |
||
189 | |||
190 | // -------------------------------------------------------------------- |
||
191 | |||
192 | /** |
||
193 | * Migrate to a schema version |
||
194 | * |
||
195 | * Calls each migration step required to get to the schema version of |
||
196 | * choice |
||
197 | * |
||
198 | * @param string $type Any key from _migration_paths, or {module_name} |
||
199 | * @param string $target_version Target schema version |
||
200 | * |
||
201 | * @return mixed TRUE if already latest, FALSE if failed, string if upgraded |
||
202 | */ |
||
203 | public function version($type='all', $target_version) |
||
204 | { |
||
205 | // Note: We use strings, so that timestamp versions work on 32-bit systems |
||
206 | $current_version = $this->get_version($type); |
||
207 | |||
208 | View Code Duplication | if ($this->_migration_type === 'sequential') |
|
209 | { |
||
210 | $target_version = sprintf('%03d', $target_version); |
||
211 | } |
||
212 | else |
||
213 | { |
||
214 | $target_version = (string) $target_version; |
||
215 | } |
||
216 | |||
217 | $migrations = $this->find_migrations($type); |
||
218 | |||
219 | View Code Duplication | if ($target_version > 0 && ! isset($migrations[$target_version])) |
|
220 | { |
||
221 | $this->_error_string = sprintf($this->lang->line('migration_not_found'), $target_version); |
||
222 | return FALSE; |
||
223 | } |
||
224 | |||
225 | if ($target_version > $current_version) |
||
226 | { |
||
227 | // Moving Up |
||
228 | $method = 'up'; |
||
229 | } |
||
230 | else |
||
231 | { |
||
232 | // Moving Down, apply in reverse order |
||
233 | $method = 'down'; |
||
234 | krsort($migrations); |
||
235 | } |
||
236 | |||
237 | if (empty($migrations)) |
||
238 | { |
||
239 | return TRUE; |
||
240 | } |
||
241 | |||
242 | $previous = FALSE; |
||
243 | |||
244 | // Validate all available migrations, and run the ones within our target range |
||
245 | View Code Duplication | foreach ($migrations as $number => $file) |
|
246 | { |
||
247 | // Check for sequence gaps |
||
248 | if ($this->_migration_type === 'sequential' && $previous !== FALSE && abs($number - $previous) > 1) |
||
249 | { |
||
250 | $this->_error_string = sprintf($this->lang->line('migration_sequence_gap'), $number); |
||
251 | return FALSE; |
||
252 | } |
||
253 | |||
254 | include_once($file); |
||
255 | $class = 'Migration_'.ucfirst(strtolower($this->_get_migration_name(basename($file, '.php')))); |
||
256 | |||
257 | // Validate the migration file structure |
||
258 | if ( ! class_exists($class, FALSE)) |
||
259 | { |
||
260 | $this->_error_string = sprintf($this->lang->line('migration_class_doesnt_exist'), $class); |
||
261 | return FALSE; |
||
262 | } |
||
263 | |||
264 | $previous = $number; |
||
265 | |||
266 | // Run migrations that are inside the target range |
||
267 | if ( |
||
268 | ($method === 'up' && $number > $current_version && $number <= $target_version) OR |
||
269 | ($method === 'down' && $number <= $current_version && $number > $target_version) |
||
270 | ) |
||
271 | { |
||
272 | $instance = new $class(); |
||
273 | if ( ! is_callable(array($instance, $method))) |
||
274 | { |
||
275 | $this->_error_string = sprintf($this->lang->line('migration_missing_'.$method.'_method'), $class); |
||
276 | return FALSE; |
||
277 | } |
||
278 | |||
279 | log_message('debug', 'Migrating '.$method.' from version '.$current_version.' to version '.$number); |
||
280 | call_user_func(array($instance, $method)); |
||
281 | $current_version = $number; |
||
282 | $this->_update_version($type, $current_version); |
||
283 | } |
||
284 | } |
||
285 | |||
286 | // This is necessary when moving down, since the the last migration applied |
||
287 | // will be the down() method for the next migration up from the target |
||
288 | if ($current_version <> $target_version) |
||
289 | { |
||
290 | $current_version = $target_version; |
||
291 | $this->_update_version($type, $current_version); |
||
292 | } |
||
293 | |||
294 | log_message('debug', 'Finished migrating to '.$current_version); |
||
295 | |||
296 | return $current_version; |
||
297 | } |
||
298 | |||
299 | // -------------------------------------------------------------------- |
||
300 | |||
301 | /** |
||
302 | * Sets the schema to the latest migration |
||
303 | * |
||
304 | * @param string $type Any key from _migration_paths, or {module_name} |
||
305 | * |
||
306 | * @return mixed TRUE if already latest, FALSE if failed, string if upgraded |
||
307 | */ |
||
308 | public function latest($type='app') |
||
309 | { |
||
310 | $last_migration = $this->get_latest($type); |
||
311 | |||
312 | // Calculate the last migration step from existing migration |
||
313 | // filenames and proceed to the standard version migration |
||
314 | return $this->version($type, $this->_get_migration_number($last_migration)); |
||
0 ignored issues
–
show
It seems like
$last_migration defined by $this->get_latest($type) on line 310 can also be of type false ; however, CI_Migration::_get_migration_number() does only seem to accept string , did you maybe forget to handle an error condition?
This check looks for type mismatches where the missing type is Consider the follow example <?php
function getDate($date)
{
if ($date !== null) {
return new DateTime($date);
}
return false;
}
This function either returns a new ![]() |
|||
315 | } |
||
316 | |||
317 | // -------------------------------------------------------------------- |
||
318 | |||
319 | /** |
||
320 | * Retrieves the latest migration version available. |
||
321 | * |
||
322 | * @param string $type Any key from _migration_paths, or {module_name} |
||
323 | * |
||
324 | * @return bool|string |
||
325 | */ |
||
326 | public function get_latest($type='app') |
||
327 | { |
||
328 | $migrations = $this->find_migrations($type); |
||
329 | |||
330 | if (empty($migrations)) |
||
331 | { |
||
332 | $this->_error_string = $this->lang->line('migration_none_found'); |
||
333 | return FALSE; |
||
334 | } |
||
335 | |||
336 | return basename(end($migrations)); |
||
337 | } |
||
338 | |||
339 | //-------------------------------------------------------------------- |
||
340 | |||
341 | |||
342 | |||
343 | /** |
||
344 | * Sets the schema to the migration version set in config |
||
345 | * |
||
346 | * @return mixed TRUE if already current, FALSE if failed, string if upgraded |
||
347 | */ |
||
348 | public function current() |
||
349 | { |
||
350 | return $this->version($this->_migration_version); |
||
351 | } |
||
352 | |||
353 | // -------------------------------------------------------------------- |
||
354 | |||
355 | /** |
||
356 | * Error string |
||
357 | * |
||
358 | * @return string Error message returned as a string |
||
359 | */ |
||
360 | public function error_string() |
||
361 | { |
||
362 | return $this->_error_string; |
||
363 | } |
||
364 | |||
365 | // -------------------------------------------------------------------- |
||
366 | |||
367 | /** |
||
368 | * Retrieves list of available migration scripts |
||
369 | * |
||
370 | * @return array list of migration file paths sorted by version |
||
371 | */ |
||
372 | public function find_migrations($type='app') |
||
373 | { |
||
374 | $migrations = array(); |
||
375 | |||
376 | $path = $this->determine_migration_path($type); |
||
377 | |||
378 | // Load all *_*.php files in the migrations path |
||
379 | View Code Duplication | foreach (glob($path.'*_*.php') as $file) |
|
380 | { |
||
381 | $name = basename($file, '.php'); |
||
382 | |||
383 | // Filter out non-migration files |
||
384 | if (preg_match($this->_migration_regex, $name)) |
||
385 | { |
||
386 | $number = $this->_get_migration_number($name); |
||
387 | |||
388 | // There cannot be duplicate migration numbers |
||
389 | if (isset($migrations[$number])) |
||
390 | { |
||
391 | $this->_error_string = sprintf($this->lang->line('migration_multiple_version'), $number); |
||
392 | show_error($this->_error_string); |
||
393 | } |
||
394 | |||
395 | $migrations[$number] = $file; |
||
396 | } |
||
397 | } |
||
398 | |||
399 | ksort($migrations); |
||
400 | return $migrations; |
||
401 | } |
||
402 | |||
403 | // -------------------------------------------------------------------- |
||
404 | |||
405 | /** |
||
406 | * Retrieves current schema version |
||
407 | * |
||
408 | * @return string Current migration version |
||
409 | */ |
||
410 | public function get_version($type='app') |
||
411 | { |
||
412 | $row = $this->db->select('version') |
||
413 | ->where('alias', $type) |
||
414 | ->get($this->_migration_table) |
||
415 | ->row(); |
||
416 | |||
417 | return $row ? $row->version : '0'; |
||
418 | } |
||
419 | |||
420 | // -------------------------------------------------------------------- |
||
421 | |||
422 | /** |
||
423 | * Given the string for the name of the file, will |
||
424 | * generate the rest of the filename based on the current |
||
425 | * $config['migration_type'] setting. |
||
426 | * |
||
427 | * @param $name |
||
428 | * @return string The final name (with extension) |
||
429 | */ |
||
430 | public function make_name($name) |
||
431 | { |
||
432 | if (empty($name)) |
||
433 | { |
||
434 | return null; |
||
435 | } |
||
436 | |||
437 | if ($this->_migration_type == 'timestamp') |
||
438 | { |
||
439 | $prefix = date('YmdHis'); |
||
440 | } |
||
441 | else |
||
442 | { |
||
443 | $prefix = str_pad($this->get_version() + 1, 3, '0', STR_PAD_LEFT); |
||
444 | } |
||
445 | |||
446 | return $prefix .'_'. ucfirst(strtolower($name)) .'.php'; |
||
447 | } |
||
448 | |||
449 | //-------------------------------------------------------------------- |
||
450 | |||
451 | /** |
||
452 | * Enable the use of CI super-global |
||
453 | * |
||
454 | * @param string $var |
||
455 | * @return mixed |
||
456 | */ |
||
457 | public function __get($var) |
||
458 | { |
||
459 | return get_instance()->$var; |
||
460 | } |
||
461 | |||
462 | //-------------------------------------------------------------------- |
||
463 | |||
464 | |||
465 | /** |
||
466 | * Based on the 'type', determines the correct migration path. |
||
467 | * |
||
468 | * @param $type |
||
469 | * @param bool $create |
||
470 | * |
||
471 | * @return null|string |
||
472 | */ |
||
473 | public function determine_migration_path($type, $create=false) |
||
474 | { |
||
475 | $type = strtolower($type); |
||
476 | |||
477 | // Is it a module? |
||
478 | if (strpos($type, 'mod:') === 0) |
||
479 | { |
||
480 | $module = str_replace('mod:', '', $type); |
||
481 | |||
482 | $path = \Myth\Modules::path($module, 'migrations'); |
||
483 | |||
484 | // Should we return a 'created' module? |
||
485 | // Use the first module path. |
||
486 | if (empty($path) && $create === true) |
||
487 | { |
||
488 | $folders = config_item('modules_locations'); |
||
489 | |||
490 | if (is_array($folders) && count($folders)) |
||
491 | { |
||
492 | $path = $folders[0] . $module .'/migrations'; |
||
493 | } |
||
494 | } |
||
495 | |||
496 | return rtrim($path, '/') .'/'; |
||
497 | } |
||
498 | |||
499 | // Look in our predefined groups. |
||
500 | if (! empty($this->_migration_paths[$type])) |
||
501 | { |
||
502 | return rtrim($this->_migration_paths[$type], '/') .'/'; |
||
503 | } |
||
504 | |||
505 | return null; |
||
506 | } |
||
507 | |||
508 | //-------------------------------------------------------------------- |
||
509 | |||
510 | /** |
||
511 | * Returns the default migration path. This is basically the first |
||
512 | * path in the migration_paths array. |
||
513 | * |
||
514 | * @return string |
||
515 | */ |
||
516 | public function default_migration_path() |
||
517 | { |
||
518 | return key($this->_migration_paths); |
||
519 | } |
||
520 | |||
521 | //-------------------------------------------------------------------- |
||
522 | |||
523 | |||
524 | //-------------------------------------------------------------------- |
||
525 | // Protected Methods |
||
526 | //-------------------------------------------------------------------- |
||
527 | |||
528 | /** |
||
529 | * Extracts the migration number from a filename |
||
530 | * |
||
531 | * @param string $migration |
||
532 | * @return string Numeric portion of a migration filename |
||
533 | */ |
||
534 | protected function _get_migration_number($migration) |
||
535 | { |
||
536 | return sscanf($migration, '%[0-9]+', $number) |
||
537 | ? $number : '0'; |
||
538 | } |
||
539 | |||
540 | // -------------------------------------------------------------------- |
||
541 | |||
542 | /** |
||
543 | * Extracts the migration class name from a filename |
||
544 | * |
||
545 | * @param string $migration |
||
546 | * @return string text portion of a migration filename |
||
547 | */ |
||
548 | protected function _get_migration_name($migration) |
||
549 | { |
||
550 | $parts = explode('_', $migration); |
||
551 | array_shift($parts); |
||
552 | return implode('_', $parts); |
||
553 | } |
||
554 | |||
555 | // -------------------------------------------------------------------- |
||
556 | |||
557 | /** |
||
558 | * Stores the current schema version |
||
559 | * |
||
560 | * @param string $type Any key from _migration_paths, or {module_name} |
||
561 | * @param string $migration Migration reached |
||
562 | * @return mixed Outputs a report of the migration |
||
563 | */ |
||
564 | protected function _update_version($type='all', $migration) |
||
565 | { |
||
566 | $this->db->where('alias', $type) |
||
567 | ->delete($this->_migration_table); |
||
568 | |||
569 | return $this->db->insert($this->_migration_table, array( |
||
570 | 'version' => $migration, |
||
571 | 'alias' => $type, |
||
572 | 'ondate' => date('Y-m-d H:i:s') |
||
573 | )); |
||
574 | } |
||
575 | |||
576 | // -------------------------------------------------------------------- |
||
577 | |||
578 | } |
||
579 |
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.