Formatting: Prevent wp_slash from returning non-strings as strings.

If a bool/float/int is passed into wp_slash it will be coerced into a string.

This changes the behavior to only slash strings. At the same time, handles recursion a little nicer by calling array_map for arrays.

Fixes #42195, #24106.

Props johnbillion, andizer, jrf, ryotasakamoto, SergeyBiryukov, donmhico, TobiasBg, markoheijnen, ryan, nacin, devesine, whyisjake.



git-svn-id: https://develop.svn.wordpress.org/trunk@48433 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Jake Spurlock
2020-07-11 00:11:57 +00:00
parent d42bdcb877
commit 21273c3c49
3 changed files with 111 additions and 10 deletions

View File

@@ -5496,27 +5496,24 @@ function sanitize_trackback_urls( $to_ping ) {
}
/**
* Add slashes to a string or array of strings.
* Add slashes to a string or array of strings, in a recursive manner.
*
* This should be used when preparing data for core API that expects slashed data.
* This should not be used to escape data going directly into an SQL query.
*
* @since 3.6.0
* @since 5.5.0 Leave a non-string value untouched.
*
* @param string|array $value String or array of strings to slash.
* @return string|array Slashed $value
*/
function wp_slash( $value ) {
if ( is_array( $value ) ) {
foreach ( $value as $k => $v ) {
if ( is_array( $v ) ) {
$value[ $k ] = wp_slash( $v );
} else {
$value[ $k ] = addslashes( $v );
}
}
} else {
$value = addslashes( $value );
$value = array_map( 'wp_slash', $value );
}
if ( is_string( $value ) ) {
return addslashes( $value );
}
return $value;

View File

@@ -2,6 +2,7 @@
/**
* @group formatting
* @group slashes
*/
class Tests_Formatting_StripSlashesDeep extends WP_UnitTestCase {
/**

View File

@@ -0,0 +1,103 @@
<?php
/**
* @group formatting
*/
class Tests_Formatting_WPSlash extends WP_UnitTestCase {
/**
* @dataProvider data_wp_slash
*
* @ticket 42195
*
* @param string $value
* @param string $expected
*/
public function test_wp_slash_with( $value, $expected ) {
$this->assertSame( $expected, wp_slash( $value ) );
}
/**
* Data provider for test_wp_slash().
*
* @return array {
* @type array {
* @type mixed $value The value passed to wp_slash().
* @type string $expected The expected output of wp_slash().
* }
* }
*/
public function data_wp_slash() {
return array(
array( 123, 123 ),
array( 123.4, 123.4 ),
array( true, true ),
array( false, false ),
array(
array(
'hello',
null,
'"string"',
125.41,
),
array(
'hello',
null,
'\"string\"',
125.41,
),
),
array( "first level 'string'", "first level \'string\'" ),
);
}
/**
* @ticket 24106
*/
function test_adds_slashes() {
$old = "I can't see, isn't that it?";
$new = "I can\'t see, isn\'t that it?";
$this->assertEquals( $new, wp_slash( $old ) );
$this->assertEquals( "I can\\\\\'t see, isn\\\\\'t that it?", wp_slash( $new ) );
$this->assertEquals( array( 'a' => $new ), wp_slash( array( 'a' => $old ) ) ); // Keyed array
$this->assertEquals( array( $new ), wp_slash( array( $old ) ) ); // Non-keyed
}
/**
* @ticket 24106
*/
function test_preserves_original_datatype() {
$this->assertEquals( true, wp_slash( true ) );
$this->assertEquals( false, wp_slash( false ) );
$this->assertEquals( 4, wp_slash( 4 ) );
$this->assertEquals( 'foo', wp_slash( 'foo' ) );
$arr = array(
'a' => true,
'b' => false,
'c' => 4,
'd' => 'foo',
);
$arr['e'] = $arr; // Add a sub-array
$this->assertEquals( $arr, wp_slash( $arr ) ); // Keyed array
$this->assertEquals( array_values( $arr ), wp_slash( array_values( $arr ) ) ); // Non-keyed
$obj = new stdClass;
foreach ( $arr as $k => $v ) {
$obj->$k = $v;
}
$this->assertEquals( $obj, wp_slash( $obj ) );
}
/**
* @ticket 24106
*/
function test_add_even_more_slashes() {
$old = 'single\\slash double\\\\slash triple\\\\\\slash';
$new = 'single\\\\slash double\\\\\\\\slash triple\\\\\\\\\\\\slash';
$this->assertEquals( $new, wp_slash( $old ) );
$this->assertEquals( array( 'a' => $new ), wp_slash( array( 'a' => $old ) ) ); // Keyed array
$this->assertEquals( array( $new ), wp_slash( array( $old ) ) ); // Non-keyed
}
}