├── .gitignore ├── composer.json ├── transformations └── phalanger │ └── StaticToSelf.php ├── LICENSE ├── README.md └── php-code-downgrade /.gitignore: -------------------------------------------------------------------------------- 1 | composer.lock 2 | vendor 3 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "endel/php-code-downgrade", 3 | "version": "0.2.0", 4 | "keywords": ["php", "code", "downgrade", "tool"], 5 | "license": "MIT", 6 | "require": { 7 | "php": ">=5.4.0", 8 | "endel/galapagos": "dev-master", 9 | "nategood/commando": "~0.2" 10 | }, 11 | "bin": ["php-code-downgrade"] 12 | } 13 | -------------------------------------------------------------------------------- /transformations/phalanger/StaticToSelf.php: -------------------------------------------------------------------------------- 1 | class->parts[0] == "static") || 11 | ($node instanceof \PhpParser\Node\Expr\New_ && $node->class->parts[0] == "static")) 12 | { 13 | $node->class->parts[0] = "self"; 14 | return $node; 15 | } 16 | } 17 | 18 | } 19 | 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Endel Dreyer 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | php-code-downgrade 2 | === 3 | 4 | Tool to downgrade your PHP codebase from PHP 5.4+ to PHP 5.3. Built on top of 5 | [galapagos](https://github.com/endel/galapagos). 6 | 7 | Consider including 8 | [php5.3-compatibility](https://github.com/packfire/php5.3-compatibility) package 9 | in your project, which includes `JsonSerializable` and 10 | `SessionHandlerInterface`. 11 | 12 | You may have to manually fix some remaining problems, usually they're quite simple. 13 | 14 | Why? 15 | --- 16 | 17 | Use it when you have a PHP 5.4+ codebase and just can't upgrade your client's 18 | infrastructure. 19 | 20 | Features 21 | --- 22 | 23 | - Convert new array syntax to old one. (`[1,2,3]` to `array(1,2,3)`) 24 | - Inject traits code into classes that use them. 25 | - Analyze every vendor's `composer.json` and convert them if it's needed 26 | - Downgrade function calls with different signature. 27 | * `stream_context_create` 28 | * `session_set_save_handler` 29 | - Custom node transformations 30 | 31 | Usage 32 | --- 33 | 34 | ``` 35 | ./php-code-downgrade [path-to-downgrade] 36 | ``` 37 | 38 | Using custom node transformations: 39 | 40 | ``` 41 | ./php-code-downgrade [path-to-downgrade] -t transformations/phalanger 42 | ``` 43 | 44 | License 45 | --- 46 | 47 | MIT 48 | -------------------------------------------------------------------------------- /php-code-downgrade: -------------------------------------------------------------------------------- 1 | #!/usr/bin/php 2 | argument() 17 | ->describeAs('Directory with your codebase to be transformed.'); 18 | 19 | $cli->option('t') 20 | ->aka('transform') 21 | ->describeAs('Directory with custom transformations.'); 22 | 23 | $transform_instances = array(); 24 | if ($cli['t']) { 25 | $transforms = array(); 26 | foreach(glob_recursive($cli['t'] . '/**.php') as $t) { 27 | require $t; 28 | $transform = basename($t, ".php"); 29 | array_push($transforms, $transform); 30 | array_push($transform_instances, new $transform); 31 | } 32 | echo "Transformations to apply: " . join($transforms, ", ") . "\n\n"; 33 | } 34 | 35 | if ($cli[0]) { 36 | $root_path = $cli[0]; 37 | 38 | echo "** Warning **\n"; 39 | echo "Every '$root_path/**.php' file will be changed into a downgraded PHP version.\n"; 40 | echo "It's highly recommended to create a backup of those files.\n"; 41 | echo "Continue? (y/n) "; 42 | 43 | $handle = fopen("php://stdin", 'r'); 44 | $input = strtolower(trim(fgets($handle, 100))); 45 | if ($input !== "y") { 46 | die("Aborted.\n"); 47 | } 48 | 49 | } else { 50 | die("Usage:\n\tphp-code-downgrade [path]\n\n"); 51 | } 52 | 53 | $files_to_retry = array(); 54 | $libraries_to_ignore = array(); 55 | 56 | $previous_dir = ""; 57 | 58 | function transform($file, $transform_instances) { 59 | $code = file_get_contents($file); 60 | 61 | $transformed_code = galapagos\transform_with_visitors($code, array_merge( 62 | galapagos\visitors(), 63 | $transform_instances 64 | )); 65 | 66 | file_put_contents($file, $transformed_code); 67 | echo "transform: {$file}\n"; 68 | 69 | return true; 70 | } 71 | 72 | // // Disabled by now. We shoudn't ignore any file 73 | // 74 | // // libraries requiring version <= 5.3 should be ignored. 75 | // 76 | // foreach(glob_recursive($root_path . '/**/composer.json') as $composer_file) { 77 | // $composer = json_decode(file_get_contents($composer_file), true); 78 | // if (isset($composer['require']) && isset($composer['require']['php'])) { 79 | // preg_match_all('/[0-9]+/', $composer['require']['php'], $versions); 80 | // $versions = array_map(function($str) { return intval($str); }, $versions[0]); 81 | // 82 | // if ($versions[0] >= 5 && $versions[1] > 3) { 83 | // echo "{$composer_file}\n"; 84 | // } else { 85 | // array_push($libraries_to_ignore, dirname($composer_file) . '/'); 86 | // } 87 | // } 88 | // } 89 | 90 | $is_ignored = function($path) use ($libraries_to_ignore) { 91 | foreach($libraries_to_ignore as $library_to_ignore) { 92 | if (strpos($path, $library_to_ignore) !== false) { 93 | return true; 94 | } 95 | } 96 | }; 97 | 98 | $i = 0; 99 | foreach(glob_recursive($root_path . '/**.php') as $php_file) { 100 | $i++; 101 | $dir = dirname($php_file); 102 | 103 | if (preg_match('/\/vendor\/composer\//', $php_file) || 104 | $is_ignored($php_file)) { 105 | continue; 106 | } 107 | 108 | if ($dir != $previous_dir && count($files_to_retry) > 0) { 109 | foreach($files_to_retry as $i => $php_file_to_retry) { 110 | try { 111 | transform($php_file_to_retry, $transform_instances); 112 | $idx = array_search($php_file_to_retry, $files_to_retry); 113 | array_splice($files_to_retry, $idx); 114 | } catch (Exception $e) { 115 | echo "Need to retry... {$php_file_to_retry}\n"; 116 | } 117 | } 118 | } 119 | 120 | if (!preg_match('/\/tests?\//i', $php_file)) { 121 | try { 122 | transform($php_file, $transform_instances); 123 | } catch (Exception $e) { 124 | array_push($files_to_retry, $php_file); 125 | } 126 | } 127 | 128 | $previous_dir = $dir; 129 | } 130 | 131 | echo "Done.\n"; 132 | --------------------------------------------------------------------------------