Showing posts with label error. Show all posts
Showing posts with label error. Show all posts

Wednesday, 20 May 2009

Drupal 5: Problems with unserialize in bootstrap.inc

Today I had a problem where Drupal 5 kept reporting a problem with unserialize in bootstrap.inc on line 428.

On closer inspection, bootstrap.inc, which is in the includes directory in the root of Drupal 5, contains a number of functions that are used when Drupal 'boots up'. The function in question here was variable_init(), and this is where all variables are drawn from the database. These variables are in serialized form, allowing Drupal to store anything, from objects to arrays, in string format.

If the serialized item got corrupted somehow, it wouldn't be able to unserialize properly in variable_init(), leading to this error. My problem was that I was not able to see which variables were causing the problem; only that the problem existed. With over 200 variables on the site, manually checking each one for valid serialization was not a viable option!

My solution was to change the core bootstrap.inc to print the names of the offending variables, thereby enabling me to find them in the database and fix them. Here's the original snippet from line 427 of bootstrap.inc:


while ($variable = db_fetch_object($result)) {
$variables[$variable->name] = unserialize($variable->value);
}

Here's what I changed it to, temporarily:


while ($variable = db_fetch_object($result)) {
if (($variables[$variable->name] = unserialize($variable->value)) === FALSE) {
print $variable->name;
}
}

Once I had my variable names, I was able to find them in the database, using phpMyAdmin, and edit them. I found that I had something like s:5:" in there. This had been truncated, and should have been something like s:5:"hello". The first letter indicates that the variable is a string. The number indicated how many characters the string has, and the value of the string is encapsulated within double quotes.

Afterwards, I just changed bootstrap.inc back to the way it was before, and my unserialize problems vanished!

Wednesday, 12 November 2008

Drupal: Pitfalls when converting CCK field modules from Drupal 5 to Drupal 6

I recently needed to convert a CCK field module from Drupal 5 to Drupal 6. There is a lot to take in, but I was faced with a particular problem:

warning: array_shift() [function.array-shift]: The argument should be an array in D:\wamp\www\drupal6\includes\form.inc on line 1320.

Oh dear. It's always difficult to debug this kind of thing because the problem lies in the code that called the function on line 1320 of form.inc, rather than there being a problem with form.inc. I used debug_backtrace() to see what parameters the previous functions in the call stack were using, and noticed that only the first two parameters in _form_set_value() were populated; the other two were NULL. This was the immediate source of the error. The following line was failing because $parents was NULL:

$parent = array_shift($parents);

Obviously you can't array_shift() NULL. I then went back further in the backtrace, to the form_set_value() function (note the function is not preceded by an underscore, like the last one). In this function, the second parameter ($value) was NULL. This was causing the NULL in the _form_set_value() function.

The solution
It turns out that I was using this code to handle the form widget's processing in my CCK field module:

/**
* Process the mcimage element.
*/
function mcimage_mcimage_process($element, $edit, $form_state, $form) {
$field_name = $element['#field_name'];
$field = $form['#field_info'][$field_name];
$field_key = $element['#columns'][0];
$value = isset($element['#value'][$field_key]) ? $element['#value'][$field_key] : '';

$element[$field_key] = array(
'#type' => 'hidden',
'#default_value' => $value,
// The following values were set by the content module and need
// to be passed down to the nested element.
'#title' => $element['#title'],
'#description' => $element['#description'],
'#required' => $element['#required'],
'#field_name' => $element['#field_name'],
'#type_name' => $element['#type_name'],
'#delta' => $element['#delta'],
'#columns' => $element['#columns'],
);
}
My mistake? The function does not return anything! It was as simple as adding a return statement at the end of the function, so that the form element could be processed correctly:

/**
* Process the mcimage element.
*/
function mcimage_mcimage_process($element, $edit, $form_state, $form) {
$field_name = $element['#field_name'];
$field = $form['#field_info'][$field_name];
$field_key = $element['#columns'][0];
$value = isset($element['#value'][$field_key]) ? $element['#value'][$field_key] : '';

$element[$field_key] = array(
'#type' => 'hidden',
'#default_value' => $value,
// The following values were set by the content module and need
// to be passed down to the nested element.
'#title' => $element['#title'],
'#description' => $element['#description'],
'#required' => $element['#required'],
'#field_name' => $element['#field_name'],
'#type_name' => $element['#type_name'],
'#delta' => $element['#delta'],
'#columns' => $element['#columns'],
);

return $element;
}