File manager - Edit - /home/vblioqus/dlskitsurl.com/wp-content/plugins/litespeed-cache/src/img-optm-send.trait.php
Back
<?php /** * Image optimization send trait * * @package LiteSpeed * @since 7.8 */ namespace LiteSpeed; defined( 'WPINC' ) || exit(); /** * Trait Img_Optm_Send * * Handles image optimization request sending. */ trait Img_Optm_Send { /** * Gather images auto when update attachment meta * This is to optimize new uploaded images first. Stored in img_optm table. * Later normal process will auto remove these records when trying to optimize these images again * * @since 4.0 * @param array $meta_value The meta value array. * @param int $post_id The post ID. */ public function wp_update_attachment_metadata( $meta_value, $post_id ) { global $wpdb; self::debug2( '🖌️ Auto update attachment meta [id] ' . $post_id ); if ( empty( $meta_value['file'] ) ) { return; } // Load gathered images if ( ! $this->_existed_src_list ) { // To aavoid extra query when recalling this function self::debug( 'SELECT src from img_optm table' ); if ( $this->__data->tb_exist( 'img_optm' ) ) { $q = "SELECT src FROM `$this->_table_img_optm` WHERE post_id = %d"; // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared $list = $wpdb->get_results( $wpdb->prepare( $q, $post_id ) ); foreach ( $list as $v ) { $this->_existed_src_list[] = $post_id . '.' . $v->src; } } if ( $this->__data->tb_exist( 'img_optming' ) ) { $q = "SELECT src FROM `$this->_table_img_optming` WHERE post_id = %d"; // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared $list = $wpdb->get_results( $wpdb->prepare( $q, $post_id ) ); foreach ( $list as $v ) { $this->_existed_src_list[] = $post_id . '.' . $v->src; } } else { $this->__data->tb_create( 'img_optming' ); } } // Prepare images $this->tmp_pid = $post_id; $this->tmp_path = pathinfo( $meta_value['file'], PATHINFO_DIRNAME ) . '/'; $this->_append_img_queue( $meta_value, true ); if ( ! empty( $meta_value['sizes'] ) ) { foreach ( $meta_value['sizes'] as $img_size_name => $img_size ) { $this->_append_img_queue( $img_size, false, $img_size_name ); } } if ( ! $this->_img_in_queue ) { self::debug( 'auto update attachment meta 2 bypass: empty _img_in_queue' ); return; } // Save to DB $this->_save_raw(); // $this->_send_request(); } /** * Auto send optm request * * @since 2.4.1 * @access public */ public static function cron_auto_request() { if ( ! wp_doing_cron() ) { return false; } $instance = self::cls(); $instance->new_req(); } /** * Calculate wet run allowance * * @since 3.0 * @return int|false The wet limit or false if no limit. */ public function wet_limit() { $wet_limit = 1; if ( ! empty( $this->_summary['img_taken'] ) ) { $wet_limit = pow( $this->_summary['img_taken'], 2 ); } if ( 1 === $wet_limit && ! empty( $this->_summary[ 'img_status.' . self::STATUS_ERR_OPTM ] ) ) { $wet_limit = pow( $this->_summary[ 'img_status.' . self::STATUS_ERR_OPTM ], 2 ); } if ( $wet_limit < Cloud::IMG_OPTM_DEFAULT_GROUP ) { return $wet_limit; } // No limit return false; } /** * Push raw img to image optm server * * @since 1.6 * @access public */ public function new_req() { global $wpdb; // check if is running if ( ! empty( $this->_summary['is_running'] ) && time() - $this->_summary['is_running'] < apply_filters( 'litespeed_imgoptm_new_req_interval', 3600 ) ) { self::debug( 'The previous req was in 3600s.' ); return; } $this->_summary['is_running'] = time(); self::save_summary(); // Check if has credit to push $err = false; $allowance = Cloud::cls()->allowance( Cloud::SVC_IMG_OPTM, $err ); $wet_limit = $this->wet_limit(); self::debug( "allowance_max $allowance wet_limit $wet_limit" ); if ( $wet_limit && $wet_limit < $allowance ) { $allowance = $wet_limit; } if ( ! $allowance ) { self::debug( '❌ No credit' ); Admin_Display::error( Error::msg( $err ) ); $this->_finished_running(); return; } self::debug( 'preparing images to push' ); $this->__data->tb_create( 'img_optming' ); $q = "SELECT COUNT(1) FROM `$this->_table_img_optming` WHERE optm_status = %d"; // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared $q = $wpdb->prepare( $q, [ self::STATUS_REQUESTED ] ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared $total_requested = $wpdb->get_var( $q ); $max_requested = $allowance * 1; if ( $total_requested > $max_requested ) { self::debug( '❌ Too many queued images (' . $total_requested . ' > ' . $max_requested . ')' ); Admin_Display::error( Error::msg( 'too_many_requested' ) ); $this->_finished_running(); return; } $allowance -= $total_requested; if ( $allowance < 1 ) { self::debug( '❌ Too many requested images ' . $total_requested ); Admin_Display::error( Error::msg( 'too_many_requested' ) ); $this->_finished_running(); return; } // Limit maximum number of items waiting to be pulled $q = "SELECT COUNT(1) FROM `$this->_table_img_optming` WHERE optm_status = %d"; // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared $q = $wpdb->prepare( $q, [ self::STATUS_NOTIFIED ] ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared $total_notified = $wpdb->get_var( $q ); if ( $total_notified > 0 ) { self::debug( '❌ Too many notified images (' . $total_notified . ')' ); Admin_Display::error( Error::msg( 'too_many_notified' ) ); $this->_finished_running(); return; } $q = "SELECT COUNT(1) FROM `$this->_table_img_optming` WHERE optm_status IN (%d, %d)"; // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared $q = $wpdb->prepare( $q, [ self::STATUS_NEW, self::STATUS_RAW ] ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared $total_new = $wpdb->get_var( $q ); // $allowance -= $total_new; // May need to get more images $list = []; $more = $allowance - $total_new; if ( $more > 0 ) { $q = "SELECT b.post_id, b.meta_value FROM `$wpdb->posts` a LEFT JOIN `$wpdb->postmeta` b ON b.post_id = a.ID WHERE b.meta_key = '_wp_attachment_metadata' AND a.post_type = 'attachment' AND a.post_status = 'inherit' AND a.ID>%d AND a.post_mime_type IN ('image/jpeg', 'image/png', 'image/gif') ORDER BY a.ID LIMIT %d "; // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared $q = $wpdb->prepare( $q, [ $this->_summary['next_post_id'], $more ] ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared $list = $wpdb->get_results( $q ); foreach ( $list as $v ) { if ( ! $v->post_id ) { continue; } $this->_summary['next_post_id'] = $v->post_id; $meta_value = $this->_parse_wp_meta_value( $v ); if ( ! $meta_value ) { continue; } $meta_value['file'] = wp_normalize_path( $meta_value['file'] ); $basedir = $this->wp_upload_dir['basedir'] . '/'; if ( strpos( $meta_value['file'], $basedir ) === 0 ) { $meta_value['file'] = substr( $meta_value['file'], strlen( $basedir ) ); } $this->tmp_pid = $v->post_id; $this->tmp_path = pathinfo( $meta_value['file'], PATHINFO_DIRNAME ) . '/'; $this->_append_img_queue( $meta_value, true ); if ( ! empty( $meta_value['sizes'] ) ) { foreach ( $meta_value['sizes'] as $img_size_name => $img_size ) { $this->_append_img_queue( $img_size, false, $img_size_name ); } } } self::save_summary(); $num_a = count( $this->_img_in_queue ); self::debug( 'Images found: ' . $num_a ); $this->_filter_duplicated_src(); self::debug( 'Images after duplicated: ' . count( $this->_img_in_queue ) ); $this->_filter_invalid_src(); self::debug( 'Images after invalid: ' . count( $this->_img_in_queue ) ); // Check w/ legacy imgoptm table, bypass finished images $this->_filter_legacy_src(); $num_b = count( $this->_img_in_queue ); if ( $num_b !== $num_a ) { self::debug( 'Images after filtered duplicated/invalid/legacy src: ' . $num_b ); } // Save to DB $this->_save_raw(); } // Push to Cloud server $accepted_imgs = $this->_send_request( $allowance ); $this->_finished_running(); if ( ! $accepted_imgs ) { return; } $placeholder1 = Admin_Display::print_plural( $accepted_imgs[0], 'image' ); $placeholder2 = Admin_Display::print_plural( $accepted_imgs[1], 'image' ); $msg = sprintf( __( 'Pushed %1$s to Cloud server, accepted %2$s.', 'litespeed-cache' ), $placeholder1, $placeholder2 ); Admin_Display::success( $msg ); } /** * Set running to done * * @since 3.0 * @access private */ private function _finished_running() { $this->_summary['is_running'] = 0; self::save_summary(); } /** * Add a new img to queue which will be pushed to request * * @since 1.6 * @since 7.5 Allow to choose which image sizes should be optimized + added parameter $img_size_name. * @access private * @param array $meta_value The meta value array. * @param bool $is_ori_file Whether this is the original file. * @param string|bool $img_size_name The image size name or false. */ private function _append_img_queue( $meta_value, $is_ori_file = false, $img_size_name = false ) { if ( empty( $meta_value['file'] ) || empty( $meta_value['width'] ) || empty( $meta_value['height'] ) ) { self::debug2( 'bypass image due to lack of file/w/h: pid ' . $this->tmp_pid, $meta_value ); return; } $short_file_path = $meta_value['file']; // Test if need to skip image size. if ( ! $is_ori_file ) { $short_file_path = $this->tmp_path . $short_file_path; $skip = false !== array_search( $img_size_name, $this->_sizes_skipped, true ); if ( $skip ) { self::debug2( 'bypass image ' . $short_file_path . ' due to skipped size: ' . $img_size_name ); return; } } // Check if src is gathered already or not if ( in_array( $this->tmp_pid . '.' . $short_file_path, $this->_existed_src_list, true ) ) { // Debug2::debug2( '[Img_Optm] bypass image due to gathered: pid ' . $this->tmp_pid . ' ' . $short_file_path ); return; } else { // Append handled images $this->_existed_src_list[] = $this->tmp_pid . '.' . $short_file_path; } // check file exists or not $_img_info = $this->__media->info( $short_file_path, $this->tmp_pid ); $extension = pathinfo( $short_file_path, PATHINFO_EXTENSION ); if ( ! $_img_info || ! in_array( $extension, [ 'jpg', 'jpeg', 'png', 'gif' ], true ) ) { self::debug2( 'bypass image due to file not exist: pid ' . $this->tmp_pid . ' ' . $short_file_path ); return; } // Check if optimized file exists or not $target_needed = false; if ( $this->_format ) { $target_file_path = $short_file_path . '.' . $this->_format; if ( ! $this->__media->info( $target_file_path, $this->tmp_pid ) ) { $target_needed = true; } } if ( $this->conf( self::O_IMG_OPTM_ORI ) ) { $target_file_path = substr( $short_file_path, 0, -strlen( $extension ) ) . 'bk.' . $extension; if ( ! $this->__media->info( $target_file_path, $this->tmp_pid ) ) { $target_needed = true; } } if ( ! $target_needed ) { self::debug2( 'bypass image due to optimized file exists: pid ' . $this->tmp_pid . ' ' . $short_file_path ); return; } // Debug2::debug2( '[Img_Optm] adding image: pid ' . $this->tmp_pid ); $this->_img_in_queue[] = [ 'pid' => $this->tmp_pid, 'md5' => $_img_info['md5'], 'url' => $_img_info['url'], 'src' => $short_file_path, // not needed in LiteSpeed IAPI, just leave for local storage after post 'mime_type' => ! empty( $meta_value['mime-type'] ) ? $meta_value['mime-type'] : '', ]; } /** * Save gathered image raw data * * @since 3.0 * @access private */ private function _save_raw() { if ( empty( $this->_img_in_queue ) ) { return; } $data = []; $pid_list = []; foreach ( $this->_img_in_queue as $k => $v ) { $_img_info = $this->__media->info( $v['src'], $v['pid'] ); // attachment doesn't exist, delete the record if ( empty( $_img_info['url'] ) || empty( $_img_info['md5'] ) ) { unset( $this->_img_in_queue[ $k ] ); continue; } $pid_list[] = (int) $v['pid']; $data[] = $v['pid']; $data[] = self::STATUS_RAW; $data[] = $v['src']; } global $wpdb; $fields = 'post_id, optm_status, src'; $q = "INSERT INTO `$this->_table_img_optming` ( $fields ) VALUES "; // Add placeholder $q .= Utility::chunk_placeholder( $data, $fields ); // Store data // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared $wpdb->query( $wpdb->prepare( $q, $data ) ); $count = count( $this->_img_in_queue ); self::debug( 'Added raw images [total] ' . $count ); $this->_img_in_queue = []; // Save thumbnail groups for future rescan index $this->_gen_thumbnail_set(); $pid_list = array_unique( $pid_list ); self::debug( 'pid list to append to postmeta', $pid_list ); $pid_list = array_diff( $pid_list, $this->_pids_set ); $this->_pids_set = array_merge( $this->_pids_set, $pid_list ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared $existed_meta = $wpdb->get_results( "SELECT * FROM `$wpdb->postmeta` WHERE post_id IN ('" . implode( "','", $pid_list ) . "') AND meta_key='" . self::DB_SET . "'" ); $existed_pid = []; if ( $existed_meta ) { foreach ( $existed_meta as $v ) { $existed_pid[] = $v->post_id; } self::debug( 'pid list to update postmeta', $existed_pid ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery $wpdb->query( // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- $existed_pid is array of sanitized IDs $wpdb->prepare( "UPDATE `$wpdb->postmeta` SET meta_value=%s WHERE post_id IN (" . implode( ',', $existed_pid ) . ') AND meta_key=%s', [ $this->_thumbnail_set, self::DB_SET, ] ) ); } // Add new meta $new_pids = $existed_pid ? array_diff( $pid_list, $existed_pid ) : $pid_list; if ( $new_pids ) { self::debug( 'pid list to update postmeta', $new_pids ); foreach ( $new_pids as $v ) { self::debug( 'New group set info [pid] ' . $v ); $q = "INSERT INTO `$wpdb->postmeta` (post_id, meta_key, meta_value) VALUES (%d, %s, %s)"; // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared $wpdb->query( $wpdb->prepare( $q, [ $v, self::DB_SET, $this->_thumbnail_set ] ) ); } } } /** * Generate thumbnail sets of current image group * * @since 5.4 * @access private */ private function _gen_thumbnail_set() { if ( $this->_thumbnail_set ) { return; } $set = []; foreach ( Media::cls()->get_image_sizes() as $size ) { $curr_size = $size['width'] . 'x' . $size['height']; if ( in_array( $curr_size, $set, true ) ) { continue; } $set[] = $curr_size; } $this->_thumbnail_set = implode( PHP_EOL, $set ); } /** * Filter duplicated src in work table and $this->_img_in_queue, then mark them as duplicated * * @since 2.0 * @access private */ private function _filter_duplicated_src() { global $wpdb; $srcpath_list = []; // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared $list = $wpdb->get_results( "SELECT src FROM `$this->_table_img_optming`" ); foreach ( $list as $v ) { $srcpath_list[] = $v->src; } foreach ( $this->_img_in_queue as $k => $v ) { if ( in_array( $v['src'], $srcpath_list, true ) ) { unset( $this->_img_in_queue[ $k ] ); continue; } $srcpath_list[] = $v['src']; } } /** * Filter legacy finished ones * * @since 5.4 * @access private */ private function _filter_legacy_src() { global $wpdb; if ( ! $this->__data->tb_exist( 'img_optm' ) ) { return; } if ( ! $this->_img_in_queue ) { return; } $finished_ids = []; Utility::compatibility(); $post_ids = array_unique( array_column( $this->_img_in_queue, 'pid' ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared $list = $wpdb->get_results( "SELECT post_id FROM `$this->_table_img_optm` WHERE post_id in (" . implode( ',', $post_ids ) . ') GROUP BY post_id' ); foreach ( $list as $v ) { $finished_ids[] = $v->post_id; } foreach ( $this->_img_in_queue as $k => $v ) { if ( in_array( $v['pid'], $finished_ids, true ) ) { self::debug( 'Legacy image optimized [pid] ' . $v['pid'] ); unset( $this->_img_in_queue[ $k ] ); continue; } } // Drop all existing legacy records // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared $wpdb->query( "DELETE FROM `$this->_table_img_optm` WHERE post_id in (" . implode( ',', $post_ids ) . ')' ); } /** * Filter the invalid src before sending * * @since 3.0.8.3 * @access private */ private function _filter_invalid_src() { $img_in_queue_invalid = []; foreach ( $this->_img_in_queue as $k => $v ) { if ( $v['src'] ) { $extension = pathinfo( $v['src'], PATHINFO_EXTENSION ); } if ( ! $v['src'] || empty( $extension ) || ! in_array( $extension, [ 'jpg', 'jpeg', 'png', 'gif' ], true ) ) { $img_in_queue_invalid[] = $v['id']; unset( $this->_img_in_queue[ $k ] ); continue; } } if ( ! $img_in_queue_invalid ) { return; } $count = count( $img_in_queue_invalid ); $msg = sprintf( __( 'Cleared %1$s invalid images.', 'litespeed-cache' ), $count ); Admin_Display::success( $msg ); self::debug( 'Found invalid src [total] ' . $count ); } /** * Push img request to Cloud server * * @since 1.6.7 * @access private * @param int $allowance The allowance limit. * @return array|void Array with pushed and accepted counts. */ private function _send_request( $allowance ) { global $wpdb; $q = "SELECT id, src, post_id FROM `$this->_table_img_optming` WHERE optm_status=%d LIMIT %d"; // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared $q = $wpdb->prepare( $q, [ self::STATUS_RAW, $allowance ] ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared $_img_in_queue = $wpdb->get_results( $q ); if ( ! $_img_in_queue ) { return; } self::debug( 'Load img in queue [total] ' . count( $_img_in_queue ) ); $list = []; foreach ( $_img_in_queue as $v ) { $_img_info = $this->__media->info( $v->src, $v->post_id ); // If record is invalid, remove from img_optming table if ( empty( $_img_info['url'] ) || empty( $_img_info['md5'] ) ) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared $wpdb->query( $wpdb->prepare( "DELETE FROM `$this->_table_img_optming` WHERE id=%d", $v->id ) ); continue; } $img = [ 'id' => $v->id, 'url' => $_img_info['url'], 'md5' => $_img_info['md5'], ]; // Build the needed image types for request as we now support soft reset counter if ( $this->_format ) { $target_file_path = $v->src . '.' . $this->_format; if ( $this->__media->info( $target_file_path, $v->post_id ) ) { $img[ 'optm_' . $this->_format ] = 0; } } if ( $this->conf( self::O_IMG_OPTM_ORI ) ) { $extension = pathinfo( $v->src, PATHINFO_EXTENSION ); $target_file_path = substr( $v->src, 0, -strlen( $extension ) ) . 'bk.' . $extension; if ( $this->__media->info( $target_file_path, $v->post_id ) ) { $img['optm_ori'] = 0; } } $list[] = $img; } if ( ! $list ) { $msg = __( 'No valid image found in the current request.', 'litespeed-cache' ); Admin_Display::error( $msg ); return; } $data = [ 'action' => self::CLOUD_ACTION_NEW_REQ, 'list' => wp_json_encode( $list ), 'optm_ori' => $this->conf( self::O_IMG_OPTM_ORI ) ? 1 : 0, 'optm_lossless' => $this->conf( self::O_IMG_OPTM_LOSSLESS ) ? 1 : 0, 'keep_exif' => $this->conf( self::O_IMG_OPTM_EXIF ) ? 1 : 0, ]; if ( $this->_format ) { $data[ 'optm_' . $this->_format ] = 1; } // Push to Cloud server $json = Cloud::post( Cloud::SVC_IMG_OPTM, $data ); if ( ! $json ) { return; } // Check data format if ( empty( $json['ids'] ) ) { self::debug( 'Failed to parse response data from Cloud server ', $json ); $msg = __( 'No valid image found by Cloud server in the current request.', 'litespeed-cache' ); Admin_Display::error( $msg ); return; } self::debug( 'Returned data from Cloud server count: ' . count( $json['ids'] ) ); $ids = implode( ',', array_map( 'intval', $json['ids'] ) ); // Update img table $q = "UPDATE `$this->_table_img_optming` SET optm_status = '" . self::STATUS_REQUESTED . "' WHERE id IN ( $ids )"; // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared $wpdb->query( $q ); $this->_summary['last_requested'] = time(); self::save_summary(); return [ count( $list ), count( $json['ids'] ) ]; } /** * Parse wp's meta value * * @since 1.6.7 * @access private * @param object $v The database row object. * @return array|false The parsed meta value or false on failure. */ private function _parse_wp_meta_value( $v ) { if ( empty( $v ) ) { self::debug( 'bypassed parsing meta due to null value' ); return false; } if ( ! $v->meta_value ) { self::debug( 'bypassed parsing meta due to no meta_value: pid ' . $v->post_id ); return false; } // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- Suppress warnings from corrupted metadata $meta_value = @maybe_unserialize( $v->meta_value ); if ( ! is_array( $meta_value ) ) { self::debug( 'bypassed parsing meta due to meta_value not json: pid ' . $v->post_id ); return false; } if ( empty( $meta_value['file'] ) ) { self::debug( 'bypassed parsing meta due to no ori file: pid ' . $v->post_id ); return false; } return $meta_value; } }
| ver. 1.4 |
Github
|
.
| PHP 8.2.30 | Generation time: 0 |
proxy
|
phpinfo
|
Settings