WordPress.org

Make WordPress Core

Opened 4 years ago

Closed 4 years ago

Last modified 4 years ago

#35493 closed defect (bug) (fixed)

get_terms does not return correct value when a term is searched by a name containing a single quote

Reported by: maximeschoeni Owned by: boonebgorges
Milestone: 4.5 Priority: normal
Severity: normal Version: 4.3
Component: Taxonomy Keywords:
Focuses: Cc:

Description

get_terms() function does not return correct value when a term is searched by a name containing a single quote ('). Apparently the terms name get escaped twice.

To reproduce it, first add one tag with name containing ', like Chef d'oeuvre, then use this function:

$name = "Chef d'oeuvre";

$terms = get_terms('post_tag', array(
	'name' => $name,
	'hide_empty' => false
));

var_dump($terms); // array(0) { }

I think the problem lies in /wp-includes/taxonomy.php, lines 1296-1301 (https://core.trac.wordpress.org/browser/tags/4.4/src/wp-includes/taxonomy.php#L1296):

$names = (array) $args['name'];

var_dump($names); // array(1) { [0]=> string(13) "Chef d'oeuvre" }

foreach ( $names as &$_name ) {
       $_name = sanitize_term_field( 'name', $_name, 0, reset( $taxonomies ), 'db' );
}

var_dump($names); // array(1) { [0]=> &string(14) "Chef d\'oeuvre" }

$where .= " AND t.name IN ('" . implode( "', '", array_map( 'esc_sql', $names ) ) . "')";

var_dump($where ); // "tt.taxonomy IN ('post_tag') AND t.name IN ('Chef d\\\'oeuvre')"

I'd suggest to just remove the last esc_sql formatting, but I am not sure if it may lead to other problems.

Change History (3)

#1 @boonebgorges
4 years ago

  • Milestone changed from Awaiting Review to 4.5
  • Version changed from 4.4.1 to 4.3

@maximeschoeni Welcome to WordPress Trac! Thanks for the detailed report.

I've confirmed the issue, and traced it to [32353]. In that changeset, we switched from sanitizing using sanitize_text_field() on the value of name to using sanitize_term_field( 'name' ). This change was necessary because terms go through the sanitize_term_field() filter when being saved in the first place, so that terms names are run through a couple different sanitization routines before being stored in the database.

One thing that sanitize_term_field( 'name' ) does is run the $name through wp_filter_kses(). This function runs stripslashes() on the value passed to it, and then runs addslashes() to it again before returning it. This is because wp_filter_kses() expects slashed data. But get_terms() expects the 'name' param to be unslashed already; see eg WP_Terms_List_Table::prepare_items(), where the search term is unslashed before being passed to get_terms().

Technically, the addslashes() performed by wp_filter_kses() does the same thing as the call to esc_sql() that you've pointed out. But this is partially an accident of how wp_filter_kses() - a function that was not designed for MySQL escaping - was designed. So, for developer clarity, it's probably wiser to keep the late esc_sql() escaping as-is but remove slashes on what's returned from sanitize_term_field().

#2 @boonebgorges
4 years ago

  • Owner set to boonebgorges
  • Resolution set to fixed
  • Status changed from new to closed

In 36348:

Don't double-escape the 'name' param in get_terms().

[32353] changed the way the 'name' param in get_terms() is sanitized, by
running it through sanitize_term_field( 'name' ) before performing the SQL
query. An unintentional side effect of this change was that the string is
double-escaped: once by wp_filter_kses(), and once by esc_sql(). The
double-escaping was causing 'name' queries to fail when the param contained
apostrophes or other escaped characters.

Fixes #35493.

#3 @nicolasrenard
4 years ago

#35752 was marked as a duplicate.

Note: See TracTickets for help on using tickets.