WordPress.org

Make WordPress Core

Opened 20 months ago

Last modified 20 months ago

#43451 new feature request

Disallow objects as meta values

Reported by: tonybogdanov Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version: 4.9.2
Component: Options, Meta APIs Keywords:
Focuses: Cc:
PR Number:

Description

OK, I know this is probably going to be closed before anyone even reads it, but I recon it's worth to at least try and spark a discussion.

As probably many people know at this point meta functions do not like backslashes. For some reason (probably db related) meta and option add / update functions run all values through stripslashes_deep, which means they expect the input values to be slashed. Actually this "requirement" seems to be undocumented even though it's here since version 3.something, why, that's beyond me.

So, imagine you're a noobie WordPress developer and for some reason you have a backslash in a string you want to persist (happens more often than one might think), so you go ahead and run the following code:

$value = 'hello \world';

update_user_meta(get_current_user_id(), '_test', $value);
$meta = get_user_meta(get_current_user_id(), '_test', true);

var_dump($value, $meta);

You save hello \world and expect to get hello \world back, but surprise surprise, the backslash is gone.

So you start scratching your head, dig through stackoverflow or the source and you discover $meta_value = wp_unslash($meta_value);.

You think this isn't right, but who are you to argue with software that's here for more than 10 years already. So, now, you are a bit more "experienced" and know you need to run all your values through wp_slash before you pass it to the meta functions.

Then one day you need to save an array, you read through the docs which doesn't seem to forbid it, so you glance at the source and see $meta_value = maybe_serialize( $meta_value ); - YES! - you say, you can pass basically anything and WordPress will take care of the serialization, awesome!

So, now you run:

$value = [
    'hello' => 'again \world'
];

update_user_meta(get_current_user_id(), '_test', wp_slash($value));
$meta = get_user_meta(get_current_user_id(), '_test', true);

var_dump($value, $meta);

Which results in the same input you gave it, now that you know you need to slash everything. You weren't sure wp_slash could actually handle arrays, but it does, so life's good!

Later on you mature even more and decide you want to save whole objects now. You know about serialization, so no worries here, right?

You adapt your previous code and try to run the following:

$value = new \stdClass();
$value->hello = 'world \again';

update_user_meta(get_current_user_id(), '_test', wp_slash($value));
$meta = get_user_meta(get_current_user_id(), '_test', true);

var_dump($value, $meta);

...and you get Warning: addslashes() expects parameter 1 to be string, object given in. Turns out wp_slash can't handle objects :|

Alright, maybe you don't need it, so you remove it aaand the slash is gone.
Then you look at the code and realize now the slash is gone even from your original object! What the...

So trying to store an object as a meta value is not only not gonna work properly, but it's also going to mess with your original object!

So, what then?
Serialize it into a string before and after?

OK, you serialize the object so it's just a string now, then run it through wp_slash to fix the slashes issue and then give it to the meta function:

$value = new \stdClass();
$value->hello = 'world \again';

update_user_meta(get_current_user_id(), '_test', wp_slash(serialize($value)));
$meta = unserialize(get_user_meta(get_current_user_id(), '_test', true));

var_dump($value, $meta);

Whew, finally everything works just fine, even though you're not absolutely sure you've covered all possible cases making sure nothing can ever go wrong again.


So, can anyone elaborate on this a bit more?

Why are slashes such a big problem when it comes to options and meta, shouldn't the value just be converted to a string and then treated as a black box all the way up to when it needs to go in the database?

Why does object serialization cause so much trouble?

You can't seriously expect users to be aware that their objects are going to be deepslashed to death, values of properties modified to god-knows how deep, and be okay with it.

If meta functions can't handle objects, just don't allow objects, shift the responsibility to the user, but be blunt about it. Don't say, it's okay, we're gonna take care of serialization for you, then strip the slashes off of properties of deep objects which might not even be part of WordPress whatsoever. This is a debugging nightmare.

Lastly I would like to apologize for my tone, but I've dealt with this issue for years now. There are bug reports opened 7 years ago that still haven't been resolved properly.

If nothing else it's really surprising to me that we're at 4.9.4 and such a mundane activity (persisting objects in meta) can cause so much trouble. Is it just me having these issues? Does no one else serialize stuff?

Change History (1)

#1 @jdgrimes
20 months ago

Related: #41593

I think that changing the behavior at this point is probably not possible, for legacy reasons (there is probably a lot of code out there that is expecting the current behavior). However, better documentation at least would be nice. Also so that if these functions are ever replaced by a new API in the future, persisting these quirks can be avoided.

Note: See TracTickets for help on using tickets.