Filter fields through kses upon display. Introduce sanitize_user_object() and sanitize_user_field(). see #10751

git-svn-id: http://svn.automattic.com/wordpress/trunk@11929 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
ryan 2009-09-14 13:57:48 +00:00
parent 3709397168
commit aa1e377ede
9 changed files with 260 additions and 86 deletions

View File

@ -1892,6 +1892,7 @@ function user_row( $user_object, $style = '', $role = '' ) {
if ( !( is_object( $user_object) && is_a( $user_object, 'WP_User' ) ) )
$user_object = new WP_User( (int) $user_object );
$user_object = sanitize_user_object($user_object, 'display');
$email = $user_object->user_email;
$url = $user_object->user_url;
$short_url = str_replace( 'http://', '', $url );

View File

@ -25,15 +25,16 @@ function add_user() {
$user_id = (int) func_get_arg( 0 );
if ( isset( $_POST['role'] ) ) {
$new_role = sanitize_text_field( $_POST['role'] );
// Don't let anyone with 'edit_users' (admins) edit their own role to something without it.
if( $user_id != $current_user->id || $wp_roles->role_objects[$_POST['role']]->has_cap( 'edit_users' ) ) {
if ( $user_id != $current_user->id || $wp_roles->role_objects[$new_role]->has_cap( 'edit_users' ) ) {
// If the new role isn't editable by the logged-in user die with error
$editable_roles = get_editable_roles();
if (!$editable_roles[$_POST['role']])
if ( !$editable_roles[$new_role] )
wp_die(__('You can’t give users that role.'));
$user = new WP_User( $user_id );
$user->set_role( $_POST['role'] );
$user->set_role( $new_role );
}
}
} else {
@ -64,8 +65,8 @@ function edit_user( $user_id = 0 ) {
$user = '';
}
if ( isset( $_POST['user_login'] ))
$user->user_login = esc_html( trim( $_POST['user_login'] ));
if ( !$update && isset( $_POST['user_login'] ) )
$user->user_login = sanitize_user($userdata['user_login'], true);
$pass1 = $pass2 = '';
if ( isset( $_POST['pass1'] ))
@ -74,62 +75,55 @@ function edit_user( $user_id = 0 ) {
$pass2 = $_POST['pass2'];
if ( isset( $_POST['role'] ) && current_user_can( 'edit_users' ) ) {
$new_role = sanitize_text_field( $_POST['role'] );
// Don't let anyone with 'edit_users' (admins) edit their own role to something without it.
if( $user_id != $current_user->id || $wp_roles->role_objects[$_POST['role']]->has_cap( 'edit_users' ))
$user->role = $_POST['role'];
if( $user_id != $current_user->id || $wp_roles->role_objects[$new_role]->has_cap( 'edit_users' ))
$user->role = $new_role;
// If the new role isn't editable by the logged-in user die with error
$editable_roles = get_editable_roles();
if (!$editable_roles[$_POST['role']])
if ( !$editable_roles[$new_role] )
wp_die(__('You can’t give users that role.'));
}
if ( isset( $_POST['email'] ))
$user->user_email = esc_html( trim( $_POST['email'] ));
$user->user_email = sanitize_text_field( $_POST['email'] );
if ( isset( $_POST['url'] ) ) {
if ( empty ( $_POST['url'] ) || $_POST['url'] == 'http://' ) {
$user->user_url = '';
} else {
$user->user_url = esc_url( trim( $_POST['url'] ));
$user->user_url = sanitize_url( $_POST['url'] );
$user->user_url = preg_match('/^(https?|ftps?|mailto|news|irc|gopher|nntp|feed|telnet):/is', $user->user_url) ? $user->user_url : 'http://'.$user->user_url;
}
}
if ( isset( $_POST['first_name'] ))
$user->first_name = esc_html( trim( $_POST['first_name'] ));
if ( isset( $_POST['last_name'] ))
$user->last_name = esc_html( trim( $_POST['last_name'] ));
if ( isset( $_POST['nickname'] ))
$user->nickname = esc_html( trim( $_POST['nickname'] ));
if ( isset( $_POST['display_name'] ))
$user->display_name = esc_html( trim( $_POST['display_name'] ));
if ( isset( $_POST['description'] ))
$user->description = trim( $_POST['description'] );
$user_contactmethods = _wp_get_user_contactmethods();
foreach ($user_contactmethods as $method => $name) {
if ( isset( $_POST[$method] ))
$user->$method = esc_html( trim( $_POST[$method] ) );
}
if ( !$update )
$user->rich_editing = 'true'; // Default to true for new users.
else if ( isset( $_POST['rich_editing'] ) )
$user->rich_editing = $_POST['rich_editing'];
else
$user->rich_editing = 'true';
if ( isset( $_POST['first_name'] ) )
$user->first_name = sanitize_text_field( $_POST['first_name'] );
if ( isset( $_POST['last_name'] ) )
$user->last_name = sanitize_text_field( $_POST['last_name'] );
if ( isset( $_POST['nickname'] ) )
$user->nickname = sanitize_text_field( $_POST['nickname'] );
if ( isset( $_POST['display_name'] ) )
$user->display_name = sanitize_text_field( $_POST['display_name'] );
$user->comment_shortcuts = isset( $_POST['comment_shortcuts'] )? $_POST['comment_shortcuts'] : '';
if ( isset( $_POST['description'] ) )
$user->description = trim( $_POST['description'] );
foreach ( _wp_get_user_contactmethods() as $method => $name ) {
if ( isset( $_POST[$method] ))
$user->$method = sanitize_text_field( $_POST[$method] );
}
if ( $update ) {
$user->rich_editing = isset( $_POST['rich_editing'] ) && 'false' == $_POST['rich_editing'] ? 'false' : 'true';
$user->admin_color = isset( $_POST['admin_color'] ) ? sanitize_text_field( $_POST['admin_color'] ) : 'fresh';
}
$user->comment_shortcuts = isset( $_POST['comment_shortcuts'] ) && 'true' == $_POST['comment_shortcuts'] ? 'true' : '';
$user->use_ssl = 0;
if ( !empty($_POST['use_ssl']) )
$user->use_ssl = 1;
if ( !$update )
$user->admin_color = 'fresh'; // Default to fresh for new users.
else if ( isset( $_POST['admin_color'] ) )
$user->admin_color = $_POST['admin_color'];
else
$user->admin_color = 'fresh';
$errors = new WP_Error();
/* checking that username has been typed */
@ -159,34 +153,34 @@ function edit_user( $user_id = 0 ) {
if ( $pass1 != $pass2 )
$errors->add( 'pass', __( '<strong>ERROR</strong>: Please enter the same password in the two password fields.' ), array( 'form-field' => 'pass1' ) );
if (!empty ( $pass1 ))
if ( !empty( $pass1 ) )
$user->user_pass = $pass1;
if ( !$update && !validate_username( $user->user_login ) )
$errors->add( 'user_login', __( '<strong>ERROR</strong>: This username is invalid. Please enter a valid username.' ));
if (!$update && username_exists( $user->user_login ))
if ( !$update && username_exists( $user->user_login ) )
$errors->add( 'user_login', __( '<strong>ERROR</strong>: This username is already registered. Please choose another one.' ));
/* checking e-mail address */
if ( empty ( $user->user_email ) ) {
if ( empty( $user->user_email ) ) {
$errors->add( 'empty_email', __( '<strong>ERROR</strong>: Please enter an e-mail address.' ), array( 'form-field' => 'email' ) );
} elseif (!is_email( $user->user_email ) ) {
} elseif ( !is_email( $user->user_email ) ) {
$errors->add( 'invalid_email', __( '<strong>ERROR</strong>: The e-mail address isn&#8217;t correct.' ), array( 'form-field' => 'email' ) );
} elseif ( ( $owner_id = email_exists($user->user_email) ) && $owner_id != $user->ID ) {
$errors->add( 'email_exists', __('<strong>ERROR</strong>: This email is already registered, please choose another one.'), array( 'form-field' => 'email' ) );
}
// Allow plugins to return there own errors.
// Allow plugins to return their own errors.
do_action_ref_array('user_profile_update_errors', array ( &$errors, $update, &$user ) );
if ( $errors->get_error_codes() )
return $errors;
if ( $update ) {
$user_id = wp_update_user( get_object_vars( $user ));
$user_id = wp_update_user( get_object_vars( $user ) );
} else {
$user_id = wp_insert_user( get_object_vars( $user ));
$user_id = wp_insert_user( get_object_vars( $user ) );
wp_new_user_notification( $user_id, isset($_POST['send_password']) ? $pass1 : '' );
}
return $user_id;
@ -370,20 +364,17 @@ function get_others_pending($user_id) {
*/
function get_user_to_edit( $user_id ) {
$user = new WP_User( $user_id );
$user->user_login = esc_attr($user->user_login);
$user->user_email = esc_attr($user->user_email);
$user->user_url = esc_url($user->user_url);
$user->first_name = esc_attr($user->first_name);
$user->last_name = esc_attr($user->last_name);
$user->display_name = esc_attr($user->display_name);
$user->nickname = esc_attr($user->nickname);
$user_contactmethods = _wp_get_user_contactmethods();
foreach ($user_contactmethods as $method => $name) {
$user->{$method} = isset( $user->{$method} ) && !empty( $user->{$method} ) ? esc_attr($user->{$method}) : '';
if ( empty( $user->{$method} ) )
$user->{$method} = '';
}
$user->description = isset( $user->description ) && !empty( $user->description ) ? esc_html($user->description) : '';
if ( empty($user->description) )
$user->description = '';
$user = sanitize_user_object($user, 'edit');
return $user;
}

View File

@ -284,7 +284,7 @@ else
<table class="form-table">
<tr>
<th><label for="description"><?php _e('Biographical Info'); ?></label></th>
<td><textarea name="description" id="description" rows="5" cols="30"><?php echo $profileuser->description ?></textarea><br />
<td><textarea name="description" id="description" rows="5" cols="30"><?php echo esc_html($profileuser->description); ?></textarea><br />
<span class="description"><?php _e('Share a little biographical information to fill out your profile. This may be shown publicly.'); ?></span></td>
</tr>
@ -311,16 +311,17 @@ if ( $show_password_fields ) :
}
?>
<?php if (count($profileuser->caps) > count($profileuser->roles) && apply_filters('additional_capabilities_display', true, $profileuser)): ?>
<?php if ( count($profileuser->caps) > count($profileuser->roles) && apply_filters('additional_capabilities_display', true, $profileuser) ) { ?>
<br class="clear" />
<table width="99%" style="border: none;" cellspacing="2" cellpadding="3" class="editform">
<tr>
<th scope="row"><?php _e('Additional Capabilities') ?></th>
<td><?php
$output = '';
foreach($profileuser->caps as $cap => $value) {
if(!$wp_roles->is_role($cap)) {
if($output != '') $output .= ', ';
foreach ( $profileuser->caps as $cap => $value ) {
if ( !$wp_roles->is_role($cap) ) {
if ( $output != '' )
$output .= ', ';
$output .= $value ? $cap : "Denied: {$cap}";
}
}
@ -328,7 +329,7 @@ if ( $show_password_fields ) :
?></td>
</tr>
</table>
<?php endif; ?>
<?php } ?>
<p class="submit">
<input type="hidden" name="action" value="update" />

View File

@ -385,14 +385,6 @@ foreach ( $wp_user_search->get_results() as $userid ) {
</form>
</div>
<?php
foreach ( array('user_login' => 'user_login', 'first_name' => 'user_firstname', 'last_name' => 'user_lastname', 'email' => 'user_email', 'url' => 'user_uri', 'role' => 'user_role') as $formpost => $var ) {
$var = 'new_' . $var;
$$var = isset($_REQUEST[$formpost]) ? esc_attr(stripslashes($_REQUEST[$formpost])) : '';
}
unset($name);
?>
<br class="clear" />
<?php
break;

View File

@ -448,6 +448,15 @@ class WP_User {
*/
var $last_name = '';
/**
* The filter context applied to user data fields.
*
* @since 2.9.0
* @access private
* @var string
*/
var $filter = null;
/**
* PHP4 Constructor - Sets up the object properties.
*

View File

@ -17,19 +17,26 @@ $filters = array('pre_term_name', 'pre_comment_author_name', 'pre_link_name', 'p
'pre_link_rel', 'pre_user_display_name', 'pre_user_first_name', 'pre_user_last_name',
'pre_user_nickname');
foreach ( $filters as $filter ) {
add_filter($filter, 'strip_tags');
add_filter($filter, 'trim');
add_filter($filter, 'sanitize_text_field');
add_filter($filter, 'wp_filter_kses');
add_filter($filter, '_wp_specialchars', 30);
}
// Kses only for textarea saves
$filters = array('pre_term_description', 'pre_link_description', 'pre_link_notes', 'pre_user_description');
// Strip, kses, special chars for string display
$filters = array('term_name', 'comment_author_name', 'link_name', 'link_target', 'link_rel', 'user_display_name', 'user_first_name', 'user_last_name', 'user_nickname');
foreach ( $filters as $filter ) {
add_filter($filter, 'sanitize_text_field');
add_filter($filter, 'wp_filter_kses');
add_filter($filter, '_wp_specialchars', 30);
}
// Kses only for textarea saves and displays
$filters = array('pre_term_description', 'term_description', 'pre_link_description', 'link_description', 'pre_link_notes', 'link_notes', 'pre_user_description', 'user_description');
foreach ( $filters as $filter ) {
add_filter($filter, 'wp_filter_kses');
}
// Email
// Email saves
$filters = array('pre_comment_author_email', 'pre_user_email');
foreach ( $filters as $filter ) {
add_filter($filter, 'trim');
@ -37,12 +44,18 @@ foreach ( $filters as $filter ) {
add_filter($filter, 'wp_filter_kses');
}
// Email display
$filters = array('comment_author_email', 'user_email');
foreach ( $filters as $filter ) {
add_filter($filter, 'sanitize_email');
add_filter($filter, 'wp_filter_kses');
}
// Save URL
$filters = array('pre_comment_author_url', 'pre_user_url', 'pre_link_url', 'pre_link_image',
'pre_link_rss');
foreach ( $filters as $filter ) {
add_filter($filter, 'strip_tags');
add_filter($filter, 'trim');
add_filter($filter, 'wp_strip_all_tags');
add_filter($filter, 'esc_url_raw');
add_filter($filter, 'wp_filter_kses');
}
@ -50,8 +63,7 @@ foreach ( $filters as $filter ) {
// Display URL
$filters = array('user_url', 'link_url', 'link_image', 'link_rss', 'comment_url');
foreach ( $filters as $filter ) {
add_filter($filter, 'strip_tags');
add_filter($filter, 'trim');
add_filter($filter, 'wp_strip_all_tags');
add_filter($filter, 'esc_url');
add_filter($filter, 'wp_filter_kses');
}

View File

@ -628,7 +628,7 @@ function sanitize_file_name( $filename ) {
*/
function sanitize_user( $username, $strict = false ) {
$raw_username = $username;
$username = strip_tags($username);
$username = wp_strip_all_tags($username);
// Kill octets
$username = preg_replace('|%([a-fA-F0-9][a-fA-F0-9])|', '', $username);
$username = preg_replace('/&.+?;/', '', $username); // Kill entities
@ -2245,7 +2245,6 @@ function esc_html( $text ) {
$safe_text = wp_check_invalid_utf8( $text );
$safe_text = _wp_specialchars( $safe_text, ENT_QUOTES );
return apply_filters( 'esc_html', $safe_text, $text );
return $text;
}
/**
@ -2601,7 +2600,7 @@ function wp_sprintf_l($pattern, $args) {
* @return string The excerpt.
*/
function wp_html_excerpt( $str, $count ) {
$str = strip_tags( $str );
$str = wp_strip_all_tags( $str, true );
$str = mb_substr( $str, 0, $count );
// remove part of an entity at the end
$str = preg_replace( '/&[^;\s]{0,6}$/', '', $str );
@ -2668,6 +2667,7 @@ function links_add_target( $content, $target = '_blank', $tags = array('a') ) {
create_function('$m', 'return _links_add_target($m, "' . $target . '");'),
$content);
}
/**
* Callback to add a target attribute to all links in passed content.
*
@ -2692,4 +2692,54 @@ function normalize_whitespace( $str ) {
return $str;
}
/**
* Properly strip all HTML tags including script and style
*
* @since 2.9.0
*
* @param string $string String containing HTML tags
* @param bool $remove_breaks optional Whether to remove left over line breaks and white space chars
* @return string The processed string.
*/
function wp_strip_all_tags($string, $remove_breaks = false) {
$string = preg_replace( '@<(script|style)[^>]*?>.*?</\\1>@si', '', $string );
$string = strip_tags($string);
if ( $remove_breaks )
$string = preg_replace('/\s+/', ' ', $string);
return trim($string);
}
/**
* Sanitize a string from user input or from the db
*
* check for invalid UTF-8,
* Convert single < characters to entity,
* strip all tags,
* remove line breaks, tabs and extra whitre space,
* strip octets.
*
* @since 2.9
*
* @param string $str
* @return string
*/
function sanitize_text_field($str) {
$filtered = wp_check_invalid_utf8( $str );
if ( strpos($filtered, '<') !== false ) {
$filtered = wp_pre_kses_less_than( $filtered );
$filtered = wp_strip_all_tags( $filtered, true );
} else {
$filtered = trim( preg_replace('/\s+/', ' ', $filtered) );
}
$match = array();
while ( preg_match('/%[a-f0-9]{2}/i', $filtered, $match) )
$filtered = str_replace($match[0], '', $filtered);
return apply_filters('sanitize_text_field', $filtered, $str);
}
?>

View File

@ -169,7 +169,7 @@ function wp_insert_user($userdata) {
$user_nicename_check = $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->users WHERE user_nicename = %s AND user_login != %s LIMIT 1" , $user_nicename, $user_login));
if ($user_nicename_check) {
if ( $user_nicename_check ) {
$suffix = 2;
while ($user_nicename_check) {
$alt_user_nicename = $user_nicename . "-$suffix";
@ -198,10 +198,11 @@ function wp_insert_user($userdata) {
update_usermeta( $user_id, 'comment_shortcuts', $comment_shortcuts);
update_usermeta( $user_id, 'admin_color', $admin_color);
update_usermeta( $user_id, 'use_ssl', $use_ssl);
foreach (_wp_get_user_contactmethods() as $method => $name) {
foreach ( _wp_get_user_contactmethods() as $method => $name ) {
if ( empty($$method) )
$$method = '';
update_usermeta( $user_id, $method, $$method );
}

View File

@ -617,4 +617,121 @@ function _fill_user( &$user ) {
wp_cache_add($user->user_nicename, $user->ID, 'userslugs');
}
/**
* Sanitize every user field.
*
* If the context is 'raw', then the user object or array will get minimal santization of the int fields.
*
* @since 2.3.0
* @uses sanitize_user_field() Used to sanitize the fields.
*
* @param object|array $user The User Object or Array
* @param string $context Optional, default is 'display'. How to sanitize user fields.
* @return object|array The now sanitized User Object or Array (will be the same type as $user)
*/
function sanitize_user_object($user, $context = 'display') {
if ( is_object($user) ) {
if ( !isset($user->ID) )
$user->ID = 0;
if ( isset($user->data) )
$vars = get_object_vars( $user->data );
else
$vars = get_object_vars($user);
foreach ( array_keys($vars) as $field ) {
if ( is_array($user->$field) )
continue;
$user->$field = sanitize_user_field($field, $user->$field, $user->ID, $context);
}
$user->filter = $context;
} else {
if ( !isset($user['ID']) )
$user['ID'] = 0;
foreach ( array_keys($user) as $field )
$user[$field] = sanitize_user_field($field, $user[$field], $user['ID'], $context);
$user['filter'] = $context;
}
return $user;
}
/**
* Sanitize user field based on context.
*
* Possible context values are: 'raw', 'edit', 'db', 'display', 'attribute' and 'js'. The
* 'display' context is used by default. 'attribute' and 'js' contexts are treated like 'display'
* when calling filters.
*
* @since 2.3.0
* @uses apply_filters() Calls 'edit_$field' and '${field_no_prefix}_edit_pre' passing $value and
* $user_id if $context == 'edit' and field name prefix == 'user_'.
*
* @uses apply_filters() Calls 'edit_user_$field' passing $value and $user_id if $context == 'db'.
* @uses apply_filters() Calls 'pre_$field' passing $value if $context == 'db' and field name prefix == 'user_'.
* @uses apply_filters() Calls '${field}_pre' passing $value if $context == 'db' and field name prefix != 'user_'.
*
* @uses apply_filters() Calls '$field' passing $value, $user_id and $context if $context == anything
* other than 'raw', 'edit' and 'db' and field name prefix == 'user_'.
* @uses apply_filters() Calls 'user_$field' passing $value if $context == anything other than 'raw',
* 'edit' and 'db' and field name prefix != 'user_'.
*
* @param string $field The user Object field name.
* @param mixed $value The user Object value.
* @param int $user_id user ID.
* @param string $context How to sanitize user fields. Looks for 'raw', 'edit', 'db', 'display',
* 'attribute' and 'js'.
* @return mixed Sanitized value.
*/
function sanitize_user_field($field, $value, $user_id, $context) {
$int_fields = array('ID');
if ( in_array($field, $int_fields) )
$value = (int) $value;
if ( 'raw' == $context )
return $value;
if ( is_array($value) )
return $value;
$prefixed = false;
if ( false !== strpos($field, 'user_') ) {
$prefixed = true;
$field_no_prefix = str_replace('user_', '', $field);
}
if ( 'edit' == $context ) {
if ( $prefixed ) {
$value = apply_filters("edit_$field", $value, $user_id);
} else {
$value = apply_filters("edit_user_$field", $value, $user_id);
}
if ( 'description' == $field )
$value = esc_html($value);
else
$value = esc_attr($value);
} else if ( 'db' == $context ) {
if ( $prefixed ) {
$value = apply_filters("pre_$field", $value);
} else {
$value = apply_filters("pre_user_$field", $value);
}
} else {
// Use display filters by default.
if ( $prefixed )
$value = apply_filters($field, $value, $user_id, $context);
else
$value = apply_filters("user_$field", $value, $user_id, $context);
}
if ( 'user_url' == $field )
$value = esc_url($value);
if ( 'attribute' == $context )
$value = esc_attr($value);
else if ( 'js' == $context )
$value = esc_js($value);
return $value;
}
?>