18

I recently upgraded PHP from version 5.3.27 to 5.5.0. Everything is working fine in my Symfony 2.3.2 project, and I can enjoy the latest PHP functionalities.

Now when I am going back to my other Symfony 1.4.16 project, I get a PHP error about preg_replace being deprecated with the /e modifier.

I can find no reference about this error in the forums: Has anyone had this problem before ? Is there any kind of patch that I could apply out of the box ? Is an upgrade to Symfony 1.4.20 going to fix this issue ?

The error message goes like this:

Deprecated: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead in /myproject/lib/vendor/symfony/lib/response/sfWebResponse.class.php on line 409

One way to go may be to modify the code as recommended in the message, and in the manual. How can I change my preg_replace expression to a preg_replace_callback call ?

Any help / hint will be very welcome.

EDIT:

To this date, there is no patch for this (and Symfony 1.4.20 does not address the issue). The solution is to replace failing calls to preg_replace with corresponding call to preg_replace_callback in the sourche, which is easily done in the sfWebResponse class (thanks for the hint Jon). Now next failing occurrence is slightly more complex, unfortunately... And on the other hand, we probably would have to grep for preg_replace uses with /e option in order to find out where Symfony is likely to break. Which gives quite a few results :o

So... My conclusion would be that Symfony 1.4 users would better not upgrade PHP to version 5.5 until some serious patch comes out. What do you think ? Any alternative ?

hakre
  • 178,314
  • 47
  • 389
  • 754
mika
  • 1,911
  • 3
  • 17
  • 31
  • 1
    possible duplicate of [Replace preg\_replace() e modifier with preg\_replace\_callback](http://stackoverflow.com/questions/15454220/replace-preg-replace-e-modifier-with-preg-replace-callback) – Jon Aug 06 '13 at 10:27
  • 2
    This [isn't fixed in symfony 1.4.x](http://trac.symfony-project.org/browser/branches/1.4/lib/response/sfWebResponse.class.php#L409). You should patch the class on your own. And if you can make a pull request with your change on [*our* symfony1](https://github.com/LExpress/symfony1), it'll be awesome :) – j0k Aug 06 '13 at 11:10
  • @Jon The main issue here is about getting Symfony 1.4 to work with PHP 5.5. In that sense, I would say it is no duplicate (and I would keep the original title :o ). What do you think ? I agree replacing preg_replace with preg_replace_callback is the way to get it done, but previous thread does not fully address that... – mika Aug 06 '13 at 14:45
  • @mika: Possibly... the thing is that the question begins with "how can I modify the code", which is what I answered, but then goes on to ask about patches and possible future updates -- for which the Symfony developer resources would be the place to go to. (I see that 1.4.x has not seen any commits for 8 months, so I would not expect this to ever be fixed in stock Symfony). Perhaps I was carried away by the "line 429" part which is way too specific. In any case IMHO the aim of the question should be clarified. – Jon Aug 06 '13 at 15:36
  • @Jon: Sure, I started to try to answer my question before I actually finished to formulate it. Mea culpa (let me reformulate it). Your answer was very helpful to dig in. Now in the bigger context, editing Symfony 1.4 code does not seem to be the simplest fix. – mika Aug 06 '13 at 15:53
  • Many symfony1 preg_replace() deprecations are fixed in @j0k 's symfony1 fork. See this pull request diff for how to fix these issues: https://github.com/LExpress/symfony1/pull/26/files – John Kary Mar 12 '17 at 22:33

7 Answers7

37

The errors do not show up in prod unless you have enabled debug in index.php. It' s also possible to remove them in dev by unsetting the E_DEPRECATED flag in settings.yml :

dev:
  .settings:
    error_reporting:  <?php echo ((E_ALL | E_STRICT) ^ E_DEPRECATED)."\n" ?>
flm
  • 952
  • 8
  • 14
  • The one quick and easy fix :) Thanks a lot ! – mika Sep 02 '13 at 08:08
  • 5
    -1 This is not a solution! You should fix the code and below comments made it possible xtech - fixed sfToolkit.class.php and mika - fixed sfWebResponse.class.php (he also offers fix for second file, but it does not work for me, giving fatal error) – Radamanf Aug 06 '14 at 09:11
  • Duplicate http://stackoverflow.com/questions/21091955/symfony-1-4-deprecated-function-in-php/25156792#25156792 – Radamanf Aug 06 '14 at 11:59
  • Definitely not the best solution to hide something that doesn't work, just to say, *now it works !* -_- – j0k Sep 02 '14 at 11:12
  • 5
    As below suggested, but little bit hidden, the best option nowadays to use the community maintained version of symfony1... It is kind a symfony 1.5: https://github.com/LExpress/symfony1 Fully compatible with php 5.5 and 5.6 – Zoltan Feb 25 '15 at 08:18
  • 1
    Thank you @szines for posting that link. I'm maintaining our complex production Symfony 1.4 app and this might buy us some time. I wish SensioLabs had put a link to that fork ages ago, this is the first I've heard of it. – ybull Jun 11 '15 at 14:11
14

Basically what you have to do is take the replacement argument from the preg_replace call and factor it out into a proper PHP expression, then make that expression the body of a function that will be used as the callback to the equivalent preg_replace_callback call.

In your case the relevant code is

return preg_replace('/\-(.)/e', "'-'.strtoupper('\\1')", /* input */)

So you would do that as

$callback = function($matches) {
    return '-'.strtoupper($matches[1]);
};

return preg_replace_callback('/\-(.)/', $callback, /* input */)

As you can see the callback code is the same as the original replace expression, the only difference being that references such as \\1 are replaced with array accesses like $matches[1].

Jon
  • 396,160
  • 71
  • 697
  • 768
  • This looks really good, and gives a fix for the error message. Now further down the line, I get the same problem with myproject/lib/vendor/symfony/lib/util/sfToolkit.class.php on line 362. This means the code will need to be updated in various places in the Symfony version I use... :/ @jOk Ah ok, well, this matches your above comment :) You mean this is an opportunity for me to participate in the Symfony source code ? Sounds nice :) – mika Aug 06 '13 at 13:30
  • I had to change only /lib/vendor/symfony/lib/response/sfWebResponse.class.php, thanks! – Arkadiusz Cieśliński Feb 10 '20 at 19:58
11

All in all, the best solution is to avoid upgrading PHP to version 5.5, as it is no more compatible with Symfony 1.4

If you have both Symfony 2 and 1.4 versions in a development environment, you may want to be able to switch your PHP version, as nicely described here.

If you really need to, it is possible to setup two different versions of PHP running on the same Apache server at the same time: this will need some more configuration, the above link explains that too.

Alternative HOT FIX:

With a couple of updates in the Symfony code, I can get most of my webpages running in dev. Of course, it would be dangerous to apply this in production, as the "deprecated" error may turn up again at any time, arising from another Symfony library.

In myproject/lib/vendor/symfony/lib/response/sfWebResponse.class.php on line 409, I have now (commented code is original Symfony code):

  protected function normalizeHeaderName($name)
  {
    // return preg_replace('/\-(.)/e', "'-'.strtoupper('\\1')", strtr(ucfirst(strtolower($name)), '_', '-'));    

    return preg_replace_callback(
                  '/\-(.)/', 
                  function ($matches) {
                    return '-'.strtoupper($matches[1]);
                  }, 
                  strtr(ucfirst(strtolower($name)), '_', '-')
        );
  }

And in myproject/lib/vendor/symfony/lib/util/sfToolkit.class.php on line 362 we get:

  public static function pregtr($search, $replacePairs)
  {
    // return preg_replace(array_keys($replacePairs), array_values($replacePairs), $search);
    foreach($replacePairs as $pattern => $replacement)
        $search = preg_replace_callback(
                    $pattern, 
                    function ($matches) use ($replacement){
                        if(array_key_exists(1, $matches)){ $replacement = str_replace("\\1", $matches[1], $replacement);}
                        if(array_key_exists(2, $matches)){ $replacement = str_replace("\\2", $matches[2], $replacement);}
                        return $replacement;
                    }, 
                    $search
                );
    return $search;
  }

Use at your own risks :)

Community
  • 1
  • 1
mika
  • 1,911
  • 3
  • 17
  • 31
  • Why do you need to modify `pregtr` function? It doesn't use `/e` .. And by the way, we know have [an opened issue about that](https://github.com/LExpress/symfony1/issues/19). – j0k Aug 19 '13 at 14:47
  • @jOk pregtr comes with two arguments which are used in the preg_replace call. It turns out that the $search argument is sometimes using the /e option, and this is why the preg_replace call needs to be changed here. In the same way, the current symfony code gets to work with maximum two matching patterns in the pregtr calls, and for this reason the patch I propose is working fine (with only array_key_exists 1 and 2, and not 3, 4, 5, etc...). If there is a more general way to deal with this, I will be pleased to see it :) Oh, and thanks for the issue. This is good to know. – mika Aug 21 '13 at 14:00
  • 2
    The error does not show up in prod unless you have enabled debug in index.php. It' s also possible to remove them in dev by unsetting the E_DEPRECATED flag in settings.yml : – flm Aug 26 '13 at 13:19
  • @flm: this is the quick fix I was looking for. If you put your tip in a post, I will flag it as the correct answer. Many Thanks ! – mika Aug 29 '13 at 14:41
  • @flm Mute all messages is bad practice, yous could better to fix such little problems imediately, thx to google search and people who did it before :). – Arkemlar Jul 12 '16 at 19:16
11

FIX for normalizeHeaderName method in /lib/vendor/symfony/lib/response/sfWebResponse.class.php on line 407

protected function normalizeHeaderName($name)
{
  //return preg_replace('/\-(.)/e', "'-'.strtoupper('\\1')", 
  strtr(ucfirst(strtolower($name)), '_', '-');
  return str_replace(array('\'$1$3\'','\'$2$4\'','\'$1\'', '\'$2\'', '$1', '$2'),array('$matches[1].$matches[3]','$matches[2].$matches[4]','$matches[1]','$matches[2]','$matches[1]','$matches[2]'),
$name);
}

FIX for pregtr method in /lib/vendor/symfony/lib/util/sfToolkit.class.php on line 360

public static function pregtr($search, $replacePairs){
  // return preg_replace(array_keys($replacePairs), array_values($replacePairs), $search);
  foreach($replacePairs as $pattern => $replacement)
  {
    if (preg_match('/(.*)e$/', $pattern, $matches))
    {
      $pattern = $matches[1];
      $search = preg_replace_callback($pattern, function ($matches) use ($replacement) {
        preg_match("/('::'\.)?([a-z]*)\('\\\\([0-9]{1})'\)/", $replacement, $match);
        return ($match[1]==''?'':'::').call_user_func($match[2], $matches[$match[3]]);
      }, $search);
    }
    else
    {
      $search = preg_replace($pattern, $replacement, $search);
    }
  }
  return $search;
}
macatapichon
  • 111
  • 1
  • 5
8

There is a community version of Symfony that maintains and patches the older code:

https://github.com/LExpress/symfony1

Kevin
  • 352
  • 2
  • 4
5

Alternative FIX for pregtr method in /lib/vendor/symfony/lib/util/sfToolkit.class.php on line 360

public static function pregtr($search, $replacePairs)
{
  // return preg_replace(array_keys($replacePairs), array_values($replacePairs), $search);
  foreach($replacePairs as $pattern => $replacement)
  {
    if (preg_match('/(.*)e$/', $pattern, $matches))
    {
      $pattern = $matches[1];
      $search = preg_replace_callback($pattern, function ($matches) use ($replacement) {
        preg_match("/('::'\.)?([a-z]*)\('\\\\([0-9]{1})'\)/", $replacement, $match);
        return ($match[1]==''?'':'::').call_user_func($match[2], $matches[$match[3]]);
      }, $search);
    }
    else
    {
      $search = preg_replace($pattern, $replacement, $search);
    }
  }
  return $search;
}
sadikoff
  • 91
  • 1
  • 8
0
Deprecated: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead in lib/vendor/symfony/…This changelog will solve the problem for all symfony 1.4.x. Tested on Symfony 1.4.20
---
 lib/vendor/symfony/lib/command/sfCommandManager.class.php     |  4 +++-
 lib/vendor/symfony/lib/form/addon/sfFormObject.class.php      |  2 +-
 lib/vendor/symfony/plugins/sfDoctrinePlugin/lib/form/sfFormFilterDoctrine.class.php  |  2 +-
 lib/vendor/symfony/plugins/sfPropelPlugin/lib/form/sfFormFilterPropel.class.php      |  2 +-
 lib/vendor/symfony/lib/response/sfWebResponse.class.php       |  2 +-
 lib/vendor/symfony/lib/util/sfInflector.class.php             |  5 +----
 lib/vendor/symfony/lib/util/sfToolkit.class.php               | 11 +++++++++++
 7 files changed, 19 insertions(+), 9 deletions(-)

lib/vendor/symfony/lib/command/sfCommandManager.class.php
@@ -108,7 +108,9 @@ class sfCommandManager
     else if (!is_array($arguments))
     {
       // hack to split arguments with spaces : --test="with some spaces"
-      $arguments = preg_replace('/(\'|")(.+?)\\1/e', "str_replace(' ', '=PLACEHOLDER=', '\\2')", $arguments);
+      $arguments = preg_replace_callback('/(\'|")(.+?)\\1/', function($matches) {
+         return str_replace(' ', '=PLACEHOLDER=', $matches[2]);
+     }, $arguments);
       $arguments = preg_split('/\s+/', $arguments);
       $arguments = str_replace('=PLACEHOLDER=', ' ', $arguments);
     }

lib/vendor/symfony/lib/form/addon/sfFormObject.class.php
@@ -278,6 +278,6 @@ abstract class sfFormObject extends BaseForm

   protected function camelize($text)
   {
-    return preg_replace(array('#/(.?)#e', '/(^|_|-)+(.)/e'), array("'::'.strtoupper('\\1')", "strtoupper('\\2')"), $text);
+    return sfToolkit::camelize($text);
   }
 }

lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/form/sfFormFilterDoctrine.class.php
@@ -323,7 +323,7 @@ abstract class sfFormFilterDoctrine extends sfFormFilter

   protected function camelize($text)
   {
-    return sfToolkit::pregtr($text, array('#/(.?)#e' => "'::'.strtoupper('\\1')", '/(^|_|-)+(.)/e' => "strtoupper('\\2')"));
+    return sfToolkit::camelize($text);
   }

   protected function getTable()

lib/vendor/symfony/lib/plugins/sfPropelPlugin/lib/form/sfFormFilterPropel.class.php
@@ -263,6 +263,6 @@ abstract class sfFormFilterPropel extends sfFormFilter

   protected function camelize($text)
   {
-    return sfToolkit::pregtr($text, array('#/(.?)#e' => "'::'.strtoupper('\\1')", '/(^|_|-)+(.)/e' => "strtoupper('\\2')"));
+       return sfToolkit::camelize($text);
   }
 }

lib/vendor/symfony/lib/response/sfWebResponse.class.php
@@ -406,7 +406,7 @@ class sfWebResponse extends sfResponse
    */
   protected function normalizeHeaderName($name)
   {
-    return preg_replace('/\-(.)/e', "'-'.strtoupper('\\1')", strtr(ucfirst(strtolower($name)), '_', '-'));
+    return preg_replace_callback('/\-(.)/', function ($matches) { return '-'.strtoupper($matches[1]); }, strtr(ucfirst(strtolower($name)), '_', '-'));
   }

   /**

lib/vendor/symfony/lib/util/sfInflector.class.php
@@ -28,10 +28,7 @@ class sfInflector
   public static function camelize($lower_case_and_underscored_word)
   {
     $tmp = $lower_case_and_underscored_word;
-    $tmp = sfToolkit::pregtr($tmp, array('#/(.?)#e'    => "'::'.strtoupper('\\1')",
-                                         '/(^|_|-)+(.)/e' => "strtoupper('\\2')"));
-
-    return $tmp;
+    return sfToolkit::camelize($tmp);;
   }

   /**

lib/vendor/symfony/lib/util/sfToolkit.class.php
@@ -608,4 +608,15 @@ class sfToolkit

     return set_include_path(join(PATH_SEPARATOR, $paths));
   }
+
+   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;
+   }
 }
--
ImLeo
  • 789
  • 8
  • 16