This new issue continued from post - https://www.drupal.org/node/2656548#comment-12182491.
First major problem observed after my move to PHP71, easily reproduced in my configurations.
Create a book node. Add some children. Try to edit and save the book node and I get this error...
Warning: Illegal string offset 'weight' in drupal_array_set_nested_value() (line 6781 of /..../includes/common.inc).
Error: Cannot create references to/from string offsets in drupal_array_set_nested_value() (line 6781 of /..../includes/common.inc).
Drupal does not white screen, but the page presented is the basic error only screen. I was initially concerned thinking that I broke things while creating book node content programmatically. However, the error occurs the same whether I create the book content manually or programmatically... and also when editing/saving every one of my book node content pages.
Also curious is that the error does not occur when logged in as user 1, but does occur when logged in as another user.
And likewise when I drop back to PHP56 the error goes away.
I am also using the course module and book_made_simple module which both tap into book hooks and may be contributing factors.
Articles online say this this error is usually caused by attempting to reference an array key index on a simple string.
What additional information can I provide to help discover the solution?
Comment | File | Size | Author |
---|---|---|---|
#25 | book-access-2897415-25.patch | 434 bytes | David_Rothstein |
Comments
Comment #2
webservant316 CreditAttribution: webservant316 commentedComment #3
webservant316 CreditAttribution: webservant316 commentedComment #4
cilefen CreditAttribution: cilefen commentedComment #5
webservant316 CreditAttribution: webservant316 commentedComment #6
webservant316 CreditAttribution: webservant316 commented@cilefen switched the component from 'base system' to 'book.module'. I will not change that back, but I was uncertain what the problem really was and was not convinced that there was an actual problem with the book.module, but instead that PHP71 requires stronger or more accurate variable 'typing' that must be fixed in the general purpose function in common.inc, drupal_array_set_nested_value().
Since the problem goes away when switching back to PHP56 I thought perhaps there is no real problem in the 'book.module' but instead in the base system.
Comment #7
Ayesh CreditAttribution: Ayesh as a volunteer commentedThanks for raising this issue. I tried to reproduce this (PHP 7.1.7, Drupal 7.56, with book_made_simple enabled, as a non-admin user), but I could not.
Above is from
drupal_array_set_nested_value()
. Notice the comment.If you try to set/get an array index from a string, you will get this error, it does not seem to be version specific.
It looks like there is a problem with the book order array that it expects a "weight" key but it only got a string (most likely an empty string). Can you try to isolate the problem with book made simple module disabled, as admin user? A backtrace would be a lot of help (you can install the Devel module and set error handler "Krumo backtrace in the message area" in Devel settings in addition to the standard Drupal handler).
Comment #8
cilefen CreditAttribution: cilefen commentedWell, book nodes have weight but not ordinary page nodes so in a case like this I blame the book module first. I don't know how the fact that downgrading PHP fixes it is more evidence pointing to the base system.
But yes if a function in common.inc is wrong it will be base system.
Comment #9
webservant316 CreditAttribution: webservant316 commentedOkay sorry to raise the alarm. This problem is caused by the book_made_simple module. That module offers permission to hide the book weight field in order to simplify the UI for certain users. Apparently when doing this the book weight field does not then properly default.
I hope to look into this further and post back here and create an issue at book_made_simple once I figure out why this is the case and why it works in PHP56 and not in PHP71. It may still be that the drupal_array_set_nested_value() could be improved to handle cases when contrib modules do not properly initialize node variables.
Comment #10
Ayesh CreditAttribution: Ayesh as a volunteer commentedI think we should still try to fix the problem.
I moved the issue to the book made simple module so its maintainers can take a look. I'll try to see what could be the problem too.
Comment #11
webservant316 CreditAttribution: webservant316 commentedI think it should be easily reproduced by anyone by installing book_made_simple and then visit the perms page and restrict the book_made_simple perm 'User will have all rights on books' from a user that has the right the create books. When this user then tries to edit/save a book the error will surface in PHP71 but not PHP56.
Comment #12
webservant316 CreditAttribution: webservant316 commentedThe foul play happens in book_made_simple.module in book_made_simple_form_alter() beginning line 240.
book_made_simple provides permissions to take 'Book Outline' off the book content edit form vertical tabs. So that means that information is not available on the book node edit submit. However, I am not sure what the Drupal solution is for this.
Who is the guilty party?
I guess if book_made_simple takes that off the form it ought to also provide proper defaults.
However, maybe Drupal core book.module could also be better prepared for this.
Certainly, Drupal core drupal_array_set_nested_value() should also be better prepared for this and protected from contrib modules.
Still trying to understand this better, especially why PHP56 and PHP71 makes a difference.
Comment #13
webservant316 CreditAttribution: webservant316 commentedOkay, more info.
When book_made_simple enabled and is used to take 'Book Outline' off the book content edit form then book_made_simple_form_alter() is called and _book_add_form_elements() is NOT called from book.module. The _book_add_form_elements() function in book.module assigns two important defaults to the book content edit form which are then not assigned.scratch that.
I viewed $form['book'] for the working and non-working case and the only difference is
working: $form[book][#type] => fieldset
non-working: $form[book][#type] => hidden
otherwise all the remaining element of $form[book] are the same.
oh, the non-working also includes an additional element $form[book][reorder], but that seems innocent enough
turning to devel next
Comment #14
webservant316 CreditAttribution: webservant316 commentedI have the devel backtrace, but how do I copy that from the message area to here?
Comment #15
webservant316 CreditAttribution: webservant316 commentedOkay I think I understand the problems now, but do not know the solution. There appears to be a PHP71 Drupal core problem and also a book_made_simple misuse of the book node edit form api.
FIRST, this code snippet works for PHP56 and not for PHP71
Explain the above and we will be on our way to understanding the Drupal side of this problem. What I don't understand in my use case / problem is that the $force argument is FALSE which seems to mean that really this should fail for both PHP56 and PHP71. So perhaps it is an accident that it is working for PHP56. Or maybe my PHP ini has a setting that is more permissive for PHP56.
SECOND, $array->book should be an array when this function is called, but is a string instead. As far as I understand it, $array->book is a string instead of an array because I use book_made_simple to change a book vertical tab form item to 'hidden'. Then the form is submitted and rebuilt through the following backtrace...
10: drupal_array_set_nested_value() (Array, 2 elements)
9: _form_builder_handle_input_element() (Array, 2 elements)
8: form_builder() (Array, 2 elements)
7: form_builder() (Array, 2 elements)
6: form_builder() (Array, 2 elements)
5: drupal_process_form() (Array, 2 elements)
4: drupal_build_form() (Array, 2 elements)
3: drupal_get_form() (Array, 2 elements)
2: node_page_edit() (Array, 2 elements)
1: menu_execute_active_handler() (Array, 2 elements)
0: main() (Array, 2 elements)
At this point since the book node vertical form elements were hidden, then the $form_state['input'] array is never assigned $form_state['input']['book']['weight']. So when drupal_array_set_nested_value() is called with the values demonstrated above... barf!
So in conclusion the Drupal include/common.inc function drupal_array_set_nested_value() performs differently for PHP56 and PHP71 in my configuration and is the reason that my use of book_made_simple when from working to not working.
Comment #16
webservant316 CreditAttribution: webservant316 commentedChanging line 2102 in drupal/includes/form.inc from this
drupal_array_set_nested_value($form_state['input'], $element['#parents'], NULL);
to this
drupal_array_set_nested_value($form_state['input'], $element['#parents'], NULL, TRUE);
fixes the problem and allows my use case to work in PHP56 and PHP71.
However, I don't know if that is the real fix. Drupal core experts?
Comment #17
cilefen CreditAttribution: cilefen commentedIt is one of the backwards-incompatible changes or a PHP bug.
Comment #18
webservant316 CreditAttribution: webservant316 commentedThanks. So any input on the best solution? Should this issue be moved back to the Drupal queue?
Comment #19
David_Rothstein CreditAttribution: David_Rothstein as a volunteer commentedIf it's specific to PHP 7.1 (rather than PHP 7.0) then #17 has the wrong link - should be http://php.net/manual/en/migration71.incompatible.php instead.
It's not obvious to me from that page what causes it, but #2832900: PHP 7.1 no longer converts string to arrays the first time a value is assigned with square bracket notation could be the same thing. There is clearly some kind of difference in PHP 7.1 regarding what happens if your code treats a string like an array, and it sounds like it might go deeper than what the PHP documentation says.
Comment #20
webservant316 CreditAttribution: webservant316 commentedSeems to me this issue needs to move back to Drupal core / base system since drupal_array_set_nested_value() is a base system function which performs differently between PHP56 and PHP71. That is a core issue. I would have moved the issue back myself, but wasn't sure which Drupal project to pick from the pull down.
Comment #21
David_Rothstein CreditAttribution: David_Rothstein as a volunteer commentedI think the primary bug here is in book_made_simple - it is trying to transform multiple form elements to hidden by setting
$form['book']['#type'] = 'hidden'
on the fieldset element which contains them, but that doesn't really work. It should either mark each individual element as hidden, or (more likely) just set$form['book']['#access'] = FALSE
to prevent all of them from appearing on the form in the first place.For core, we could maybe use an issue to clarify the documentation, but I don't think there's an actual bug - it documents that you can get a PHP error if the $force parameter is FALSE and you pass something in with the wrong structure, and that's exactly what's happening.
In particular, I tested a few scenarios:
Works on all versions of PHP.
Gives an error on PHP 7.1, but works on other versions of PHP.
Gives an error on all versions of PHP.
So maybe the documentation that says this:
could be tweaked to indicate that some PHP versions are lenient with empty strings as well as with NULL - if we want to get into that level of detail?
Thanks for all the good investigating on this issue!
Comment #22
webservant316 CreditAttribution: webservant316 commentedif book_made_simple sets $form['book']['#access'] = FALSE will the Drupal form processor then still assign the default value for all the contained fields on update?
Comment #23
webservant316 CreditAttribution: webservant316 commentedOkay, understood. Thanks.
Unfortunately this module does not seem to be well maintained, so I need to decide whether to limp along with a custom patch or find an alternative.
This module has an excellent feature of presenting an add child page button at the bottom of book and child pages so that novice content creators can create books super easily. I wonder if there are other alternatives?
Comment #24
David_Rothstein CreditAttribution: David_Rothstein as a volunteer commentedYes, it should automatically preserve all existing values on those fields.
Comment #25
David_Rothstein CreditAttribution: David_Rothstein as a volunteer commentedHere's the code change as a patch. (I haven't tested it at all.)
Comment #26
webservant316 CreditAttribution: webservant316 commentedThanks for the patch offer. However, after the radio silence from book_made_simple maintainers in the queue and email I decided to hack a quick fix. I just liked the access to book reordering from a tab on the book and also expanded links to add children of various contents types from the book. I never understood why Drupal core only allows you to choose one content type for the add child link when many content types might be added as a child.
Note, if the maintainers do not follow up, this module is broken for PHP71.
It is like you say this modules fault and not Drupals. However, I do still find the different performance of drupal_array_set_nested_value() between PHP56 and PHP71 disturbing. Seems like that should be visited so that the performance is the same. Really book_made_simple should have been breaking for PHP56. I wonder if any other code would be impacted when moving to PHP71.
Anyway here is my replacement code for the book_made_simple functions that I needed for any followers. I also used the 'prepopulate' module to help make my code below pretty simple.
Comment #27
webservant316 CreditAttribution: webservant316 commentedChanging to major since book_made_simple misuses the form api and is broken for PHP71.
Comment #28
dgtlmoon CreditAttribution: dgtlmoon commented#2313517: Cannot create references to/from string offsets nor overloaded objects here's a core issue reported but needs more information, it's hard to say what the cause is, but if someone could chime in on that core issue, would be interesting to hear..
Comment #29
dgtlmoon CreditAttribution: dgtlmoon commented@webservant316 what exactly version of 5.6 are you running? I can confirm this on 5.6.33 ..
Comment #30
webservant316 CreditAttribution: webservant316 commentedI am now fully on PHP71 and have abandoned the book_made_simple module. I may not be much further help here. I found it easier to maintain the small code in #26 for my needs than to continue working with book_made_simple.
Best wishes.
Comment #31
osopolarIs this issue still valid? I am updating one site which uses Book made simple to php 7.1. I didn't get the reported error, although I made sure that the code
$form['book']['#type'] = 'hidden';
got executed.Comment #32
johnennew CreditAttribution: johnennew at Deeson commentedPatch in #25 fixed it for me.
Comment #33
osopolar@johnennew: Did you see the error before applying the patch or did you, or did you apply the patch, just in case it might be necessary and just observed the absence of the error?
Comment #34
MustangGB CreditAttribution: MustangGB commentedComment #35
joseph.olstadComment #36
RedEight CreditAttribution: RedEight at 95Visual commented#25 fixed the issue for me as well once I finally tracked it down.
Comment #37
indigoxela CreditAttribution: indigoxela commentedPatch #25 fixes the problem for php7.2, too.
Although this module is marked as getting "No further development", I still hope for a bugfix release.
Comment #38
mcdruidAs this is for a contrib module and not Drupal core, I'm removing the "Drupal 7.6* target" tag.
If I've misunderstood and it should indeed be there, it'd now be "Drupal 7.68 target".
Comment #39
indigoxela CreditAttribution: indigoxela commentedI can still confirm that patch #25 fixes the php compatibility issue (this time with 7.3). Still hoping for this crucial fix to get merged and released.
Comment #40
larynThanks to all involved in this issue over the years.
Merged in the actively-being-ported Backdrop version.