Server : Apache System : Linux pod-100823:apache2_74:v0.5.7 5.4.0-1138-gcp #147~18.04.1-Ubuntu SMP Mon Oct 7 21:46:26 UTC 2024 x86_64 User : www-data ( 33) PHP Version : 7.4.33.7 Disable Function : apache_child_terminate,apache_get_modules,apache_get_version,apache_getenv,apache_note,apache_setenv,disk_free_space,disk_total_space,diskfreespace,dl,exec,fastcgi_finish_request,link,opcache_compile_file,opcache_get_configuration,opcache_invalidate,opcache_is_script_cached,opcache_reset,passthru,pclose,pcntl_exec,popen,posix_getpid,posix_getppid,posix_getpwuid,posix_kill,posix_mkfifo,posix_setegid,posix_seteuid,posix_setgid,posix_setpgid,posix_setsid,posix_setuid,posix_uname,proc_close,proc_get_status,proc_nice,proc_open,proc_terminate,realpath_cache_get,shell_exec,show_source,symlink,system Directory : /nas/content/live/attorneyexperi/wp-content/plugins/imagify/inc/classes/ |
<?php defined( 'ABSPATH' ) || die( 'Cheatin’ uh?' ); /** * Imagify DB class. It reunites tools to work with the DB. * * @since 1.6.13 * @author Grégory Viguier */ class Imagify_DB { /** * Class version. * * @var string */ const VERSION = '1.0.1'; /** * Some hosts limit the number of JOINs in SQL queries, but we need them. * * @since 1.6.13 * @access public * @author Grégory Viguier */ public static function unlimit_joins() { global $wpdb; static $done = false; if ( $done ) { return; } $done = true; $query = 'SET SQL_BIG_SELECTS=1'; /** * Filter the SQL query allowing to remove the limit on JOINs. * * @since 1.6.13 * @author Grégory Viguier * * @param string|bool $query The query. False to prevent any query. */ $query = apply_filters( 'imagify_db_unlimit_joins_query', $query ); if ( $query && is_string( $query ) ) { $wpdb->query( $query ); // WPCS: unprepared SQL ok. } } /** * Change an array of values into a comma separated list, ready to be used in a `IN ()` clause. * * @since 1.6.13 * @access public * @author Grégory Viguier * * @param array $values An array of values. * @return string A comma separated list of values. */ public static function prepare_values_list( $values ) { $values = esc_sql( (array) $values ); $values = array_map( array( __CLASS__, 'quote_string' ), $values ); return implode( ',', $values ); } /** * Wrap a value in quotes, unless it's an integer. * * @since 1.6.13 * @access public * @author Grégory Viguier * * @param int|string $value A value. * @return int|string */ public static function quote_string( $value ) { return is_numeric( $value ) ? $value : "'" . addcslashes( $value, "'" ) . "'"; } /** * First half of escaping for LIKE special characters % and _ before preparing for MySQL. * Use this only before wpdb::prepare() or esc_sql(). Reversing the order is very bad for security. * * Example Prepared Statement: * $wild = '%'; * $find = 'only 43% of planets'; * $like = $wild . $wpdb->esc_like( $find ) . $wild; * $sql = $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE post_content LIKE %s", $like ); * * Example Escape Chain: * $sql = esc_sql( $wpdb->esc_like( $input ) ); * * @since 1.7 * @access public * @author Grégory Viguier * * @param string $text The raw text to be escaped. The input typed by the user should have no extra or deleted slashes. * @return string Text in the form of a LIKE phrase. The output is not SQL safe. Call $wpdb::prepare() or real_escape next. */ public static function esc_like( $text ) { global $wpdb; if ( method_exists( $wpdb, 'esc_like' ) ) { // Introduced in WP 4.0.0. return $wpdb->esc_like( $text ); } return addcslashes( $text, '_%\\' ); } /** * Get Imagify mime types, ready to be used in a `IN ()` clause. * * @since 1.6.13 * @since 1.9 Added $type parameter. * @access public * @author Grégory Viguier * * @param string $type One of 'image', 'not-image'. Any other value will return all mime types. * @return string A comma separated list of mime types. */ public static function get_mime_types( $type = null ) { static $mime_types = []; if ( empty( $type ) ) { $type = 'all'; } if ( ! isset( $mime_types[ $type ] ) ) { $mime_types[ $type ] = self::prepare_values_list( imagify_get_mime_types( $type ) ); } return $mime_types[ $type ]; } /** * Get post statuses related to attachments, ready to be used in a `IN ()` clause. * * @since 1.7 * @access public * @author Grégory Viguier * * @return string A comma separated list of post statuses. */ public static function get_post_statuses() { static $statuses; if ( ! isset( $statuses ) ) { $statuses = self::prepare_values_list( imagify_get_post_statuses() ); } return $statuses; } /** * Get the SQL JOIN clause to use to get only attachments that have the required WP metadata. * It returns an empty string if the database has no attachments without the required metadada. * It also triggers Imagify_DB::unlimit_joins(). * * @param string $id_field An ID field to match the metadata ID against in the JOIN clause. * Default is the posts table `ID` field, using the `p` alias: `p.ID`. * In case of "false" value or PEBKAC, fallback to the same field without alias. * @param bool $matching Set to false to get a query to fetch metas NOT matching the file extensions. * @param bool $test Test if the site has attachments without required metadata before returning the query. False to bypass the test and get the query anyway. * @param string $special_join_conditions Special conditions to apply on the join. * * @return string * @author Grégory Viguier * * @since 1.7 * @access public */ public static function get_required_wp_metadata_join_clause( $id_field = 'p.ID', $matching = true, $test = true, $special_join_conditions = '' ) { global $wpdb; if ( $test && ! imagify_has_attachments_without_required_metadata() ) { return ''; } self::unlimit_joins(); $clause = ''; if ( ! $id_field || ! is_string( $id_field ) ) { $id_field = "$wpdb->posts.ID"; } $join = $matching ? 'INNER' : 'LEFT'; $first = true; foreach ( self::get_required_wp_metadata_aliases() as $meta_name => $alias ) { if ( $first ) { $first = false; $clause .= " $join JOIN $wpdb->postmeta AS $alias ON ( $id_field = $alias.post_id AND $alias.meta_key = '$meta_name' $special_join_conditions )"; continue; } $clause .= " $join JOIN $wpdb->postmeta AS $alias ON ( $id_field = $alias.post_id AND $alias.meta_key = '$meta_name' )"; } return $clause; } /** * Get the SQL part to be used in a WHERE clause, to get only attachments that have (in)valid '_wp_attached_file' and '_wp_attachment_metadata' metadatas. * It returns an empty string if the database has no attachments without the required metadada. * * @since 1.7 * @since 1.7.1.2 Use a single $arg parameter instead of 3. New $prepared parameter. * @access public * @author Grégory Viguier * * @param array $args { * Optional. An array of arguments. * * string $aliases The aliases to use for the meta values. * bool $matching Set to false to get a query to fetch invalid metas. * bool $test Test if the site has attachments without required metadata before returning the query. False to bypass the test and get the query anyway. * bool $prepared Set to true if the query will be prepared with using $wpdb->prepare(). * }. * @return string A query. */ public static function get_required_wp_metadata_where_clause( $args = array() ) { static $query = array(); $args = imagify_merge_intersect( $args, array( 'aliases' => array(), 'matching' => true, 'test' => true, 'prepared' => false, ) ); list( $aliases, $matching, $test, $prepared ) = array_values( $args ); if ( $test && ! imagify_has_attachments_without_required_metadata() ) { return ''; } if ( $aliases && is_string( $aliases ) ) { $aliases = array( '_wp_attached_file' => $aliases, ); } elseif ( ! is_array( $aliases ) ) { $aliases = array(); } $aliases = imagify_merge_intersect( $aliases, self::get_required_wp_metadata_aliases() ); $key = implode( '|', $aliases ) . '|' . (int) $matching; if ( isset( $query[ $key ] ) ) { return $prepared ? str_replace( '%', '%%', $query[ $key ] ) : $query[ $key ]; } unset( $args['prepared'] ); $alias_1 = $aliases['_wp_attached_file']; $alias_2 = $aliases['_wp_attachment_metadata']; $extensions = self::get_extensions_where_clause( $args ); if ( $matching ) { $query[ $key ] = "AND $alias_1.meta_value NOT LIKE '%://%' AND $alias_1.meta_value NOT LIKE '_:\\\\\%' $extensions"; } else { $query[ $key ] = "AND ( $alias_2.meta_value IS NULL OR $alias_1.meta_value IS NULL OR $alias_1.meta_value LIKE '%://%' OR $alias_1.meta_value LIKE '_:\\\\\%' $extensions )"; } return $prepared ? str_replace( '%', '%%', $query[ $key ] ) : $query[ $key ]; } /** * Get the SQL part to be used in a WHERE clause, to get only attachments that have a valid file extensions. * It returns an empty string if the database has no attachments without the required metadada. * * @since 1.7 * @since 1.7.1.2 Use a single $arg parameter instead of 3. New $prepared parameter. * @access public * @author Grégory Viguier * * @param array $args { * Optional. An array of arguments. * * string $alias The alias to use for the meta value. * bool $matching Set to false to get a query to fetch metas NOT matching the file extensions. * bool $test Test if the site has attachments without required metadata before returning the query. False to bypass the test and get the query anyway. * bool $prepared Set to true if the query will be prepared with using $wpdb->prepare(). * }. * @return string A query. */ public static function get_extensions_where_clause( $args = false ) { static $extensions; static $query = array(); $args = imagify_merge_intersect( $args, array( 'alias' => array(), 'matching' => true, 'test' => true, 'prepared' => false, ) ); list( $alias, $matching, $test, $prepared ) = array_values( $args ); if ( $test && ! imagify_has_attachments_without_required_metadata() ) { return ''; } if ( ! isset( $extensions ) ) { $extensions = array_keys( imagify_get_mime_types() ); $extensions = implode( '|', $extensions ); $extensions = explode( '|', $extensions ); $extensions = array_map(function ( $ex ) { return strrev( $ex ); }, $extensions); } if ( ! $alias ) { $alias = self::get_required_wp_metadata_aliases(); $alias = $alias['_wp_attached_file']; } $key = $alias . '|' . (int) $matching; if ( isset( $query[ $key ] ) ) { return $prepared ? str_replace( '%', '%%', $query[ $key ] ) : $query[ $key ]; } $regex = '^' . implode( '\..*|^', $extensions ) . '\..*'; if ( $matching ) { $query[ $key ] = "AND REVERSE (LOWER( $alias.meta_value )) REGEXP '$regex'"; } else { $query[ $key ] = "AND REVERSE (LOWER( $alias.meta_value )) NOT REGEXP '$regex'"; } return $prepared ? str_replace( '%', '%%', $query[ $key ] ) : $query[ $key ]; } /** * Get the aliases used for the metas in self::get_required_wp_metadata_join_clause(), self::get_required_wp_metadata_where_clause(), and self::get_extensions_where_clause(). * * @since 1.7 * @access public * @author Grégory Viguier * * @return array An array with the meta name as key and its alias as value. */ public static function get_required_wp_metadata_aliases() { return array( '_wp_attached_file' => 'imrwpmt1', '_wp_attachment_metadata' => 'imrwpmt2', ); } /** * Combine two arrays with some specific keys. * We use this function to combine the result of 2 SQL queries. * * @since 1.6.13 * @access public * @author Grégory Viguier * * @param array $keys An array of keys. * @param array $values An array of arrays like array( 'id' => id, 'value' => value ). * @param int $keep_keys_order Set to true to return an array ordered like $keys instead of $values. * @return array The combined arrays. */ public static function combine_query_results( $keys, $values, $keep_keys_order = false ) { if ( ! $keys || ! $values ) { return array(); } $result = array(); $keys = array_flip( $keys ); foreach ( $values as $v ) { if ( isset( $keys[ $v['id'] ] ) ) { $result[ $v['id'] ] = $v['value']; } } if ( $keep_keys_order ) { $keys = array_intersect_key( $keys, $result ); return array_replace( $keys, $result ); } return $result; } /** * A helper to retrieve all values from one or several post metas, given a list of post IDs. * The $wpdb cache is flushed to save memory. * * @since 1.6.13 * @access public * @author Grégory Viguier * * @param array $metas An array of meta names like: * array( * 'key1' => 'meta_name_1', * 'key2' => 'meta_name_2', * 'key3' => 'meta_name_3', * ) * If a key contains 'data', the results will be unserialized. * @param array $ids An array of post IDs. * @return array An array of arrays of results like: * array( * 'key1' => array( post_id_1 => 'result_1', post_id_2 => 'result_2', post_id_3 => 'result_3' ), * 'key2' => array( post_id_1 => 'result_4', post_id_3 => 'result_5' ), * 'key3' => array( post_id_1 => 'result_6', post_id_2 => 'result_7' ), * ) */ public static function get_metas( $metas, $ids ) { global $wpdb; if ( ! $ids ) { return array_fill_keys( array_keys( $metas ), array() ); } $sql_ids = implode( ',', $ids ); foreach ( $metas as $result_name => $meta_name ) { $metas[ $result_name ] = $wpdb->get_results( // WPCS: unprepared SQL ok. "SELECT pm.post_id as id, pm.meta_value as value FROM $wpdb->postmeta as pm WHERE pm.meta_key = '$meta_name' AND pm.post_id IN ( $sql_ids ) ORDER BY pm.post_id DESC", ARRAY_A ); $wpdb->flush(); $metas[ $result_name ] = self::combine_query_results( $ids, $metas[ $result_name ], true ); if ( strpos( $result_name, 'data' ) !== false ) { $metas[ $result_name ] = array_map( 'maybe_unserialize', $metas[ $result_name ] ); } } return $metas; } /** * Create/Upgrade the table in the database. * * @since 1.7 * @access public * @author Grégory Viguier * * @param string $table_name The (prefixed) table name. * @param string $schema_query Query representing the table schema. * @return bool True on success. False otherwise. */ public static function create_table( $table_name, $schema_query ) { global $wpdb; require_once ABSPATH . 'wp-admin/includes/upgrade.php'; $wpdb->hide_errors(); $schema_query = trim( $schema_query ); $charset_collate = $wpdb->get_charset_collate(); dbDelta( "CREATE TABLE $table_name ($schema_query) $charset_collate;" ); return empty( $wpdb->last_error ) && self::table_exists( $table_name ); } /** * Tell if the given table exists. * * @since 1.7 * @access public * @author Grégory Viguier * * @param string $table_name Full name of the table (with DB prefix). * @return bool */ public static function table_exists( $table_name ) { global $wpdb; $escaped_table = self::esc_like( $table_name ); $result = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $escaped_table ) ); return $result === $table_name; } /** * Cache transients used for optimization process locks. * * @since 1.9 * @access public * @author Grégory Viguier * * @param string $context The context. * @param array $media_ids The media IDs. */ public static function cache_process_locks( $context, $media_ids ) { global $wpdb; if ( ! $context || ! $media_ids || wp_using_ext_object_cache() ) { return; } // Sanitize the IDs. $media_ids = array_filter( $media_ids ); $media_ids = array_unique( $media_ids ); if ( ! $media_ids ) { return; } $context_instance = imagify_get_context( $context ); $context = $context_instance->get_name(); $process_class_name = imagify_get_optimization_process_class_name( $context ); $transient_name = sprintf( $process_class_name::LOCK_NAME, $context, '%' ); $is_network_wide = $context_instance->is_network_wide(); // Do 1 DB query per context (and cache results) before doing 1 get_transient() (2 DB queries) per media ID. $prefix = $is_network_wide ? '_site_transient_' : '_transient_'; if ( $is_network_wide && is_multisite() ) { $network_id = function_exists( 'get_current_network_id' ) ? get_current_network_id() : (int) $wpdb->siteid; $cache_prefix = "$network_id:"; $notoptions_key = "$network_id:notoptions"; $cache_group = 'site-options'; $results = $wpdb->get_results( $wpdb->prepare( "SELECT meta_key as name, meta_value as value FROM $wpdb->sitemeta WHERE ( meta_key LIKE %s OR meta_key LIKE %s ) AND site_id = %d", $prefix . $transient_name, $prefix . 'timeout_' . $transient_name, $network_id ), OBJECT_K ); // WPCS: unprepared SQL ok. } else { $cache_prefix = ''; $notoptions_key = 'notoptions'; $cache_group = 'options'; $results = $wpdb->get_results( $wpdb->prepare( "SELECT option_name as name, option_value as value FROM $wpdb->options WHERE ( option_name LIKE %s OR option_name LIKE %s )", $prefix . $transient_name, $prefix . 'timeout_' . $transient_name ), OBJECT_K ); // WPCS: unprepared SQL ok. } $not_exist = []; foreach ( [ '', 'timeout_' ] as $maybe_timeout ) { foreach ( $media_ids as $id ) { $option_name = $prefix . $maybe_timeout . str_replace( '%', $id, $transient_name ); if ( isset( $results[ $option_name ] ) ) { // Cache the value. $value = $results[ $option_name ]->value; $value = maybe_unserialize( $value ); wp_cache_set( "$cache_prefix$option_name", $value, $cache_group ); } else { // No value. $not_exist[ $option_name ] = true; } } } if ( ! $not_exist ) { return; } // Cache the options that don't exist in the DB. $notoptions = wp_cache_get( $notoptions_key, $cache_group ); $notoptions = is_array( $notoptions ) ? $notoptions : []; $notoptions = array_merge( $notoptions, $not_exist ); wp_cache_set( $notoptions_key, $notoptions, $cache_group ); } }