文件操作 - Offloader.php
返回文件管理
返回主菜单
删除本文件
文件: /storage/v12552/solsculpting/public_html/wp-content/plugins/bunnycdn/src/Offloader.php
编辑文件内容
<?php // bunny.net WordPress Plugin // Copyright (C) 2024-2025 BunnyWay d.o.o. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. declare(strict_types=1); namespace Bunny\Wordpress; use Bunny\Storage\Client as StorageClient; use Bunny\Wordpress\Config\Offloader as OffloaderConfig; use Bunny\Wordpress\Utils\Offloader as OffloaderUtils; use Bunny\Wordpress\Utils\StorageClientFactory; class Offloader { /** @var string[] */ private array $delete_original = []; /** @var string[] */ private array $excluded; private \Closure $storageFactory; private ?StorageClient $storage = null; /** * @param string[] $excluded */ public function __construct(\Closure $storageFactory, array $excluded) { // using Closure, so StorageClient is only created when needed $this->storageFactory = $storageFactory; $this->excluded = $excluded; } public static function register(): void { // no container, as this is loaded in the frontend $config = OffloaderConfig::fromWpOptions(); if (!$config->isEnabled()) { return; } $instance = new self(fn () => StorageClientFactory::createFromConfig($config), $config->getExcluded()); add_filter('wp_handle_upload_overrides', [$instance, 'wp_handle_upload_overrides']); add_filter('update_attached_file', [$instance, 'update_attached_file'], 10, 2); add_action('delete_attachment', [$instance, 'delete_attachment'], 10, 2); add_filter('wp_delete_file', [$instance, 'wp_delete_file'], 10, 1); add_filter('image_make_intermediate_size', [$instance, 'image_make_intermediate_size'], 10, 1); add_filter('wp_generate_attachment_metadata', [$instance, 'wp_generate_attachment_metadata'], 10, 3); add_action('updated_postmeta', [$instance, 'updated_postmeta'], 10, 4); } /** * @param array<string, mixed>|false $overrides * * @return array<string, mixed> */ public function wp_handle_upload_overrides($overrides): array { if (false === $overrides) { return []; } $overrides['unique_filename_callback'] = function ($dir, $name, $ext) { $remote_dir = dirname(bunnycdn_offloader_remote_path($dir.'/'.$name)); $number = 1; $filename = $name; $filenameBase = pathinfo($name, \PATHINFO_FILENAME); while ($this->getStorage()->exists(path_join($remote_dir, $filename)) || file_exists(path_join($dir, $filename))) { $filename = sprintf('%s-%d%s', $filenameBase, $number, $ext); ++$number; } return $filename; }; return $overrides; } public function update_attached_file(string $file, int $attachment_id): string { global $action; if (!$this->is_uploading_new_attachment() && !$this->is_attachment_handled_by_bunny($attachment_id)) { return $file; } $remote_path = bunnycdn_offloader_remote_path($file); if (bunnycdn_is_path_excluded($remote_path, $this->excluded)) { update_post_meta($attachment_id, OffloaderUtils::WP_POSTMETA_EXCLUDED_KEY, true); return $file; } try { $this->getStorage()->upload($file, $remote_path); $this->delete_original[] = $file; update_post_meta($attachment_id, OffloaderUtils::WP_POSTMETA_KEY, true); } catch (\Bunny\Storage\Exception $e) { if ('image-editor' !== $action) { throw $e; } } return $file; } public function delete_attachment(int $post_id, \WP_Post $post): void { $file = (string) get_attached_file($post_id); if (empty($file)) { return; } $metadata = wp_get_attachment_metadata($post_id); $file = bunnycdn_offloader_remote_path($file); $to_delete = [$file]; if (!empty($metadata['original_image'])) { $to_delete[] = path_join(dirname($file), $metadata['original_image']); } if (!empty($metadata['sizes'])) { foreach ($metadata['sizes'] as $size) { if (empty($size['file'])) { continue; } $to_delete[] = path_join(dirname($file), $size['file']); } } $backup_sizes = get_post_meta($post_id, '_wp_attachment_backup_sizes', true); if (is_array($backup_sizes)) { foreach ($backup_sizes as $size) { if (empty($size['file'])) { continue; } $to_delete[] = path_join(dirname($file), $size['file']); } } $to_delete = bunnycdn_offloader_filter_delete_paths($to_delete); $to_delete = array_unique($to_delete); $errors = $this->getStorage()->deleteMultiple($to_delete); foreach ($errors as $path => $error) { trigger_error(sprintf('bunnycdn: failed to delete %s: %s', $path, $error), \E_USER_WARNING); } } public function wp_delete_file(string $file): string { if ('' === $file) { return ''; } $to_delete = bunnycdn_offloader_filter_delete_paths([bunnycdn_offloader_remote_path($file)]); try { foreach ($to_delete as $remote_path) { $this->getStorage()->delete($remote_path); } } catch (\Bunny\Storage\FileNotFoundException $e) { // noop: this has likely already been deleted in the delete_attachment() method } catch (\Exception $e) { trigger_error(sprintf('bunnycdn: failed to remove "%s" from storage zone: %s', $file, $e->getMessage()), \E_USER_WARNING); } if (file_exists($file)) { return $file; } return ''; } public function image_make_intermediate_size(string $filename): string { global $action; if ('image-editor' === $action) { $attachment_id = (int) sanitize_key($_POST['postid'] ?? 0); if (!$this->is_attachment_handled_by_bunny($attachment_id)) { return $filename; } } $remote_path = bunnycdn_offloader_remote_path($filename); if (bunnycdn_is_path_excluded($remote_path, $this->excluded)) { return $filename; } $this->getStorage()->upload($filename, $remote_path); $this->delete_original[] = $filename; return $filename; } /** * @param array<string, mixed> $metadata * * @return array<string, mixed> */ public function wp_generate_attachment_metadata(array $metadata, int $attachment_id, string $action): array { if ('create' === $action && count($this->delete_original) > 0) { foreach ($this->delete_original as $file_to_delete) { if (!file_exists($file_to_delete)) { continue; } @unlink($file_to_delete); } $this->delete_original = []; } return $metadata; } /** * @param mixed $meta_value */ public function updated_postmeta(int $meta_id, int $object_id, string $meta_key, $meta_value): void { // making sure the original image isn't deleted before generating the subsizes if ($this->is_uploading_new_attachment() && '_wp_attachment_metadata' === $meta_key) { return; } if ('_wp_attachment_metadata' !== $meta_key) { return; } foreach ($this->delete_original as $file_to_delete) { if (!file_exists($file_to_delete)) { continue; } @unlink($file_to_delete); } $this->delete_original = []; } private function is_attachment_handled_by_bunny(int $post_id): bool { return (bool) get_post_meta($post_id, OffloaderUtils::WP_POSTMETA_KEY, true); } private function is_uploading_new_attachment(): bool { global $pagenow, $wp; if ('async-upload.php' === $pagenow || 'media-new.php' === $pagenow) { return true; } if ('index.php' === $pagenow && isset($wp->query_vars['rest_route']) && '/wp/v2/media' === $wp->query_vars['rest_route']) { return true; } return false; } private function getStorage(): StorageClient { if (null !== $this->storage) { return $this->storage; } $this->storage = ($this->storageFactory)(); if (null === $this->storage) { throw new \Exception('Failed to instantiate storage'); } return $this->storage; } }
修改文件时间
将文件时间修改为当前时间的前一年
删除文件