I am running 6.x-29 and when I switched to PHP 5.4 I started getting an error on my one node add form for a field thats Granularity is set to year and the default value is set to now with no "To Date".

I did some searching and I could not find another issue that seems to be related.

It looks like _form_set_value is expecting form_values to be an array and is receiving a date formated string EG: '2013-05-26 13:41:06'.

I tried to trace the root of the problem but I was unsuccessful.

Any help or direction would be greatly appreciated.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

EvaldsUrtans’s picture

It can be fixed using patches from this thread https://drupal.org/node/1808416

davidhk’s picture

I have the same problem since updating to php 5.4. Have you found any way to solve the problem?

The suggestion at #1 refers to the date_popup module. That module is disabled on my site.

I see the same error message when I edit a node that has a date field with granularity set to year. However, the error isn't displayed when I create a node, perhaps because I do not have any default date set.

A backtrace shows the same problem you describe. (Apologies if I get the syntax wrong below, but I hope the message is clear) As _form_set_value(&$form_values, $form_item, $parents, $value) is building up $form_values, the first time it is called on the date field, $parents is:

                    [2] => Array
                        (
                            [0] => field_date_completed
                            [1] => 0
                            [2] => value
                            [3] => date
                        )

So it is trying to build up [field_date_completed][0][value][date]

But when it is building [field_date_completed][0], it is assigned an array

                            [0] => Array
                                (
                                    [value] => 1897-01-01 00:00:00
                                    [timezone] => Asia/Hong_Kong
                                    [timezone_db] => Asia/Hong_Kong
                                    [date_type] => date
                                )

Note that [field_date_completed][0] now has an array element [value], that is a string.

When _form_set_value recurses down to the final line of $parents, "[3] => date", it runs the code:
$form_values[$parent] = $value;
That's trying to set:
[field_date_completed][0][value]['date']= "1897-01-01 00:00:00"
at which point it throws the error, because [field_date_completed][0][value] is already a string.

The strange thing is that it still works - I can create / view / edit / update the node ok but it displays red warning messages to users. I'm wondering if there is some bug hidden in the code that just got handled ok by accident with php 5.3?

I'm not sure where to look next. Any pointers welcome.

davidhk’s picture

I've edited _form_set_value in form.inc to change

  if (empty($parents)) {
    $form_values[$parent] = $value;
  }

to

  if (empty($parents)) {
    if (!is_string($form_values)) {
      $form_values[$parent] = $value;
    }
  } 

It just masks the problem rather than solving it, but that's all I need for now until I can upgrade to D7.

nekobul’s picture

Hi David,

The modification you've made in form.inc was the right move. I did review the D7 implementation of drupal_array_set_nested_value function and decided to make _form_set_value function similar and lo and behold it works fine now. The newer implementation is actually better because it doesn't use recursion to accomplish the same result. Here is the modified function:

function _form_set_value(&$form_values, $form, $parents, $value) {
  $ref = &$form_values;
  foreach ($parents as $parent) {
    // PHP auto-creates container arrays and NULL entries without error if $ref
    // is NULL, but throws an error if $ref is set, but not an array.
    if (isset($ref) && !is_array($ref)) {
      $ref = array();
    }
    $ref = &$ref[$parent];
  }
  $ref = $value;
}
jennifer.chang’s picture

Issue summary: View changes

Same here.

rakun’s picture

Will this be included in the new release?

mtcs’s picture

#4 works for me. Thanks.

SocialNicheGuru’s picture

Version: 6.x-2.9 » 7.x-2.x-dev
akbardhedhi’s picture

The issue seems to be as davidhk describes, therefore I have modified the field to return an array of date parts. Please find attached patch.

SocialNicheGuru’s picture

Status: Active » Needs review

Status: Needs review » Needs work

The last submitted patch, 9: date_popup-2004508-9-illegal-offset.patch, failed testing.

rooby’s picture

That patch doesn't apply with "patch -p1" and it also has a space at the front of the file name.

japerry’s picture

Status: Needs work » Needs review
FileSize
2.52 KB

Here is a re-roll of that patch.

Status: Needs review » Needs work

The last submitted patch, 13: date_popup-2004508-illegal-offset-13.patch, failed testing.

pvgoran’s picture

FileSize
4.18 KB

I'm using Drupal 6, and while upgrading PHP from 5.3 to 5.5/5.6 I encountered this problem. I applied the patch from the comments above, but it broke the date functionality for me. So I ended up reworking it with a different approach: enclosing date_text/date_select element #value's in an array rather than converting them to DATE_ARRAY type. (I [b]hope[/b] this makes at least some sense to anyone; I have almost no idea of how Drupal widgets/forms/CCK work, and I don't know how to call things properly.)

The patch against the 6.x-2.x branch is attached. It works fine for my use cases (a text widget and a select widget, both single-value, without "date to" component). If anyone tries it and it turns out to break things, please let me know.

texas-bronius’s picture

@pvgoran - Thanks for the 6.x patch! What date module version are you using? I had what appears to be the same issue using date 6.x-2.7 on php 5.6, but updating to date 6.x-2.10 shows the date values again (see https://www.drupal.org/node/70963/release?api_version%5B%5D=87) sans patch.

pvgoran’s picture

I'm using 6.x-2.10. I didn't have problems with date values not being shown; I had warning that were shown at the top of "edit node" pages, and the patch is supposed to fix these warnings.

Fernando Iglesias’s picture

Unfortunately the patch in #15 doesn't seem to fix the issue for me (Date 6x-2.10). I'm seeing the errors when trying to use an exposed date filter in views.

I'll try and fix it, will report back with a patch if I figure it out.

kliker’s picture

#3 works for me, tested with select widgets on create/edit nodes.

#15 worked for all but 'timezone': warning: Illegal string offset 'timezone' in /includes/form.inc on line 1429.

PHP 5.5
Drupal 6.38
Date 6.x-2.10

Gold’s picture

Status: Needs work » Needs review

I was just about to reroll this patch against 7.x-2.x and in the process of verifying that it's still an issue I found I couldn't replicate the errors.

Can someone else test the 7.x-2.x branch and verify that the errors no longer appear?

DamienMcKenna’s picture

Status: Needs review » Needs work

I don't like nesting the default value like this, it seems unnecessary.

izmeez’s picture

With the latest date module 2.11 version, with or without the patch from comment #15, there is a residual warning as described in comment #19

Illegal string offset 'timezone' in public_html/includes/form.inc on line 1470.

The suggestions in both comment #3 and #4 work to eliminate the warning but may be masking the warning as suggested in comment #3. Doing so may be useful for D6 LTS to address other contrib modules #3026754: [core] form.inc helper function commit needs work and may also be a satisfactory solution for the timezone warning or it may be possible to fix the source where it is coming from possibly in the date module.

izmeez’s picture

There may be very few people left interested in this issue or the related issue #2090389: Date: warning: Illegal string offset in form.inc on line 1345..

Here's my take after recently poking around here, again.

This issue thread covers 3 items.

1. In comment #3 and #4 were suggestions for a fix at the form.inc helper function rather than at the source of origin. There was concern this would just mask the issue at origin. However, in comment #4 an improvement to the helper function is included that eliminates recursion and is modeled along drupal 7 lines. It also includes brief comments to explain the php behaviour and this could be adjusted. Since the form.inc helper function has also been modified in the D6LTS project I have opened #3026754: [core] form.inc helper function commit needs work for further discussion.

2. The issue warning: Illegal string offset 'date' in /includes/form.inc

This is also described in #2090389: Date: warning: Illegal string offset in form.inc on line 1345. which has the identical patch as in comment #15 of this thread and has been closed as a duplicate although it included observation of issues export and cloning.

As described in that issue, the warning is seen when using the date select widget either in a content type or a views exposed filter.
To reproduce the warning(s) create or edit a content type that includes a datetime field with the date select widget, such as an event.

The patch in #15 is no longer needed with date 2.11 even though it can be applied. I am unable to reproduce the warning in tests I have done.

With date-2.11 warnings are not seen with php 5.6 or 7.2 and the fix may be the result of recent commits, https://github.com/d6lts/date/commits/6.x-2.x

3. The timezone, warning: illegal string offset described in comment #19 above was observed when the patch in #15 was applied and is still present with date-2.11 without the patch and would be masked if the solutions in item 1 were used.

Again, this can be reproduced as above for the date warning when creating or editing content type with date select widget that also includes the timezone select widget.

The fix for this is an easy drupal configuration in the field settings, change field time zone handling as described https://www.freelock.com/blog/john-locke/2014-12/drupal-dates-timezone-o...

Looking at the settings that were present and seeing it was set to Date's timezone, changing it to Site's timezone, or User's timezone, eliminates the warning. It is worth noting the Drupal UI warns that changing this can result in loss of existing data so do this on a test server! And the blog post goes on to explain the need and how to update the database.

The whole issue of Drupal's handling of date timezones has been ongoing for years, in several issues, and recently a fix advanced for Drupal 8.5 #2627512: Datetime Views plugins don't support timezones and is ongoing for drupal 7 #998076: Problem with timezone handling (caused by date_get_timezone_db returning only UTC), there maybe something there that can help. In particular the comment #998076-7: Problem with timezone handling (caused by date_get_timezone_db returning only UTC) includes a patch and insightful comments.

Hope this helps.

benkewell’s picture

For those who need a simple fix to get rid of the illegal string offset warning without digging deep into codes is to simply replace function _form_set_value() in Drupal file includes/form.inc with this version:

/**
 * Helper function for form_set_value().
 *
 * We iterate over $parents and create nested arrays for them
 * in $form_state['values'] if needed. Then we insert the value into
 * the right array.
 */
function _form_set_value(&$form_values, $form_item, $parents, $value) {
  // This makes PHP 7 have the same behavior as PHP 5 when the value is an
  // empty string, rather than an array. This is depended on surprisingly
  // often in Drupal 6 contrib.
  if ($form_values === '') {
    $form_values = array();
  }

  $parent = array_shift($parents);
  if (empty($parents)) {
    @$form_values[$parent] = $value;
  }
  else {
    if (!isset($form_values[$parent])) {
      @$form_values[$parent] = array();
    }
    _form_set_value($form_values[$parent], $form_item, $parents, $value);
  }
}

This is the latest PHP7 compatible version from D6LTS (https://github.com/d6lts/drupal/),
with a small change to rewrite "$form_values[$parent] =" as "@$form_values[$parent] =",
to hide the anonying warning message produced by date_select element.

Date 2.11 release from D6LTS does not solve the issue for me.

This version of _form_set_value() on PHP 5.4+ will behave identically to Drupal 6 default on PHP 5.3, tested on production website.

roderik’s picture

Title: PHP5.4 issue: warning: Illegal string offset 'date' in /includes/form.inc on line 1340. » [date] PHP8 fatal (PHP5.4 warning): Illegal string offset 'date' in /includes/form.inc on line 1340.
Project: Date » Drupal 6 Long Term Support
Version: 7.x-2.x-dev »
Component: Date Field » Code
Status: Needs work » Needs review
FileSize
2.13 KB

This warning in PHP5.4 is now turning into a fatal error in PHP8.

This error does not happen in D7 anymore... because form_set_value() -> drupal_array_set_nested_value() has been changed in D7 to bluntly override form values set in the below way. (The change occurred as a side effect in #745590-24: #managed_file element does not work when #extended not TRUE, or when ancestor element doesn't have #tree=TRUE and I cannot find anyone commenting on this behavior change. It arguably obfuscates potential errors, but it's no use arguing that by now.)

Because of this / the fact that my patch won't have benefits for D7, I'm changing project / title.

Problem description

The date module has an 'interesting' way of nesting form items, which creates trouble.
For example if the date input is a text element,

  • It has a 'date' form element (of type 'date_text') containing another 'date' element (of type 'textfield').
  • It classifies both 'date' and 'date']['date' as being input elements.

Why does this throw an error? It instructs the form API to (during form build) first set $form_state['values']['field_<name>'][0]['date'] to the date (string) value, and after that, set $form_state['values']['field_<name>'][0]['date']['date'] to that same string value. That is obviously going to go wrong: the form API is explicitly instructed to use a string value as an array.

(
Why does the date module do it like this? Apparently because

  • It needs the child elements to be dynamic / handle input in different ways (so they are created just-in-time by a form #process function. Which only runs if the parent element's #input = TRUE).
  • It wants the parent input to be the 'main' element which in the end gets the processed/validated value back, regardless of the structure of the child elements... which Drupal/CCK can then save. (For which all parent elements have #validate functions that get/validate the value and set it in the right place.)

This has all kinds of interesting effects for form/element validation which we luckily don't need to go into.
)

How to fix the error:

We can hack the #process functions to remove the parent element's $element['#value'] if it is a string, just after it has been copied into the child elements and just before it gets passed into form_set_value(). We are sure that immediately after that, all child elements' values get passed into form_set_value() too, so this doesn't really have side effects besides getting rid of the error.

The code in element validate functions makes implicitly clear that $element['#value'] is only a string when the form is first built, not when it is submitted. This figures, because otherwise, form validation would likely have seen errors after the form_set_value() calls had strange results. Also... this is lucky for us, because if we had needed to empty out $element['#value'] during form submission... there would be many more places to fix. (I tested. It's a rabbit hole.)

roderik’s picture

FileSize
1.56 KB

Actually, after significantly reducing some code changes I'd done while testing... I think these 3 copies of code comments are just overkill. Stripping them down.

(Edit: that six-line comment still reads crappily. I can trim it down or reword it it a reviewer/committer wants me to.)

DamienMcKenna’s picture

Issue tags: +PHP 8.0
izmeez’s picture

@roderik Thank you for your investigation and detailed comments. It has been a couple of years since I looked at this issue.

In my last comment #23 it appeared as though with date 6.x-2.11 item #3

The timezone, warning: illegal string offset described in comment #19

was the residual problem and the solution was to review the timezone setting and if it is set to the Date's timezone

changing it to Site's timezone, or User's timezone, eliminates the warning.

although this may require updating the database as described in the blog post referenced in that comment.

I have not had time to review and test your patch to confirm if it addresses the timezone issue in particular. I'm not even sure if I have a test site configured with the Date's timezone to test this.

roderik’s picture

@izmeez my patch addresses the issue with the 'timezone' element/warning too; it has the same cause. (I forgot to explicitly mention that, after going in a few circles around the solution.)

izmeez’s picture

The patch in #26 applies without difficulty to D6LTS date-6.x-2.11 and appears to be working fine. The patch looks remarkably simple but I would defer, and hope, that maybe @DamienMcKenna might comment on the code as a maintainer of the date module, although he may not be actively doing that for the 6.x branch.

DamienMcKenna’s picture

I cannot speak to the 6.x-2.x branch, it has been far too long since I last looked at D6's Field API to comment on the patch, I defer to roderik's research on the matter.

izmeez’s picture

Status: Needs review » Reviewed & tested by the community

Well, I guess it's back to me. Testing this patch reveals no problems, the code looks remarkably simple and the explanation in #25 is illuminating. Changing status to RTBC.

roderik’s picture

Re. #31 just for completeness: this is plain Form API (which hasn't changed between D6-D7). Regardless of whatever changed between CCK and FieldAPI, here's the summary:

  • The source of the error is that form_set_value() is called twice for the same input value (because Date's #process functions are doing complicated things).
  • Since we can't cancel form_set_value() being called, all we can do is hack the value used by the first call, at the end of those #process functions - only in the case where that would be overwritten anyway and cause the warning/error. So no backward incompatibility.

I dived into it more, but in the end was happy to conclude that the fix could tiptoe around all the interesting string-vs-array manipulations in those element #process / #validate functions.

The patch should also apply to D7, but D7's form_set_value() is modified and doesn't warn/fail, so there's no real difference there.

dsnopek’s picture

Status: Reviewed & tested by the community » Fixed

Wow, thanks, everyone! @roderik's patch works great in my testing.

I've committed it to https://github.com/d6lts/date:

https://github.com/d6lts/date/commit/f368386a2d3b66c03c6deb21b2f3a99ff7c...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.