[wp-trac] [WordPress Trac] #43451: Disallow objects as meta values
WordPress Trac
noreply at wordpress.org
Thu Mar 1 13:01:23 UTC 2018
#43451: Disallow objects as meta values
--------------------------------+-----------------------------
Reporter: tonybogdanov | Owner:
Type: feature request | Status: new
Priority: normal | Milestone: Awaiting Review
Component: Options, Meta APIs | Version: 4.9.2
Severity: normal | Keywords:
Focuses: |
--------------------------------+-----------------------------
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:
{{{#!php
$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:
{{{#!php
$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:
{{{#!php
$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:
{{{#!php
$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?
--
Ticket URL: <https://core.trac.wordpress.org/ticket/43451>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list