+ $content_length = $wpdb->get_col_length( $wpdb->comments, 'comment_content' );
+
+ 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 LENGTH( `comment_content` ) >= {$allowed_length}
+ AND ( `comment_content` LIKE '%<%' OR `comment_content` LIKE '%>%' )"
+ );
+
+ foreach ( $comments as $comment ) {
+ wp_delete_comment( $comment->comment_ID, true );
+ }
+}
+
+/**
+ * Executes changes made in WordPress 4.3.1.
+ *
+ * @ignore
+ * @since 4.3.1
+ */
+function upgrade_431() {
+ // Fix incorrect cron entries for term splitting
+ $cron_array = _get_cron_array();
+ if ( isset( $cron_array['wp_batch_split_terms'] ) ) {
+ unset( $cron_array['wp_batch_split_terms'] );
+ _set_cron_array( $cron_array );
+ }
+}
+
+/**
+ * Executes changes made in WordPress 4.4.0.
+ *
+ * @ignore
+ * @since 4.4.0
+ *
+ * @global int $wp_current_db_version Current version.
+ * @global wpdb $wpdb WordPress database abstraction object.
+ */
+function upgrade_440() {
+ global $wp_current_db_version, $wpdb;
+
+ if ( $wp_current_db_version < 34030 ) {
+ $wpdb->query( "ALTER TABLE {$wpdb->options} MODIFY option_name VARCHAR(191)" );
+ }
+
+ // Remove the unused 'add_users' role.
+ $roles = wp_roles();
+ foreach ( $roles->role_objects as $role ) {
+ if ( $role->has_cap( 'add_users' ) ) {
+ $role->remove_cap( 'add_users' );
+ }
+ }
+}
+
+/**
+ * Executes changes made in WordPress 4.5.0.
+ *
+ * @ignore
+ * @since 4.5.0
+ *
+ * @global int $wp_current_db_version Current database version.
+ * @global wpdb $wpdb WordPress database abstraction object.
+ */
+function upgrade_450() {
+ global $wp_current_db_version, $wpdb;
+
+ if ( $wp_current_db_version < 36180 ) {
+ wp_clear_scheduled_hook( 'wp_maybe_auto_update' );
+ }
+
+ // Remove unused email confirmation options, moved to usermeta.
+ if ( $wp_current_db_version < 36679 && is_multisite() ) {
+ $wpdb->query( "DELETE FROM $wpdb->options WHERE option_name REGEXP '^[0-9]+_new_email$'" );
+ }
+
+ // Remove unused user setting for wpLink.
+ delete_user_setting( 'wplink' );
+}
+
+/**
+ * Executes network-level upgrade routines.
+ *
+ * @since 3.0.0
+ *
+ * @global int $wp_current_db_version
+ * @global wpdb $wpdb
+ */
+function upgrade_network() {
+ global $wp_current_db_version, $wpdb;
+
+ // Always.
+ if ( is_main_network() ) {
+ /*
+ * Deletes all expired transients. The multi-table delete syntax is used
+ * to delete the transient record from table a, and the corresponding
+ * transient_timeout record from table b.
+ */
+ $time = time();
+ $sql = "DELETE a, b FROM $wpdb->sitemeta a, $wpdb->sitemeta b
+ WHERE a.meta_key LIKE %s
+ AND a.meta_key NOT LIKE %s
+ AND b.meta_key = CONCAT( '_site_transient_timeout_', SUBSTRING( a.meta_key, 17 ) )
+ AND b.meta_value < %d";
+ $wpdb->query( $wpdb->prepare( $sql, $wpdb->esc_like( '_site_transient_' ) . '%', $wpdb->esc_like ( '_site_transient_timeout_' ) . '%', $time ) );
+ }
+
+ // 2.8.
+ if ( $wp_current_db_version < 11549 ) {
+ $wpmu_sitewide_plugins = get_site_option( 'wpmu_sitewide_plugins' );
+ $active_sitewide_plugins = get_site_option( 'active_sitewide_plugins' );
+ if ( $wpmu_sitewide_plugins ) {
+ if ( !$active_sitewide_plugins )
+ $sitewide_plugins = (array) $wpmu_sitewide_plugins;
+ else
+ $sitewide_plugins = array_merge( (array) $active_sitewide_plugins, (array) $wpmu_sitewide_plugins );
+
+ update_site_option( 'active_sitewide_plugins', $sitewide_plugins );
+ }
+ delete_site_option( 'wpmu_sitewide_plugins' );
+ delete_site_option( 'deactivated_sitewide_plugins' );
+
+ $start = 0;
+ while( $rows = $wpdb->get_results( "SELECT meta_key, meta_value FROM {$wpdb->sitemeta} ORDER BY meta_id LIMIT $start, 20" ) ) {
+ foreach ( $rows as $row ) {
+ $value = $row->meta_value;
+ if ( !@unserialize( $value ) )
+ $value = stripslashes( $value );
+ if ( $value !== $row->meta_value ) {
+ update_site_option( $row->meta_key, $value );
+ }
+ }
+ $start += 20;
+ }
+ }
+
+ // 3.0
+ if ( $wp_current_db_version < 13576 )
+ update_site_option( 'global_terms_enabled', '1' );
+
+ // 3.3
+ if ( $wp_current_db_version < 19390 )
+ update_site_option( 'initial_db_version', $wp_current_db_version );
+
+ if ( $wp_current_db_version < 19470 ) {
+ if ( false === get_site_option( 'active_sitewide_plugins' ) )
+ update_site_option( 'active_sitewide_plugins', array() );
+ }
+
+ // 3.4
+ if ( $wp_current_db_version < 20148 ) {
+ // 'allowedthemes' keys things by stylesheet. 'allowed_themes' keyed things by name.
+ $allowedthemes = get_site_option( 'allowedthemes' );
+ $allowed_themes = get_site_option( 'allowed_themes' );
+ if ( false === $allowedthemes && is_array( $allowed_themes ) && $allowed_themes ) {
+ $converted = array();
+ $themes = wp_get_themes();
+ foreach ( $themes as $stylesheet => $theme_data ) {
+ if ( isset( $allowed_themes[ $theme_data->get('Name') ] ) )
+ $converted[ $stylesheet ] = true;
+ }
+ update_site_option( 'allowedthemes', $converted );
+ delete_site_option( 'allowed_themes' );
+ }
+ }
+
+ // 3.5
+ if ( $wp_current_db_version < 21823 )
+ update_site_option( 'ms_files_rewriting', '1' );
+
+ // 3.5.2
+ if ( $wp_current_db_version < 24448 ) {
+ $illegal_names = get_site_option( 'illegal_names' );
+ if ( is_array( $illegal_names ) && count( $illegal_names ) === 1 ) {
+ $illegal_name = reset( $illegal_names );
+ $illegal_names = explode( ' ', $illegal_name );
+ update_site_option( 'illegal_names', $illegal_names );
+ }
+ }
+
+ // 4.2
+ if ( $wp_current_db_version < 31351 && $wpdb->charset === 'utf8mb4' ) {
+ if ( wp_should_upgrade_global_tables() ) {
+ $wpdb->query( "ALTER TABLE $wpdb->usermeta DROP INDEX meta_key, ADD INDEX meta_key(meta_key(191))" );
+ $wpdb->query( "ALTER TABLE $wpdb->site DROP INDEX domain, ADD INDEX domain(domain(140),path(51))" );
+ $wpdb->query( "ALTER TABLE $wpdb->sitemeta DROP INDEX meta_key, ADD INDEX meta_key(meta_key(191))" );
+ $wpdb->query( "ALTER TABLE $wpdb->signups DROP INDEX domain_path, ADD INDEX domain_path(domain(140),path(51))" );
+
+ $tables = $wpdb->tables( 'global' );
+
+ // sitecategories may not exist.
+ if ( ! $wpdb->get_var( "SHOW TABLES LIKE '{$tables['sitecategories']}'" ) ) {
+ unset( $tables['sitecategories'] );
+ }
+
+ foreach ( $tables as $table ) {
+ maybe_convert_table_to_utf8mb4( $table );
+ }
+ }
+ }
+
+ // 4.3
+ if ( $wp_current_db_version < 33055 && 'utf8mb4' === $wpdb->charset ) {
+ if ( wp_should_upgrade_global_tables() ) {
+ $upgrade = false;
+ $indexes = $wpdb->get_results( "SHOW INDEXES FROM $wpdb->signups" );
+ foreach ( $indexes as $index ) {
+ if ( 'domain_path' == $index->Key_name && 'domain' == $index->Column_name && 140 != $index->Sub_part ) {
+ $upgrade = true;
+ break;
+ }
+ }
+
+ if ( $upgrade ) {
+ $wpdb->query( "ALTER TABLE $wpdb->signups DROP INDEX domain_path, ADD INDEX domain_path(domain(140),path(51))" );
+ }
+
+ $tables = $wpdb->tables( 'global' );
+
+ // sitecategories may not exist.
+ if ( ! $wpdb->get_var( "SHOW TABLES LIKE '{$tables['sitecategories']}'" ) ) {
+ unset( $tables['sitecategories'] );
+ }
+
+ foreach ( $tables as $table ) {
+ maybe_convert_table_to_utf8mb4( $table );
+ }
+ }
+ }
+}
+
+//
+// General functions we use to actually do stuff
+//
+
+/**
+ * Creates a table in the database if it doesn't already exist.
+ *
+ * This method checks for an existing database and creates a new one if it's not
+ * already present. It doesn't rely on MySQL's "IF NOT EXISTS" statement, but chooses
+ * to query all tables first and then run the SQL statement creating the table.
+ *
+ * @since 1.0.0
+ *
+ * @global wpdb $wpdb
+ *
+ * @param string $table_name Database table name to create.
+ * @param string $create_ddl SQL statement to create table.
+ * @return bool If table already exists or was created by function.
+ */
+function maybe_create_table($table_name, $create_ddl) {
+ global $wpdb;
+
+ $query = $wpdb->prepare( "SHOW TABLES LIKE %s", $wpdb->esc_like( $table_name ) );
+
+ if ( $wpdb->get_var( $query ) == $table_name ) {
+ return true;
+ }
+
+ // Didn't find it try to create it..
+ $wpdb->query($create_ddl);
+
+ // We cannot directly tell that whether this succeeded!
+ if ( $wpdb->get_var( $query ) == $table_name ) {
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Drops a specified index from a table.
+ *
+ * @since 1.0.1
+ *
+ * @global wpdb $wpdb
+ *
+ * @param string $table Database table name.
+ * @param string $index Index name to drop.
+ * @return true True, when finished.
+ */
+function drop_index($table, $index) {
+ global $wpdb;
+ $wpdb->hide_errors();
+ $wpdb->query("ALTER TABLE `$table` DROP INDEX `$index`");
+ // Now we need to take out all the extra ones we may have created
+ for ($i = 0; $i < 25; $i++) {
+ $wpdb->query("ALTER TABLE `$table` DROP INDEX `{$index}_$i`");
+ }
+ $wpdb->show_errors();
+ return true;
+}
+
+/**
+ * Adds an index to a specified table.
+ *
+ * @since 1.0.1
+ *
+ * @global wpdb $wpdb
+ *
+ * @param string $table Database table name.
+ * @param string $index Database table index column.
+ * @return true True, when done with execution.
+ */
+function add_clean_index($table, $index) {
+ global $wpdb;
+ drop_index($table, $index);
+ $wpdb->query("ALTER TABLE `$table` ADD INDEX ( `$index` )");
+ return true;
+}
+
+/**
+ * Adds column to a database table if it doesn't already exist.
+ *
+ * @since 1.3.0
+ *
+ * @global wpdb $wpdb
+ *
+ * @param string $table_name The table name to modify.
+ * @param string $column_name The column name to add to the table.
+ * @param string $create_ddl The SQL statement used to add the column.
+ * @return bool True if already exists or on successful completion, false on error.
+ */
+function maybe_add_column($table_name, $column_name, $create_ddl) {
+ global $wpdb;
+ foreach ($wpdb->get_col("DESC $table_name", 0) as $column ) {
+ if ($column == $column_name) {
+ return true;
+ }
+ }
+
+ // Didn't find it try to create it.
+ $wpdb->query($create_ddl);
+
+ // We cannot directly tell that whether this succeeded!
+ foreach ($wpdb->get_col("DESC $table_name", 0) as $column ) {
+ if ($column == $column_name) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * If a table only contains utf8 or utf8mb4 columns, convert it to utf8mb4.
+ *
+ * @since 4.2.0
+ *
+ * @global wpdb $wpdb
+ *
+ * @param string $table The table to convert.
+ * @return bool true if the table was converted, false if it wasn't.
+ */
+function maybe_convert_table_to_utf8mb4( $table ) {
+ global $wpdb;
+
+ $results = $wpdb->get_results( "SHOW FULL COLUMNS FROM `$table`" );
+ if ( ! $results ) {
+ return false;
+ }
+
+ foreach ( $results as $column ) {
+ if ( $column->Collation ) {
+ list( $charset ) = explode( '_', $column->Collation );
+ $charset = strtolower( $charset );
+ if ( 'utf8' !== $charset && 'utf8mb4' !== $charset ) {
+ // Don't upgrade tables that have non-utf8 columns.
+ return false;
+ }
+ }
+ }
+
+ $table_details = $wpdb->get_row( "SHOW TABLE STATUS LIKE '$table'" );
+ if ( ! $table_details ) {
+ return false;
+ }
+
+ list( $table_charset ) = explode( '_', $table_details->Collation );
+ $table_charset = strtolower( $table_charset );
+ if ( 'utf8mb4' === $table_charset ) {
+ return true;
+ }
+
+ return $wpdb->query( "ALTER TABLE $table CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci" );
+}
+
+/**
+ * Retrieve all options as it was for 1.2.
+ *
+ * @since 1.2.0
+ *
+ * @global wpdb $wpdb
+ *
+ * @return stdClass List of options.
+ */
+function get_alloptions_110() {
+ global $wpdb;
+ $all_options = new stdClass;
+ if ( $options = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options" ) ) {
+ foreach ( $options as $option ) {
+ if ( 'siteurl' == $option->option_name || 'home' == $option->option_name || 'category_base' == $option->option_name )
+ $option->option_value = untrailingslashit( $option->option_value );
+ $all_options->{$option->option_name} = stripslashes( $option->option_value );
+ }
+ }
+ return $all_options;
+}
+
+/**
+ * Utility version of get_option that is private to install/upgrade.
+ *
+ * @ignore
+ * @since 1.5.1
+ * @access private
+ *
+ * @global wpdb $wpdb
+ *
+ * @param string $setting Option name.
+ * @return mixed
+ */
+function __get_option($setting) {
+ global $wpdb;
+
+ if ( $setting == 'home' && defined( 'WP_HOME' ) )
+ return untrailingslashit( WP_HOME );
+
+ if ( $setting == 'siteurl' && defined( 'WP_SITEURL' ) )
+ return untrailingslashit( WP_SITEURL );
+
+ $option = $wpdb->get_var( $wpdb->prepare("SELECT option_value FROM $wpdb->options WHERE option_name = %s", $setting ) );
+
+ if ( 'home' == $setting && '' == $option )
+ return __get_option( 'siteurl' );
+
+ if ( 'siteurl' == $setting || 'home' == $setting || 'category_base' == $setting || 'tag_base' == $setting )
+ $option = untrailingslashit( $option );
+
+ return maybe_unserialize( $option );
+}
+
+/**
+ * Filters for content to remove unnecessary slashes.
+ *
+ * @since 1.5.0
+ *
+ * @param string $content The content to modify.
+ * @return string The de-slashed content.
+ */
+function deslash($content) {
+ // Note: \\\ inside a regex denotes a single backslash.
+
+ /*
+ * Replace one or more backslashes followed by a single quote with
+ * a single quote.
+ */
+ $content = preg_replace("/\\\+'/", "'", $content);
+
+ /*
+ * Replace one or more backslashes followed by a double quote with
+ * a double quote.
+ */
+ $content = preg_replace('/\\\+"/', '"', $content);
+
+ // Replace one or more backslashes with one backslash.
+ $content = preg_replace("/\\\+/", "\\", $content);
+
+ return $content;
+}
+
+/**
+ * Modifies the database based on specified SQL statements.
+ *
+ * Useful for creating new tables and updating existing tables to a new structure.
+ *
+ * @since 1.5.0
+ *
+ * @global wpdb $wpdb
+ *
+ * @param string|array $queries Optional. The query to run. Can be multiple queries
+ * in an array, or a string of queries separated by
+ * semicolons. Default empty.
+ * @param bool $execute Optional. Whether or not to execute the query right away.
+ * Default true.
+ * @return array Strings containing the results of the various update queries.
+ */
+function dbDelta( $queries = '', $execute = true ) {
+ global $wpdb;
+
+ if ( in_array( $queries, array( '', 'all', 'blog', 'global', 'ms_global' ), true ) )
+ $queries = wp_get_db_schema( $queries );
+
+ // Separate individual queries into an array
+ if ( !is_array($queries) ) {