Compare commits

...

32 Commits
4.0.4 ... 4.0.9

Author SHA1 Message Date
Gary Pendergast
e3f99b30d1 Tag 4.0.9
Built from https://develop.svn.wordpress.org/tags/4.0.9@36210


git-svn-id: http://core.svn.wordpress.org/tags/4.0.9@36177 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2016-01-06 23:38:09 +00:00
Dominik Schilling
2fdd2703ed Bump 4.0 branch to 4.0.9.
Built from https://develop.svn.wordpress.org/branches/4.0@36200


git-svn-id: http://core.svn.wordpress.org/branches/4.0@36167 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2016-01-06 18:50:38 +00:00
Aaron Jorbin
126b1f3caf Theme: Escape error messages
[36185] for 4.0 branch

Built from https://develop.svn.wordpress.org/branches/4.0@36190


git-svn-id: http://core.svn.wordpress.org/branches/4.0@36157 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2016-01-06 17:27:17 +00:00
Dion Hulse
3d3c9ab179 Background Updates: Remove the 7am/7pm background update check.
This changeset is a more basic version of [36180], clearing the extra now redundant schedule.
As the functionality for this was introduced in 3.9, [28129] has been backported to 3.7/3.8, allowing the API TTL to be respected by those versions.

See #27772.
Fixes #35323.

Built from https://develop.svn.wordpress.org/trunk@36184


git-svn-id: http://core.svn.wordpress.org/branches/4.0@36151 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2016-01-06 13:24:33 +00:00
Dion Hulse
c84e59ec6d Update Akismet externals
git-svn-id: http://core.svn.wordpress.org/branches/4.0@35107 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2015-10-13 17:19:01 +00:00
Helen Hou-Sandí
7fd9eac86a Finish bumping the 4.0 branch to 4.0.8.
Built from https://develop.svn.wordpress.org/branches/4.0@34193


git-svn-id: http://core.svn.wordpress.org/branches/4.0@34161 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2015-09-15 14:51:53 +00:00
Helen Hou-Sandí
2cb538bcd1 Bump 4.0 branch to 4.0.8.
Built from https://develop.svn.wordpress.org/branches/4.0@34184


git-svn-id: http://core.svn.wordpress.org/branches/4.0@34152 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2015-09-15 14:29:25 +00:00
Dominik Schilling
b81cdd60a3 XMLRPC: Don't allow private posts to be sticky.
Merge of [33325], [33612], and [34135] to the 4.0 branch.

See #20662.
Built from https://develop.svn.wordpress.org/branches/4.0@34154


git-svn-id: http://core.svn.wordpress.org/branches/4.0@34122 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2015-09-14 23:01:37 +00:00
Nikolay Bachiyski
536f3b6517 Shortcodes: don't allow unclosed HTML elements in attributes
Merges [34134] for 4.0 branch

Built from https://develop.svn.wordpress.org/branches/4.0@34147


git-svn-id: http://core.svn.wordpress.org/branches/4.0@34115 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2015-09-14 22:49:17 +00:00
Nikolay Bachiyski
2a0ec142b2 List tables: escape user e-mails
Merges [34133] for 4.0 branch

Built from https://develop.svn.wordpress.org/branches/4.0@34140


git-svn-id: http://core.svn.wordpress.org/branches/4.0@34108 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2015-09-14 22:43:17 +00:00
Gary Pendergast
21c8cc7e5a WPDB: get_table_from_query() didn't find table names with hyphens in them.
Merge of [33718] to the 4.0 branch.

Props dustinbolton, pento.

See #33470.


Built from https://develop.svn.wordpress.org/branches/4.0@33994


git-svn-id: http://core.svn.wordpress.org/branches/4.0@33963 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2015-09-10 07:05:17 +00:00
Gary Pendergast
4379874534 Capabilities: Fall back to the edit_posts capability for orphaned comments.
Merge of the `capabilities.php` part of [33614] to the 4.0 branch.

Props pento, dd32.

See #33154.


Built from https://develop.svn.wordpress.org/branches/4.0@33974


git-svn-id: http://core.svn.wordpress.org/branches/4.0@33943 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2015-09-09 06:10:38 +00:00
Dominik Schilling
a782df35d7 Bump 4.0 branch to version 4.0.7.
Built from https://develop.svn.wordpress.org/branches/4.0@33575


git-svn-id: http://core.svn.wordpress.org/branches/4.0@33542 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2015-08-04 11:52:35 +00:00
Dion Hulse
b5a80e84fe Fix do_shortcode('<[shortcode]') edge case.
Props miqrogroove.

Merges [33499] to the 4.0 branch.
See #33116.

Built from https://develop.svn.wordpress.org/branches/4.0@33565


git-svn-id: http://core.svn.wordpress.org/branches/4.0@33532 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2015-08-04 07:18:33 +00:00
Dominik Schilling
e8797fc7d0 Comments: IDs are integers.
Merge of [33555] to the 4.0 branch.
Built from https://develop.svn.wordpress.org/branches/4.0@33558


git-svn-id: http://core.svn.wordpress.org/branches/4.0@33525 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2015-08-04 04:59:53 +00:00
Dominik Schilling
acd70d39a4 Themes: Fix some broken links in the legacy theme preview.
Merge of [33549] to the 4.0 branch.
Built from https://develop.svn.wordpress.org/branches/4.0@33551


git-svn-id: http://core.svn.wordpress.org/branches/4.0@33518 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2015-08-04 04:57:43 +00:00
Dominik Schilling
53957f2276 Heartbeat: Ensure post locks are released.
Merge of [33542] to the 4.0 branch.
Built from https://develop.svn.wordpress.org/branches/4.0@33545


git-svn-id: http://core.svn.wordpress.org/branches/4.0@33512 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2015-08-04 04:55:53 +00:00
Dominik Schilling
9e21a4aaf5 Customizer: Use hash_equals() for widgets.
Merge of [33535] to the 4.0 branch.
Built from https://develop.svn.wordpress.org/branches/4.0@33538


git-svn-id: http://core.svn.wordpress.org/branches/4.0@33505 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2015-08-04 04:53:08 +00:00
Dominik Schilling
30df27a0c7 Nav menus: Consistent titles in widgets.
Merge of [33529] to the 4.0 branch.
Built from https://develop.svn.wordpress.org/branches/4.0@33531


git-svn-id: http://core.svn.wordpress.org/branches/4.0@33498 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2015-08-03 20:58:37 +00:00
Andrew Ozz
5b23ca5d93 Backport r33469 and r33470 to 4.0.
See #33106.
Built from https://develop.svn.wordpress.org/branches/4.0@33522


git-svn-id: http://core.svn.wordpress.org/branches/4.0@33489 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2015-07-31 01:44:36 +00:00
Gary Pendergast
b3356b6f77 Bump 4.0 branch to version 4.0.6.
Built from https://develop.svn.wordpress.org/branches/4.0@33397


git-svn-id: http://core.svn.wordpress.org/branches/4.0@33365 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2015-07-23 11:07:33 +00:00
Gary Pendergast
60eb789f93 Shortcodes: Improve the reliablity of shortcodes inside HTML tags.
Merge of [33359] to the 4.0 branch.

Props miqrogroove.

See #15694.


Built from https://develop.svn.wordpress.org/branches/4.0@33381


git-svn-id: http://core.svn.wordpress.org/branches/4.0@33352 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2015-07-23 04:50:37 +00:00
Gary Pendergast
5d196f2b09 Capabilities: When creating an auto-draft, ensure that the current user still has permission to do so.
Merge of [33357] to the 4.0 branch.


Built from https://develop.svn.wordpress.org/branches/4.0@33376


git-svn-id: http://core.svn.wordpress.org/branches/4.0@33347 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2015-07-23 04:01:36 +00:00
Dominik Schilling
9e426bbb49 4.0.5 version bumps.
Built from https://develop.svn.wordpress.org/branches/4.0@32436


git-svn-id: http://core.svn.wordpress.org/branches/4.0@32406 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2015-05-06 23:28:36 +00:00
Michael Adams
cfd130d33a Upgrade: $wpdb->get_col_length() sanity check: bail on unexpected return value.
Merges [32429] for the 4.0 branch.

See #32165.

Built from https://develop.svn.wordpress.org/branches/4.0@32432


git-svn-id: http://core.svn.wordpress.org/branches/4.0@32402 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2015-05-06 23:13:58 +00:00
Michael Adams
551057bb68 Upgrade: Ensure unintelligible DB schemas don't result in content loss.
Merge of [32417] to the 4.0 branch.

See #32165.

Props ocean90.

Built from https://develop.svn.wordpress.org/branches/4.0@32420


git-svn-id: http://core.svn.wordpress.org/branches/4.0@32390 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2015-05-06 21:52:03 +00:00
John Blackbourn
6dbcbfae60 WPDB: Allow queries to reference tables in the dbname.tablename format, and allow table names to contain any valid character, rather than just ASCII.
Merge of [32368] to the 4.0 branch.

Props pento, willstedt for the initial patch.

See #32090.

Built from https://develop.svn.wordpress.org/branches/4.0@32413


git-svn-id: http://core.svn.wordpress.org/branches/4.0@32383 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2015-05-06 21:04:34 +00:00
Aaron Jorbin
a820c920f9 When upgrading WordPress remove genericons example.html files
[32385] for 4.0 branch

Props @dd32, @boonebgorges, @johnjamesjacoby, @drewapicture, @jorbin


Built from https://develop.svn.wordpress.org/branches/4.0@32404


git-svn-id: http://core.svn.wordpress.org/branches/4.0@32374 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2015-05-06 20:05:33 +00:00
Dominik Schilling
c9168e3a54 WPDB: When sanity checking query character sets, there's no need to check queries that don't return user data.
Merges [32374] to the 4.0 branch.

props pento.
see #32104.
Built from https://develop.svn.wordpress.org/branches/4.0@32403


git-svn-id: http://core.svn.wordpress.org/branches/4.0@32373 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2015-05-06 20:04:38 +00:00
Helen Hou-Sandí
69de48fd72 The UTF-8 regex can occasionally fail on very low memory machines. Reduce the amount of memory it uses.
Merges [32375] to the 4.0 branch.

props pento.
See #32204.

Built from https://develop.svn.wordpress.org/branches/4.0@32397


git-svn-id: http://core.svn.wordpress.org/branches/4.0@32367 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2015-05-06 19:43:37 +00:00
Michael Adams
7e35f92679 WPDB: When checking that a string can be sent to MySQL, we shouldn't use mb_convert_encoding(), as it behaves differently to MySQL's character encoding conversion.
Merge of [32364] to the 4.0 branch.

Props mdawaffe, pento, nbachiyski, jorbin, johnjamesjacoby, jeremyfelt.

See #32165.

Built from https://develop.svn.wordpress.org/branches/4.0@32388


git-svn-id: http://core.svn.wordpress.org/branches/4.0@32358 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2015-05-06 19:09:39 +00:00
Andrew Ozz
d6df175451 TinyMCE: work-around a bug in the tags matching regex.
For 4.0.
Built from https://develop.svn.wordpress.org/branches/4.0@32372


git-svn-id: http://core.svn.wordpress.org/branches/4.0@32342 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2015-05-06 05:34:38 +00:00
29 changed files with 990 additions and 220 deletions

View File

@@ -9,7 +9,7 @@
<body>
<h1 id="logo">
<a href="https://wordpress.org/"><img alt="WordPress" src="wp-admin/images/wordpress-logo.png" /></a>
<br /> Version 4.0.4
<br /> Version 4.0.9
</h1>
<p style="text-align: center">Semantic Personal Publishing Platform</p>

View File

@@ -42,10 +42,30 @@ include( ABSPATH . 'wp-admin/admin-header.php' );
</h2>
<div class="changelog point-releases">
<h3><?php echo _n( 'Maintenance and Security Release', 'Maintenance and Security Releases', 4 ); ?></h3>
<h3><?php echo _n( 'Maintenance and Security Release', 'Maintenance and Security Releases', 9 ); ?></h3>
<p><?php printf( _n( '<strong>Version %1$s</strong> addressed a security issue.',
'<strong>Version %1$s</strong> addressed some security issues.', 1 ), '4.0.9' ); ?>
<?php printf( __( 'For more information, see <a href="%s">the release notes</a>.' ), 'https://codex.wordpress.org/Version_4.0.9' ); ?>
</p>
<p><?php printf( _n( '<strong>Version %1$s</strong> addressed some security issues and fixed %2$s bug.',
'<strong>Version %1$s</strong> addressed some security issues and fixed %2$s bugs.', 2 ), '4.0.8', number_format_i18n( 2 ) ); ?>
<?php printf( __( 'For more information, see <a href="%s">the release notes</a>.' ), 'https://codex.wordpress.org/Version_4.0.8' ); ?>
</p>
<p><?php printf( _n( '<strong>Version %1$s</strong> addressed some security issues and fixed %2$s bug.',
'<strong>Version %1$s</strong> addressed some security issues and fixed %2$s bugs.', 2 ), '4.0.7', number_format_i18n( 2 ) ); ?>
<?php printf( __( 'For more information, see <a href="%s">the release notes</a>.' ), 'https://codex.wordpress.org/Version_4.0.7' ); ?>
</p>
<p><?php printf( _n( '<strong>Version %1$s</strong> addressed a security issue.',
'<strong>Version %1$s</strong> addressed some security issues.', 2 ), '4.0.6' ); ?>
<?php printf( __( 'For more information, see <a href="%s">the release notes</a>.' ), 'https://codex.wordpress.org/Version_4.0.6' ); ?>
</p>
<p><?php printf( _n( '<strong>Version %1$s</strong> addressed some security issues and fixed %2$s bug.',
'<strong>Version %1$s</strong> addressed some security issues and fixed %2$s bugs.', 3 ), '4.0.5', number_format_i18n( 3 ) ); ?>
<?php printf( __( 'For more information, see <a href="%s">the release notes</a>.' ), 'https://codex.wordpress.org/Version_4.0.5' ); ?>
</p>
<p><?php printf( _n( '<strong>Version %1$s</strong> addressed a security issue.',
'<strong>Version %1$s</strong> addressed some security issues.', 1 ), '4.0.4' ); ?>
<?php printf( __( 'For more information, see <a href="%s">the release notes</a>.' ), 'http://codex.wordpress.org/Version_4.0.4' ); ?>
<?php printf( __( 'For more information, see <a href="%s">the release notes</a>.' ), 'https://codex.wordpress.org/Version_4.0.4' ); ?>
</p>
<p><?php printf( _n( '<strong>Version %1$s</strong> addressed %2$s bug.',
'<strong>Version %1$s</strong> addressed %2$s bugs.', 1 ), '4.0.3', number_format_i18n( 1 ) ); ?>
@@ -53,11 +73,11 @@ include( ABSPATH . 'wp-admin/admin-header.php' );
</p>
<p><?php printf( _n( '<strong>Version %1$s</strong> addressed a security issue.',
'<strong>Version %1$s</strong> addressed some security issues.', 8 ), '4.0.2' ); ?>
<?php printf( __( 'For more information, see <a href="%s">the release notes</a>.' ), 'http://codex.wordpress.org/Version_4.0.2' ); ?>
<?php printf( __( 'For more information, see <a href="%s">the release notes</a>.' ), 'https://codex.wordpress.org/Version_4.0.2' ); ?>
</p>
<p><?php printf( _n( '<strong>Version %1$s</strong> addressed some security issues and fixed %2$s bug.',
'<strong>Version %1$s</strong> addressed some security issues and fixed %2$s bugs.', 23 ), '4.0.1', number_format_i18n( 23 ) ); ?>
<?php printf( __( 'For more information, see <a href="%s">the release notes</a>.' ), 'http://codex.wordpress.org/Version_4.0.1' ); ?>
<?php printf( __( 'For more information, see <a href="%s">the release notes</a>.' ), 'https://codex.wordpress.org/Version_4.0.1' ); ?>
</p>
</div>

View File

@@ -1529,10 +1529,12 @@ function wp_ajax_inline_save() {
$data['parent_id'] = $data['post_parent'];
// Status.
if ( isset($data['keep_private']) && 'private' == $data['keep_private'] )
if ( isset( $data['keep_private'] ) && 'private' == $data['keep_private'] ) {
$data['visibility'] = 'private';
$data['post_status'] = 'private';
else
} else {
$data['post_status'] = $data['_status'];
}
if ( empty($data['comment_status']) )
$data['comment_status'] = 'closed';

View File

@@ -221,7 +221,7 @@ class WP_MS_Users_List_Table extends WP_List_Table {
break;
case 'email':
echo "<td $attributes><a href='mailto:$user->user_email'>$user->user_email</a></td>";
echo "<td $attributes><a href='" . esc_url( "mailto:$user->user_email" ) . "'>$user->user_email</a></td>";
break;
case 'registered':

View File

@@ -419,7 +419,7 @@ class WP_Users_List_Table extends WP_List_Table {
$r .= "<td $attributes>$user_object->first_name $user_object->last_name</td>";
break;
case 'email':
$r .= "<td $attributes><a href='mailto:$email' title='" . esc_attr( sprintf( __( 'E-mail: %s' ), $email ) ) . "'>$email</a></td>";
$r .= "<td $attributes><a href='" . esc_url( "mailto:$email" ) . "' title='" . esc_attr( sprintf( __( 'E-mail: %s' ), $email ) ) . "'>$email</a></td>";
break;
case 'role':
$r .= "<td $attributes>$role_name</td>";

View File

@@ -416,6 +416,10 @@ function wp_network_dashboard_right_now() {
function wp_dashboard_quick_press( $error_msg = false ) {
global $post_ID;
if ( ! current_user_can( 'edit_posts' ) ) {
return;
}
/* Check if a new auto-draft (= no new post_ID) is needed or if the old can be used */
$last_post_id = (int) get_user_option( 'dashboard_quick_press_last_post_id' ); // Get the last post_ID
if ( $last_post_id ) {

View File

@@ -1477,7 +1477,7 @@ function _admin_notice_post_locked() {
// Allow plugins to prevent some users overriding the post lock
if ( $override ) {
?>
<a class="button button-primary wp-tab-last" href="<?php echo esc_url( add_query_arg( 'get-post-lock', '1', get_edit_post_link( $post->ID, 'url' ) ) ); ?>"><?php _e('Take over'); ?></a>
<a class="button button-primary wp-tab-last" href="<?php echo esc_url( add_query_arg( 'get-post-lock', '1', wp_nonce_url( get_edit_post_link( $post->ID, 'url' ), 'lock-post_' . $post->ID ) ) ); ?>"><?php _e('Take over'); ?></a>
<?php
}

View File

@@ -1011,6 +1011,9 @@ function update_core($from, $to) {
$wp_filesystem->delete($old_file, true);
}
// Remove any Genericons example.html's from the filesystem
_upgrade_422_remove_genericons();
// Upgrade DB with separate request
/** This filter is documented in wp-admin/includes/update-core.php */
apply_filters( 'update_feedback', __( 'Upgrading database&#8230;' ) );
@@ -1149,3 +1152,67 @@ window.location = 'about.php?updated';
exit();
}
add_action( '_core_updated_successfully', '_redirect_to_about_wordpress' );
/**
* Cleans up Genericons example files.
*
* @since 4.2.2
*/
function _upgrade_422_remove_genericons() {
global $wp_theme_directories, $wp_filesystem;
// A list of the affected files using the filesystem absolute paths.
$affected_files = array();
// Themes
foreach ( $wp_theme_directories as $directory ) {
$affected_theme_files = _upgrade_422_find_genericons_files_in_folder( $directory );
$affected_files = array_merge( $affected_files, $affected_theme_files );
}
// Plugins
$affected_plugin_files = _upgrade_422_find_genericons_files_in_folder( WP_PLUGIN_DIR );
$affected_files = array_merge( $affected_files, $affected_plugin_files );
foreach ( $affected_files as $file ) {
$gen_dir = $wp_filesystem->find_folder( trailingslashit( dirname( $file ) ) );
if ( empty( $gen_dir ) ) {
continue;
}
// The path when the file is accessed via WP_Filesystem may differ in the case of FTP
$remote_file = $gen_dir . basename( $file );
if ( ! $wp_filesystem->exists( $remote_file ) ) {
continue;
}
if ( ! $wp_filesystem->delete( $remote_file, false, 'f' ) ) {
$wp_filesystem->put_contents( $remote_file, '' );
}
}
}
/**
* Recursively find Genericons example files in a given folder.
*
* @ignore
* @since 4.2.2
*
* @param string $directory Directory path. Expects trailingslashed.
* @return array
*/
function _upgrade_422_find_genericons_files_in_folder( $directory ) {
$directory = trailingslashit( $directory );
$files = array();
if ( file_exists( "{$directory}example.html" ) && false !== strpos( file_get_contents( "{$directory}example.html" ), '<title>Genericons</title>' ) ) {
$files[] = "{$directory}example.html";
}
foreach ( glob( $directory . '*', GLOB_ONLYDIR ) as $dir ) {
$files = array_merge( $files, _upgrade_422_find_genericons_files_in_folder( $dir ) );
}
return $files;
}

View File

@@ -440,8 +440,8 @@ function upgrade_all() {
if ( $wp_current_db_version < 29630 )
upgrade_400();
if ( $wp_current_db_version < 29631 )
upgrade_404();
if ( $wp_current_db_version < 29632 )
upgrade_405();
maybe_disable_link_manager();
@@ -1335,19 +1335,48 @@ function upgrade_400() {
* @since 4.0.4
*/
function upgrade_404() {
}
/**
* Execute changes made in WordPress 4.0.5.
*
* @since 4.0.5
*/
function upgrade_405() {
global $wp_current_db_version, $wpdb;
if ( $wp_current_db_version < 29631 ) {
if ( $wp_current_db_version < 29632 ) {
$content_length = $wpdb->get_col_length( $wpdb->comments, 'comment_content' );
if ( ! $content_length ) {
$content_length = 65535;
if ( is_wp_error( $content_length ) ) {
return;
}
if ( false === $content_length ) {
$content_length = array(
'type' => 'byte',
'length' => 65535,
);
} elseif ( ! is_array( $content_length ) ) {
$length = (int) $content_length > 0 ? (int) $content_length : 65535;
$content_length = array(
'type' => 'byte',
'length' => $length
);
}
if ( 'byte' !== $content_length['type'] || 0 === $content_length['length'] ) {
// Sites with malformed DB schemas are on their own.
return;
}
$allowed_length = intval( $content_length['length'] ) - 10;
$comments = $wpdb->get_results(
"SELECT comment_ID FROM $wpdb->comments
WHERE comment_date_gmt > '2015-04-26'
AND CHAR_LENGTH( comment_content ) >= $content_length
AND ( comment_content LIKE '%<%' OR comment_content LIKE '%>%' )"
"SELECT `comment_ID` FROM `{$wpdb->comments}`
WHERE `comment_date_gmt` > '2015-04-26'
AND LENGTH( `comment_content` ) >= {$allowed_length}
AND ( `comment_content` LIKE '%<%' OR `comment_content` LIKE '%>%' )"
);
foreach ( $comments as $comment ) {

View File

@@ -113,8 +113,9 @@ case 'post-quickdraft-save':
if ( ! wp_verify_nonce( $nonce, 'add-post' ) )
$error_msg = __( 'Unable to submit this form, please refresh and try again.' );
if ( ! current_user_can( 'edit_posts' ) )
$error_msg = __( 'Oops, you don&#8217;t have access to add new drafts.' );
if ( ! current_user_can( 'edit_posts' ) ) {
exit;
}
if ( $error_msg )
return wp_dashboard_quick_press( $error_msg );
@@ -157,6 +158,7 @@ case 'edit':
wp_die( __( 'You can&#8217;t edit this item because it is in the Trash. Please restore it and try again.' ) );
if ( ! empty( $_GET['get-post-lock'] ) ) {
check_admin_referer( 'lock-post_' . $post_id );
wp_set_post_lock( $post_id );
wp_redirect( get_edit_post_link( $post_id, 'url' ) );
exit();

View File

@@ -1114,8 +1114,10 @@ function map_meta_cap( $cap, $user_id ) {
case 'edit_post':
case 'edit_page':
$post = get_post( $args[0] );
if ( empty( $post ) )
if ( empty( $post ) ) {
$caps[] = 'do_not_allow';
break;
}
if ( 'revision' == $post->post_type ) {
$post = get_post( $post->post_parent );
@@ -1229,7 +1231,16 @@ function map_meta_cap( $cap, $user_id ) {
if ( empty( $comment ) )
break;
$post = get_post( $comment->comment_post_ID );
$caps = map_meta_cap( 'edit_post', $user_id, $post->ID );
/*
* If the post doesn't exist, we have an orphaned comment.
* Fall back to the edit_posts capability, instead.
*/
if ( $post ) {
$caps = map_meta_cap( 'edit_post', $user_id, $post->ID );
} else {
$caps = map_meta_cap( 'edit_posts', $user_id );
}
break;
case 'unfiltered_upload':
if ( defined('ALLOW_UNFILTERED_UPLOADS') && ALLOW_UNFILTERED_UPLOADS && ( !is_multisite() || is_super_admin( $user_id ) ) )

View File

@@ -1195,7 +1195,7 @@ final class WP_Customize_Widgets {
return null;
}
if ( $this->get_instance_hash_key( $decoded ) !== $value['instance_hash_key'] ) {
if ( ! hash_equals( $this->get_instance_hash_key( $decoded ), $value['instance_hash_key'] ) ) {
return null;
}

View File

@@ -60,7 +60,7 @@ class WP_Embed {
add_shortcode( 'embed', array( $this, 'shortcode' ) );
// Do the shortcode (only the [embed] one is registered)
$content = do_shortcode( $content );
$content = do_shortcode( $content, true );
// Put the original shortcodes back
$shortcode_tags = $orig_shortcode_tags;
@@ -326,7 +326,14 @@ class WP_Embed {
* @return string Potentially modified $content.
*/
public function autoembed( $content ) {
return preg_replace_callback( '|^\s*(https?://[^\s"]+)\s*$|im', array( $this, 'autoembed_callback' ), $content );
// Replace line breaks from all HTML elements with placeholders.
$content = wp_replace_in_html_tags( $content, array( "\n" => '<!-- wp-line-break -->' ) );
// Find URLs that are on their own line.
$content = preg_replace_callback( '|^\s*(https?://[^\s"]+)\s*$|im', array( $this, 'autoembed_callback' ), $content );
// Put the line breaks back.
return str_replace( '<!-- wp-line-break -->', "\n", $content );
}
/**

View File

@@ -216,7 +216,7 @@ final class WP_Theme implements ArrayAccess {
} elseif ( ! file_exists( $this->theme_root . '/' . $theme_file ) ) {
$this->headers['Name'] = $this->stylesheet;
if ( ! file_exists( $this->theme_root . '/' . $this->stylesheet ) )
$this->errors = new WP_Error( 'theme_not_found', sprintf( __( 'The theme directory "%s" does not exist.' ), $this->stylesheet ) );
$this->errors = new WP_Error( 'theme_not_found', sprintf( __( 'The theme directory "%s" does not exist.' ), esc_html( $this->stylesheet ) ) );
else
$this->errors = new WP_Error( 'theme_no_stylesheet', __( 'Stylesheet is missing.' ) );
$this->template = $this->stylesheet;
@@ -263,7 +263,7 @@ final class WP_Theme implements ArrayAccess {
$theme_root_template = $directories[ $this->template ]['theme_root'];
} else {
// Parent theme is missing.
$this->errors = new WP_Error( 'theme_no_parent', sprintf( __( 'The parent theme is missing. Please install the "%s" parent theme.' ), $this->template ) );
$this->errors = new WP_Error( 'theme_no_parent', sprintf( __( 'The parent theme is missing. Please install the "%s" parent theme.' ), esc_html( $this->template ) ) );
$this->cache_add( 'theme', array( 'headers' => $this->headers, 'errors' => $this->errors, 'stylesheet' => $this->stylesheet, 'template' => $this->template ) );
$this->parent = new WP_Theme( $this->template, $this->theme_root, $this );
return;
@@ -275,11 +275,11 @@ final class WP_Theme implements ArrayAccess {
// If we are a parent, then there is a problem. Only two generations allowed! Cancel things out.
if ( is_a( $_child, 'WP_Theme' ) && $_child->template == $this->stylesheet ) {
$_child->parent = null;
$_child->errors = new WP_Error( 'theme_parent_invalid', sprintf( __( 'The "%s" theme is not a valid parent theme.' ), $_child->template ) );
$_child->errors = new WP_Error( 'theme_parent_invalid', sprintf( __( 'The "%s" theme is not a valid parent theme.' ), esc_html( $_child->template ) ) );
$_child->cache_add( 'theme', array( 'headers' => $_child->headers, 'errors' => $_child->errors, 'stylesheet' => $_child->stylesheet, 'template' => $_child->template ) );
// The two themes actually reference each other with the Template header.
if ( $_child->stylesheet == $this->template ) {
$this->errors = new WP_Error( 'theme_parent_invalid', sprintf( __( 'The "%s" theme is not a valid parent theme.' ), $this->template ) );
$this->errors = new WP_Error( 'theme_parent_invalid', sprintf( __( 'The "%s" theme is not a valid parent theme.' ), esc_html( $this->template ) ) );
$this->cache_add( 'theme', array( 'headers' => $this->headers, 'errors' => $this->errors, 'stylesheet' => $this->stylesheet, 'template' => $this->template ) );
}
return;

View File

@@ -1138,6 +1138,56 @@ class wp_xmlrpc_server extends IXR_Server {
return $count > 1;
}
private function _validate_boolean( $var ) {
if ( is_bool( $var ) ) {
return $var;
}
if ( is_string( $var ) && 'false' === strtolower( $var ) ) {
return false;
}
return (bool) $var;
}
/**
* Encapsulate the logic for sticking a post
* and determining if the user has permission to do so
*
* @since 4.3.0
* @access private
*
* @param array $post_data
* @param bool $update
* @return void|IXR_Error
*/
private function _toggle_sticky( $post_data, $update = false ) {
$post_type = get_post_type_object( $post_data['post_type'] );
// Private and password-protected posts cannot be stickied.
if ( 'private' === $post_data['post_status'] || ! empty( $post_data['post_password'] ) ) {
// Error if the client tried to stick the post, otherwise, silently unstick.
if ( ! empty( $post_data['sticky'] ) ) {
return new IXR_Error( 401, __( 'Sorry, you cannot stick a private post.' ) );
}
if ( $update ) {
unstick_post( $post_data['ID'] );
}
} elseif ( isset( $post_data['sticky'] ) ) {
if ( ! current_user_can( $post_type->cap->edit_others_posts ) ) {
return new IXR_Error( 401, __( 'Sorry, you are not allowed to stick this post.' ) );
}
$sticky = $this->_validate_boolean( $post_data['sticky'] );
if ( $sticky ) {
stick_post( $post_data['ID'] );
} else {
unstick_post( $post_data['ID'] );
}
}
}
/**
* Helper method for wp_newPost and wp_editPost, containing shared logic.
*
@@ -1230,20 +1280,9 @@ class wp_xmlrpc_server extends IXR_Server {
$post_ID = $post_data['ID'];
if ( $post_data['post_type'] == 'post' ) {
// Private and password-protected posts cannot be stickied.
if ( $post_data['post_status'] == 'private' || ! empty( $post_data['post_password'] ) ) {
// Error if the client tried to stick the post, otherwise, silently unstick.
if ( ! empty( $post_data['sticky'] ) )
return new IXR_Error( 401, __( 'Sorry, you cannot stick a private post.' ) );
if ( $update )
unstick_post( $post_ID );
} elseif ( isset( $post_data['sticky'] ) ) {
if ( ! current_user_can( $post_type->cap->edit_others_posts ) )
return new IXR_Error( 401, __( 'Sorry, you are not allowed to stick this post.' ) );
if ( $post_data['sticky'] )
stick_post( $post_ID );
else
unstick_post( $post_ID );
$error = $this->_toggle_sticky( $post_data, $update );
if ( $error ) {
return $error;
}
}
@@ -4617,10 +4656,12 @@ class wp_xmlrpc_server extends IXR_Server {
// Only posts can be sticky
if ( $post_type == 'post' && isset( $content_struct['sticky'] ) ) {
if ( $content_struct['sticky'] == true )
stick_post( $post_ID );
elseif ( $content_struct['sticky'] == false )
unstick_post( $post_ID );
$data = $postdata;
$data['sticky'] = $content_struct['sticky'];
$error = $this->_toggle_sticky( $data );
if ( $error ) {
return $error;
}
}
if ( isset($content_struct['custom_fields']) )
@@ -4902,11 +4943,12 @@ class wp_xmlrpc_server extends IXR_Server {
$tags_input = isset( $content_struct['mt_keywords'] ) ? $content_struct['mt_keywords'] : null;
if ( ('publish' == $post_status) ) {
if ( ( 'page' == $post_type ) && !current_user_can('publish_pages') )
return new IXR_Error(401, __('Sorry, you do not have the right to publish this page.'));
else if ( !current_user_can('publish_posts') )
return new IXR_Error(401, __('Sorry, you do not have the right to publish this post.'));
if ( 'publish' == $post_status || 'private' == $post_status ) {
if ( 'page' == $post_type && ! current_user_can( 'publish_pages' ) ) {
return new IXR_Error( 401, __( 'Sorry, you do not have the right to publish this page.' ) );
} elseif ( ! current_user_can( 'publish_posts' ) ) {
return new IXR_Error( 401, __( 'Sorry, you do not have the right to publish this post.' ) );
}
}
if ( $post_more )
@@ -4946,10 +4988,13 @@ class wp_xmlrpc_server extends IXR_Server {
// Only posts can be sticky
if ( $post_type == 'post' && isset( $content_struct['sticky'] ) ) {
if ( $content_struct['sticky'] == true )
stick_post( $post_ID );
elseif ( $content_struct['sticky'] == false )
unstick_post( $post_ID );
$data = $newpost;
$data['sticky'] = $content_struct['sticky'];
$data['post_type'] = 'post';
$error = $this->_toggle_sticky( $data, true );
if ( $error ) {
return $error;
}
}
if ( isset($content_struct['custom_fields']) )

View File

@@ -13,23 +13,141 @@ if ( !function_exists('_') ) {
}
}
if ( !function_exists('mb_substr') ):
function mb_substr( $str, $start, $length=null, $encoding=null ) {
return _mb_substr($str, $start, $length, $encoding);
/**
* Returns whether PCRE/u (PCRE_UTF8 modifier) is available for use.
*
* @ignore
* @since 4.2.2
* @access private
*
* @param bool $set - Used for testing only
* null : default - get PCRE/u capability
* false : Used for testing - return false for future calls to this function
* 'reset': Used for testing - restore default behavior of this function
*/
function _wp_can_use_pcre_u( $set = null ) {
static $utf8_pcre = 'reset';
if ( null !== $set ) {
$utf8_pcre = $set;
}
if ( 'reset' === $utf8_pcre ) {
$utf8_pcre = @preg_match( '/^./u', 'a' );
}
return $utf8_pcre;
}
if ( ! function_exists( 'mb_substr' ) ) :
function mb_substr( $str, $start, $length = null, $encoding = null ) {
return _mb_substr( $str, $start, $length, $encoding );
}
endif;
function _mb_substr( $str, $start, $length=null, $encoding=null ) {
// the solution below, works only for utf-8, so in case of a different
// charset, just use built-in substr
$charset = get_option( 'blog_charset' );
if ( !in_array( $charset, array('utf8', 'utf-8', 'UTF8', 'UTF-8') ) ) {
return is_null( $length )? substr( $str, $start ) : substr( $str, $start, $length);
/*
* Only understands UTF-8 and 8bit. All other character sets will be treated as 8bit.
* For $encoding === UTF-8, the $str input is expected to be a valid UTF-8 byte sequence.
* The behavior of this function for invalid inputs is undefined.
*/
function _mb_substr( $str, $start, $length = null, $encoding = null ) {
if ( null === $encoding ) {
$encoding = get_option( 'blog_charset' );
}
// use the regex unicode support to separate the UTF-8 characters into an array
preg_match_all( '/./us', $str, $match );
$chars = is_null( $length )? array_slice( $match[0], $start ) : array_slice( $match[0], $start, $length );
return implode( '', $chars );
// The solution below works only for UTF-8,
// so in case of a different charset just use built-in substr()
if ( ! in_array( $encoding, array( 'utf8', 'utf-8', 'UTF8', 'UTF-8' ) ) ) {
return is_null( $length ) ? substr( $str, $start ) : substr( $str, $start, $length );
}
if ( _wp_can_use_pcre_u() ) {
// Use the regex unicode support to separate the UTF-8 characters into an array
preg_match_all( '/./us', $str, $match );
$chars = is_null( $length ) ? array_slice( $match[0], $start ) : array_slice( $match[0], $start, $length );
return implode( '', $chars );
}
$regex = '/(
[\x00-\x7F] # single-byte sequences 0xxxxxxx
| [\xC2-\xDF][\x80-\xBF] # double-byte sequences 110xxxxx 10xxxxxx
| \xE0[\xA0-\xBF][\x80-\xBF] # triple-byte sequences 1110xxxx 10xxxxxx * 2
| [\xE1-\xEC][\x80-\xBF]{2}
| \xED[\x80-\x9F][\x80-\xBF]
| [\xEE-\xEF][\x80-\xBF]{2}
| \xF0[\x90-\xBF][\x80-\xBF]{2} # four-byte sequences 11110xxx 10xxxxxx * 3
| [\xF1-\xF3][\x80-\xBF]{3}
| \xF4[\x80-\x8F][\x80-\xBF]{2}
)/x';
$chars = array( '' ); // Start with 1 element instead of 0 since the first thing we do is pop
do {
// We had some string left over from the last round, but we counted it in that last round.
array_pop( $chars );
// Split by UTF-8 character, limit to 1000 characters (last array element will contain the rest of the string)
$pieces = preg_split( $regex, $str, 1000, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY );
$chars = array_merge( $chars, $pieces );
} while ( count( $pieces ) > 1 && $str = array_pop( $pieces ) ); // If there's anything left over, repeat the loop.
return join( '', array_slice( $chars, $start, $length ) );
}
if ( ! function_exists( 'mb_strlen' ) ) :
function mb_strlen( $str, $encoding = null ) {
return _mb_strlen( $str, $encoding );
}
endif;
/*
* Only understands UTF-8 and 8bit. All other character sets will be treated as 8bit.
* For $encoding === UTF-8, the $str input is expected to be a valid UTF-8 byte sequence.
* The behavior of this function for invalid inputs is undefined.
*/
function _mb_strlen( $str, $encoding = null ) {
if ( null === $encoding ) {
$encoding = get_option( 'blog_charset' );
}
// The solution below works only for UTF-8,
// so in case of a different charset just use built-in strlen()
if ( ! in_array( $encoding, array( 'utf8', 'utf-8', 'UTF8', 'UTF-8' ) ) ) {
return strlen( $str );
}
if ( _wp_can_use_pcre_u() ) {
// Use the regex unicode support to separate the UTF-8 characters into an array
preg_match_all( '/./us', $str, $match );
return count( $match[0] );
}
$regex = '/(?:
[\x00-\x7F] # single-byte sequences 0xxxxxxx
| [\xC2-\xDF][\x80-\xBF] # double-byte sequences 110xxxxx 10xxxxxx
| \xE0[\xA0-\xBF][\x80-\xBF] # triple-byte sequences 1110xxxx 10xxxxxx * 2
| [\xE1-\xEC][\x80-\xBF]{2}
| \xED[\x80-\x9F][\x80-\xBF]
| [\xEE-\xEF][\x80-\xBF]{2}
| \xF0[\x90-\xBF][\x80-\xBF]{2} # four-byte sequences 11110xxx 10xxxxxx * 3
| [\xF1-\xF3][\x80-\xBF]{3}
| \xF4[\x80-\x8F][\x80-\xBF]{2}
)/x';
$count = 1; // Start at 1 instead of 0 since the first thing we do is decrement
do {
// We had some string left over from the last round, but we counted it in that last round.
$count--;
// Split by UTF-8 character, limit to 1000 characters (last array element will contain the rest of the string)
$pieces = preg_split( $regex, $str, 1000 );
// Increment
$count += count( $pieces );
} while ( $str = array_pop( $pieces ) ); // If there's anything left over, repeat the loop.
// Fencepost: preg_split() always returns one extra item in the array
return --$count;
}
if ( !function_exists('hash_hmac') ):

View File

@@ -1354,7 +1354,7 @@ class WP_Widget_Tag_Cloud extends WP_Widget {
?>
<p>
<label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:') ?></label>
<input type="text" class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" value="<?php echo $title; ?>" />
<input type="text" class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" value="<?php echo esc_attr( $title ); ?>" />
</p>
<p>
<label for="<?php echo $this->get_field_id('nav_menu'); ?>"><?php _e('Select Menu:'); ?></label>

View File

@@ -405,6 +405,9 @@ function wpautop($pee, $br = true) {
$pee = preg_replace('!(</' . $allblocks . '>)!', "$1\n\n", $pee);
$pee = str_replace(array("\r\n", "\r"), "\n", $pee); // cross-platform newlines
// Find newlines in all elements and add placeholders.
$pee = wp_replace_in_html_tags( $pee, array( "\n" => " <!-- wpnl --> " ) );
if ( strpos( $pee, '<option' ) !== false ) {
// no P/BR around option
$pee = preg_replace( '|\s*<option|', '<option', $pee );
@@ -456,9 +459,109 @@ function wpautop($pee, $br = true) {
if ( !empty($pre_tags) )
$pee = str_replace(array_keys($pre_tags), array_values($pre_tags), $pee);
// Restore newlines in all elements.
$pee = str_replace( " <!-- wpnl --> ", "\n", $pee );
return $pee;
}
/**
* Separate HTML elements and comments from the text.
*
* @since 4.2.4
*
* @param string $input The text which has to be formatted.
* @return array The formatted text.
*/
function wp_html_split( $input ) {
static $regex;
if ( ! isset( $regex ) ) {
$comments =
'!' // Start of comment, after the <.
. '(?:' // Unroll the loop: Consume everything until --> is found.
. '-(?!->)' // Dash not followed by end of comment.
. '[^\-]*+' // Consume non-dashes.
. ')*+' // Loop possessively.
. '(?:-->)?'; // End of comment. If not found, match all input.
$cdata =
'!\[CDATA\[' // Start of comment, after the <.
. '[^\]]*+' // Consume non-].
. '(?:' // Unroll the loop: Consume everything until ]]> is found.
. '](?!]>)' // One ] not followed by end of comment.
. '[^\]]*+' // Consume non-].
. ')*+' // Loop possessively.
. '(?:]]>)?'; // End of comment. If not found, match all input.
$regex =
'/(' // Capture the entire match.
. '<' // Find start of element.
. '(?(?=!--)' // Is this a comment?
. $comments // Find end of comment.
. '|'
. '(?(?=!\[CDATA\[)' // Is this a comment?
. $cdata // Find end of comment.
. '|'
. '[^>]*>?' // Find end of element. If not found, match all input.
. ')'
. ')'
. ')/s';
}
return preg_split( $regex, $input, -1, PREG_SPLIT_DELIM_CAPTURE );
}
/**
* Replace characters or phrases within HTML elements only.
*
* @since 4.2.3
*
* @param string $haystack The text which has to be formatted.
* @param array $replace_pairs In the form array('from' => 'to', ...).
* @return string The formatted text.
*/
function wp_replace_in_html_tags( $haystack, $replace_pairs ) {
// Find all elements.
$textarr = wp_html_split( $haystack );
$changed = false;
// Optimize when searching for one item.
if ( 1 === count( $replace_pairs ) ) {
// Extract $needle and $replace.
foreach ( $replace_pairs as $needle => $replace );
// Loop through delimeters (elements) only.
for ( $i = 1, $c = count( $textarr ); $i < $c; $i += 2 ) {
if ( false !== strpos( $textarr[$i], $needle ) ) {
$textarr[$i] = str_replace( $needle, $replace, $textarr[$i] );
$changed = true;
}
}
} else {
// Extract all $needles.
$needles = array_keys( $replace_pairs );
// Loop through delimeters (elements) only.
for ( $i = 1, $c = count( $textarr ); $i < $c; $i += 2 ) {
foreach ( $needles as $needle ) {
if ( false !== strpos( $textarr[$i], $needle ) ) {
$textarr[$i] = strtr( $textarr[$i], $replace_pairs );
$changed = true;
// After one strtr() break out of the foreach loop and look at next element.
break;
}
}
}
}
if ( $changed ) {
$haystack = implode( $textarr );
}
return $haystack;
}
/**
* Newline preservation help function for wpautop
*

View File

@@ -102,6 +102,10 @@ tinymce.PluginManager.add( 'wordpress', function( editor ) {
'<img src="' + tinymce.Env.transparentSrc + '" data-wp-more="nextpage" class="wp-more-tag mce-wp-nextpage" ' +
'title="' + title + '" data-mce-resize="false" data-mce-placeholder="1" />' );
}
if ( e.content.indexOf( '<?"' ) !== -1 ) {
e.content = e.content.replace( /<\?"/g, '' );
}
}
});

File diff suppressed because one or more lines are too long

View File

@@ -493,6 +493,82 @@ function wp_kses( $string, $allowed_html, $allowed_protocols = array() ) {
return wp_kses_split($string, $allowed_html, $allowed_protocols);
}
/**
* Filters one attribute only and ensures its value is allowed.
*
* This function has the advantage of being more secure than esc_attr() and can
* escape data in some situations where wp_kses() must strip the whole attribute.
*
* @since 4.2.3
*
* @param string $string The 'whole' attribute, including name and value.
* @param string $element The element name to which the attribute belongs.
* @return string Filtered attribute.
*/
function wp_kses_one_attr( $string, $element ) {
$uris = array('xmlns', 'profile', 'href', 'src', 'cite', 'classid', 'codebase', 'data', 'usemap', 'longdesc', 'action');
$allowed_html = wp_kses_allowed_html( 'post' );
$allowed_protocols = wp_allowed_protocols();
$string = wp_kses_no_null( $string, array( 'slash_zero' => 'keep' ) );
$string = wp_kses_js_entities( $string );
$string = wp_kses_normalize_entities( $string );
// Preserve leading and trailing whitespace.
$matches = array();
preg_match('/^\s*/', $string, $matches);
$lead = $matches[0];
preg_match('/\s*$/', $string, $matches);
$trail = $matches[0];
if ( empty( $trail ) ) {
$string = substr( $string, strlen( $lead ) );
} else {
$string = substr( $string, strlen( $lead ), -strlen( $trail ) );
}
// Parse attribute name and value from input.
$split = preg_split( '/\s*=\s*/', $string, 2 );
$name = $split[0];
if ( count( $split ) == 2 ) {
$value = $split[1];
// Remove quotes surrounding $value.
// Also guarantee correct quoting in $string for this one attribute.
if ( '' == $value ) {
$quote = '';
} else {
$quote = $value[0];
}
if ( '"' == $quote || "'" == $quote ) {
if ( substr( $value, -1 ) != $quote ) {
return '';
}
$value = substr( $value, 1, -1 );
} else {
$quote = '"';
}
// Sanitize quotes and angle braces.
$value = htmlspecialchars( $value, ENT_QUOTES, null, false );
// Sanitize URI values.
if ( in_array( strtolower( $name ), $uris ) ) {
$value = wp_kses_bad_protocol( $value, $allowed_protocols );
}
$string = "$name=$quote$value$quote";
$vless = 'n';
} else {
$value = '';
$vless = 'y';
}
// Sanitize attribute by name.
wp_kses_attr_check( $name, $value, $string, $vless, $element, $allowed_html );
// Restore whitespace.
return $lead . $string . $trail;
}
/**
* Return a list of allowed tags and attributes for a given context.
*
@@ -714,45 +790,11 @@ function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols) {
# Go through $attrarr, and save the allowed attributes for this element
# in $attr2
$attr2 = '';
$allowed_attr = $allowed_html[strtolower($element)];
foreach ($attrarr as $arreach) {
if ( ! isset( $allowed_attr[strtolower($arreach['name'])] ) )
continue; # the attribute is not allowed
$current = $allowed_attr[strtolower($arreach['name'])];
if ( $current == '' )
continue; # the attribute is not allowed
if ( strtolower( $arreach['name'] ) == 'style' ) {
$orig_value = $arreach['value'];
$value = safecss_filter_attr( $orig_value );
if ( empty( $value ) )
continue;
$arreach['value'] = $value;
$arreach['whole'] = str_replace( $orig_value, $value, $arreach['whole'] );
}
if ( ! is_array($current) ) {
foreach ( $attrarr as $arreach ) {
if ( wp_kses_attr_check( $arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html ) ) {
$attr2 .= ' '.$arreach['whole'];
# there are no checks
} else {
# there are some checks
$ok = true;
foreach ($current as $currkey => $currval) {
if ( ! wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval) ) {
$ok = false;
break;
}
}
if ( $ok )
$attr2 .= ' '.$arreach['whole']; # it passed them
} # if !is_array($current)
} # foreach
}
}
# Remove any "<" or ">" characters
$attr2 = preg_replace('/[<>]/', '', $attr2);
@@ -760,6 +802,53 @@ function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols) {
return "<$element$attr2$xhtml_slash>";
}
/**
* Determine whether an attribute is allowed.
*
* @since 4.2.3
*
* @param string $name The attribute name. Returns empty string when not allowed.
* @param string $value The attribute value. Returns a filtered value.
* @param string $whole The name=value input. Returns filtered input.
* @param string $vless 'y' when attribute like "enabled", otherwise 'n'.
* @param string $element The name of the element to which this attribute belongs.
* @param array $allowed_html The full list of allowed elements and attributes.
* @return bool Is the attribute allowed?
*/
function wp_kses_attr_check( &$name, &$value, &$whole, $vless, $element, $allowed_html ) {
$allowed_attr = $allowed_html[strtolower( $element )];
$name_low = strtolower( $name );
if ( ! isset( $allowed_attr[$name_low] ) || '' == $allowed_attr[$name_low] ) {
$name = $value = $whole = '';
return false;
}
if ( 'style' == $name_low ) {
$new_value = safecss_filter_attr( $value );
if ( empty( $new_value ) ) {
$name = $value = $whole = '';
return false;
}
$whole = str_replace( $value, $new_value, $whole );
$value = $new_value;
}
if ( is_array( $allowed_attr[$name_low] ) ) {
// there are some checks
foreach ( $allowed_attr[$name_low] as $currkey => $currval ) {
if ( ! wp_kses_check_attr_val( $value, $vless, $currkey, $currval ) ) {
$name = $value = $whole = '';
return false;
}
}
}
return true;
}
/**
* Builds an attribute list from string containing attributes.
*
@@ -889,6 +978,109 @@ function wp_kses_hair($attr, $allowed_protocols) {
return $attrarr;
}
/**
* Finds all attributes of an HTML element.
*
* Does not modify input. May return "evil" output.
*
* Based on wp_kses_split2() and wp_kses_attr()
*
* @since 4.2.3
*
* @param string $element HTML element/tag
* @return array|bool List of attributes found in $element. Returns false on failure.
*/
function wp_kses_attr_parse( $element ) {
$valid = preg_match('%^(<\s*)(/\s*)?([a-zA-Z0-9]+\s*)([^>]*)(>?)$%', $element, $matches);
if ( 1 !== $valid ) {
return false;
}
$begin = $matches[1];
$slash = $matches[2];
$elname = $matches[3];
$attr = $matches[4];
$end = $matches[5];
if ( '' !== $slash ) {
// Closing elements do not get parsed.
return false;
}
// Is there a closing XHTML slash at the end of the attributes?
if ( 1 === preg_match( '%\s*/\s*$%', $attr, $matches ) ) {
$xhtml_slash = $matches[0];
$attr = substr( $attr, 0, -strlen( $xhtml_slash ) );
} else {
$xhtml_slash = '';
}
// Split it
$attrarr = wp_kses_hair_parse( $attr );
if ( false === $attrarr ) {
return false;
}
// Make sure all input is returned by adding front and back matter.
array_unshift( $attrarr, $begin . $slash . $elname );
array_push( $attrarr, $xhtml_slash . $end );
return $attrarr;
}
/**
* Builds an attribute list from string containing attributes.
*
* Does not modify input. May return "evil" output.
* In case of unexpected input, returns false instead of stripping things.
*
* Based on wp_kses_hair() but does not return a multi-dimensional array.
*
* @since 4.2.3
*
* @param string $attr Attribute list from HTML element to closing HTML element tag
* @return array|bool List of attributes found in $attr. Returns false on failure.
*/
function wp_kses_hair_parse( $attr ) {
if ( '' === $attr ) {
return array();
}
$regex =
'(?:'
. '[-a-zA-Z:]+' // Attribute name.
. '|'
. '\[\[?[^\[\]]+\]\]?' // Shortcode in the name position implies unfiltered_html.
. ')'
. '(?:' // Attribute value.
. '\s*=\s*' // All values begin with '='
. '(?:'
. '"[^"]*"' // Double-quoted
. '|'
. "'[^']*'" // Single-quoted
. '|'
. '[^\s"\']+' // Non-quoted
. '(?:\s|$)' // Must have a space
. ')'
. '|'
. '(?:\s|$)' // If attribute has no value, space is required.
. ')'
. '\s*'; // Trailing space is optional except as mentioned above.
// Although it is possible to reduce this procedure to a single regexp,
// we must run that regexp twice to get exactly the expected result.
$validation = "%^($regex)+$%";
$extraction = "%$regex%";
if ( 1 === preg_match( $validation, $attr ) ) {
preg_match_all( $extraction, $attr, $attrarr );
return $attrarr[0];
} else {
return false;
}
}
/**
* Performs different checks for attribute values.
*

View File

@@ -801,6 +801,8 @@ function img_caption_shortcode( $attr, $content = null ) {
$content = $matches[1];
$attr['caption'] = trim( $matches[2] );
}
} elseif ( strpos( $attr['caption'], '<' ) !== false ) {
$attr['caption'] = wp_kses( $attr['caption'], 'post' );
}
/**

View File

@@ -2888,10 +2888,11 @@ function wp_untrash_post_comments( $post = null ) {
foreach ( $group_by_status as $status => $comments ) {
// Sanity check. This shouldn't happen.
if ( 'post-trashed' == $status )
if ( 'post-trashed' == $status ) {
$status = '0';
$comments_in = implode( "', '", $comments );
$wpdb->query( "UPDATE $wpdb->comments SET comment_approved = '$status' WHERE comment_ID IN ('" . $comments_in . "')" );
}
$comments_in = implode( ', ', array_map( 'intval', $comments ) );
$wpdb->query( $wpdb->prepare( "UPDATE $wpdb->comments SET comment_approved = %s WHERE comment_ID IN ($comments_in)", $status ) );
}
clean_comment_cache( array_keys($statuses) );

View File

@@ -188,9 +188,10 @@ function has_shortcode( $content, $tag ) {
* @uses get_shortcode_regex() Gets the search pattern for searching shortcodes.
*
* @param string $content Content to search for shortcodes
* @param bool $ignore_html When true, shortcodes inside HTML elements will be skipped.
* @return string Content with shortcodes filtered out.
*/
function do_shortcode($content) {
function do_shortcode( $content, $ignore_html = false ) {
global $shortcode_tags;
if ( false === strpos( $content, '[' ) ) {
@@ -200,8 +201,24 @@ function do_shortcode($content) {
if (empty($shortcode_tags) || !is_array($shortcode_tags))
return $content;
$tagnames = array_keys($shortcode_tags);
$tagregexp = join( '|', array_map('preg_quote', $tagnames) );
$pattern = "/\\[($tagregexp)/s";
if ( 1 !== preg_match( $pattern, $content ) ) {
// Avoids parsing HTML when there are no shortcodes or embeds anyway.
return $content;
}
$content = do_shortcodes_in_html_tags( $content, $ignore_html );
$pattern = get_shortcode_regex();
return preg_replace_callback( "/$pattern/s", 'do_shortcode_tag', $content );
$content = preg_replace_callback( "/$pattern/s", 'do_shortcode_tag', $content );
// Always restore square braces so we don't break things like <!--[if IE ]>
$content = unescape_invalid_shortcodes( $content );
return $content;
}
/**
@@ -294,6 +311,127 @@ function do_shortcode_tag( $m ) {
}
}
/**
* Search only inside HTML elements for shortcodes and process them.
*
* Any [ or ] characters remaining inside elements will be HTML encoded
* to prevent interference with shortcodes that are outside the elements.
* Assumes $content processed by KSES already. Users with unfiltered_html
* capability may get unexpected output if angle braces are nested in tags.
*
* @since 4.2.3
*
* @param string $content Content to search for shortcodes
* @param bool $ignore_html When true, all square braces inside elements will be encoded.
* @return string Content with shortcodes filtered out.
*/
function do_shortcodes_in_html_tags( $content, $ignore_html ) {
// Normalize entities in unfiltered HTML before adding placeholders.
$trans = array( '&#91;' => '&#091;', '&#93;' => '&#093;' );
$content = strtr( $content, $trans );
$trans = array( '[' => '&#91;', ']' => '&#93;' );
$pattern = get_shortcode_regex();
$textarr = wp_html_split( $content );
foreach ( $textarr as &$element ) {
if ( '' == $element || '<' !== $element[0] ) {
continue;
}
$noopen = false === strpos( $element, '[' );
$noclose = false === strpos( $element, ']' );
if ( $noopen || $noclose ) {
// This element does not contain shortcodes.
if ( $noopen xor $noclose ) {
// Need to encode stray [ or ] chars.
$element = strtr( $element, $trans );
}
continue;
}
if ( $ignore_html || '<!--' === substr( $element, 0, 4 ) || '<![CDATA[' === substr( $element, 0, 9 ) ) {
// Encode all [ and ] chars.
$element = strtr( $element, $trans );
continue;
}
$attributes = wp_kses_attr_parse( $element );
if ( false === $attributes ) {
// Some plugins are doing things like [name] <[email]>.
if ( 1 === preg_match( '%^<\s*\[\[?[^\[\]]+\]%', $element ) ) {
$element = preg_replace_callback( "/$pattern/s", 'do_shortcode_tag', $element );
}
// Looks like we found some crazy unfiltered HTML. Skipping it for sanity.
$element = strtr( $element, $trans );
continue;
}
// Get element name
$front = array_shift( $attributes );
$back = array_pop( $attributes );
$matches = array();
preg_match('%[a-zA-Z0-9]+%', $front, $matches);
$elname = $matches[0];
// Look for shortcodes in each attribute separately.
foreach ( $attributes as &$attr ) {
$open = strpos( $attr, '[' );
$close = strpos( $attr, ']' );
if ( false === $open || false === $close ) {
continue; // Go to next attribute. Square braces will be escaped at end of loop.
}
$double = strpos( $attr, '"' );
$single = strpos( $attr, "'" );
if ( ( false === $single || $open < $single ) && ( false === $double || $open < $double ) ) {
// $attr like '[shortcode]' or 'name = [shortcode]' implies unfiltered_html.
// In this specific situation we assume KSES did not run because the input
// was written by an administrator, so we should avoid changing the output
// and we do not need to run KSES here.
$attr = preg_replace_callback( "/$pattern/s", 'do_shortcode_tag', $attr );
} else {
// $attr like 'name = "[shortcode]"' or "name = '[shortcode]'"
// We do not know if $content was unfiltered. Assume KSES ran before shortcodes.
$count = 0;
$new_attr = preg_replace_callback( "/$pattern/s", 'do_shortcode_tag', $attr, -1, $count );
if ( $count > 0 ) {
// Sanitize the shortcode output using KSES.
$new_attr = wp_kses_one_attr( $new_attr, $elname );
if ( '' !== $new_attr ) {
// The shortcode is safe to use now.
$attr = $new_attr;
}
}
}
}
$element = $front . implode( '', $attributes ) . $back;
// Now encode any remaining [ or ] chars.
$element = strtr( $element, $trans );
}
$content = implode( '', $textarr );
return $content;
}
/**
* Remove placeholders added by do_shortcodes_in_html_tags().
*
* @since 4.2.3
*
* @param string $content Content to search for placeholders.
* @return string Content with placeholders removed.
*/
function unescape_invalid_shortcodes( $content ) {
// Clean up entire string, avoids re-parsing HTML.
$trans = array( '&#91;' => '[', '&#93;' => ']' );
$content = strtr( $content, $trans );
return $content;
}
/**
* Retrieve all attributes from the shortcodes tag.
*
@@ -323,6 +461,15 @@ function shortcode_parse_atts($text) {
elseif (isset($m[8]))
$atts[] = stripcslashes($m[8]);
}
// Reject any unclosed HTML elements
foreach( $atts as &$value ) {
if ( false !== strpos( $value, '<' ) ) {
if ( 1 !== preg_match( '/^[^<]*+(?:<[^>]*+>[^<]*+)*+$/', $value ) ) {
$value = '';
}
}
}
} else {
$atts = ltrim($text);
}
@@ -393,9 +540,15 @@ function strip_shortcodes( $content ) {
if (empty($shortcode_tags) || !is_array($shortcode_tags))
return $content;
$pattern = get_shortcode_regex();
$content = do_shortcodes_in_html_tags( $content, true );
return preg_replace_callback( "/$pattern/s", 'strip_shortcode_tag', $content );
$pattern = get_shortcode_regex();
$content = preg_replace_callback( "/$pattern/s", 'strip_shortcode_tag', $content );
// Always restore square braces so we don't break things like <!--[if IE ]>
$content = unescape_invalid_shortcodes( $content );
return $content;
}
function strip_shortcode_tag( $m ) {

View File

@@ -673,8 +673,6 @@ function preview_theme() {
// Prevent theme mods to current theme being used on theme being previewed
add_filter( 'pre_option_theme_mods_' . get_option( 'stylesheet' ), '__return_empty_array' );
ob_start( 'preview_theme_ob_filter' );
}
add_action('setup_theme', 'preview_theme');
@@ -712,7 +710,7 @@ function _preview_theme_stylesheet_filter() {
* @return string
*/
function preview_theme_ob_filter( $content ) {
return preg_replace_callback( "|(<a.*?href=([\"']))(.*?)([\"'].*?>)|", 'preview_theme_ob_filter_callback', $content );
return $content;
}
/**
@@ -727,26 +725,7 @@ function preview_theme_ob_filter( $content ) {
* @return string
*/
function preview_theme_ob_filter_callback( $matches ) {
if ( strpos($matches[4], 'onclick') !== false )
$matches[4] = preg_replace('#onclick=([\'"]).*?(?<!\\\)\\1#i', '', $matches[4]); //Strip out any onclicks from rest of <a>. (?<!\\\) means to ignore the '" if it's escaped by \ to prevent breaking mid-attribute.
if (
( false !== strpos($matches[3], '/wp-admin/') )
||
( false !== strpos( $matches[3], '://' ) && 0 !== strpos( $matches[3], home_url() ) )
||
( false !== strpos($matches[3], '/feed/') )
||
( false !== strpos($matches[3], '/trackback/') )
)
return $matches[1] . "#$matches[2] onclick=$matches[2]return false;" . $matches[4];
$stylesheet = isset( $_GET['stylesheet'] ) ? $_GET['stylesheet'] : '';
$template = isset( $_GET['template'] ) ? $_GET['template'] : '';
$link = add_query_arg( array( 'preview' => 1, 'template' => $template, 'stylesheet' => $stylesheet, 'preview_iframe' => 1 ), $matches[3] );
if ( 0 === strpos($link, 'preview=1') )
$link = "?$link";
return $matches[1] . esc_attr( $link ) . $matches[4];
return $matches[0];
}
/**

View File

@@ -633,19 +633,8 @@ function wp_schedule_update_checks() {
if ( !wp_next_scheduled('wp_update_themes') && !defined('WP_INSTALLING') )
wp_schedule_event(time(), 'twicedaily', 'wp_update_themes');
if ( ! wp_next_scheduled( 'wp_maybe_auto_update' ) && ! defined( 'WP_INSTALLING' ) ) {
// Schedule auto updates for 7 a.m. and 7 p.m. in the timezone of the site.
$next = strtotime( 'today 7am' );
$now = time();
// Find the next instance of 7 a.m. or 7 p.m., but skip it if it is within 3 hours from now.
while ( ( $now + 3 * HOUR_IN_SECONDS ) > $next ) {
$next += 12 * HOUR_IN_SECONDS;
}
$next = $next - get_option( 'gmt_offset' ) * HOUR_IN_SECONDS;
// Add a random number of minutes, so we don't have all sites trying to update exactly on the hour
$next = $next + rand( 0, 59 ) * MINUTE_IN_SECONDS;
wp_schedule_event( $next, 'twicedaily', 'wp_maybe_auto_update' );
}
if ( ( wp_next_scheduled( 'wp_maybe_auto_update' ) > ( time() + HOUR_IN_SECONDS ) ) && ! defined('WP_INSTALLING') )
wp_clear_scheduled_hook( 'wp_maybe_auto_update' );
}
if ( ( ! is_main_site() && ! is_network_admin() ) || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) )

View File

@@ -4,21 +4,21 @@
*
* @global string $wp_version
*/
$wp_version = '4.0.4';
$wp_version = '4.0.9';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
*
* @global int $wp_db_version
*/
$wp_db_version = 29631;
$wp_db_version = 29632;
/**
* Holds the TinyMCE version
*
* @global string $tinymce_version
*/
$tinymce_version = '4104-20140822';
$tinymce_version = '4104-20150505';
/**
* Holds the required PHP version

View File

@@ -1787,6 +1787,8 @@ class wpdb {
* @return int|false The number of rows affected, or false on error.
*/
function _insert_replace_helper( $table, $data, $format = null, $type = 'INSERT' ) {
$this->insert_id = 0;
if ( ! in_array( strtoupper( $type ), array( 'REPLACE', 'INSERT' ) ) ) {
return false;
}
@@ -1807,7 +1809,6 @@ class wpdb {
$sql = "$type INTO `$table` ($fields) VALUES ($formats)";
$this->insert_id = 0;
$this->check_current_query = false;
return $this->query( $this->prepare( $sql, $values ) );
}
@@ -2003,17 +2004,11 @@ class wpdb {
// We can skip this field if we know it isn't a string.
// This checks %d/%f versus ! %s because it's sprintf() could take more.
$value['charset'] = false;
} elseif ( $this->check_ascii( $value['value'] ) ) {
// If it's ASCII, then we don't need the charset. We can skip this field.
$value['charset'] = false;
} else {
$value['charset'] = $this->get_col_charset( $table, $field );
if ( is_wp_error( $value['charset'] ) ) {
return false;
}
// This isn't ASCII. Don't have strip_invalid_text() re-check.
$value['ascii'] = false;
}
$data[ $field ] = $value;
@@ -2046,10 +2041,6 @@ class wpdb {
}
}
if ( false !== $value['length'] && strlen( $value['value'] ) > $value['length'] ) {
return false;
}
$data[ $field ] = $value;
}
@@ -2254,7 +2245,10 @@ class wpdb {
}
$charsets = $columns = array();
$results = $this->get_results( "SHOW FULL COLUMNS FROM `$table`" );
$table_parts = explode( '.', $table );
$table = '`' . implode( '`.`', $table_parts ) . '`';
$results = $this->get_results( "SHOW FULL COLUMNS FROM $table" );
if ( ! $results ) {
return new WP_Error( 'wpdb_get_table_charset_failure' );
}
@@ -2379,14 +2373,16 @@ class wpdb {
/**
* Retrieve the maximum string length allowed in a given column.
* The length may either be specified as a byte length or a character length.
*
* @since 4.2.1
* @access public
*
* @param string $table Table name.
* @param string $column Column name.
* @return mixed Max column length as an int. False if the column has no
* length. WP_Error object if there was an error.
* @return mixed array( 'length' => (int), 'type' => 'byte' | 'char' )
* false if the column has no length (for example, numeric column)
* WP_Error object if there was an error.
*/
public function get_col_length( $table, $column ) {
$tablekey = strtolower( $table );
@@ -2419,27 +2415,47 @@ class wpdb {
}
switch( $type ) {
case 'binary':
case 'char':
case 'varbinary':
case 'varchar':
return $length;
return array(
'type' => 'char',
'length' => (int) $length,
);
break;
case 'binary':
case 'varbinary':
return array(
'type' => 'byte',
'length' => (int) $length,
);
break;
case 'tinyblob':
case 'tinytext':
return 255; // 2^8 - 1
return array(
'type' => 'byte',
'length' => 255, // 2^8 - 1
);
break;
case 'blob':
case 'text':
return 65535; // 2^16 - 1
return array(
'type' => 'byte',
'length' => 65535, // 2^16 - 1
);
break;
case 'mediumblob':
case 'mediumtext':
return 16777215; // 2^24 - 1
return array(
'type' => 'byte',
'length' => 16777215, // 2^24 - 1
);
break;
case 'longblob':
case 'longtext':
return 4294967295; // 2^32 - 1
return array(
'type' => 'byte',
'length' => 4294967295, // 2^32 - 1
);
break;
default:
return false;
@@ -2488,7 +2504,7 @@ class wpdb {
// We don't need to check the collation for queries that don't read data.
$query = ltrim( $query, "\r\n\t (" );
if ( preg_match( '/^(?:SHOW|DESCRIBE|DESC|EXPLAIN)\s/i', $query ) ) {
if ( preg_match( '/^(?:SHOW|DESCRIBE|DESC|EXPLAIN|CREATE)\s/i', $query ) ) {
return true;
}
@@ -2546,50 +2562,55 @@ class wpdb {
*/
// If any of the columns don't have one of these collations, it needs more sanity checking.
protected function strip_invalid_text( $data ) {
// Some multibyte character sets that we can check in PHP.
$mb_charsets = array(
'ascii' => 'ASCII',
'big5' => 'BIG-5',
'eucjpms' => 'eucJP-win',
'gb2312' => 'EUC-CN',
'ujis' => 'EUC-JP',
'utf32' => 'UTF-32',
);
$supported_charsets = array();
if ( function_exists( 'mb_list_encodings' ) ) {
$supported_charsets = mb_list_encodings();
}
$db_check_string = false;
foreach ( $data as &$value ) {
$charset = $value['charset'];
// Column isn't a string, or is latin1, which will will happily store anything.
if ( false === $charset || 'latin1' === $charset ) {
if ( is_array( $value['length'] ) ) {
$length = $value['length']['length'];
} else {
$length = false;
}
// There's no charset to work with.
if ( false === $charset ) {
continue;
}
// Column isn't a string.
if ( ! is_string( $value['value'] ) ) {
continue;
}
// ASCII is always OK.
if ( ! isset( $value['ascii'] ) && $this->check_ascii( $value['value'] ) ) {
continue;
$truncate_by_byte_length = 'byte' === $value['length']['type'];
$needs_validation = true;
if (
// latin1 can store any byte sequence
'latin1' === $charset
||
// ASCII is always OK.
( ! isset( $value['ascii'] ) && $this->check_ascii( $value['value'] ) )
) {
$truncate_by_byte_length = true;
$needs_validation = false;
}
// Convert the text locally.
if ( $supported_charsets ) {
if ( isset( $mb_charsets[ $charset ] ) && in_array( $mb_charsets[ $charset ], $supported_charsets ) ) {
$value['value'] = mb_convert_encoding( $value['value'], $mb_charsets[ $charset ], $mb_charsets[ $charset ] );
if ( $truncate_by_byte_length ) {
mbstring_binary_safe_encoding();
if ( false !== $length && strlen( $value['value'] ) > $length ) {
$value['value'] = substr( $value['value'], 0, $length );
}
reset_mbstring_encoding();
if ( ! $needs_validation ) {
continue;
}
}
// utf8 can be handled by regex, which is a bunch faster than a DB lookup.
if ( 'utf8' === $charset || 'utf8mb3' === $charset || 'utf8mb4' === $charset ) {
if ( ( 'utf8' === $charset || 'utf8mb3' === $charset || 'utf8mb4' === $charset ) && function_exists( 'mb_strlen' ) ) {
$regex = '/
(
(?: [\x00-\x7F] # single-byte sequences 0xxxxxxx
@@ -2599,7 +2620,7 @@ class wpdb {
| \xED[\x80-\x9F][\x80-\xBF]
| [\xEE-\xEF][\x80-\xBF]{2}';
if ( 'utf8mb4' === $charset) {
if ( 'utf8mb4' === $charset ) {
$regex .= '
| \xF0[\x90-\xBF][\x80-\xBF]{2} # four-byte sequences 11110xxx 10xxxxxx * 3
| [\xF1-\xF3][\x80-\xBF]{3}
@@ -2607,11 +2628,16 @@ class wpdb {
';
}
$regex .= '){1,50} # ...one or more times
$regex .= '){1,40} # ...one or more times
)
| . # anything else
/x';
$value['value'] = preg_replace( $regex, '$1', $value['value'] );
if ( false !== $length && mb_strlen( $value['value'], 'UTF-8' ) > $length ) {
$value['value'] = mb_substr( $value['value'], 0, $length, 'UTF-8' );
}
continue;
}
@@ -2628,8 +2654,14 @@ class wpdb {
$queries[ $value['charset'] ] = array();
}
// Split the CONVERT() calls by charset, so we can make sure the connection is right
$queries[ $value['charset'] ][ $col ] = $this->prepare( "CONVERT( %s USING {$value['charset']} )", $value['value'] );
// We're going to need to truncate by characters or bytes, depending on the length value we have.
if ( 'byte' === $value['length']['type'] ) {
// Split the CONVERT() calls by charset, so we can make sure the connection is right
$queries[ $value['charset'] ][ $col ] = $this->prepare( "CONVERT( LEFT( CONVERT( %s USING binary ), %d ) USING {$value['charset']} )", $value['value'], $value['length']['length'] );
} else {
$queries[ $value['charset'] ][ $col ] = $this->prepare( "LEFT( CONVERT( %s USING {$value['charset']} ), %d )", $value['value'], $value['length']['length'] );
}
unset( $data[ $col ]['db'] );
}
}
@@ -2648,16 +2680,19 @@ class wpdb {
$this->check_current_query = false;
$row = $this->get_row( "SELECT " . implode( ', ', $query ), ARRAY_N );
$sql = array();
foreach ( $query as $column => $column_query ) {
$sql[] = $column_query . " AS x_$column";
}
$row = $this->get_row( "SELECT " . implode( ', ', $sql ), ARRAY_A );
if ( ! $row ) {
$this->set_charset( $this->dbh, $connection_charset );
return new WP_Error( 'wpdb_strip_invalid_text_failure' );
}
$cols = array_keys( $query );
$col_count = count( $cols );
for ( $ii = 0; $ii < $col_count; $ii++ ) {
$data[ $cols[ $ii ] ]['value'] = $row[ $ii ];
foreach ( array_keys( $query ) as $column ) {
$data[ $column ]['value'] = $row["x_$column"];
}
}
@@ -2680,6 +2715,12 @@ class wpdb {
* @return string|WP_Error The converted query, or a {@see WP_Error} object if the conversion fails.
*/
protected function strip_invalid_text_from_query( $query ) {
// We don't need to check the collation for queries that don't read data.
$trimmed_query = ltrim( $query, "\r\n\t (" );
if ( preg_match( '/^(?:SHOW|DESCRIBE|DESC|EXPLAIN|CREATE)\s/i', $trimmed_query ) ) {
return $query;
}
$table = $this->get_table_from_query( $query );
if ( $table ) {
$charset = $this->get_table_charset( $table );
@@ -2699,6 +2740,7 @@ class wpdb {
'value' => $query,
'charset' => $charset,
'ascii' => false,
'length' => false,
);
$data = $this->strip_invalid_text( array( $data ) );
@@ -2721,7 +2763,7 @@ class wpdb {
* @return string|WP_Error The converted string, or a `WP_Error` object if the conversion fails.
*/
public function strip_invalid_text_for_column( $table, $column, $value ) {
if ( ! is_string( $value ) || $this->check_ascii( $value ) ) {
if ( ! is_string( $value ) ) {
return $value;
}
@@ -2738,7 +2780,7 @@ class wpdb {
$column => array(
'value' => $value,
'charset' => $charset,
'ascii' => false,
'length' => $this->get_col_length( $table, $column ),
)
);
@@ -2779,16 +2821,16 @@ class wpdb {
. '|REPLACE(?:\s+LOW_PRIORITY|\s+DELAYED)?(?:\s+INTO)?'
. '|UPDATE(?:\s+LOW_PRIORITY)?(?:\s+IGNORE)?'
. '|DELETE(?:\s+LOW_PRIORITY|\s+QUICK|\s+IGNORE)*(?:\s+FROM)?'
. ')\s+`?([\w-]+)`?/is', $query, $maybe ) ) {
return $maybe[1];
. ')\s+((?:[0-9a-zA-Z$_.`-]|[\xC2-\xDF][\x80-\xBF])+)/is', $query, $maybe ) ) {
return str_replace( '`', '', $maybe[1] );
}
// SHOW TABLE STATUS and SHOW TABLES
if ( preg_match( '/^\s*(?:'
. 'SHOW\s+TABLE\s+STATUS.+(?:LIKE\s+|WHERE\s+Name\s*=\s*)'
. '|SHOW\s+(?:FULL\s+)?TABLES.+(?:LIKE\s+|WHERE\s+Name\s*=\s*)'
. ')\W([\w-]+)\W/is', $query, $maybe ) ) {
return $maybe[1];
. ')\W((?:[0-9a-zA-Z$_.`-]|[\xC2-\xDF][\x80-\xBF])+)\W/is', $query, $maybe ) ) {
return str_replace( '`', '', $maybe[1] );
}
// Big pattern for the rest of the table-related queries.
@@ -2806,8 +2848,8 @@ class wpdb {
. '|LOAD\s+DATA.*INFILE.*INTO\s+TABLE'
. '|(?:GRANT|REVOKE).*ON\s+TABLE'
. '|SHOW\s+(?:.*FROM|.*TABLE)'
. ')\s+\(*\s*`?([\w-]+)`?\s*\)*/is', $query, $maybe ) ) {
return $maybe[1];
. ')\s+\(*\s*((?:[0-9a-zA-Z$_.`-]|[\xC2-\xDF][\x80-\xBF])+)\s*\)*/is', $query, $maybe ) ) {
return str_replace( '`', '', $maybe[1] );
}
return false;