web-dev-qa-db-ja.com

複数のメタフィールドを持つメタボックスを安全にする正しい方法

私は複数のフィールドを含むメタボックスを持つプラグインを作るためにいくつかのオンラインチュートリアルを使いました。私のプラグインが安全であることを確認したいのですが、うまく機能してデータを保存しているようです。コードは以下の通りです。任意の提案は大歓迎です。

<?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

まず、100%安全なWebアプリケーションはないとしましょう。

そうは言っても、あなたはノンスを正しく使っています。あなたが使っている関数update_post_meta()は、 wpdbクラス のinsert/updateメソッドを使っているので、データをSQLスケールします。そのため、最も一般的なセキュリティ問題としてのリスクはありません。

気をつけなければならないのは、データ検証であり、あなたはそれを間違って行っています。すべてのメタフィールドの値をwp_kses()関数に渡し、すべてのフィールドで<a>要素を許可します。それはあなたが望むものではないと思います。たとえば、Eメールや電話のフィールドで<a>要素を許可したくないとします。

すべての値をwp_kses()に渡す代わりに、それぞれに対して特定のデータ検証やサニタイズを行うべきです。例えば:

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'] ) );
}

さらに進んで、特定のメタフィールドが更新または作成されるたびに実行されるカスタム検証関数を定義できます。例えば:

//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;
    }

}

次に、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
     }
}

この方法では、もう少し作業が必要ですが、電話メタが作成されたり更新されたりするたびに、サニテーションコードを再度記述することなく、電話メタフィールドが定義済みフィルタに対してサニタイズされます。

でより多くの:

1
cybmeta