Closed McZazz closed 2 years ago
Updated comment for explaining why the test case is set up the way it is.
Hi,
I can't reproduce your issue, either on PHP5, 7 or 8.
Can you provide another test sample?
I was able to reproduce the issue.. but it appears to be nothing rally framework related.. see this:
$data = (object) [
'�foo' => 123,
];
var_dump(Template::instance()->esc($data));
First char before key name "foo" is a NUL
aka \0
. The error simply comes from php telling you that this property is not accessible. it was only setted by array to object conversion, as there's also no way to set a "\0foo" key manually to an object. Hence this error is a hint that you have stored a malicious key somewhere, which is tried to be accessed within the template rendering auto-escaping mechanism. Applying trim wont fix your issue, as the stored key is still not accessible.
As it only happens randomly on your side, I would suspect the session data.
It happens randomly as far as I can tell, but, not on my side only. It happens locally and on the server. Restarting the browser does not fix it, so it shouldn't be a session issue. One thing I have not tried is seeing if it still happens inbetween php 5 and 7.4 (currently running 7.4 and 8.0.10), but I won't be working on anything php oriented for some time unfortunately. This pops up while working on a site. Simply setting up a project with a working site rarely if ever produces the problem (hence why I posted a different example to induce the error with an obvious user error).
One would have to sit around modding methods and classes for a while before it pops up. Controlled environment vs. working in the field issues at their best.
Does any of the class or classmap info end up in the temp, or cache folders?
The bug traces only to base.php, and simply doing another "composer dump-autoload" to clear up the classmap doesn't help.
This happens locally and when deployed to a server (yet, sometimes it pops up on one and not the other), meaning, one can't simply edit their site, and expect it to work on both without verifying by hand, checking everything, every link, every page. Otherwise it's necessary to delete everything composer related, then redo "composer install" and "composer dump-autoload" over and over which eats time (or just add the trim() in base.php to avoid it altogether).
One thing of note, I've not had this issue when avoiding use of the F3 SESSION management (and using the proper placement of session_start(), unlike my "intentional bug inducement for a controlled environment demo" above). If I just do session_start() as if I wasn't using F3 (correctly), and use the php builtin $_SESSION['whateverkey'] only, it never pops up.
Edit:
Did some more searching and found that this issue is several years old. https://wordpress.org/support/topic/uncaught-error-cannot-access-property-started-with-0-in/ https://forum.virtuemart.net/index.php?topic=133607.0
So, they used the trim() like I did at first, but apparently that is not the best way to fix it. They (users named Jumbo! and Milbo) offered a number of other solutions on page 2 of the second link.
They claim it had something to do with the switch from php 5 to 7.
So, I wish I had saved a "tainted" version of an entire project, I could just try to run it off php 5, but then composer / F3 would be out of date. They say it has something to do with "protected variables" which I guess is what ikkez is referring to with "this property is not accessible".
Also, this premature "bogus / invalid" claim is... yeah, I'm thinking I just found out why people don't always use the F3 builtin way of dealing with session.
I was able to reproduce this issue like this:
class Foo {
protected $x = '';
function __construct($x) {
$this->x = $x;
}
}
$var = (object) (array) (new Foo('foo')));
var_dump(Template::instance()->esc($var));
The problem arise when you cast an object with protected properties as array and manually convert it back to object again. As the problem is only visible randomly, I bet it's some object in your app that got set to session somehow which breaks once unserialized.
The proper fix would be to use a ->toArray() method or implement the Serializable interface. I'm still not sure though if we should fix this at all, as it will hide the real issue that you'll probably never find otherwise. On the other hand the damage is done already and the error message wont help you find the root cause either 🤔 . We could inspect everything once it's set to the hive, but that won't help here too when used in the global $_SESSION var. I guess we need to live with that this beauty mistake can happen and just plug the holes.
fixed in latest commit
Bugfix to: Cannot access property starting with "\0" [<...>\vendor\bcosca\fatfree-core\base.php:885]
Loading the site causes the above message to be the only thing that displays at the top of the webpage. The "\0" is a NUL-byte as per https://www.php.net/manual/en/function.trim.php. With the bug, keys in a particular foreach loop in base.php were getting cut into pieces it appears. I tried checking if each $key was set, however, running a counter on it revealed that only 1 out of several keys were getting checked that way. Using trim() revealed that several keys were being looped through, so I went with that, though, I'm not sure if removing the "\0" could cause a problem somewhere else.
Also, by checking with a counter in the loop, using trim() vs just commenting out the call to recursive() proved that all keys were checked either way, and without, only 2 were getting checked before the crashes. So I'm assuming trim() is the way to fix this, though I'm not 100% sure.
The bug occurs when either or both of the following two conditions are true (depending on whether using the F3 way of managing SESSION or not):
1) When using a setup where the F3 Base::instance() is passed into an object and set as a property of that object (aka member variable) in the project's root index.php,
2) The F3 method of setting SESSION variables is not being used, and instead $_SESSION is being used to get and set session variables and session_start() is being called at the top of index.php
It was easiest to get consistent behavior with the bug by only using $_SESSION for gets and sets, with session_start() also in the index.php. However, this bug would occasionally still happen when not using session_start() anywhere, while only using the F3 way of dealing with SESSION: $this->_f3->get('SESSION.anything'). I couldn't get a reliable test going to replicate the bug that way though, so here I'm illustrating the more easy to reproduce version.
It would happen either upon immediately visiting the site, or, after refreshing once already on the site.
The bug appears to be occurring somewhere inside the session_start() call, commenting it in and out on a setup that was using $_SESSION instead of the F3 way of accessing SESSION would cause the bug to not happen, of course, SESSION does not work if only using $_SESSION so it's still a bug. According to the docs, it is the user's preference whether to use the F3 handing of SESSION or the $_SESSION way:
https://fatfreeframework.com/3.8/framework-variables
"If you use $_SESSION (or session-related functions) directly, instead of the framework variable SESSION, your application becomes responsible for managing sessions."
Starting at line 884 of base.php, the fix is as follows (trim() call and brackets for the foreach):
echo inside the foreach without trim(): __PHP_Incomplete_Class_NameApplicant_fname
echo inside the foreach with trim(): __PHP_Incomplete_Class_NameApplicant_fnameApplicant_lnameApplicant_emailApplicant_stateApplicant_phoneApplicant_githubApplicant_experienceApplicant_relocateApplicant_bio
Pattern that causes the crash most reliably:
Inside index.php:
Inside controller.php:
Thank you!