web-dev-qa-db-fra.com

Désinfection des données de l'API des paramètres Wordpress par défaut

Il me semble que lors de la sauvegarde de données dans la base de données via les paramètres API, Wordpress supprime les données par défaut. J'entends par là que si je regarde les options de paramètres bruts de la base de données, elles ont (au moins) été passées à travers l'équivalent wordpress de htmlentities (). Existe-t-il une documentation sur le processus de désinfection exact? Je ne veux pas répéter cela dans ma propre fonction de validation, et je veux m'assurer d'utiliser correctement les données lorsque je les rappelle .....

UPDATE: En réponse à l'excellente réponse de Christopher Davis, voici un peu plus de détails. J'utilise register_setting pour enregistrer un groupe de paramètres. Ce groupe est défini à l'aide du add_settings_field. Le tableau de tous les paramètres est transmis (à l'aide du rappel register_settings) à une seule méthode de validation, qui vérifie simplement que tout semble correct (c'est-à-dire que reg exp vérifie qu'un email est un email, un entier est un entier, etc.). Je ne fais aucune désinfection ou ne fais référence à aucune des méthodes de désinfection de Wordpress. Cependant, une valeur d'option contient une balise qui, une fois affichée dans la base de données, a été convertie en entités HTML. J'ai supposé que Wordpress le faisait (au moins) par défaut pour toutes les options stockées dans la base de données. Peut-être juste par la façon dont il convertit un tableau en chaîne pour le stocker dans la base de données?

3
sigF

WordPress ne procédera à aucune purification des données pour vous. Cela désinfecte/valide les options par défaut.

Vous devez passer le troisième argument de register_setting et jouer votre propre rappel de validation ou utiliser l'une des fonctions intégrées.

Si vos options ne contiennent qu'une chaîne, vous pouvez par exemple faire quelque chose comme cela.

<?php
register_setting('your_group', 'your_setting', 'esc_attr');

Vous pouvez suivre comment WP enregistre une option, si vous regardez le code source pour register_setting (dans wp-admin/includes/plugin.php):

<?php
/**
 * Register a setting and its sanitization callback
 *
 * @since 2.7.0
 *
 * @param string $option_group A settings group name. Should correspond to a whitelisted option key name.
 *  Default whitelisted option key names include "general," "discussion," and "reading," among others.
 * @param string $option_name The name of an option to sanitize and save.
 * @param unknown_type $sanitize_callback A callback function that sanitizes the option's value.
 * @return unknown
 */
function register_setting( $option_group, $option_name, $sanitize_callback = '' ) {
    global $new_whitelist_options;

    if ( 'misc' == $option_group ) {
        _deprecated_argument( __FUNCTION__, '3.0', __( 'The miscellaneous options group has been removed. Use another settings group.' ) );
        $option_group = 'general';
    }

    $new_whitelist_options[ $option_group ][] = $option_name;
    if ( $sanitize_callback != '' )
        add_filter( "sanitize_option_{$option_name}", $sanitize_callback );
}

Le bit clé correspond aux dernières lignes de la fonction. S'il y a un rappel de désinfection, WP l'ajoutera au filtre sanitize_option_{$name}.

Ce filtre est appliqué dans sanitize_option (dans wp-includes/formatting.php):

<?php
/**
 * Sanitises various option values based on the nature of the option.
 *
 * This is basically a switch statement which will pass $value through a number
 * of functions depending on the $option.
 *
 * @since 2.0.5
 *
 * @param string $option The name of the option.
 * @param string $value The unsanitised value.
 * @return string Sanitized value.
 */
function sanitize_option($option, $value) {

    switch ( $option ) {
        case 'admin_email' :
        case 'new_admin_email' :
            $value = sanitize_email( $value );
            if ( ! is_email( $value ) ) {
                $value = get_option( $option ); // Resets option to stored value in the case of failed sanitization
                if ( function_exists( 'add_settings_error' ) )
                    add_settings_error( $option, 'invalid_admin_email', __( 'The email address entered did not appear to be a valid email address. Please enter a valid email address.' ) );
            }
            break;

        case 'thumbnail_size_w':
        case 'thumbnail_size_h':
        case 'medium_size_w':
        case 'medium_size_h':
        case 'large_size_w':
        case 'large_size_h':
        case 'embed_size_h':
        case 'default_post_edit_rows':
        case 'mailserver_port':
        case 'comment_max_links':
        case 'page_on_front':
        case 'page_for_posts':
        case 'rss_excerpt_length':
        case 'default_category':
        case 'default_email_category':
        case 'default_link_category':
        case 'close_comments_days_old':
        case 'comments_per_page':
        case 'thread_comments_depth':
        case 'users_can_register':
        case 'start_of_week':
            $value = absint( $value );
            break;

        case 'embed_size_w':
            if ( '' !== $value )
                $value = absint( $value );
            break;

        case 'posts_per_page':
        case 'posts_per_rss':
            $value = (int) $value;
            if ( empty($value) )
                $value = 1;
            if ( $value < -1 )
                $value = abs($value);
            break;

        case 'default_ping_status':
        case 'default_comment_status':
            // Options that if not there have 0 value but need to be something like "closed"
            if ( $value == '0' || $value == '')
                $value = 'closed';
            break;

        case 'blogdescription':
        case 'blogname':
            $value = addslashes($value);
            $value = wp_filter_post_kses( $value ); // calls stripslashes then addslashes
            $value = stripslashes($value);
            $value = esc_html( $value );
            break;

        case 'blog_charset':
            $value = preg_replace('/[^a-zA-Z0-9_-]/', '', $value); // strips slashes
            break;

        case 'date_format':
        case 'time_format':
        case 'mailserver_url':
        case 'mailserver_login':
        case 'mailserver_pass':
        case 'ping_sites':
        case 'upload_path':
            $value = strip_tags($value);
            $value = addslashes($value);
            $value = wp_filter_kses($value); // calls stripslashes then addslashes
            $value = stripslashes($value);
            break;

        case 'gmt_offset':
            $value = preg_replace('/[^0-9:.-]/', '', $value); // strips slashes
            break;

        case 'siteurl':
            if ( (bool)preg_match( '#http(s?)://(.+)#i', $value) ) {
                $value = esc_url_raw($value);
            } else {
                $value = get_option( $option ); // Resets option to stored value in the case of failed sanitization
                if ( function_exists('add_settings_error') )
                    add_settings_error('siteurl', 'invalid_siteurl', __('The WordPress address you entered did not appear to be a valid URL. Please enter a valid URL.'));
            }
            break;

        case 'home':
            if ( (bool)preg_match( '#http(s?)://(.+)#i', $value) ) {
                $value = esc_url_raw($value);
            } else {
                $value = get_option( $option ); // Resets option to stored value in the case of failed sanitization
                if ( function_exists('add_settings_error') )
                    add_settings_error('home', 'invalid_home', __('The Site address you entered did not appear to be a valid URL. Please enter a valid URL.'));
            }
            break;

        case 'WPLANG':
            $allowed = get_available_languages();
            if ( ! in_array( $value, $allowed ) && ! empty( $value ) )
                $value = get_option( $option );
            break;

        case 'timezone_string':
            $allowed_zones = timezone_identifiers_list();
            if ( ! in_array( $value, $allowed_zones ) && ! empty( $value ) ) {
                $value = get_option( $option ); // Resets option to stored value in the case of failed sanitization
                if ( function_exists('add_settings_error') )
                    add_settings_error('timezone_string', 'invalid_timezone_string', __('The timezone you have entered is not valid. Please select a valid timezone.') );
            }
            break;

        case 'permalink_structure':
        case 'category_base':
        case 'tag_base':
            $value = esc_url_raw( $value );
            $value = str_replace( 'http://', '', $value );
            break;
    }

    $value = apply_filters("sanitize_option_{$option}", $value, $option);

    return $value;
}

Comme vous pouvez le constater, il existe de nombreux cas pour gérer tous les éléments intégrés, mais aucune désinfection par défaut.

L'option Sanitize est appelée dans update_option pour nettoyer/valider les éléments avant qu'ils ne soient insérés dans la base de données.

<?php
/**
 * Update the value of an option that was already added.
 *
 * You do not need to serialize values. If the value needs to be serialized, then
 * it will be serialized before it is inserted into the database. Remember,
 * resources can not be serialized or added as an option.
 *
 * If the option does not exist, then the option will be added with the option
 * value, but you will not be able to set whether it is autoloaded. If you want
 * to set whether an option is autoloaded, then you need to use the add_option().
 *
 * @since 1.0.0
 * @package WordPress
 * @subpackage Option
 *
 * @uses apply_filters() Calls 'pre_update_option_$option' hook to allow overwriting the
 *  option value to be stored.
 * @uses do_action() Calls 'update_option' hook before updating the option.
 * @uses do_action() Calls 'update_option_$option' and 'updated_option' hooks on success.
 *
 * @param string $option Option name. Expected to not be SQL-escaped.
 * @param mixed $newvalue Option value. Expected to not be SQL-escaped.
 * @return bool False if value was not updated and true if value was updated.
 */
function update_option( $option, $newvalue ) {
    global $wpdb;

    $option = trim($option);
    if ( empty($option) )
        return false;

    wp_protect_special_option( $option );

    if ( is_object($newvalue) )
        $newvalue = clone $newvalue;

    $newvalue = sanitize_option( $option, $newvalue );
    $oldvalue = get_option( $option );
    $newvalue = apply_filters( 'pre_update_option_' . $option, $newvalue, $oldvalue );

    // If the new and old values are the same, no need to update.
    if ( $newvalue === $oldvalue )
        return false;

    if ( false === $oldvalue )
        return add_option( $option, $newvalue );

    $notoptions = wp_cache_get( 'notoptions', 'options' );
    if ( is_array( $notoptions ) && isset( $notoptions[$option] ) ) {
        unset( $notoptions[$option] );
        wp_cache_set( 'notoptions', $notoptions, 'options' );
    }

    $_newvalue = $newvalue;
    $newvalue = maybe_serialize( $newvalue );

    do_action( 'update_option', $option, $oldvalue, $_newvalue );
    if ( ! defined( 'WP_INSTALLING' ) ) {
        $alloptions = wp_load_alloptions();
        if ( isset( $alloptions[$option] ) ) {
            $alloptions[$option] = $_newvalue;
            wp_cache_set( 'alloptions', $alloptions, 'options' );
        } else {
            wp_cache_set( $option, $_newvalue, 'options' );
        }
    }

    $result = $wpdb->update( $wpdb->options, array( 'option_value' => $newvalue ), array( 'option_name' => $option ) );

    if ( $result ) {
        do_action( "update_option_{$option}", $oldvalue, $_newvalue );
        do_action( 'updated_option', $option, $oldvalue, $_newvalue );
        return true;
    }
    return false;
}

C'est un peu long. Je voulais juste montrer le processus par lequel vous pouvez passer et comprendre ce genre de chose.

Edit

Il est à noter que les tableaux d’options seront sérialisés (via maybe_serialize ).

10
chrisguitarguy