ing.func_overload') & MB_OVERLOAD_STRING ) { /** * substr() implementation that isn't brittle to mbstring.func_overload * * This version uses mb_substr() in '8bit' mode to treat strings as raw * binary rather than UTF-8, ISO-8859-1, etc * * @param string $binary_string * @param int $start * @param int $length (optional) * * @throws TypeError * * @return string */ function RandomCompat_substr($binary_string, $start, $length = null) { if (!is_string($binary_string)) { throw new TypeError( 'RandomCompat_substr(): First argument should be a string' ); } if (!is_int($start)) { throw new TypeError( 'RandomCompat_substr(): Second argument should be an integer' ); } if ($length === null) { /** * mb_substr($str, 0, NULL, '8bit') returns an empty string on * PHP 5.3, so we have to find the length ourselves. */ $length = RandomCompat_strlen($length) - $start; } elseif (!is_int($length)) { throw new TypeError( 'RandomCompat_substr(): Third argument should be an integer, or omitted' ); } return mb_substr($binary_string, $start, $length, '8bit'); } } else { /** * substr() implementation that isn't brittle to mbstring.func_overload * * This version just uses the default substr() * * @param string $binary_string * @param int $start * @param int $length (optional) * * @throws TypeError * * @return string */ function RandomCompat_substr($binary_string, $start, $length = null) { if (!is_string($binary_string)) { throw new TypeError( 'RandomCompat_substr(): First argument should be a string' ); } if (!is_int($start)) { throw new TypeError( 'RandomCompat_substr(): Second argument should be an integer' ); } if ($length !== null) { if (!is_int($length)) { throw new TypeError( 'RandomCompat_substr(): Third argument should be an integer, or omitted' ); } return substr($binary_string, $start, $length); } return substr($binary_string, $start); } } } e (~PHP_INT_MAX, PHP_INT_MAX) * (non-inclusive), it will sanely cast it to an int. If you it's equal to * ~PHP_INT_MAX or PHP_INT_MAX, we let it fail as not an integer. Floats * lose precision, so the <= and => operators might accidentally let a float * through. * * @param numeric $number The number we want to convert to an int * @param boolean $fail_open Set to true to not throw an exception * * @return int (or float if $fail_open) */ function RandomCompat_intval($number, $fail_open = false) { if (is_numeric($number)) { $number += 0; } if ( is_float($number) && $number > ~PHP_INT_MAX && $number < PHP_INT_MAX ) { $number = (int) $number; } if (is_int($number) || $fail_open) { return $number; } throw new TypeError( 'Expected an integer.' ); } } * * @param array $fields List of fields to revision. Contains 'post_title', * 'post_content', and 'post_excerpt' by default. */ $fields = apply_filters( '_wp_post_revision_fields', $fields ); // WP uses these internally either in versioning or elsewhere - they cannot be versioned foreach ( array( 'ID', 'post_name', 'post_parent', 'post_date', 'post_date_gmt', 'post_status', 'post_type', 'comment_count', 'post_author' ) as $protect ) unset( $fields[$protect] ); } if ( !is_array($post) ) return $fields; $return = array(); foreach ( array_intersect( array_keys( $post ), array_keys( $fields ) ) as $field ) $return[$field] = $post[$field]; $return['post_parent'] = $post['ID']; $return['post_status'] = 'inherit'; $return['post_type'] = 'revision'; $return['post_name'] = $autosave ? "$post[ID]-autosave-v1" : "$post[ID]-revision-v1"; // "1" is the revisioning system version $return['post_date'] = isset($post['post_modified']) ? $post['post_modified'] : ''; $return['post_date_gmt'] = isset($post['post_modified_gmt']) ? $post['post_modified_gmt'] : ''; return $return; } /** * Creates a revision for the current version of a post. * * Typically used immediately after a post update, as every update is a revision, * and the most recent revision always matches the current post. * * @since 2.6.0 * * @param int $post_id The ID of the post to save as a revision. * @return int|WP_Error|void Void or 0 if error, new revision ID, if success. */ function wp_save_post_revision( $post_id ) { if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return; if ( ! $post = get_post( $post_id ) ) return; if ( ! post_type_supports( $post->post_type, 'revisions' ) ) return; if ( 'auto-draft' == $post->post_status ) return; if ( ! wp_revisions_enabled( $post ) ) return; // Compare the proposed update with the last stored revision verifying that // they are different, unless a plugin tells us to always save regardless. // If no previous revisions, save one if ( $revisions = wp_get_post_revisions( $post_id ) ) { // grab the last revision, but not an autosave foreach ( $revisions as $revision ) { if ( false !== strpos( $revision->post_name, "{$revision->post_parent}-revision" ) ) { $last_revision = $revision; break; } } /** * Filter whether the post has changed since the last revision. * * By default a revision is saved only if one of the revisioned fields has changed. * This filter can override that so a revision is saved even if nothing has changed. * * @since 3.6.0 * * @param bool $check_for_changes Whether to check for changes before saving a new revision. * Default true. * @param WP_Post $last_revision The the last revision post object. * @param WP_Post $post The post object. * */ if ( isset( $last_revision ) && apply_filters( 'wp_save_post_revision_check_for_changes', $check_for_changes = true, $last_revision, $post ) ) { $post_has_changed = false; foreach ( array_keys( _wp_post_revision_fields() ) as $field ) { if ( normalize_whitespace( $post->$field ) != normalize_whitespace( $last_revision->$field ) ) { $post_has_changed = true; break; } } /** * Filter whether a post has changed. * * By default a revision is saved only if one of the revisioned fields has changed. * This filter allows for additional checks to determine if there were changes. * * @since 4.1.0 * * @param bool $post_has_changed Whether the post has changed. * @param WP_Post $last_revision The last revision post object. * @param WP_Post $post The post object. * */ $post_has_changed = (bool) apply_filters( 'wp_save_post_revision_post_has_changed', $post_has_changed, $last_revision, $post ); //don't save revision if post unchanged if ( ! $post_has_changed ) { return; } } } $return = _wp_put_post_revision( $post ); // If a limit for the number of revisions to keep has been set, // delete the oldest ones. $revisions_to_keep = wp_revisions_to_keep( $post ); if ( $revisions_to_keep < 0 ) return $return; $revisions = wp_get_post_revisions( $post_id, array( 'order' => 'ASC' ) ); $delete = count($revisions) - $revisions_to_keep; if ( $delete < 1 ) return $return; $revisions = array_slice( $revisions, 0, $delete ); for ( $i = 0; isset( $revisions[$i] ); $i++ ) { if ( false !== strpos( $revisions[ $i ]->post_name, 'autosave' ) ) continue; wp_delete_post_revision( $revisions[ $i ]->ID ); } return $return; } /** * Retrieve the autosaved data of the specified post. * * Returns a post object containing the information that was autosaved for the * specified post. If the optional $user_id is passed, returns the autosave for that user * otherwise returns the latest autosave. * * @since 2.6.0 * * @param int $post_id The post ID. * @param int $user_id Optional The post author ID. * @return WP_Post|false The autosaved data or false on failure or when no autosave exists. */ function wp_get_post_autosave( $post_id, $user_id = 0 ) { $revisions = wp_get_post_revisions( $post_id, array( 'check_enabled' => false ) ); foreach ( $revisions as $revision ) { if ( false !== strpos( $revision->post_name, "{$post_id}-autosave" ) ) { if ( $user_id && $user_id != $revision->post_author ) continue; return $revision; } } return false; } /** * Determines if the specified post is a revision. * * @since 2.6.0 * * @param int|WP_Post $post Post ID or post object. * @return false|int False if not a revision, ID of revision's parent otherwise. */ function wp_is_post_revision( $post ) { if ( !$post = wp_get_post_revision( $post ) ) return false; return (int) $post->post_parent; } /** * Determines if the specified post is an autosave. * * @since 2.6.0 * * @param int|WP_Post $post Post ID or post object. * @return false|int False if not a revision, ID of autosave's parent otherwise */ function wp_is_post_autosave( $post ) { if ( !$post = wp_get_post_revision( $post ) ) return false; if ( false !== strpos( $post->post_name, "{$post->post_parent}-autosave" ) ) return (int) $post->post_parent; return false; } /** * Inserts post data into the posts table as a post revision. * * @since 2.6.0 * @access private * * @param int|WP_Post|array|null $post Post ID, post object OR post array. * @param bool $autosave Optional. Is the revision an autosave? * @return int|WP_Error WP_Error or 0 if error, new revision ID if success. */ function _wp_put_post_revision( $post = null, $autosave = false ) { if ( is_object($post) ) $post = get_object_vars( $post ); elseif ( !is_array($post) ) $post = get_post($post, ARRAY_A); if ( ! $post || empty($post['ID']) ) return new WP_Error( 'invalid_post', __( 'Invalid post ID.' ) ); if ( isset($post['post_type']) && 'revision' == $post['post_type'] ) return new WP_Error( 'post_type', __( 'Cannot create a revision of a revision' ) ); $post = _wp_post_revision_fields( $post, $autosave ); $post = wp_slash($post); //since data is from db $revision_id = wp_insert_post( $post ); if ( is_wp_error($revision_id) ) return $revision_id; if ( $revision_id ) { /** * Fires once a revision has been saved. * * @since 2.6.0 * * @param int $revision_id Post revision ID. */ do_action( '_wp_put_post_revision', $revision_id ); } return $revision_id; } /** * Gets a post revision. * * @since 2.6.0 * * @param int|WP_Post $post The post ID or object. * @param string $output Optional. OBJECT, ARRAY_A, or ARRAY_N. * @param string $filter Optional sanitation filter. @see sanitize_post(). * @return WP_Post|array|null Null if error or post object if success. */ function wp_get_post_revision(&$post, $output = OBJECT, $filter = 'raw') { if ( !$revision = get_post( $post, OBJECT, $filter ) ) return $revision; if ( 'revision' !== $revision->post_type ) return null; if ( $output == OBJECT ) { return $revision; } elseif ( $output == ARRAY_A ) { $_revision = get_object_vars($revision); return $_revision; } elseif ( $output == ARRAY_N ) { $_revision = array_values(get_object_vars($revision)); return $_revision; } return $revision; } /** * Restores a post to the specified revision. * * Can restore a past revision using all fields of the post revision, or only selected fields. * * @since 2.6.0 * * @param int|WP_Post $revision_id Revision ID or revision object. * @param array $fields Optional. What fields to restore from. Defaults to all. * @return int|false|null Null if error, false if no fields to restore, (int) post ID if success. */ function wp_restore_post_revision( $revision_id, $fields = null ) { if ( !$revision = wp_get_post_revision( $revision_id, ARRAY_A ) ) return $revision; if ( !is_array( $fields ) ) $fields = array_keys( _wp_post_revision_fields() ); $update = array(); foreach ( array_intersect( array_keys( $revision ), $fields ) as $field ) { $update[$field] = $revision[$field]; } if ( !$update ) return false; $update['ID'] = $revision['post_parent']; $update = wp_slash( $update ); //since data is from db $post_id = wp_update_post( $update ); if ( ! $post_id || is_wp_error( $post_id ) ) return $post_id; // Add restore from details $restore_details = array( 'restored_revision_id' => $revision_id, 'restored_by_user' => get_current_user_id(), 'restored_time' => time() ); update_post_meta( $post_id, '_post_restored_from', $restore_details ); // Update last edit user update_post_meta( $post_id, '_edit_last', get_current_user_id() ); /** * Fires after a post revision has been restored. * * @since 2.6.0 * * @param int $post_id Post ID. * @param int $revision_id Post revision ID. */ do_action( 'wp_restore_post_revision', $post_id, $revision['ID'] ); return $post_id; } /** * Deletes a revision. * * Deletes the row from the posts table corresponding to the specified revision. * * @since 2.6.0 * * @param int|WP_Post $revision_id Revision ID or revision object. * @return array|false|WP_Post|WP_Error|null Null or WP_Error if error, deleted post if success. */ function wp_delete_post_revision( $revision_id ) { if ( ! $revision = wp_get_post_revision( $revision_id ) ) { return $revision; } $delete = wp_delete_post( $revision->ID ); if ( $delete ) { /** * Fires once a post revision has been deleted. * * @since 2.6.0 * * @param int $revision_id Post revision ID. * @param object|array $revision Post revision object or array. */ do_action( 'wp_delete_post_revision', $revision->ID, $revision ); } return $delete; } /** * Returns all revisions of specified post. * * @since 2.6.0 * * @param int|WP_Post $post_id Optional. Post ID or WP_Post object. Default is global $post. * @return array An array of revisions, or an empty array if none. */ function wp_get_post_revisions( $post_id = 0, $args = null ) { $post = get_post( $post_id ); if ( ! $post || empty( $post->ID ) ) return array(); $defaults = array( 'order' => 'DESC', 'orderby' => 'date ID', 'check_enabled' => true ); $args = wp_parse_args( $args, $defaults ); if ( $args['check_enabled'] && ! wp_revisions_enabled( $post ) ) return array(); $args = array_merge( $args, array( 'post_parent' => $post->ID, 'post_type' => 'revision', 'post_status' => 'inherit' ) ); if ( ! $revisions = get_children( $args ) ) return array(); return $revisions; } /** * Determine if revisions are enabled for a given post. * * @since 3.6.0 * * @param WP_Post $post The post object. * @return bool True if number of revisions to keep isn't zero, false otherwise. */ function wp_revisions_enabled( $post ) { return wp_revisions_to_keep( $post ) !== 0; } /** * Determine how many revisions to retain for a given post. * * By default, an infinite number of revisions are kept. * * The constant WP_POST_REVISIONS can be set in wp-config to specify the limit * of revisions to keep. * * @since 3.6.0 * * @param WP_Post $post The post object. * @return int The number of revisions to keep. */ function wp_revisions_to_keep( $post ) { $num = WP_POST_REVISIONS; if ( true === $num ) $num = -1; else $num = intval( $num ); if ( ! post_type_supports( $post->post_type, 'revisions' ) ) $num = 0; /** * Filter the number of revisions to save for the given post. * * Overrides the value of WP_POST_REVISIONS. * * @since 3.6.0 * * @param int $num Number of revisions to store. * @param WP_Post $post Post object. */ return (int) apply_filters( 'wp_revisions_to_keep', $num, $post ); } /** * Sets up the post object for preview based on the post autosave. * * @since 2.7.0 * @access private * * @param WP_Post $post * @return WP_Post|false */ function _set_preview( $post ) { if ( ! is_object( $post ) ) { return $post; } $preview = wp_get_post_autosave( $post->ID ); if ( ! is_object( $preview ) ) { return $post; } $preview = sanitize_post( $preview ); $post->post_content = $preview->post_content; $post->post_title = $preview->post_title; $post->post_excerpt = $preview->post_excerpt; add_filter( 'get_the_terms', '_wp_preview_terms_filter', 10, 3 ); return $post; } /** * Filters the latest content for preview from the post autosave. * * @since 2.7.0 * @access private */ function _show_post_preview() { if ( isset($_GET['preview_id']) && isset($_GET['preview_nonce']) ) { $id = (int) $_GET['preview_id']; if ( false === wp_verify_nonce( $_GET['preview_nonce'], 'post_preview_' . $id ) ) wp_die( __('You do not have permission to preview drafts.') ); add_filter('the_preview', '_set_preview'); } } /** * Filters terms lookup to set the post format. * * @since 3.6.0 * @access private * * @param array $terms * @param int $post_id * @param string $taxonomy * @return array */ function _wp_preview_terms_filter( $terms, $post_id, $taxonomy ) { if ( ! $post = get_post() ) return $terms; if ( empty( $_REQUEST['post_format'] ) || $post->ID != $post_id || 'post_format' != $taxonomy || 'revision' == $post->post_type ) return $terms; if ( 'standard' == $_REQUEST['post_format'] ) $terms = array(); elseif ( $term = get_term_by( 'slug', 'post-format-' . sanitize_key( $_REQUEST['post_format'] ), 'post_format' ) ) $terms = array( $term ); // Can only have one post format return $terms; } /** * Gets the post revision version. * * @since 3.6.0 * @access private * * @param WP_Post $revision * @return int|false */ function _wp_get_post_revision_version( $revision ) { if ( is_object( $revision ) ) $revision = get_object_vars( $revision ); elseif ( !is_array( $revision ) ) return false; if ( preg_match( '/^\d+-(?:autosave|revision)-v(\d+)$/', $revision['post_name'], $matches ) ) return (int) $matches[1]; return 0; } /** * Upgrade the revisions author, add the current post as a revision and set the revisions version to 1 * * @since 3.6.0 * @access private * * @global wpdb $wpdb WordPress database abstraction object. * * @param WP_Post $post Post object * @param array $revisions Current revisions of the post * @return bool true if the revisions were upgraded, false if problems */ function _wp_upgrade_revisions_of_post( $post, $revisions ) { global $wpdb; // Add post option exclusively $lock = "revision-upgrade-{$post->ID}"; $now = time(); $result = $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO `$wpdb->options` (`option_name`, `option_value`, `autoload`) VALUES (%s, %s, 'no') /* LOCK */", $lock, $now ) ); if ( ! $result ) { // If we couldn't get a lock, see how old the previous lock is $locked = get_option( $lock ); if ( ! $locked ) { // Can't write to the lock, and can't read the lock. // Something broken has happened return false; } if ( $locked > $now - 3600 ) { // Lock is not too old: some other process may be upgrading this post. Bail. return false; } // Lock is too old - update it (below) and continue } // If we could get a lock, re-"add" the option to fire all the correct filters. update_option( $lock, $now ); reset( $revisions ); $add_last = true; do { $this_revision = current( $revisions ); $prev_revision = next( $revisions ); $this_revision_version = _wp_get_post_revision_version( $this_revision ); // Something terrible happened if ( false === $this_revision_version ) continue; // 1 is the latest revision version, so we're already up to date. // No need to add a copy of the post as latest revision. if ( 0 < $this_revision_version ) { $add_last = false; continue; } // Always update the revision version $update = array( 'post_name' => preg_replace( '/^(\d+-(?:autosave|revision))[\d-]*$/', '$1-v1', $this_revision->post_name ), ); // If this revision is the oldest revision of the post, i.e. no $prev_revision, // the correct post_author is probably $post->post_author, but that's only a good guess. // Update the revision version only and Leave the author as-is. if ( $prev_revision ) { $prev_revision_version = _wp_get_post_revision_version( $prev_revision ); // If the previous revision is already up to date, it no longer has the information we need :( if ( $prev_revision_version < 1 ) $update['post_author'] = $prev_revision->post_author; } // Upgrade this revision $result = $wpdb->update( $wpdb->posts, $update, array( 'ID' => $this_revision->ID ) ); if ( $result ) wp_cache_delete( $this_revision->ID, 'posts' ); } while ( $prev_revision ); delete_option( $lock ); // Add a copy of the post as latest revision. if ( $add_last ) wp_save_post_revision( $post->ID ); return true; } * @since 1.2.0 */ if ( ! defined( 'CUSTOM_TAGS' ) ) define( 'CUSTOM_TAGS', false ); // Ensure that these variables are added to the global namespace // (e.g. if using namespaces / autoload in the current PHP environment). global $allowedposttags, $allowedtags, $allowedentitynames; if ( ! CUSTOM_TAGS ) { /** * Kses global for default allowable HTML tags. * * Can be override by using CUSTOM_TAGS constant. * * @global array $allowedposttags * @since 2.0.0 */ $allowedposttags = array( 'address' => array(), 'a' => array( 'href' => true, 'rel' => true, 'rev' => true, 'name' => true, 'target' => true, ), 'abbr' => array(), 'acronym' => array(), 'area' => array( 'alt' => true, 'coords' => true, 'href' => true, 'nohref' => true, 'shape' => true, 'target' => true, ), 'article' => array( 'align' => true, 'dir' => true, 'lang' => true, 'xml:lang' => true, ), 'aside' => array( 'align' => true, 'dir' => true, 'lang' => true, 'xml:lang' => true, ), 'audio' => array( 'autoplay' => true, 'controls' => true, 'loop' => true, 'muted' => true, 'preload' => true, 'src' => true, ), 'b' => array(), 'bdo' => array( 'dir' => true, ), 'big' => array(), 'blockquote' => array( 'cite' => true, 'lang' => true, 'xml:lang' => true, ), 'br' => array(), 'button' => array( 'disabled' => true, 'name' => true, 'type' => true, 'value' => true, ), 'caption' => array( 'align' => true, ), 'cite' => array( 'dir' => true, 'lang' => true, ), 'code' => array(), 'col' => array( 'align' => true, 'char' => true, 'charoff' => true, 'span' => true, 'dir' => true, 'valign' => true, 'width' => true, ), 'colgroup' => array( 'align' => true, 'char' => true, 'charoff' => true, 'span' => true, 'valign' => true, 'width' => true, ), 'del' => array( 'datetime' => true, ), 'dd' => array(), 'dfn' => array(), 'details' => array( 'align' => true, 'dir' => true, 'lang' => true, 'open' => true, 'xml:lang' => true, ), 'div' => array( 'align' => true, 'dir' => true, 'lang' => true, 'xml:lang' => true, ), 'dl' => array(), 'dt' => array(), 'em' => array(), 'fieldset' => array(), 'figure' => array( 'align' => true, 'dir' => true, 'lang' => true, 'xml:lang' => true, ), 'figcaption' => array( 'align' => true, 'dir' => true, 'lang' => true, 'xml:lang' => true, ), 'font' => array( 'color' => true, 'face' => true, 'size' => true, ), 'footer' => array( 'align' => true, 'dir' => true, 'lang' => true, 'xml:lang' => true, ), 'form' => array( 'action' => true, 'accept' => true, 'accept-charset' => true, 'enctype' => true, 'method' => true, 'name' => true, 'target' => true, ), 'h1' => array( 'align' => true, ), 'h2' => array( 'align' => true, ), 'h3' => array( 'align' => true, ), 'h4' => array( 'align' => true, ), 'h5' => array( 'align' => true, ), 'h6' => array( 'align' => true, ), 'header' => array( 'align' => true, 'dir' => true, 'lang' => true, 'xml:lang' => true, ), 'hgroup' => array( 'align' => true, 'dir' => true, 'lang' => true, 'xml:lang' => true, ), 'hr' => array( 'align' => true, 'noshade' => true, 'size' => true, 'width' => true, ), 'i' => array(), 'img' => array( 'alt' => true, 'align' => true, 'border' => true, 'height' => true, 'hspace' => true, 'longdesc' => true, 'vspace' => true, 'src' => true, 'usemap' => true, 'width' => true, ), 'ins' => array( 'datetime' => true, 'cite' => true, ), 'kbd' => array(), 'label' => array( 'for' => true, ), 'legend' => array( 'align' => true, ), 'li' => array( 'align' => true, 'value' => true, ), 'map' => array( 'name' => true, ), 'mark' => array(), 'menu' => array( 'type' => true, ), 'nav' => array( 'align' => true, 'dir' => true, 'lang' => true, 'xml:lang' => true, ), 'p' => array( 'align' => true, 'dir' => true, 'lang' => true, 'xml:lang' => true, ), 'pre' => array( 'width' => true, ), 'q' => array( 'cite' => true, ), 's' => array(), 'samp' => array(), 'span' => array( 'dir' => true, 'align' => true, 'lang' => true, 'xml:lang' => true, ), 'section' => array( 'align' => true, 'dir' => true, 'lang' => true, 'xml:lang' => true, ), 'small' => array(), 'strike' => array(), 'strong' => array(), 'sub' => array(), 'summary' => array( 'align' => true, 'dir' => true, 'lang' => true, 'xml:lang' => true, ), 'sup' => array(), 'table' => array( 'align' => true, 'bgcolor' => true, 'border' => true, 'cellpadding' => true, 'cellspacing' => true, 'dir' => true, 'rules' => true, 'summary' => true, 'width' => true, ), 'tbody' => array( 'align' => true, 'char' => true, 'charoff' => true, 'valign' => true, ), 'td' => array( 'abbr' => true, 'align' => true, 'axis' => true, 'bgcolor' => true, 'char' => true, 'charoff' => true, 'colspan' => true, 'dir' => true, 'headers' => true, 'height' => true, 'nowrap' => true, 'rowspan' => true, 'scope' => true, 'valign' => true, 'width' => true, ), 'textarea' => array( 'cols' => true, 'rows' => true, 'disabled' => true, 'name' => true, 'readonly' => true, ), 'tfoot' => array( 'align' => true, 'char' => true, 'charoff' => true, 'valign' => true, ), 'th' => array( 'abbr' => true, 'align' => true, 'axis' => true, 'bgcolor' => true, 'char' => true, 'charoff' => true, 'colspan' => true, 'headers' => true, 'height' => true, 'nowrap' => true, 'rowspan' => true, 'scope' => true, 'valign' => true, 'width' => true, ), 'thead' => array( 'align' => true, 'char' => true, 'charoff' => true, 'valign' => true, ), 'title' => array(), 'tr' => array( 'align' => true, 'bgcolor' => true, 'char' => true, 'charoff' => true, 'valign' => true, ), 'track' => array( 'default' => true, 'kind' => true, 'label' => true, 'src' => true, 'srclang' => true, ), 'tt' => array(), 'u' => array(), 'ul' => array( 'type' => true, ), 'ol' => array( 'start' => true, 'type' => true, ), 'var' => array(), 'video' => array( 'autoplay' => true, 'controls' => true, 'height' => true, 'loop' => true, 'muted' => true, 'poster' => true, 'preload' => true, 'src' => true, 'width' => true, ), ); /** * Kses allowed HTML elements. * * @global array $allowedtags * @since 1.0.0 */ $allowedtags = array( 'a' => array( 'href' => true, 'title' => true, ), 'abbr' => array( 'title' => true, ), 'acronym' => array( 'title' => true, ), 'b' => array(), 'blockquote' => array( 'cite' => true, ), 'cite' => array(), 'code' => array(), 'del' => array( 'datetime' => true, ), 'em' => array(), 'i' => array(), 'q' => array( 'cite' => true, ), 's' => array(), 'strike' => array(), 'strong' => array(), ); $allowedentitynames = array( 'nbsp', 'iexcl', 'cent', 'pound', 'curren', 'yen', 'brvbar', 'sect', 'uml', 'copy', 'ordf', 'laquo', 'not', 'shy', 'reg', 'macr', 'deg', 'plusmn', 'acute', 'micro', 'para', 'middot', 'cedil', 'ordm', 'raquo', 'iquest', 'Agrave', 'Aacute', 'Acirc', 'Atilde', 'Auml', 'Aring', 'AElig', 'Ccedil', 'Egrave', 'Eacute', 'Ecirc', 'Euml', 'Igrave', 'Iacute', 'Icirc', 'Iuml', 'ETH', 'Ntilde', 'Ograve', 'Oacute', 'Ocirc', 'Otilde', 'Ouml', 'times', 'Oslash', 'Ugrave', 'Uacute', 'Ucirc', 'Uuml', 'Yacute', 'THORN', 'szlig', 'agrave', 'aacute', 'acirc', 'atilde', 'auml', 'aring', 'aelig', 'ccedil', 'egrave', 'eacute', 'ecirc', 'euml', 'igrave', 'iacute', 'icirc', 'iuml', 'eth', 'ntilde', 'ograve', 'oacute', 'ocirc', 'otilde', 'ouml', 'divide', 'oslash', 'ugrave', 'uacute', 'ucirc', 'uuml', 'yacute', 'thorn', 'yuml', 'quot', 'amp', 'lt', 'gt', 'apos', 'OElig', 'oelig', 'Scaron', 'scaron', 'Yuml', 'circ', 'tilde', 'ensp', 'emsp', 'thinsp', 'zwnj', 'zwj', 'lrm', 'rlm', 'ndash', 'mdash', 'lsquo', 'rsquo', 'sbquo', 'ldquo', 'rdquo', 'bdquo', 'dagger', 'Dagger', 'permil', 'lsaquo', 'rsaquo', 'euro', 'fnof', 'Alpha', 'Beta', 'Gamma', 'Delta', 'Epsilon', 'Zeta', 'Eta', 'Theta', 'Iota', 'Kappa', 'Lambda', 'Mu', 'Nu', 'Xi', 'Omicron', 'Pi', 'Rho', 'Sigma', 'Tau', 'Upsilon', 'Phi', 'Chi', 'Psi', 'Omega', 'alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta', 'eta', 'theta', 'iota', 'kappa', 'lambda', 'mu', 'nu', 'xi', 'omicron', 'pi', 'rho', 'sigmaf', 'sigma', 'tau', 'upsilon', 'phi', 'chi', 'psi', 'omega', 'thetasym', 'upsih', 'piv', 'bull', 'hellip', 'prime', 'Prime', 'oline', 'frasl', 'weierp', 'image', 'real', 'trade', 'alefsym', 'larr', 'uarr', 'rarr', 'darr', 'harr', 'crarr', 'lArr', 'uArr', 'rArr', 'dArr', 'hArr', 'forall', 'part', 'exist', 'empty', 'nabla', 'isin', 'notin', 'ni', 'prod', 'sum', 'minus', 'lowast', 'radic', 'prop', 'infin', 'ang', 'and', 'or', 'cap', 'cup', 'int', 'sim', 'cong', 'asymp', 'ne', 'equiv', 'le', 'ge', 'sub', 'sup', 'nsub', 'sube', 'supe', 'oplus', 'otimes', 'perp', 'sdot', 'lceil', 'rceil', 'lfloor', 'rfloor', 'lang', 'rang', 'loz', 'spades', 'clubs', 'hearts', 'diams', 'sup1', 'sup2', 'sup3', 'frac14', 'frac12', 'frac34', 'there4', ); $allowedposttags = array_map( '_wp_add_global_attributes', $allowedposttags ); } else { $allowedtags = wp_kses_array_lc( $allowedtags ); $allowedposttags = wp_kses_array_lc( $allowedposttags ); } /** * Filters content and keeps only allowable HTML elements. * * This function makes sure that only the allowed HTML element names, attribute * names and attribute values plus only sane HTML entities will occur in * $string. You have to remove any slashes from PHP's magic quotes before you * call this function. * * The default allowed protocols are 'http', 'https', 'ftp', 'mailto', 'news', * 'irc', 'gopher', 'nntp', 'feed', 'telnet, 'mms', 'rtsp' and 'svn'. This * covers all common link protocols, except for 'javascript' which should not * be allowed for untrusted users. * * @since 1.0.0 * * @param string $string Content to filter through kses * @param array $allowed_html List of allowed HTML elements * @param array $allowed_protocols Optional. Allowed protocol in links. * @return string Filtered content with only allowed HTML elements */ function wp_kses( $string, $allowed_html, $allowed_protocols = array() ) { if ( empty( $allowed_protocols ) ) $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); $string = wp_kses_hook($string, $allowed_html, $allowed_protocols); // WP changed the order of these funcs and added args to wp_kses_hook 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 ); // 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, angle braces, and entities. $value = esc_attr( $value ); // 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. * * @since 3.5.0 * * @global array $allowedposttags * @global array $allowedtags * @global array $allowedentitynames * * @param string $context The context for which to retrieve tags. * Allowed values are post, strip, data,entities, or * the name of a field filter such as pre_user_description. * @return array List of allowed tags and their allowed attributes. */ function wp_kses_allowed_html( $context = '' ) { global $allowedposttags, $allowedtags, $allowedentitynames; if ( is_array( $context ) ) { /** * Filter HTML elements allowed for a given context. * * @since 3.5.0 * * @param string $tags Allowed tags, attributes, and/or entities. * @param string $context Context to judge allowed tags by. Allowed values are 'post', * 'data', 'strip', 'entities', 'explicit', or the name of a filter. */ return apply_filters( 'wp_kses_allowed_html', $context, 'explicit' ); } switch ( $context ) { case 'post': /** This filter is documented in wp-includes/kses.php */ return apply_filters( 'wp_kses_allowed_html', $allowedposttags, $context ); case 'user_description': case 'pre_user_description': $tags = $allowedtags; $tags['a']['rel'] = true; /** This filter is documented in wp-includes/kses.php */ return apply_filters( 'wp_kses_allowed_html', $tags, $context ); case 'strip': /** This filter is documented in wp-includes/kses.php */ return apply_filters( 'wp_kses_allowed_html', array(), $context ); case 'entities': /** This filter is documented in wp-includes/kses.php */ return apply_filters( 'wp_kses_allowed_html', $allowedentitynames, $context); case 'data': default: /** This filter is documented in wp-includes/kses.php */ return apply_filters( 'wp_kses_allowed_html', $allowedtags, $context ); } } /** * You add any kses hooks here. * * There is currently only one kses WordPress hook and it is called here. All * parameters are passed to the hooks and expected to receive a string. * * @since 1.0.0 * * @param string $string Content to filter through kses * @param array $allowed_html List of allowed HTML elements * @param array $allowed_protocols Allowed protocol in links * @return string Filtered content through 'pre_kses' hook */ function wp_kses_hook( $string, $allowed_html, $allowed_protocols ) { /** * Filter content to be run through kses. * * @since 2.3.0 * * @param string $string Content to run through kses. * @param array $allowed_html Allowed HTML elements. * @param array $allowed_protocols Allowed protocol in links. */ return apply_filters( 'pre_kses', $string, $allowed_html, $allowed_protocols ); } /** * This function returns kses' version number. * * @since 1.0.0 * * @return string KSES Version Number */ function wp_kses_version() { return '0.2.2'; } /** * Searches for HTML tags, no matter how malformed. * * It also matches stray ">" characters. * * @since 1.0.0 * * @global array $pass_allowed_html * @global array $pass_allowed_protocols * * @param string $string Content to filter * @param array $allowed_html Allowed HTML elements * @param array $allowed_protocols Allowed protocols to keep * @return string Content with fixed HTML tags */ function wp_kses_split( $string, $allowed_html, $allowed_protocols ) { global $pass_allowed_html, $pass_allowed_protocols; $pass_allowed_html = $allowed_html; $pass_allowed_protocols = $allowed_protocols; return preg_replace_callback( '%(|$))|(<[^>]*(>|$)|>)%', '_wp_kses_split_callback', $string ); } /** * Callback for wp_kses_split. * * @since 3.1.0 * @access private * * @global array $pass_allowed_html * @global array $pass_allowed_protocols * * @return string */ function _wp_kses_split_callback( $match ) { global $pass_allowed_html, $pass_allowed_protocols; return wp_kses_split2( $match[0], $pass_allowed_html, $pass_allowed_protocols ); } /** * Callback for wp_kses_split for fixing malformed HTML tags. * * This function does a lot of work. It rejects some very malformed things like * <:::>. It returns an empty string, if the element isn't allowed (look ma, no * strip_tags()!). Otherwise it splits the tag into an element and an attribute * list. * * After the tag is split into an element and an attribute list, it is run * through another filter which will remove illegal attributes and once that is * completed, will be returned. * * @access private * @since 1.0.0 * * @param string $string Content to filter * @param array $allowed_html Allowed HTML elements * @param array $allowed_protocols Allowed protocols to keep * @return string Fixed HTML element */ function wp_kses_split2($string, $allowed_html, $allowed_protocols) { $string = wp_kses_stripslashes($string); if (substr($string, 0, 1) != '<') return '>'; // It matched a ">" character if ( ''), '', $string ); while ( $string != ($newstring = wp_kses($string, $allowed_html, $allowed_protocols)) ) $string = $newstring; if ( $string == '' ) return ''; // prevent multiple dashes in comments $string = preg_replace('/--+/', '-', $string); // prevent three dashes closing a comment $string = preg_replace('/-$/', '', $string); return ""; } // Allow HTML comments if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9]+)([^>]*)>?$%', $string, $matches)) return ''; // It's seriously malformed $slash = trim($matches[1]); $elem = $matches[2]; $attrlist = $matches[3]; if ( ! is_array( $allowed_html ) ) $allowed_html = wp_kses_allowed_html( $allowed_html ); if ( ! isset($allowed_html[strtolower($elem)]) ) return ''; // They are using a not allowed HTML element if ($slash != '') return ""; // No attributes are allowed for closing elements return wp_kses_attr( $elem, $attrlist, $allowed_html, $allowed_protocols ); } /** * Removes all attributes, if none are allowed for this element. * * If some are allowed it calls wp_kses_hair() to split them further, and then * it builds up new HTML code from the data that kses_hair() returns. It also * removes "<" and ">" characters, if there are any left. One more thing it does * is to check if the tag has a closing XHTML slash, and if it does, it puts one * in the returned code as well. * * @since 1.0.0 * * @param string $element HTML element/tag * @param string $attr HTML attributes from HTML element to closing HTML element tag * @param array $allowed_html Allowed HTML elements * @param array $allowed_protocols Allowed protocols to keep * @return string Sanitized HTML element */ function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols) { if ( ! is_array( $allowed_html ) ) $allowed_html = wp_kses_allowed_html( $allowed_html ); // Is there a closing XHTML slash at the end of the attributes? $xhtml_slash = ''; if (preg_match('%\s*/\s*$%', $attr)) $xhtml_slash = ' /'; // Are any attributes allowed at all for this element? if ( ! isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0 ) return "<$element$xhtml_slash>"; // Split it $attrarr = wp_kses_hair($attr, $allowed_protocols); // Go through $attrarr, and save the allowed attributes for this element // in $attr2 $attr2 = ''; foreach ( $attrarr as $arreach ) { if ( wp_kses_attr_check( $arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html ) ) { $attr2 .= ' '.$arreach['whole']; } } // Remove any "<" or ">" characters $attr2 = preg_replace('/[<>]/', '', $attr2); 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. * * This function does a lot of work. It parses an attribute list into an array * with attribute data, and tries to do the right thing even if it gets weird * input. It will add quotes around attribute values that don't have any quotes * or apostrophes around them, to make it easier to produce HTML code that will * conform to W3C's HTML specification. It will also remove bad URL protocols * from attribute values. It also reduces duplicate attributes by using the * attribute defined first (foo='bar' foo='baz' will result in foo='bar'). * * @since 1.0.0 * * @param string $attr Attribute list from HTML element to closing HTML element tag * @param array $allowed_protocols Allowed protocols to keep * @return array List of attributes after parsing */ function wp_kses_hair($attr, $allowed_protocols) { $attrarr = array(); $mode = 0; $attrname = ''; $uris = array('xmlns', 'profile', 'href', 'src', 'cite', 'classid', 'codebase', 'data', 'usemap', 'longdesc', 'action'); // Loop through the whole attribute list while (strlen($attr) != 0) { $working = 0; // Was the last operation successful? switch ($mode) { case 0 : // attribute name, href for instance if ( preg_match('/^([-a-zA-Z:]+)/', $attr, $match ) ) { $attrname = $match[1]; $working = $mode = 1; $attr = preg_replace( '/^[-a-zA-Z:]+/', '', $attr ); } break; case 1 : // equals sign or valueless ("selected") if (preg_match('/^\s*=\s*/', $attr)) // equals sign { $working = 1; $mode = 2; $attr = preg_replace('/^\s*=\s*/', '', $attr); break; } if (preg_match('/^\s+/', $attr)) // valueless { $working = 1; $mode = 0; if(false === array_key_exists($attrname, $attrarr)) { $attrarr[$attrname] = array ('name' => $attrname, 'value' => '', 'whole' => $attrname, 'vless' => 'y'); } $attr = preg_replace('/^\s+/', '', $attr); } break; case 2 : // attribute value, a URL after href= for instance if (preg_match('%^"([^"]*)"(\s+|/?$)%', $attr, $match)) // "value" { $thisval = $match[1]; if ( in_array(strtolower($attrname), $uris) ) $thisval = wp_kses_bad_protocol($thisval, $allowed_protocols); if(false === array_key_exists($attrname, $attrarr)) { $attrarr[$attrname] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname=\"$thisval\"", 'vless' => 'n'); } $working = 1; $mode = 0; $attr = preg_replace('/^"[^"]*"(\s+|$)/', '', $attr); break; } if (preg_match("%^'([^']*)'(\s+|/?$)%", $attr, $match)) // 'value' { $thisval = $match[1]; if ( in_array(strtolower($attrname), $uris) ) $thisval = wp_kses_bad_protocol($thisval, $allowed_protocols); if(false === array_key_exists($attrname, $attrarr)) { $attrarr[$attrname] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname='$thisval'", 'vless' => 'n'); } $working = 1; $mode = 0; $attr = preg_replace("/^'[^']*'(\s+|$)/", '', $attr); break; } if (preg_match("%^([^\s\"']+)(\s+|/?$)%", $attr, $match)) // value { $thisval = $match[1]; if ( in_array(strtolower($attrname), $uris) ) $thisval = wp_kses_bad_protocol($thisval, $allowed_protocols); if(false === array_key_exists($attrname, $attrarr)) { $attrarr[$attrname] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname=\"$thisval\"", 'vless' => 'n'); } // We add quotes to conform to W3C's HTML spec. $working = 1; $mode = 0; $attr = preg_replace("%^[^\s\"']+(\s+|$)%", '', $attr); } break; } // switch if ($working == 0) // not well formed, remove and try again { $attr = wp_kses_html_error($attr); $mode = 0; } } // while if ($mode == 1 && false === array_key_exists($attrname, $attrarr)) // special case, for when the attribute list ends with a valueless // attribute like "selected" $attrarr[$attrname] = array ('name' => $attrname, 'value' => '', 'whole' => $attrname, 'vless' => 'y'); 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. * * The currently implemented checks are "maxlen", "minlen", "maxval", "minval" * and "valueless". * * @since 1.0.0 * * @param string $value Attribute value * @param string $vless Whether the value is valueless. Use 'y' or 'n' * @param string $checkname What $checkvalue is checking for. * @param mixed $checkvalue What constraint the value should pass * @return bool Whether check passes */ function wp_kses_check_attr_val($value, $vless, $checkname, $checkvalue) { $ok = true; switch (strtolower($checkname)) { case 'maxlen' : // The maxlen check makes sure that the attribute value has a length not // greater than the given value. This can be used to avoid Buffer Overflows // in WWW clients and various Internet servers. if (strlen($value) > $checkvalue) $ok = false; break; case 'minlen' : // The minlen check makes sure that the attribute value has a length not // smaller than the given value. if (strlen($value) < $checkvalue) $ok = false; break; case 'maxval' : // The maxval check does two things: it checks that the attribute value is // an integer from 0 and up, without an excessive amount of zeroes or // whitespace (to avoid Buffer Overflows). It also checks that the attribute // value is not greater than the given value. // This check can be used to avoid Denial of Service attacks. if (!preg_match('/^\s{0,6}[0-9]{1,6}\s{0,6}$/', $value)) $ok = false; if ($value > $checkvalue) $ok = false; break; case 'minval' : // The minval check makes sure that the attribute value is a positive integer, // and that it is not smaller than the given value. if (!preg_match('/^\s{0,6}[0-9]{1,6}\s{0,6}$/', $value)) $ok = false; if ($value < $checkvalue) $ok = false; break; case 'valueless' : // The valueless check makes sure if the attribute has a value // (like ) or not (