During _form_validate(), drupal_strlen() and then mb_strlen() get called. Each of these functions currently can only work on strings, not arrays. However, _form_validate() is not smart enough to only send strings to drupal_strlen. When using multiple value form fields, especially taxonomy related form fields, _form_validate() often gets arrays of values. A casual search turned up around a half dozen cases of contributing modules running up against this bug.

If necessary, I can provide logged backtraces of how this happens in 6.22 with TaxiSelect module, for example. However, I will need to sanitize the backtrace before I can post it here, and will do so only on request.

I recommend one of the following changes be made:
1. modify _form_validate() to more intelligently handle arrays, perhaps doing a separate drupal_strlen on each string in the array? (best solution, but I can see some cases where this could have unintended results)
2. have drupal_strlen() detect when it has been passed an array, then send mb_strlen only the first string in the array (least mess solution, but does not 100% guarantee validation as intended)
3. Force all contrib modules to work around this limitation (best case for core and consistent validation, but probably worst case for the community and truly closing this bug)

Comments

asb’s picture

I'm seeing a similar warning in watchdog log:

Warning: mb_strlen() expects parameter 1 to be string, array given in drupal_strlen() (line 409 of /var/www/drupal/includes/unicode.inc).

This is being logged dozends of times per minute, so it'd be really nice to get rid of it.

Related issues:

pokepasa’s picture

Hi, higherform.

I, bored of seeing the same error while my users edit forms in other language than english, I make a workaround, at least to evade the error in the log. Is this:

Edit the includes/unicode.inc file:

At line 406 you will find the drupal_strlen function, with the mb_strlen failing method.

function drupal_strlen($text) {
  global $multibyte;
  if ($multibyte == UNICODE_MULTIBYTE) {
    return mb_strlen($text);
  }
  else {
    // Do not count UTF-8 continuation bytes.
    return strlen(preg_replace("/[\x80-\xBF]/", '', $text));
  }
}

Now just add this code

function drupal_strlen($text) {
global $multibyte;
if (is_array($text)) {
$text = $text[1];
}

if ($multibyte == UNICODE_MULTIBYTE) {
return mb_strlen($text);
}
else {
// Do not count UTF-8 continuation bytes.
return strlen(preg_replace("/[\x80-\xBF]/", '', $text));
}
}

This checks for an array and get only the first value of the array to avoid the array error. It is not perfect, but in any case the function mb_strlen was failing with the array, so I think that no problems will be expected.

itarato’s picture

Hi Guys,

Can somebody give a sample flow of steps how could the bug be reproduced? I'm trying to get it for 2 days without any success. I installed Taxiselect and played with it couple of hours - it gave me lots of errors but none of them were the mb_string problem.

Thanks!

pokepasa’s picture

Well, I dont know about Taxiselect, but I can tell you my config:

Just nodes with imagefield, taxonomy and nothing more.
i18 module installed.

Observe that, in english, all worked fine, but when I chose spanish (I have multilanguage config as path only, it is adding /es/ to urls) then the errors appeared, always.

I'm supposing that i18 adds some arrays to have original-translated content (or something similar) and then mb_string error appears.

shaneonabike’s picture

Priority: Minor » Normal

+1

caspercash’s picture

+1

Bill Choy’s picture

+1

If an array is passed you should recursively get the length of all elements. Where the element can be either a string or an array of strings.

if (is_array($text)) {
   foreach ($text as $element) {
      $strlen += drupal_strlen($element);
   }
   return $strlen;
}

PS: I wouldn't just reference $text[1] in case it is an associated array.

Bill Choy’s picture

jcodes.me’s picture

Issue summary: View changes

Relating to #2, I got fixed it this way. Try to override the function rather than editing core files, if you want to use files in your other sites too.

Path: includes/unicode.inc

Search for function drupal_strlen($text) {

Replace that entire function as below:

function drupal_strlen($text) {
  global $multibyte;
  if (is_array($text)){
    foreach($text as $jtext) {
      if ($multibyte == UNICODE_MULTIBYTE) {
        return mb_strlen($jtext);
      }
      else {
        // Do not count UTF-8 continuation bytes.
        return strlen(preg_replace("/[\x80-\xBF]/", '', $jtext));
      }
    }
  }
  else {
    if ($multibyte == UNICODE_MULTIBYTE) {
      return mb_strlen($text);
    }
    else {
      // Do not count UTF-8 continuation bytes.
      return strlen(preg_replace("/[\x80-\xBF]/", '', $text));
    }
  }
}

Note: tested in drupal 7 only

Status: Active » Closed (outdated)

Automatically closed because Drupal 6 is no longer supported. If the issue verifiably applies to later versions, please reopen with details and update the version.