first
This commit is contained in:
@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace Smush\Core\Backups;
|
||||
|
||||
use Smush\Core\Controller;
|
||||
use Smush\Core\Core;
|
||||
use Smush\Core\File_System;
|
||||
use Smush\Core\Helper;
|
||||
use Smush\Core\Media\Media_Item_Cache;
|
||||
use Smush\Core\Media\Media_Item_Optimizer;
|
||||
use WP_Smush;
|
||||
|
||||
class Backups_Controller extends Controller {
|
||||
/**
|
||||
* @var Media_Item_Cache
|
||||
*/
|
||||
private $media_item_cache;
|
||||
/**
|
||||
* @var \WDEV_Logger|null
|
||||
*/
|
||||
private $logger;
|
||||
/**
|
||||
* @var File_System
|
||||
*/
|
||||
private $fs;
|
||||
|
||||
public function __construct() {
|
||||
$this->media_item_cache = Media_Item_Cache::get_instance();
|
||||
$this->logger = Helper::logger();
|
||||
$this->fs = new File_System();
|
||||
|
||||
$this->register_action( 'wp_ajax_smush_restore_image', array( $this, 'handle_restore_ajax' ) );
|
||||
$this->register_action( 'delete_attachment', array( $this, 'delete_backup_file' ) );
|
||||
}
|
||||
|
||||
public function handle_restore_ajax() {
|
||||
if ( empty( $_POST['attachment_id'] ) || empty( $_POST['_nonce'] ) ) {
|
||||
wp_send_json_error( array(
|
||||
'error_msg' => esc_html__( 'Error in processing restore action, fields empty.', 'wp-smushit' ),
|
||||
) );
|
||||
}
|
||||
|
||||
$nonce_value = filter_input( INPUT_POST, '_nonce', FILTER_SANITIZE_SPECIAL_CHARS );
|
||||
$attachment_id = filter_input( INPUT_POST, 'attachment_id', FILTER_SANITIZE_NUMBER_INT );
|
||||
|
||||
if ( ! wp_verify_nonce( $nonce_value, "wp-smush-restore-$attachment_id" ) ) {
|
||||
wp_send_json_error( array(
|
||||
'error_msg' => esc_html__( 'Image not restored, nonce verification failed.', 'wp-smushit' ),
|
||||
) );
|
||||
}
|
||||
|
||||
// Check capability.
|
||||
// TODO: change Helper::is_user_allowed to a non static method
|
||||
if ( ! Helper::is_user_allowed( 'upload_files' ) ) {
|
||||
wp_send_json_error( array(
|
||||
'error_msg' => esc_html__( "You don't have permission to work with uploaded files.", 'wp-smushit' ),
|
||||
) );
|
||||
}
|
||||
|
||||
$attachment_id = (int) $attachment_id;
|
||||
$media_item = Media_Item_Cache::get_instance()->get( $attachment_id );
|
||||
if ( ! $media_item->is_mime_type_supported() ) {
|
||||
wp_send_json_error( array(
|
||||
'error_msg' => $media_item->get_errors()->get_error_message(),
|
||||
) );
|
||||
}
|
||||
|
||||
$optimizer = new Media_Item_Optimizer( $media_item );
|
||||
$restored = $optimizer->restore();
|
||||
|
||||
if ( ! $restored ) {
|
||||
wp_send_json_error( array(
|
||||
'error_msg' => esc_html__( 'Unable to restore image', 'wp-smushit' ),
|
||||
) );
|
||||
}
|
||||
|
||||
$button_html = WP_Smush::get_instance()->library()->generate_markup( $attachment_id );
|
||||
$file_path = $media_item->get_main_size()->get_file_path();
|
||||
$size = $this->fs->file_exists( $file_path )
|
||||
? $this->fs->filesize( $file_path )
|
||||
: 0;
|
||||
if ( $size > 0 ) {
|
||||
$update_size = size_format( $size );
|
||||
}
|
||||
|
||||
wp_send_json_success( array(
|
||||
'stats' => $button_html,
|
||||
'new_size' => isset( $update_size ) ? $update_size : 0,
|
||||
) );
|
||||
}
|
||||
|
||||
public function delete_backup_file( $attachment_id ) {
|
||||
$media_item = $this->media_item_cache->get( $attachment_id );
|
||||
if ( $media_item->is_valid() && $media_item->get_default_backup_size() ) {
|
||||
// Delete the file
|
||||
$default_backup_path = $media_item->get_default_backup_size()->get_file_path();
|
||||
if ( $this->fs->file_exists( $default_backup_path ) ) {
|
||||
$this->fs->unlink( $default_backup_path );
|
||||
}
|
||||
|
||||
// Delete the meta
|
||||
$media_item->remove_default_backup_size();
|
||||
$media_item->save();
|
||||
} else {
|
||||
$this->logger->error( sprintf( 'Count not delete webp versions of the media item [%d]', $attachment_id ) );
|
||||
}
|
||||
}
|
||||
}
|
211
wp-content/plugins/wp-smushit/core/backups/class-backups.php
Normal file
211
wp-content/plugins/wp-smushit/core/backups/class-backups.php
Normal file
@ -0,0 +1,211 @@
|
||||
<?php
|
||||
|
||||
namespace Smush\Core\Backups;
|
||||
|
||||
use Smush\Core\File_System;
|
||||
use Smush\Core\Helper;
|
||||
use Smush\Core\Media\Media_Item;
|
||||
use Smush\Core\Media\Media_Item_Optimizer;
|
||||
use Smush\Core\Settings;
|
||||
use WDEV_Logger;
|
||||
|
||||
class Backups {
|
||||
/**
|
||||
* @var WDEV_Logger
|
||||
*/
|
||||
private $logger;
|
||||
/**
|
||||
* @var Settings|null
|
||||
*/
|
||||
private $settings;
|
||||
/**
|
||||
* @var File_System
|
||||
*/
|
||||
private $fs;
|
||||
|
||||
public function __construct() {
|
||||
$this->logger = Helper::logger()->backup();
|
||||
$this->settings = Settings::get_instance();
|
||||
$this->fs = new File_System();
|
||||
}
|
||||
|
||||
public function create_backup_file( $source_image_path ) {
|
||||
$bak_file_path = $this->generate_unique_bak_file_path( $source_image_path );
|
||||
$copied = $this->fs->copy( $source_image_path, $bak_file_path );
|
||||
if ( $copied ) {
|
||||
return basename( $bak_file_path );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function generate_unique_bak_file_path( $source_image_path ) {
|
||||
// TODO: why not use the wp_unique_filename method for this?
|
||||
$path_info = pathinfo( $source_image_path );
|
||||
$ext = $path_info['extension'];
|
||||
$bak_ext = ".bak.$ext";
|
||||
$file_without_ext = trailingslashit( $path_info['dirname'] ) . $path_info['filename'];
|
||||
$bak_file_path = $file_without_ext . $bak_ext;
|
||||
if ( ! $this->fs->file_exists( $bak_file_path ) ) {
|
||||
return $bak_file_path;
|
||||
}
|
||||
|
||||
$count = 1;
|
||||
$bak_file_path = $file_without_ext . '-' . $count . $bak_ext;
|
||||
while ( $this->fs->file_exists( $bak_file_path ) ) {
|
||||
$count ++;
|
||||
$bak_file_path = $file_without_ext . '-' . $count . $bak_ext;
|
||||
}
|
||||
|
||||
return $bak_file_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $media_item Media_Item
|
||||
* @param $optimizer Media_Item_Optimizer
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function maybe_create_backup( $media_item, $optimizer ) {
|
||||
if ( ! $this->settings->is_backup_active() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Maybe it already exists?
|
||||
$backup_size = $media_item->get_default_backup_size();
|
||||
if ( $backup_size && $backup_size->get_file_path() && $this->fs->file_exists( $backup_size->get_file_path() ) ) {
|
||||
// We have a perfectly viable backup available already
|
||||
$this->logger->info( sprintf( 'Found an existing backed up file [%s] for attachment [%d].', $backup_size->get_file(), $media_item->get_id() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$size_to_backup = $media_item->get_full_or_scaled_size();
|
||||
if ( ! $size_to_backup || ! $size_to_backup->file_exists() ) {
|
||||
$this->logger->warning( sprintf( 'File not found, could not backup up for attachment [%d].', $media_item->get_id() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$create_copy = $optimizer->should_optimize_size( $size_to_backup );
|
||||
|
||||
// Create the backup
|
||||
$file_name = $size_to_backup->get_file_name();
|
||||
$width = $size_to_backup->get_width();
|
||||
$height = $size_to_backup->get_height();
|
||||
if ( $create_copy ) {
|
||||
$file_name = $this->create_backup_file( $size_to_backup->get_file_path() );
|
||||
if ( ! $file_name ) {
|
||||
$this->logger->info( sprintf( 'File operation failed when trying to create backup file [%s] for attachment [%d].', $size_to_backup->get_file_path(), $media_item->get_id() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$media_item->add_backup_size( $file_name, $width, $height );
|
||||
$media_item->save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $media_item Media_Item
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function restore_backup( $media_item ) {
|
||||
return $this->restore_backup_to_file_path(
|
||||
$media_item,
|
||||
$media_item->get_original_image_path() // Directly using the path here because the size object is not available when the file doesn't exist on the disk
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $media_item Media_Item
|
||||
* @param $file_path
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function restore_backup_to_file_path( $media_item, $file_path ) {
|
||||
$restored = false;
|
||||
$backup_file_path = '';
|
||||
$attachment_id = $media_item->get_id();
|
||||
|
||||
do {
|
||||
$backup_size = $media_item->get_default_backup_size();
|
||||
if ( ! $backup_size ) {
|
||||
$this->logger->warning( sprintf( 'A restore was attempted for attachment [%d] but we did not find a backup file.', $media_item->get_id() ) );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$backup_file_path = $backup_size->get_file_path();
|
||||
|
||||
do_action( 'wp_smush_before_restore_backup', $backup_file_path, $attachment_id, $file_path );
|
||||
|
||||
if ( ! $this->fs->file_exists( $backup_file_path ) ) {
|
||||
// Clean up
|
||||
$media_item->remove_default_backup_size();
|
||||
$media_item->save();
|
||||
|
||||
$this->logger->warning( sprintf( 'A restore was attempted for attachment [%d] but the backup file does not exist.', $media_item->get_id() ) );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$is_separate_backup_file = $backup_file_path !== $file_path;
|
||||
if ( $is_separate_backup_file ) {
|
||||
$copied = $this->fs->copy( $backup_file_path, $file_path );
|
||||
if ( $copied ) {
|
||||
$this->fs->unlink( $backup_file_path );
|
||||
} else {
|
||||
$this->logger->warning( sprintf( 'Error copying from [%s] to [%s].', $backup_file_path, $file_path ) );
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
wp_generate_attachment_metadata( $attachment_id, $file_path );
|
||||
/*
|
||||
* TODO: we might want to follow media_handle_upload which makes an extra update attachment call like this:
|
||||
* wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $file ) );
|
||||
*/
|
||||
|
||||
// The metadata has changed because we called wp_generate_attachment_metadata. We need to reset before saving.
|
||||
$media_item->reset();
|
||||
|
||||
$media_item->remove_default_backup_size();
|
||||
$media_item->save();
|
||||
|
||||
$restored = true;
|
||||
} while ( 0 );
|
||||
|
||||
do_action( 'wp_smush_after_restore_backup', $restored, $backup_file_path, $attachment_id, $file_path );
|
||||
|
||||
return $restored;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: merge somehow with \Smush\Core\Modules\Backup::get_attachments_with_backups
|
||||
* @return int
|
||||
*/
|
||||
private function count_attachments_with_backups() {
|
||||
global $wpdb;
|
||||
$wild = '%';
|
||||
$backup_key_like = $wild . $wpdb->esc_like( Media_Item::DEFAULT_BACKUP_KEY ) . $wild;
|
||||
$no_backup_files = $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
"SELECT count(*)
|
||||
FROM {$wpdb->postmeta}
|
||||
WHERE meta_key=%s AND `meta_value` LIKE %s",
|
||||
Media_Item::BACKUP_SIZES_META_KEY,
|
||||
$backup_key_like
|
||||
)
|
||||
);
|
||||
|
||||
return (int) $no_backup_files;
|
||||
}
|
||||
|
||||
public function items_with_backup_exist() {
|
||||
return $this->count_attachments_with_backups() > 0;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user