web-dev-qa-db-fra.com

Façon correcte de créer une méta-boîte avec plusieurs champs méta sécurisés

J'ai utilisé plusieurs didacticiels en ligne pour créer un plugin doté d'une méta-boîte contenant plusieurs champs. Cela semble fonctionner correctement et sauvegarder les données, mais je veux juste m'assurer que mon plugin est sécurisé. Le code est ci-dessous. Toutes les suggestions seraient grandement appréciées.

<?php
 /*
  Typical Header info
 */

 /* Artists Galleries Function that sets up
 our custom post type and registers it */

function artist_galleries_cpt() {

$labels = array(
'name' => _x('Artist Galleries', 'post type general name'),
'singular_name' => _x('Artist Gallery', 'post type singular name'),
'add_new' => _x('Add New', 'Post'),
'add_new_item' => __('Add New Artist Gallery'),
'edit_item' => __('Edit Artist Gallery'),
'new_item' => __('New Artist Gallery'),
'view_item' => __('View Artist Gallery'),
'search_items' => __('Search Artist Galleries'),
'not_found' =>  __('No Artist Galleries found'),
'not_found_in_trash' => __('No Artist Galleries found in Trash'),
'parent_item_colon' => ''
);
$args = array(
'labels' => $labels,
'public' => true,
'publicly_queryable' => true,
'show_ui' => true,
'query_var' => true,
'rewrite' => array('slug'=>'galleries_test'),
'show_in_nav_menus' => true,
'capability_type' => 'post',
'hierarchical' => false,
'menu_position' => 5,
'supports' => array('title','editor','thumbnail'),
'has_archive' => true
);

// Custom Post Type Registers Here
register_post_type('artist_galleries',$args);
}

add_action('init', 'artist_galleries_cpt');


/* Function that changes the default messages
 seen when working on our custom post type */

function artist_galleries_updated_messages( $messages ) {

global $post, $post_ID;
$messages['artist_galleries'] = array(
0 => '',
1 => sprintf( __('Artist Gallery updated. <a href="%s">View Artist Gallery</a>'), esc_url( get_permalink($post_ID) ) ),
2 => __('Custom field updated.'),
3 => __('Custom field deleted.'),
4 => __('Arist Gallery updated.'),
5 => isset($_GET['revision']) ? sprintf( __('Artist Gallery restored to revision from %s'), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
6 => sprintf( __('Artist Gallery published. <a href="%s">View Artist Gallery</a>'), esc_url( get_permalink($post_ID) ) ),
7 => __('Artist Gallery saved.'),
8 => sprintf( __('Artist Gallery submitted. <a target="_blank" href="%s">Preview Artist Gallery</a>'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
9 => sprintf( __('Artist Gallery scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview Artist Gallery</a>'), date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ), esc_url( get_permalink($post_ID) ) ),
10 => sprintf( __('Artist Gallery draft updated. <a target="_blank" href="%s">Preview Artist Gallery</a>'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
);
return $messages;
 }
 add_filter( 'post_updated_messages', 'artist_galleries_updated_messages' );

 /* Function that will add our custom
 meta boxes to the admin screen */

function add_artist_info_meta_box() {

 // Add Meta Box Function for Products that Artist Sells
add_meta_box(
'artist-info-meta-box', // Unique ID
esc_html__( 'Artist Info', 'example' ), // Title
'artist_info_meta_box', // Callback function
'artist_galleries', // Admin page (or post type)
'side', // Context
'default' // Priority
);
}

// Add meta box using the 'add_meta_boxes' hook.
add_action( 'add_meta_boxes', 'add_artist_info_meta_box' );

 /* Function that will display our custom
 meta boxes to the screen */

function artist_info_meta_box() {

// $post is already set, and contains an object: the WordPress post
global $post;

$values = get_post_custom( $post->ID );

// Set our field variables
   $products_sold = isset( $values['products_sold'] ) ? $values['products_sold'][0] : '';
    $website = isset( $values['website'] ) ? esc_attr( $values['website'][0] ) : '';
    $address = isset( $values['address'] ) ? esc_attr( $values['address'][0] ) : '';
    $phone = isset( $values['phone'] ) ? esc_attr( $values['phone'][0] ) : '';
    $email = isset( $values['email'] ) ? esc_attr( $values['email'][0] ) : '';
    $hours = isset( $values['hours'] ) ? esc_attr( $values['hours'][0] ) : '';

    // We'll use this nonce field later on when saving.
    wp_nonce_field( 'artist_info_meta_box_nonce', 'meta_box_nonce' );
    ?>
    <p>
    <label for="products-sold">Products Sold</label> </p>
  <p>
    <input type="text" name="products_sold" id="products_sold" value="<?php echo $products_sold; ?>" />
</p>

<p>
  <label for="website">Website</label> </p>
  <p>
  <input type="text" name="website" id="website" value="<?php echo $website;    ?>" />
  </p>

  <p>
  <label for="address">Address</label> </p>
  <p>
  <input type="text" name="address" id="address" value="<?php echo $address;   ?>" />
  </p>

<p>
  <label for="phone">Phone</label> </p>
<p>
  <input type="text" name="phone" id="phone" value="<?php echo $phone; ?>" />
</p>

 <p>
 <label for="email">Email</label> </p>
 <p>
 <input type="text" name="email" id="email" value="<?php echo $email; ?>" />
 </p>

 <p>
 <label for="hours">Hours</label> </p>
  <p>
 <input type="text" name="hours" id="hours" value="<?php echo $hours; ?>" />
 </p>
 <?php
}?>
  <?php
   function artist_info_meta_box_save( $post_id )
{
     // Bail if we're doing an auto save
     if( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;

      // if our nonce isn't there, or we can't verify it, bail
       if( !isset( $_POST['meta_box_nonce'] ) || !wp_verify_nonce(    $_POST['meta_box_nonce'], 'artist_info_meta_box_nonce' ) ) return;

// if our current user can't edit this post, bail
if( !current_user_can( 'edit_post', $post_id ) ) return;

// now we can actually save the data
$allowed = array(
    'a' => array( // on allow a tags
        'href' => array() // and those anchors can only have href attribute
    )
);

  // Make sure your data is set before trying to save it
if( isset( $_POST['products_sold'] ) )
   update_post_meta( $post_id, 'products_sold', wp_kses( $_POST['products_sold'], $allowed ) );

if( isset( $_POST['website'] ) )
    update_post_meta( $post_id, 'website', wp_kses( $_POST['website'], $allowed ) );

if( isset( $_POST['address'] ) )
    update_post_meta( $post_id, 'address', wp_kses( $_POST['address'], $allowed ) );

if( isset( $_POST['phone'] ) )
    update_post_meta( $post_id, 'phone', wp_kses( $_POST['phone'], $allowed ) );

if( isset( $_POST['email'] ) )
    update_post_meta( $post_id, 'email', wp_kses( $_POST['email'], $allowed ) );

if( isset( $_POST['hours'] ) )
    update_post_meta( $post_id, 'hours', wp_kses( $_POST['hours'], $allowed ) );


 }
add_action( 'save_post', 'artist_info_meta_box_save' );
?>
1
user2875165

Tout d’abord, laissez-moi vous dire qu’il n’existe pas d’application Web 100% sécurisée.

Cela étant dit, vous utilisez le nonce correctement. La fonction que vous utilisez, update_post_meta(), sql-scape les données car elle utilise les méthodes insert/update de wpdb class . Il n'y a donc aucun risque pour les problèmes de sécurité les plus courants.

Je pense que vous devez prendre soin de valider les données, et vous ne le faites pas correctement. Vous transmettez toutes les valeurs de champs méta à la fonction wp_kses() et vous autorisez les éléments <a> dans tous les champs. Je pense que ce n'est pas ce que tu veux; Par exemple, je pense que vous ne souhaitez pas autoriser l'élément <a> dans les champs de courrier électronique ou de téléphone.

Au lieu de transmettre toutes les valeurs à wp_kses(), vous devez effectuer une validation et/ou une purification spécifiques des données pour chacune d'entre elles. Par exemple:

if( isset( $_POST['products_sold'] ) ) {
    update_post_meta( $post_id, 'products_sold', sanitize_text_field( $_POST['products_sold'] ) );
}
if( isset( $_POST['website'] ) ) {
     //Leave as it was to allow website as <a href="...">...</a>
     //update_post_meta( $post_id, 'website', wp_kses( $_POST['website'], $allowed ) );
     update_post_meta( $post_id, 'website', esc_url_raw( $_POST['website'] ) );
}

if( isset( $_POST['address'] ) ) {
    update_post_meta( $post_id, 'address', sanitize_text_field( $_POST['address'] ) );
}

if( isset( $_POST['phone'] ) ) {
     update_post_meta( $post_id, 'phone', sanitize_text_field( $_POST['phone'] ) );
}

if( isset( $_POST['email'] ) ) {
    update_post_meta( $post_id, 'email', sanitize_email( $_POST['email'] ) );
}

if( isset( $_POST['hours'] ) ) {
    update_post_meta( $post_id, 'hours', sanitize_text_field( $_POST['hours'] ) );
}

Vous pouvez aller plus loin et définir une fonction de validation personnalisée à exécuter chaque fois qu'un champ méta spécifique est mis à jour/créé. Par exemple:

//Create and define the `sanitize_phone_meta` filter:
add_filter( 'sanitize_post_meta_phone', 'sanitize_phone_meta' );
function ssanitize_phone_meta( $phone ) {

    //Perform whatever validation you want for phone value
    //For example, if you only want the phone format 000-0000-0000
    if(preg_match("/^[0-9]{3}-[0-9]{4}-[0-9]{4}$/", $phone)) {
        // $phone is valid
        return $phone;

    } else {
        return false;
    }

}

Ensuite, dans le hook save_post:

if( isset( $_POST['phone'] ) ) {
     $clean_phone = sanitize_meta( 'phone', $_POST['phone'], 'post' );
     if( $clean_phone !== false ) {
         update_post_meta( $post_id, 'phone', $clean_phone );
     } else {
         //Do something when the phone format is not what you expect
     }
}

De cette façon, un peu plus de travail est requis, mais le champ méta du téléphone sera nettoyé par rapport au filtre défini chaque fois que la méta du téléphone est créée/mise à jour à partir de n’importe quel endroit sans qu'il soit nécessaire de réécrire le code de nettoyage.

Plus dans:

1
cybmeta