Files
dostavka_vodi/wp-content/plugins/!robin-image-optimizer/includes/classes/class-rio-backup.php
User A0264400 a766acdc90 first commit
2026-04-01 23:20:16 +03:00

565 lines
16 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Класс для работы с резервным копированием изображений.
*
* @version 1.0
*/
class WIO_Backup {
const BACKUP_DIR_NAME = 'wio_backup';
const TEMP_DIR_NAME = 'temp';
/**
* The single instance of the class.
*
* @since 1.3.0
* @access protected
* @var object
*/
protected static $_instance;
/**
* @var array Данные о папке uploads, возвращаемые функцией wp_upload_dir()
*/
protected $wp_upload_dir;
/**
* @var string Путь к папке с резервными копиями изображений
*/
private $backup_dir;
/**
* @since 1.3.0
* @var string
*/
private $blog_backup_dir;
/**
* Инициализация бекапа
*/
public function __construct() {
$this->wp_upload_dir = wp_upload_dir();
}
/**
* @since 1.3.0
*
* @return object|\static object Main instance.
*/
public static function get_instance() {
if ( ! isset( static::$_instance ) ) {
static::$_instance = new static();
}
return static::$_instance;
}
/**
* Проверка возможности записи в папку uploads.
*
* @return bool
*/
public function isUploadWritable() {
$upload_dir = $this->wp_upload_dir['basedir'];
if ( is_dir( $upload_dir ) && wp_is_writable( $upload_dir ) ) {
return true;
}
return false;
}
/**
* Проверка возможности записи в папку бекап.
*
* @return bool
*/
public function isBackupWritable() {
$backup_dir = $this->getBackupDir();
if ( is_wp_error( $backup_dir ) || ! wp_is_writable( $backup_dir ) ) {
return false;
}
return true;
}
/**
* Путь к папке с бекапами
*
* @return string|WP_Error
*/
public function getBackupDir() {
if ( $this->backup_dir ) {
return $this->backup_dir;
}
$backup_dir = wp_normalize_path( trailingslashit( $this->wp_upload_dir['basedir'] ) . self::BACKUP_DIR_NAME );
if ( ! is_dir( $backup_dir ) ) {
$backup_dir = $this->mkdir( $backup_dir );
if ( is_wp_error( $backup_dir ) ) {
return $backup_dir;
}
}
$this->backup_dir = apply_filters( 'wbcr/rio/backup/backup_dir', trailingslashit( $backup_dir ) );
return $this->backup_dir;
}
/**
* Путь к папке с бекапами блога.
*
* Используется в мультисайт режиме.
*
* @return string|WP_Error
*/
public function getBlogBackupDir() {
if ( $this->blog_backup_dir ) {
return $this->blog_backup_dir;
}
$wp_upload_dir = wp_upload_dir();
$backup_dir = wp_normalize_path( trailingslashit( $wp_upload_dir['basedir'] ) . self::BACKUP_DIR_NAME );
if ( ! is_dir( $backup_dir ) ) {
$backup_dir = $this->mkdir( $backup_dir );
if ( is_wp_error( $backup_dir ) ) {
return $backup_dir;
}
}
$this->blog_backup_dir = trailingslashit( $backup_dir );
return $this->blog_backup_dir;
}
/**
* Очищает папку с резервными копиями
*
* @return bool
*/
public function removeBackupDir() {
$backup_dir = $this->getBackupDir();
return wrio_rmdir( $backup_dir );
}
/**
* Очищает папку с резервными копиями блога
* Используется в мультисайт режиме
*
* @return bool
*/
public function removeBlogBackupDir() {
$backup_dir = $this->getBlogBackupDir();
return wrio_rmdir( $backup_dir );
}
/**
* Получает путь к папке с резервными копиями
*
* @param array $attachment_meta метаданные аттачмента
*
* @return string
*/
public function getAttachmentBackupDir( $attachment_meta ) {
$backup_dir = $this->getBackupDir();
// Get all subfolders in which the image is stored.
// This is necessary to create an alternate subfolders
// in directory where they are stored in backups.
$subfolders = dirname( $attachment_meta['file'] );
$backup_dir .= $subfolders;
if ( ! is_dir( $backup_dir ) ) {
$backup_dir = $this->mkdir( $backup_dir );
if ( is_wp_error( $backup_dir ) ) {
return $backup_dir;
}
}
return trailingslashit( $backup_dir );
}
/**
* Делаем резервную копию аттачмента
*
* @param WIO_Attachment $wio_attachment аттачмент
*
* @return bool|WP_Error
*/
public function backupAttachment( WIO_Attachment $wio_attachment ) {
$backup_origin_images = WRIO_Plugin::app()->getPopulateOption( 'backup_origin_images', false );
if ( ! $backup_origin_images ) {
return false; // если бекап не требуется
}
$backup_dir = $this->getAttachmentBackupDir( $wio_attachment->get( 'attachment_meta' ) );
if ( is_wp_error( $backup_dir ) ) {
return $backup_dir;
}
$full = $this->backupAttachmentSize( $wio_attachment );
if ( is_wp_error( $full ) ) {
return $full;
}
$allowed_sizes = $wio_attachment->getAllowedSizes();
if ( ! empty( $allowed_sizes ) ) {
foreach ( (array) $allowed_sizes as $image_size ) {
$size_backup = $this->backupAttachmentSize( $wio_attachment, $image_size );
if ( is_wp_error( $size_backup ) ) {
return $size_backup;
}
}
}
return true;
}
/**
* Восстанавливаем аттачмент из резервной копии
*
* @param WIO_Attachment $wio_attachment аттачмент
*
* @return bool|WP_Error
*/
public function restoreAttachment( WIO_Attachment $wio_attachment ) {
$backup_dir = $this->getAttachmentBackupDir( $wio_attachment->get( 'attachment_meta' ) );
if ( is_wp_error( $backup_dir ) ) {
return $backup_dir;
}
$restore_result = $this->restoreAttachmentSize( $wio_attachment );
if ( is_wp_error( $restore_result ) ) {
return $restore_result;
}
$attachment_meta = wp_get_attachment_metadata( $wio_attachment->get( 'id' ) );
if ( isset( $attachment_meta['old_width'] ) && isset( $attachment_meta['old_width'] ) ) {
$attachment_meta['width'] = $attachment_meta['old_width'];
$attachment_meta['height'] = $attachment_meta['old_height'];
wp_update_attachment_metadata( $wio_attachment->get( 'id' ), $attachment_meta );
}
$allowed_sizes = $wio_attachment->getAllowedSizes();
if ( $allowed_sizes ) {
foreach ( $allowed_sizes as $image_size ) {
$this->restoreAttachmentSize( $wio_attachment, $image_size );
}
}
return true;
}
/**
* Создает временное изображение с уникальным именем.
*
* Необходимо для провайдеров, который кешируют изображения по имени файла,
* чтобы сбросить кеш, нужно отдать провайдеру изображение с другим именем.
*
* @since 1.1.2
*
* @param string $file_path путь к изображению
*
* @return array|WP_Error
*/
public function createTempAttachment( $file_path ) {
if ( $this->isBackupWritable() ) {
$temp_dir = $this->getBackupDir() . self::TEMP_DIR_NAME . '/';
$temp_dir_url = trailingslashit( $this->wp_upload_dir['baseurl'] ) . self::BACKUP_DIR_NAME . '/' . self::TEMP_DIR_NAME . '/';
if ( ! is_dir( $temp_dir ) ) {
$temp_dir = $this->mkdir( $temp_dir );
if ( is_wp_error( $temp_dir ) ) {
return $temp_dir;
}
}
$temp_file_id = uniqid();
$file_name = pathinfo( $file_path, PATHINFO_FILENAME );
$file_extension = pathinfo( $file_path, PATHINFO_EXTENSION );
$new_file_name = $temp_file_id . '_' . md5( $file_name ) . '.' . $file_extension;
$temp_file_path = $temp_dir . $new_file_name;
$temp_file_url = $temp_dir_url . $new_file_name;
if ( is_file( $file_path ) ) {
if ( ! @copy( $file_path, $temp_file_path ) ) {
WRIO_Plugin::app()->logger->error( sprintf( 'Failed to swap original file %s with %s as copy() failed.', $temp_file_path, $file_path ) );
return new WP_Error( 'copy_file_to_temp_dir_error', __( 'Could not copy the file to the temporary directory', 'robin-image-optimizer' ) );
}
}
WRIO_Plugin::app()->logger->info( sprintf( 'Creation of temporary attachment (%s) successfully completed!', $file_path ) );
return [
'id' => $temp_file_id,
'image_path' => $temp_file_path,
'image_url' => $temp_file_url,
];
}
return new WP_Error( 'backup_writable_error', __( 'It is not possible to create a temporary file, the backup folder is not writable.', 'robin-image-optimizer' ) );
}
/**
* Резервное копирование файла аттачмента.
*
* @param WIO_Attachment $wio_attachment аттачмент
* @param string $image_size Размер(thumbnail, medium ... )
*
* @return bool|WP_Error
*/
protected function backupAttachmentSize( WIO_Attachment $wio_attachment, $image_size = '' ) {
if ( $image_size ) {
$original_file = $wio_attachment->getImageSizePath( $image_size );
} else {
$original_file = $wio_attachment->get( 'path' );
}
$backup_dir = $this->getAttachmentBackupDir( $wio_attachment->get( 'attachment_meta' ) );
// проверить запись в папку
if ( is_wp_error( $backup_dir ) ) {
WRIO_Plugin::app()->logger->error( sprintf( 'Failed to create backup dir, error: %s', $backup_dir->get_error_message() ) );
return $backup_dir;
}
if ( ! $original_file ) {
// бывает такое, что размера превьюшки нет в базе данных.
// это не считается ошибкой, поэтому сразу пропускаем
return false;
}
$backup_file = $backup_dir . wp_basename( $original_file );
if ( is_file( $original_file ) ) {
if ( ! @copy( $original_file, $backup_file ) ) {
WRIO_Plugin::app()->logger->error( sprintf( 'Failed to copy %s to %s as copy() failed', $original_file, $backup_file ) );
}
}
return true;
}
/**
* Восстановление файла аттачмента из резервной копии
*
* @param WIO_Attachment $wio_attachment аттачмент
* @param string|null $image_size Размер(thumbnail, medium ... )
*
* @return bool|WP_Error
*/
protected function restoreAttachmentSize( WIO_Attachment $wio_attachment, $image_size = null ) {
if ( ! empty( $image_size ) ) {
$original_file = $wio_attachment->getImageSizePath( $image_size );
} else {
$original_file = $wio_attachment->get( 'path' );
}
$backup_dir = $this->getAttachmentBackupDir( $wio_attachment->get( 'attachment_meta' ) );
if ( is_wp_error( $backup_dir ) ) {
return $backup_dir;
}
if ( empty( $original_file ) ) {
return false;
}
$backup_file = $backup_dir . wp_basename( $original_file );
if ( ! is_file( $backup_file ) ) {
WRIO_Plugin::app()->logger->error( sprintf( 'Unable to restore from a backup. There is no file, attachment id: %s, backup file: %s', $wio_attachment->get( 'id' ), $backup_file ) );
return false;
}
if ( ! @copy( $backup_file, $original_file ) ) {
WRIO_Plugin::app()->logger->error( sprintf( 'Failed to swap %s with %s as copy() failed', $backup_file, $original_file ) );
return false;
}
if ( ! @unlink( $backup_file ) ) {
WRIO_Plugin::app()->logger->error( sprintf( 'Failed to delete backup file %s as unlink() failed', $backup_file ) );
return false;
}
WRIO_Plugin::app()->logger->info( sprintf( 'Restored file: %s.', $backup_file ) );
return true;
}
/**
* Get the backup file path for an attachment size if it exists.
*
* @param int $attachment_id The attachment ID.
* @param string $size The image size (e.g., 'original', 'thumbnail', 'medium').
*
* @return string|null The backup file path if it exists, null otherwise.
* @since 1.0.0
*/
public function getAttachmentBackupPath( $attachment_id, $size = 'original' ) {
$attachment_meta = wp_get_attachment_metadata( $attachment_id );
if ( empty( $attachment_meta ) || ! isset( $attachment_meta['file'] ) ) {
return null;
}
$backup_dir = $this->getAttachmentBackupDir( $attachment_meta );
if ( is_wp_error( $backup_dir ) ) {
return null;
}
// Get the filename based on size
if ( 'original' === $size ) {
$filename = wp_basename( $attachment_meta['file'] );
} elseif ( isset( $attachment_meta['sizes'][ $size ]['file'] ) ) {
$filename = $attachment_meta['sizes'][ $size ]['file'];
} else {
return null;
}
$backup_path = $backup_dir . $filename;
return file_exists( $backup_path ) ? $backup_path : null;
}
/**
* Удаляем резервные копии аттачмента
*
* @param int $attachment_id аттачмент id
*
* @return bool|WP_Error
*/
public function removeAttachmentBackup( $attachment_id ) {
$attachment_meta = wp_get_attachment_metadata( $attachment_id );
$backup_dir = $this->getAttachmentBackupDir( $attachment_meta );
if ( is_wp_error( $backup_dir ) ) {
return $backup_dir;
}
$main_file_path = $backup_dir . wp_basename( $attachment_meta['file'] );
if ( ! file_exists( $main_file_path ) ) {
WRIO_Plugin::app()->logger->error( sprintf( "Failed to remove an attachment file. File (%s) isn't exists. Attachment #%s", $main_file_path, $attachment_id ) );
}
if ( ! @unlink( $main_file_path ) ) {
WRIO_Plugin::app()->logger->error( sprintf( 'Failed to unlink a main file (%s) for attachment #%s', $main_file_path, $attachment_id ) );
}
if ( isset( $attachment_meta['sizes'] ) && is_array( $attachment_meta['sizes'] ) ) {
foreach ( $attachment_meta['sizes'] as $size ) {
$thumbnail_file_path = $backup_dir . $size['file'];
if ( ! file_exists( $thumbnail_file_path ) ) {
WRIO_Plugin::app()->logger->error( sprintf( "Failed to remove a thumbnail file. File (%s) isn't exists. Attachment #%s", $thumbnail_file_path, $attachment_id ) );
}
if ( ! @unlink( $thumbnail_file_path ) ) {
WRIO_Plugin::app()->logger->error( sprintf( 'Failed to unlink thumbnail (%s) for attachment #%s', $thumbnail_file_path, $attachment_id ) );
}
}
}
return true;
}
/**
* alternateStorage
*
* @param array $servers
*
* @return array
*/
public static function alternateStorage( $servers ) {
return $servers;
}
/**
* @since 1.3.0
*
* @param string $dir
*
* @return string|WP_Error
*/
protected function mkdir( $dir ) {
WRIO_Plugin::app()->logger->info( sprintf( 'Try to create backup directory. Backup dir: (%s)', $dir ) );
if ( ! wp_mkdir_p( $dir ) ) {
WRIO_Plugin::app()->logger->error( sprintf( 'Unable to create backup directory (%s) as mkdir() failed', $dir ) );
return new WP_Error( 'mkdir_failed', sprintf( 'Unable to create backup folder (%s) as mkdir() failed.', $dir ) );
}
return $dir;
}
/**
* @since 1.3.0
*
* @param string $backup_file
* @param string $original_file
*
* @return bool
*/
protected function restore_file( $backup_file, $original_file ) {
if ( is_file( $backup_file ) ) {
if ( ! @copy( $backup_file, $original_file ) ) {
WRIO_Plugin::app()->logger->error( sprintf( 'Failed to swap original file (%s) with %s as copy() failed', $backup_file, $original_file ) );
return false;
}
if ( ! @unlink( $backup_file ) ) {
WRIO_Plugin::app()->logger->error( sprintf( 'Failed to delete backup file (%s) as unlink() failed', $backup_file ) );
return false;
}
WRIO_Plugin::app()->logger->info( sprintf( 'Restored file: %s.', $backup_file ) );
return true;
}
WRIO_Plugin::app()->logger->error( sprintf( 'Unable to restore from a backup. There is no file (%s).', $backup_file ) );
return false;
}
}