确保具有多个元字段的元框安全的正确方法

时间:2014-07-19 作者:user2875165

我使用了几个在线教程制作了一个插件,它有一个包含多个字段的元框。它似乎工作正常,并保存数据,但我只想确保我的插件是安全的。代码如下所示。如有任何建议,将不胜感激。

<?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 个回复
最合适的回答,由SO网友:cybmeta 整理而成

首先,我要说的是,没有一个web应用程序是百分之百安全的。

也就是说,您正确地使用了nonce。您正在使用的函数,update_post_meta(), sql是否会在使用wpdb class. 因此,大多数常见的安全问题都没有风险。

我认为,您应该注意的是数据验证,而您这样做是错误的。将所有元字段值传递给wp_kses() 功能和您允许<a> 所有字段中的元素。我想那不是你想要的;例如,我认为您不想允许<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
     }
}
这样,需要做更多的工作,但每次从任何位置创建/更新电话元时,都会根据定义的过滤器对电话元字段进行清理,而无需再次写入清理代码。

更多信息:

结束

相关推荐

如何隐藏,而不是去掉属性的Metabox?

我需要hide, 并且不要删除后端中的属性元框。以下代码正在删除元数据库:function hide_meta_box_attributes() { remove_meta_box(\'pageparentdiv\', \'post\', \'normal\'); } add_filter(\'add_meta_boxes\', \'hide_meta_boxes_attributes\'); 问题是,我运行的是分层帖子,这意味着我需要有可能拥有此元数据库启用的帖子和子帖子。当