Sometimes, due to the quantity of code and costs of renewal, many web project still running on old PHP platforms (well not so old e.g 5.3) with legacy frameworks as Symfony 1.x. By itself, nothing is wrong with the code as it works pretty well, however is hard to find documentation for it. Besides with the time, people discover security flaws on the frameworks and they can be exploited, that's why it's always recommendable to move forward with newer versions of the framework. With Symfony the thing wasn't so easy as the workflow changed significatively , which means that all the source code needs to be changed.
If you are not willing to rewrite a huge application made in Symfony 1.4.20, you can still run it in newer versions of PHP that in return are safer than older versions as well. The only problem is that you will constantly see a Deprecated warning on your project due to an unsafe preg_replace usage.
What causes the problem specifically?
The problem is triggered in the project due to the /e modifier for regular expressions. The /e modifier in preg_replace is deprecated on PHP 5.5 because it can be used to perform arbitrary code execution, as stated in POSIX Pattern Modifiers Docs. So, the problem is that such pattern is used in many source files of Symfony 1.4.20 to simply "Camelize" some strings and that's why you see the warning graphically on your project.
The warnings do not show up in production environment unless you have enabled debug in index.php
(only appear on frontend_dev.php
), so theoretically to offer a simple solution (quick solutions) is possible to remove those warning from appearing by simply ignoring the E_DEPRECATED
flags. You can achieve this in the settings.yml
file of your project:
# YourProject/apps/YourApp/config/settings.yml
dev:
.settings:
error_reporting: <?php echo ((E_ALL | E_STRICT) ^ E_DEPRECATED)."\n" ?>
This will immediately hide those warnings from appearing in the development environment, however this is not the most correct way to proceed as in some future, those features can be removed and your app wouldn't work anymore.
How to solve it correctly?
To solve this issue correctly following the good practices of making the code lasts at least for a couple of versions more, is to solve the error implementing the preg_replace_callback function where is needed. You will need to modify totally 7 files from the source code of your Symfony 1.4.20:
1. /symfony/lib/util/sfToolkit.class.php
In this file you will need to add the following method at the end of the class:
public static function camelize($text)
{
if (preg_match('#/(.?)#', $text, $matches)) {
$text = str_replace($matches[0], '::'.strtoupper($matches[1]), $text);
}
if (preg_match('/(^|_|-)+(.)/', $text, $matches)) {
$text = str_replace($matches[0], strtoupper($matches[2]), $text);
}
return $text;
}
This method will be used for the other files later.
2. /symfony/lib/util/sfInflector.class.php
In this file near at the line 28, replace the camelize function with the following code:
public static function camelize($lower_case_and_underscored_word)
{
$tmp = $lower_case_and_underscored_word;
return sfToolkit::camelize($tmp);
}
3. /symfony/lib/response/sfWebResponse.class.php
In this file near at the line 407, replace the normalizeHeaderName
with the following code:
protected function normalizeHeaderName($name)
{
return preg_replace_callback('/\-(.)/', function ($matches) { return '-'.strtoupper($matches[1]); }, strtr(ucfirst(strtolower($name)), '_', '-'));
}
4. /symfony/lib/plugins/sfPropelPlugin/lib/form/sfFormFilterPropel.class.php
In this file near at the line 264, replace the camelize function with the following code:
protected function camelize($text)
{
return sfToolkit::camelize($text);
}
5. /symfony/lib/plugins/sfDoctrinePlugin/lib/form/sfFormFilterDoctrine.class.php
In this file near at the line 324, replace the camelize function with the following code:
protected function camelize($text)
{
return sfToolkit::camelize($text);
}
6. /symfony/lib/form/addon/sfFormObject.class.php
In this file near at the line 279, replace the camelize function with the following code:
protected function camelize($text)
{
return sfToolkit::camelize($text);
}
7. /symfony/lib/command/sfCommandManager.class.php
In this file near at the line 109, change the following code executed in the else if statement:
// hack to split arguments with spaces : --test="with some spaces"
$arguments = preg_replace('/(\'|")(.+?)\\1/e', "str_replace(' ', '=PLACEHOLDER=', '\\2')", $arguments);
$arguments = preg_split('/\s+/', $arguments);
$arguments = str_replace('=PLACEHOLDER=', ' ', $arguments);
With this new code:
// hack to split arguments with spaces : --test="with some spaces"
$arguments = preg_replace_callback('/(\'|")(.+?)\\1/', function($matches) {
return str_replace(' ', '=PLACEHOLDER=', $matches[2]);
}, $arguments);
$arguments = preg_split('/\s+/', $arguments);
$arguments = str_replace('=PLACEHOLDER=', ' ', $arguments);
After changing all the files, clear the cache of your project and access it in your browser again. Now the warnings shouldn't appear anymore.
"Happy" legacy coding !