[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