Skip to content
This repository was archived by the owner on Sep 24, 2018. It is now read-only.
This repository was archived by the owner on Sep 24, 2018. It is now read-only.

Boolean request args fail validation #2616

Description

@rachelbaker

In rest_validate_request_arg() we cannot use the ! is_bool() conditional to validate if a request argument is either true or false. The query string in the url (example: https://demo.wp-api.org/wp-json/wp/v2/categories?hide_empty=true) will be parsed as a string. Which means you will always get the error:
{ code: "rest_invalid_param", message: "Invalid parameter(s): hide_empty", data: { status: 400, params: { hide_empty: "hide_empty is not of type boolean" } } }

Activity

  1. websupporter commented on Jul 26, 2016

    @websupporter
    Member

    Hi @rachelbaker,
    my first thought was:

    if ( 'boolean' === $args['type'] && ( ! is_bool( $value ) && ! in_array( $value, array( 'true', 'false' ) ) ) )
    

    But this passes strings, and maybe we run into problems later on. Wouldn't this be better:

    class-wp-rest-terms-controller.php:

            $query_params['hide_empty'] = array(
                'description'           => __( 'Whether to hide resources not assigned to any posts.' ),
                'type'                  => 'boolean',
                'default'               => false,
                'sanitize_callback'     => 'rest_sanitize_request_arg',
                'validate_callback'     => 'rest_validate_request_arg',
            );
    

    plugin.php

    function rest_sanitize_request_arg( $value, $request, $param ) {
        $attributes = $request->get_attributes();
        if ( ! isset( $attributes['args'][ $param ] ) || ! is_array( $attributes['args'][ $param ] ) ) {
            return $value;
        }
        $args = $attributes['args'][ $param ];
    
        if( 'boolean' === $args['type'] && in_array( $value, array( 'true', 'false' ) ) ) {
            if( 'true' === $value )
                return true;
            return false;
        }
    

    EDIT:
    Maybe it should also be extended for 0 and 1...

  2. joelstransky commented on Jul 26, 2016

    @joelstransky

    I think this might be a better approach.

    $prepared_args['hide_empty'] = filter_var($prepared_args['hide_empty'], FILTER_VALIDATE_BOOLEAN);
    
  3. websupporter commented on Jul 27, 2016

    @websupporter
    Member

    Hi @joelstransky,
    where would this code be placed? If it is in the get_items() it would be too late, since validation takes place before.

    But, as far as I can see it sanitization takes place before validation (Actually, it works, but I am a bit unsure why, I thought there was some problem using both sanitization and validation together). So, if we add the boolean sanitization, it would pass the validation and we would reach get_items().

  4. rachelbaker commented on Jul 27, 2016

    @rachelbaker
    MemberAuthor

    @websupporter It would need to be in rest_validate_request_arg() for any 'type = booleanarg. We can't usefilter_var()` though because we cannot guarantee the extenstion is enabled in every installation of WordPress.

  5. websupporter commented on Jul 28, 2016

    @websupporter
    Member

    Hmmm... not sure if I am on the right track, but if its okay for all to sanitize in the get_items() let me introduce you toa neat little helper I've quickly wrote and which can sanitize and validate:

    <?php
    /**
     * Takes 'true', true, 1, 'yes, 'false', false, 0, 'no' as parameter and returns an boolean
     * @param $to_bool (mixed)
     * @return boolean|WP_Error
     **/
     function wp_bool( $to_bool ) {
        $true = array(
            true,
            1,
            '1',
            'true',
            'yes',
        );
    
        $false = array(
            false,
            0,
            '0',
            'false',
            'no',
        );
        if ( in_array( $to_bool, $true, true ) ) {
            return true;
        } 
    
        if ( in_array( $to_bool, $false, true ) ) {
            return false;
        }
    
        return new WP_Error( 'no-bool', __( 'The parameter was no boolean.' ) );
    }
    
    ?>
    

    Instead of is_bool() we would check in rest_validate_request_arg() if the outcome of wp_bool() is an WP_Error. In get_items() we can use it to sanitize.

    Would this be a better way?

  6. rachelbaker commented on Jul 31, 2016

    @rachelbaker
    MemberAuthor

    @websupporter I took a similar approach in #2630. What do you think?

  7. added a commit that references this issue on Sep 17, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions