This is an attempt to share a Drupal 5 core patch that improves compatibility with PHP 5.3. Drupal 5 will officially not support PHP 5.3 (see #853064: Alter INSTALL.txt to be clear PHP 5.3 is not compatible with Drupal 5), however some of us have no other choice and will have to make D5 work anyway.

Warning: You will have to patch many core/contributed modules as well, because of the severe PHP warning when a functions expects a reference parameter and a value is given; and the function will not be executed (example: #587568: Parameter 1 to comment_nodeapi() expected to be a reference module.inc, line 450 (php 5.3 compatibility)). In most cases the solution is to simply remove the '&' reference operator from the parameter, if the function does not need the reference.

PHP errors are logged to watchdog (admin/logs/watchdog), so if you hit broken subpages of your site visit the log where you can find the broken functions that expect references.

The patch was inspired by #360605: PHP 5.3 Compatibility

Comments

RobLoach’s picture

Thanks a lot... Here's another patch I uploaded from #853064. I haven't compared either one, just thought I'd keep it posted.

RobLoach’s picture

FileSize
14.6 KB

Whoops, forgot the patch.

dpearcefl’s picture

Status: Active » Closed (fixed)

Closing because there is no more work to be done.

NaX’s picture

Thanks a lot for these patches they helped me a great deal with a large number of D5 sites that I cant upgrade to D6.

If anybody else finds this post I thought I should add how I got around contrib module hooks where function were expecting references.

Example Error:
Parameter 2 to uc_payment_order() expected to be a reference, value given in includes/module.inc on line 436.

The problem is that I don't really have the time to investigate every hook call that causes errors like this and I cant blindly upgrade modules hoping they were fixed and I have a lot of sites that needed upgrading.

I solved this using the PHP5 Reflection API in module_invoke_all(), by looking up if a function arguments require to be passed by Reference before calling call_user_func_array().

I don't really know if this could cause other unforeseen errors, but it fixed a bunch of warnings for me so far.

I hope it helps.

function module_invoke_all() {

  global $user;

  $args = func_get_args();
  $hook = array_shift($args);
  
  // Start force the arguments to pass through by reference.
  // See ReflectionFunction below.
  $variables = $args;

  $return = array();
  foreach (module_implements($hook) as $module) {

    $function = $module .'_'. $hook; 
   
    // Use Reflection API to set pass by ref param    
    if (class_exists('ReflectionFunction')) {
      // Reset ref for each module.
      $variables = $args;
      // Start Reflection
      $reflect = new ReflectionFunction($function);
      foreach ($reflect->getParameters() as $i => $param) {
        $pname = $param->getName();
        if ($param->isPassedByReference()) {
          $variables[$i] = &$args[$i];
        }
      }
    }
    
    $result = call_user_func_array($function, $variables);
    // $result = call_user_func_array($function, $args);
    if (isset($result) && is_array($result)) {
      $return = array_merge($return, $result);
    }
    else if (isset($result)) {
      $return[] = $result;
    }
  }

  return $return;
}
RobLoach’s picture

Priority: Normal » Minor
Status: Closed (fixed) » Needs review
FileSize
11.09 KB

Might fork Drupal 5 instead of maintaining this patch.

NaX: Should that be part of this patch? Is that only for PHP 5?

RobLoach’s picture

FileSize
13.35 KB
NaX’s picture

My module_invoke_all hack will work on PHP4 and PHP5 because the passing by reference and value problem only became a problem in PHP 5.3 and the Reflection API was add in PHP5.1 (if I remember correctly). So because it does an if class_exists it will work on older and the latest PHP versions. If you want to add it to your patch is your call. It does sort of change how core works. Personally I think this could also be added to module_invoke but I have not found the need yet.

Q-Zma’s picture

Still have WSOD on user edit page :(

RobLoach’s picture

Status: Needs review » Needs work
Gomu’s picture

Status: Needs work » Reviewed & tested by the community

I had to move a Drupal 5 site to a hosting provider who supports only PHP5.3. The patch attached in comment #7 worked like a charm. Thanks a lot.

elvis2’s picture

Thanks, #7 worked for me.

tonystark’s picture

Component: base system » forms system

I using Drupal 5.12, I have problem after I transfer hosting company and web hosting company are using is PHP 5.3.18

warning: Parameter 1 to webform_client_form() expected to be a reference, value given in /home/abcdefg/public_html/includes/form.inc on line 218.

form.inc on line 218:-

$form = call_user_func_array(isset($callback) ? $callback : $form_id, $args);

please help.

NaX’s picture

@tonystark
You will need manually upgrade to the lates Dev version of Drupal 5.x and manually apply the above patches. See #7

tonystark’s picture

I update script follow #7, but the problem still same...

NaX’s picture

@tonystark
You may also need to upgrade your contribute modules as well.

See the release notes for webform 5.x-2.9 - http://drupal.org/node/624966

The 2.9 release of Webform corrects several critical bugs discovered after 2.8 was released, including fixes that allow Webform to be used with PHP 5.3 and working with default value wildcards such as %profile. This release also includes several other minor fixes and features.

If possible it would be best to upgrade to Drupal 6.x. To do that I would suggest doing a trial upgrade on a backup first.
Just remember to make backups of your database before doing any upgrades including contribute modules.

texas-bronius’s picture

Thanks guys! And here I thought patching Drupal 5 for PHP5.3 was going to take me through dragons' lairs or some grandmother's dark basement with a pale skin, shirt torn, no bath in months old man with a long grey beard down to his toes, freelancing as a Fortran/COBOL aficionado.

(What I mean to say is #7 patch worked like a charm!)

hass’s picture

Status: Reviewed & tested by the community » Needs work

warning: call_user_func_array() expects parameter 2 to be array, string given in includes/menu.inc on line 418.

Seen this on admin/logs/watchdog:

hass’s picture

Status: Needs work » Reviewed & tested by the community

Found the source of this bug in project_release.module menu hook. Here is the fix for 'callback arguments':

    $items[] = array(
      'path' => 'admin/project/project-release-settings',
      'description' => t('Configure the default version string for releases and other settings for the Project release module.'),
      'title' => t('Project release settings'),
      'callback' => 'drupal_get_form',
-      'callback arguments' => 'project_release_settings_form',
+      'callback arguments' => array('project_release_settings_form'),
      'access' => user_access('administer projects'),
      'weight' => 1,
      'type' => MENU_NORMAL_ITEM,
    );

RobLoach’s picture

Thanks hass... Made an issue in their queue: #1925580: Incorrect Callback Arguments

szt’s picture

Status: Reviewed & tested by the community » Fixed

So it's fixed.

RobLoach’s picture

Status: Fixed » Reviewed & tested by the community
FileSize
13.35 KB

Unfortunately this issue is not fixed since it hasn't been merged into Drupal 5. I haven't tested it since I posted it, and haven't forked it anywhere.

NaX’s picture

Title: Drupal 5 PHP 5.3 compatibility patch » Drupal 5 PHP 5.3/5.4 compatibility patch
Status: Reviewed & tested by the community » Needs work

I have started looking at PHP 5.4 and I thought I would share what I have found so far. This should be seen as changes after applying the above patch.

I found all these issues to be relevant.

#1812006: PHP 5.4 Illegal string offset 'data' in includes/tablesort.inc on line 110.
#996124: taxonomy_term_page() - Error: Creating default object from empty value taxonomy.pages.inc
#1680614: Illegal string offset 'region' and 'status' when saving block admin
My Drupal 5 version for this is:

/**
 * Process main block administration form submission.
 */
function block_admin_display_submit($form_id, $form_values) {
  foreach ($form_values as $block) {
    if (isset($block['module'])) {
      $block['status'] = $block['region'] != BLOCK_REGION_NONE;
      $block['region'] = $block['status'] ? $block['region'] : '';
      db_query("UPDATE {blocks} SET status = %d, weight = %d, region = '%s', throttle = %d WHERE module = '%s' AND delta = '%s' AND theme = '%s'", $block['status'], $block['weight'], $block['region'], isset($block['throttle']) ? $block['throttle'] : 0, $block['module'], $block['delta'], $block['theme']);
    }
  }
  drupal_set_message(t('The block settings have been updated.'));
  cache_clear_all();
}

And lastly, I also adapted the following patch that I we have used on D6 sites that removes E_STRICT again from error reporting. This removes a bunch of Views related warnings and notices on D6 but seems to be less useful in D5 but I still think its relevant.

--- a/includes/common.inc
+++ b/includes/common.inc
@@ -665,7 +665,11 @@ function drupal_error_handler($errno, $message, $filename, $line, $context) {
     return;
   }
 
-  if ($errno & (E_ALL ^ E_DEPRECATED)) {
+  $error_const = E_ALL ^ E_DEPRECATED ^ E_NOTICE ^ E_STRICT;
+  if (version_compare(phpversion(), '5.4.0') < 0) {
+    $error_const = E_ALL ^ E_DEPRECATED ^ E_NOTICE;
+  }
+  if ($errno & $error_const) {
     $types = array(1 => 'error', 2 => 'warning', 4 => 'parse error', 8 => 'notice', 16 => 'core error', 32 => 'core warning', 64 => 'compile error', 128 => 'compile warning', 256 => 'user error', 512 => 'user warning', 1024 => 'user notice', 2048 => 'strict warning', 4096 => 'recoverable fatal error');
 
     // For database errors, we want the line number/file name of the place that

I hope someone finds this helpful.

xenophyle’s picture

I found that the change to the signature of user_user() caused a bug for me, but the rest of the changes for the user module were sufficient to fix the user-related errors.

Specifically, the change to user_user() caused all roles to be assigned to any user that was saved.

mcurry’s picture

The 5.x-dev distro page shows a much older date than 5.23, so I'm not sure if it's the most current code base relative to 5.23. How can I tell if it's 'advisable' to run the 5.x-dev package, or if I can 'upgrade' to that if I've been using 5.23?

Edit: It does seem to apply cleanly to 5.x-dev, and 5.x-dev is marked with a VERSION string of 5.24-dev in modules/system/system.module so I assume it's the latest and greatest. I misread the date info on the 5.x-dev package page, so please disregard this message, I'm going ahead with the 5.x-dev (5.24-dev) release.

tooFATforBUTTer’s picture

I used a combination of NaX's suggestion in #4 and RobLoach's patch in #22.

The thing I like most about Nax's solution is it required a lot less code rewrite, however it's just an executed patch, so it does generate overhead. Also, I found that the call_user_func_array() function is scattered throughout our code base. I defined a new function in bootstrap.inc so I could reuse NaX's logic:

<?php
function drupal_user_func_array($function, &$variables){

    // Use Reflection API to set pass by ref param

    if (class_exists('ReflectionFunction')) {

      // Reset ref for each module.

      // Start Reflection

      $reflect = new ReflectionFunction($function);

      /**

       * create an array of keys in $variables to re-sync Reflection API

       * to $variables keys in order

       */

      $varkeys = array();

      foreach ($variables as $key => $value){

        $varkeys[] = $key;

      }

      foreach ($reflect->getParameters() as $i => $param) {

        $pname = $param->getName();

        if ($param->isPassedByReference()) {

          $variables[$i] = &$variables[$varkeys[$i]];

        }

      }

    }

}
?>

I did discover one problem with NaX's original code though. It assumes that the array of:

<?php
$reflect->getParameters()
?>

will have synchronized keys with the array of arguments being handed off to the $function. This broke some things for me, so I added an array of the keys used by $variables.

<?php
$varkeys = array();

foreach ($variables as $key => $value){

$varkeys[] = $key;

}
?>

That seems to have properly synchronized $function parameters and $variables.

Great idea Nax! It really helped us out in a pinch! I'm sure I'll have a handful of other tweaks to do in the codebase, but this alone is 90%+ of the leg work.

tooFATforBUTTer’s picture

If my comment in #26 is somewhat unclear, once you define the custom function " drupal_user_func_array", just call it right before a problematic "call_user_fanc_array" call.

<?php
drupal_user_func_array($function, $params); // D5 -> PHP 5.3 patch
call_user_func_array($function, $params);
?>

The definition of "drupal_user_func_array" in comment #26 accepts $params as a reference and will correctly reformat it right before calling "call_user_func_array".

NaX’s picture

@tooFATforBUTTer
Nice catch with the argument / parameter keys, I see now how a function call that accepts a variable number of arguments would break with my code.

Thanks for the feedback.

miiimooo’s picture

I couldn't really make sense out of xenophyle's #24 but I also found the issue with assigning all roles to a user when saving (PHP 5.4).

This change fixed the problem but I'm not sure whether its' correct:

diff --git a/modules/user/user.module b/modules/user/user.module
index 55bab38..a4ec5e1 100644
--- a/modules/user/user.module
+++ b/modules/user/user.module
@@ -463,7 +463,7 @@ function user_search($op = 'search', $keys = NULL) {
 /**
  * Implementation of hook_user().
  */
-function user_user($type, $edit, $user, $category = NULL) {
+function user_user($type, &$edit, $user, $category = NULL) {
   if ($type == 'view') {
     $items['history'] = array('title' => t('Member for'),
       'value' => format_interval(time() - $user->created),
David_Rothstein’s picture

Issue summary: View changes
Status: Needs work » Needs review
FileSize
12.82 KB
1.52 KB

I ran into that issue too, and think it's the correct change (as well as other places where the patch made $edit no longer taken by reference). Since $edit is an array, it should still be taken by reference in cases where the function needs to modify it.

Attached patch makes those changes.

Ambrosy’s picture

Hello David. Unfortunately there is problem with ampersand (&$args <=> $args) is not fixed in my case (Drupal 5.23 + PHP 5.3). I got the errors like 'Parameter 1 to phptemplate_field() expected to be a reference, value given in public_html/includes/theme.inc on sring 175' which I cannot solved yet. What could be the reason? So I need PHP 5.4 for this? Thanks.

secgeek’s picture

thanks patch mentioned in #30 worked for me. i am using it for http://rentsellmyhouse.com

chirale’s picture

Patch #30 worked for me too. In my case (CentOS 6) I have to disable APC via apc.filters on /etc/php.d/apc.ini and to enable Short tags on /etc/php.ini (short_open_tag = On). Thank you David!

hass’s picture

Attached patch fixes some issues found in PHP 5.4.36. I have not found any other issues.

Url: user/1/edit

warning: Illegal string offset 'pass1' in /includes/form.inc on line 1117.
warning: Illegal string offset 'pass2' in /includes/form.inc on line 1123.

URL admin/logs/watchdog and very many other urls:

warning: Illegal string offset 'data' in /includes/tablesort.inc on line 110.
warning: Illegal string offset 'data' in /includes/tablesort.inc on line 110.
hass’s picture

Found one issue. Not sure how to fix

warning: Parameter 1 to profile_load_profile() expected to be a reference, value given in /includes/module.inc on line 387.

japerry’s picture

Status: Needs review » Closed (won't fix)

Drupal 5 is unsupported. Cleaning up the issue queue.

RobLoach’s picture

For those who enjoy git, I've posted a Pull Request for this over at:
https://github.com/RobLoach/drupal/pull/5
https://github.com/RobLoach/drupal/pull/5.patch
https://github.com/RobLoach/drupal/pull/5.diff

Feel free to submit fixes over there.

reformatt’s picture

thanks Rob Loach! you will always be my Drupal hero ;)
the Drupal 5 patch worked magically