文章目录[隐藏]
一步步实现:为网站添加文件上传与云存储管理,通过WordPress程序的代码二次开发实现常用互联网小工具功能
引言:为什么网站需要文件上传与云存储管理?
在当今数字化时代,网站的功能性需求日益复杂。无论是企业官网、个人博客,还是电子商务平台,文件上传与管理功能已成为不可或缺的基础需求。用户期望能够轻松上传图片、文档、视频等内容,而网站管理员则需要高效、安全地管理这些文件资源。
传统的WordPress媒体库虽然提供了基础的文件上传功能,但在面对大量文件、大文件上传、多用户协作、跨平台访问等复杂场景时,往往显得力不从心。云存储解决方案的出现,为这一问题提供了完美的答案。通过将文件存储在云端,网站不仅可以减轻服务器负担,还能实现更高的可用性、可扩展性和安全性。
本文将深入探讨如何通过WordPress代码二次开发,为网站添加强大的文件上传与云存储管理功能,并在此基础上实现一系列常用互联网小工具,从而大幅提升网站的功能性和用户体验。
第一部分:WordPress文件上传机制深度解析
1.1 WordPress默认上传系统的工作原理
WordPress内置了一个相对完整的文件上传系统。当用户通过媒体上传界面或相关功能上传文件时,系统会执行以下关键步骤:
- 文件验证:检查文件类型、大小是否符合系统设置
- 安全处理:对文件名进行清理,防止安全漏洞
- 存储处理:将文件保存到wp-content/uploads目录,并按年月组织子目录
- 数据库记录:在wp_posts表中创建attachment类型的记录
- 元数据生成:为图片文件生成缩略图,提取EXIF信息等
了解这一基础流程是进行二次开发的前提。我们可以通过分析wp_handle_upload()、media_handle_upload()等核心函数,掌握WordPress处理上传文件的完整机制。
1.2 现有上传系统的局限性
尽管WordPress默认系统能够满足基本需求,但在实际应用中存在明显不足:
- 存储空间受限:依赖服务器本地存储,空间有限且不易扩展
- 性能瓶颈:大文件上传和处理可能拖慢网站响应速度
- 备份困难:文件分散在服务器上,难以实现统一备份和恢复
- 访问限制:缺乏细粒度的访问控制和权限管理
- 多站点管理复杂:对于多站点网络,文件管理变得异常复杂
这些局限性正是我们需要引入云存储解决方案的根本原因。
第二部分:云存储集成方案选择与比较
2.1 主流云存储服务概览
目前市场上有多种云存储服务可供选择,每种都有其特点和适用场景:
- Amazon S3:功能全面,生态系统完善,适合企业级应用
- Google Cloud Storage:与Google生态系统深度集成,性能优异
- 阿里云OSS:国内访问速度快,符合中国法规要求
- 腾讯云COS:性价比高,与腾讯生态整合良好
- Backblaze B2:价格实惠,适合个人和小型企业
- Wasabi:无出口费用,适合高频访问场景
2.2 选择云存储服务的关键考量因素
在选择云存储服务时,需要综合考虑以下因素:
- 成本结构:存储费用、请求费用、流量费用的综合评估
- 性能表现:上传下载速度、延迟、可用性保证
- 地理位置:服务器位置对访问速度的影响
- 集成难度:API的易用性和文档完整性
- 合规要求:数据主权、隐私保护等法规遵从性
- 生态系统:与其他服务的集成能力
2.3 WordPress云存储插件评估
在开始自定义开发前,了解现有插件解决方案是必要的:
- WP Offload Media:功能全面,支持多种云服务
- Media Cloud:专注于云存储,提供高级功能
- Stateless:与Google Cloud Platform深度集成
- Storage for WordPress:轻量级解决方案,易于定制
虽然这些插件提供了现成的解决方案,但通过自定义开发,我们可以实现更贴合特定需求、更高效集成的文件管理系统。
第三部分:构建自定义文件上传与云存储管理系统
3.1 系统架构设计
我们的自定义系统将采用模块化设计,主要包括以下组件:
- 上传处理模块:负责接收、验证和处理上传请求
- 云存储适配器:抽象不同云服务的API,提供统一接口
- 文件管理模块:提供文件的增删改查操作
- 权限控制系统:管理用户对文件的访问权限
- 缓存与优化层:提高系统性能和响应速度
- 管理界面:为管理员和用户提供友好的操作界面
3.2 核心代码实现
3.2.1 创建云存储适配器抽象类
<?php
/**
* 云存储适配器抽象类
*/
abstract class Cloud_Storage_Adapter {
protected $config;
protected $client;
public function __construct($config) {
$this->config = $config;
$this->initialize_client();
}
abstract protected function initialize_client();
abstract public function upload($local_path, $remote_path, $options = []);
abstract public function download($remote_path, $local_path);
abstract public function delete($remote_path);
abstract public function list_files($prefix = '', $options = []);
abstract public function get_url($remote_path, $expires = null);
abstract public function file_exists($remote_path);
}
3.2.2 实现S3适配器
<?php
/**
* Amazon S3适配器实现
*/
class S3_Storage_Adapter extends Cloud_Storage_Adapter {
protected function initialize_client() {
$this->client = new AwsS3S3Client([
'version' => 'latest',
'region' => $this->config['region'],
'credentials' => [
'key' => $this->config['key'],
'secret' => $this->config['secret'],
],
]);
}
public function upload($local_path, $remote_path, $options = []) {
$default_options = [
'Bucket' => $this->config['bucket'],
'Key' => $remote_path,
'SourceFile' => $local_path,
'ACL' => 'private',
];
$options = array_merge($default_options, $options);
try {
$result = $this->client->putObject($options);
return [
'success' => true,
'url' => $result['ObjectURL'],
'etag' => $result['ETag'],
];
} catch (AwsS3ExceptionS3Exception $e) {
return [
'success' => false,
'error' => $e->getMessage(),
];
}
}
// 其他方法实现...
}
3.2.3 创建文件上传处理器
<?php
/**
* 文件上传处理器
*/
class File_Upload_Handler {
private $adapter;
private $allowed_types;
private $max_size;
public function __construct($adapter) {
$this->adapter = $adapter;
$this->allowed_types = get_option('allowed_upload_types', []);
$this->max_size = get_option('max_upload_size', 10485760); // 默认10MB
}
public function handle_upload($file, $user_id, $options = []) {
// 验证文件
$validation = $this->validate_file($file);
if (!$validation['valid']) {
return $validation;
}
// 生成唯一文件名和路径
$file_info = $this->generate_file_info($file, $user_id);
// 临时保存文件
$temp_path = $this->save_temp_file($file);
// 上传到云存储
$upload_result = $this->adapter->upload(
$temp_path,
$file_info['remote_path'],
$options
);
// 清理临时文件
unlink($temp_path);
if ($upload_result['success']) {
// 保存文件记录到数据库
$file_id = $this->save_file_record($file_info, $user_id);
return [
'success' => true,
'file_id' => $file_id,
'url' => $upload_result['url'],
'file_info' => $file_info,
];
}
return [
'success' => false,
'error' => $upload_result['error'],
];
}
private function validate_file($file) {
// 检查文件大小
if ($file['size'] > $this->max_size) {
return [
'valid' => false,
'error' => '文件大小超过限制',
];
}
// 检查文件类型
$file_type = wp_check_filetype($file['name']);
if (!in_array($file_type['type'], $this->allowed_types)) {
return [
'valid' => false,
'error' => '不支持的文件类型',
];
}
// 安全检查
if (!wp_verify_nonce($_POST['upload_nonce'], 'file_upload')) {
return [
'valid' => false,
'error' => '安全验证失败',
];
}
return ['valid' => true];
}
private function generate_file_info($file, $user_id) {
$original_name = sanitize_file_name($file['name']);
$extension = pathinfo($original_name, PATHINFO_EXTENSION);
$unique_name = wp_generate_uuid4() . '.' . $extension;
// 按用户和日期组织目录结构
$date = date('Y/m');
$remote_path = "uploads/{$user_id}/{$date}/{$unique_name}";
return [
'original_name' => $original_name,
'unique_name' => $unique_name,
'remote_path' => $remote_path,
'extension' => $extension,
'size' => $file['size'],
];
}
// 其他辅助方法...
}
3.3 数据库设计优化
为了高效管理文件元数据,我们需要创建自定义数据库表:
CREATE TABLE wp_cloud_files (
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
user_id BIGINT(20) UNSIGNED NOT NULL,
original_name VARCHAR(255) NOT NULL,
unique_name VARCHAR(255) NOT NULL,
remote_path VARCHAR(500) NOT NULL,
file_type VARCHAR(100) NOT NULL,
file_size BIGINT(20) UNSIGNED NOT NULL,
mime_type VARCHAR(100),
upload_time DATETIME DEFAULT CURRENT_TIMESTAMP,
last_access DATETIME,
access_count INT UNSIGNED DEFAULT 0,
is_public TINYINT(1) DEFAULT 0,
metadata TEXT,
PRIMARY KEY (id),
INDEX user_index (user_id),
INDEX path_index (remote_path(255)),
INDEX type_index (file_type),
INDEX upload_time_index (upload_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
3.4 管理界面开发
创建用户友好的管理界面是系统成功的关键。我们可以使用WordPress的Admin API创建自定义管理页面:
<?php
/**
* 文件管理界面
*/
class File_Management_UI {
public function __construct() {
add_action('admin_menu', [$this, 'add_admin_menu']);
add_action('admin_enqueue_scripts', [$this, 'enqueue_scripts']);
}
public function add_admin_menu() {
add_menu_page(
'云文件管理',
'云文件',
'upload_files',
'cloud-file-manager',
[$this, 'render_main_page'],
'dashicons-cloud',
30
);
add_submenu_page(
'cloud-file-manager',
'上传文件',
'上传',
'upload_files',
'cloud-file-upload',
[$this, 'render_upload_page']
);
add_submenu_page(
'cloud-file-manager',
'文件统计',
'统计',
'manage_options',
'cloud-file-stats',
[$this, 'render_stats_page']
);
}
public function render_main_page() {
?>
<div class="wrap">
<h1 class="wp-heading-inline">云文件管理</h1>
<a href="<?php echo admin_url('admin.php?page=cloud-file-upload'); ?>" class="page-title-action">上传文件</a>
<hr class="wp-header-end">
<div id="cloud-file-manager">
<!-- 文件列表将通过Vue.js动态加载 -->
<div class="file-manager-container">
<div class="file-toolbar">
<div class="search-box">
<input type="search" id="file-search" placeholder="搜索文件...">
</div>
<div class="filter-options">
<select id="file-type-filter">
<option value="">所有类型</option>
<option value="image">图片</option>
<option value="document">文档</option>
<option value="video">视频</option>
</select>
</div>
</div>
<div class="file-list-container">
<!-- 文件列表将通过AJAX加载 -->
</div>
<div class="file-pagination">
<!-- 分页控件 -->
</div>
</div>
</div>
</div>
<?php
}
public function enqueue_scripts($hook) {
if (strpos($hook, 'cloud-file') === false) {
return;
}
wp_enqueue_style(
'cloud-file-manager',
plugins_url('css/file-manager.css', __FILE__),
[],
'1.0.0'
);
wp_enqueue_script(
'cloud-file-manager',
plugins_url('js/file-manager.js', __FILE__),
['jquery', 'vue'],
'1.0.0',
true
);
wp_localize_script('cloud-file-manager', 'cloudFileManager', [
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('cloud_file_manager'),
'strings' => [
'delete_confirm' => '确定要删除这个文件吗?',
'upload_success' => '文件上传成功',
'upload_failed' => '文件上传失败',
]
]);
}
}
第四部分:基于文件系统的实用小工具开发
4.1 图片水印添加工具
<?php
/**
* 图片水印工具
*/
class Image_Watermark_Tool {
private $adapter;
public function __construct($adapter) {
$this->adapter = $adapter;
add_action('wp_ajax_add_watermark', [$this, 'ajax_add_watermark']);
}
public function add_watermark($image_path, $watermark_text, $options = []) {
// 从云存储下载图片
$temp_path = $this->download_to_temp($image_path);
// 获取图片信息
$image_info = getimagesize($temp_path);
$image_type = $image_info[2];
// 根据图片类型创建图像资源
switch ($image_type) {
case IMAGETYPE_JPEG:
$image = imagecreatefromjpeg($temp_path);
break;
case IMAGETYPE_PNG:
$image = imagecreatefrompng($temp_path);
break;
case IMAGETYPE_GIF:
$image = imagecreatefromgif($temp_path);
break;
default:
return false;
}
// 设置水印颜色和字体
$text_color = imagecolorallocatealpha($image, 255, 255, 255, 60);
$font_size = isset($options['font_size']) ? $options['font_size'] : 20;
$font_path = isset($options['font_path']) ? $options['font_path'] : '';
// 计算水印位置
$text_box = imagettfbbox($font_size, 0, $font_path, $watermark_text);
$text_width = $text_box[2] - $text_box[0];
$text_height = $text_box[7] - $text_box[1];
$x = imagesx($image) - $text_width - 10;
$y = imagesy($image) - $text_height - 10;
// 添加水印
imagettftext($image, $font_size, 0, $x, $y, $text_color, $font_path, $watermark_text);
// 保存处理后的图片
$watermarked_path = $this->get_watermarked_path($temp_path);
switch ($image_type) {
case IMAGETYPE_JPEG:
imagejpeg($image, $watermarked_path, 90);
break;
case IMAGETYPE_PNG:
imagepng($image, $watermarked_path, 9);
break;
case IMAGETYPE_GIF:
imagegif($image, $watermarked_path);
break;
}
imagedestroy($image);
// 上传处理后的图片
$new_remote_path = $this->get_watermarked_remote_path($image_path);
$result = $this->adapter->upload($watermarked_path, $new_remote_path);
// 清理临时文件
unlink($temp_path);
unlink($watermarked_path);
return $result['success'] ? $new_remote_path : false;
}
public function ajax_add_watermark() {
check_ajax_referer('watermark_tool', 'nonce');
$file_id = intval($_POST['file_id']);
$watermark_text = sanitize_text_field($_POST['watermark_text']);
// 获取文件信息
$file_info = $this->get_file_info($file_id);
if (!$file_info || !$this->is_image($file_info['mime_type'])) {
4.2 文件批量处理工具
<?php
/**
* 文件批量处理工具
*/
class Batch_File_Processor {
private $adapter;
private $batch_size = 50; // 每批处理文件数量
public function __construct($adapter) {
$this->adapter = $adapter;
add_action('wp_ajax_batch_process_files', [$this, 'ajax_batch_process']);
}
public function process_batch($file_ids, $operation, $params = []) {
$results = [
'success' => [],
'failed' => [],
'total' => count($file_ids)
];
// 分批处理,避免内存溢出
$chunks = array_chunk($file_ids, $this->batch_size);
foreach ($chunks as $chunk) {
foreach ($chunk as $file_id) {
try {
$result = $this->process_single_file($file_id, $operation, $params);
if ($result['success']) {
$results['success'][] = [
'id' => $file_id,
'message' => $result['message']
];
} else {
$results['failed'][] = [
'id' => $file_id,
'error' => $result['error']
];
}
// 短暂暂停,减轻服务器压力
usleep(100000); // 0.1秒
} catch (Exception $e) {
$results['failed'][] = [
'id' => $file_id,
'error' => $e->getMessage()
];
}
}
}
return $results;
}
private function process_single_file($file_id, $operation, $params) {
global $wpdb;
// 获取文件信息
$file = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}cloud_files WHERE id = %d",
$file_id
));
if (!$file) {
return ['success' => false, 'error' => '文件不存在'];
}
switch ($operation) {
case 'compress_images':
return $this->compress_image($file, $params);
case 'convert_format':
return $this->convert_format($file, $params);
case 'add_metadata':
return $this->add_metadata($file, $params);
case 'generate_thumbnails':
return $this->generate_thumbnails($file, $params);
case 'optimize_for_web':
return $this->optimize_for_web($file, $params);
default:
return ['success' => false, 'error' => '不支持的操作'];
}
}
private function compress_image($file, $params) {
if (!$this->is_image($file->mime_type)) {
return ['success' => false, 'error' => '不是图片文件'];
}
// 下载文件到临时目录
$temp_path = $this->download_to_temp($file->remote_path);
// 根据图片类型进行压缩
$compressed_path = $this->compress_image_file($temp_path, $params);
if (!$compressed_path) {
unlink($temp_path);
return ['success' => false, 'error' => '压缩失败'];
}
// 计算压缩率
$original_size = filesize($temp_path);
$compressed_size = filesize($compressed_path);
$compression_rate = round((1 - $compressed_size / $original_size) * 100, 2);
// 上传压缩后的文件
$new_remote_path = $this->get_compressed_path($file->remote_path);
$upload_result = $this->adapter->upload($compressed_path, $new_remote_path);
// 清理临时文件
unlink($temp_path);
unlink($compressed_path);
if ($upload_result['success']) {
// 更新数据库记录
$this->update_file_record($file->id, [
'compressed_path' => $new_remote_path,
'original_size' => $original_size,
'compressed_size' => $compressed_size,
'compression_rate' => $compression_rate
]);
return [
'success' => true,
'message' => "压缩成功,压缩率:{$compression_rate}%"
];
}
return ['success' => false, 'error' => '上传压缩文件失败'];
}
private function compress_image_file($image_path, $params) {
$quality = isset($params['quality']) ? $params['quality'] : 80;
$max_width = isset($params['max_width']) ? $params['max_width'] : 1920;
$image_info = getimagesize($image_path);
$image_type = $image_info[2];
// 创建图像资源
switch ($image_type) {
case IMAGETYPE_JPEG:
$image = imagecreatefromjpeg($image_path);
break;
case IMAGETYPE_PNG:
$image = imagecreatefrompng($image_path);
// 保留透明度
imagealphablending($image, false);
imagesavealpha($image, true);
break;
default:
return false;
}
// 调整尺寸
$original_width = imagesx($image);
$original_height = imagesy($image);
if ($original_width > $max_width) {
$new_width = $max_width;
$new_height = intval($original_height * ($max_width / $original_width));
$resized_image = imagecreatetruecolor($new_width, $new_height);
// 处理PNG透明度
if ($image_type == IMAGETYPE_PNG) {
imagealphablending($resized_image, false);
imagesavealpha($resized_image, true);
$transparent = imagecolorallocatealpha($resized_image, 255, 255, 255, 127);
imagefilledrectangle($resized_image, 0, 0, $new_width, $new_height, $transparent);
}
imagecopyresampled(
$resized_image, $image,
0, 0, 0, 0,
$new_width, $new_height,
$original_width, $original_height
);
imagedestroy($image);
$image = $resized_image;
}
// 保存压缩后的图片
$compressed_path = $this->get_temp_file_path('compressed_');
switch ($image_type) {
case IMAGETYPE_JPEG:
imagejpeg($image, $compressed_path, $quality);
break;
case IMAGETYPE_PNG:
// PNG质量参数是0-9,与JPEG相反
$png_quality = 9 - round(($quality / 100) * 9);
imagepng($image, $compressed_path, $png_quality);
break;
}
imagedestroy($image);
return $compressed_path;
}
public function ajax_batch_process() {
check_ajax_referer('batch_processor', 'nonce');
if (!current_user_can('upload_files')) {
wp_send_json_error('权限不足');
}
$file_ids = array_map('intval', $_POST['file_ids']);
$operation = sanitize_text_field($_POST['operation']);
$params = isset($_POST['params']) ? $_POST['params'] : [];
// 异步处理
if (isset($_POST['async']) && $_POST['async']) {
$this->start_async_batch_process($file_ids, $operation, $params);
wp_send_json_success(['message' => '批量处理已开始']);
} else {
$results = $this->process_batch($file_ids, $operation, $params);
wp_send_json_success($results);
}
}
private function start_async_batch_process($file_ids, $operation, $params) {
// 创建后台任务
$task_id = wp_generate_uuid4();
$task_data = [
'file_ids' => $file_ids,
'operation' => $operation,
'params' => $params,
'status' => 'pending',
'progress' => 0,
'created_at' => current_time('mysql'),
'created_by' => get_current_user_id()
];
// 保存任务到数据库
$this->save_batch_task($task_id, $task_data);
// 触发后台处理
wp_schedule_single_event(time() + 5, 'process_batch_task', [$task_id]);
return $task_id;
}
}
4.3 智能文件分类器
<?php
/**
* 智能文件分类器
*/
class Smart_File_Classifier {
private $adapter;
private $categories = [
'images' => ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'],
'documents' => ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt'],
'videos' => ['mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv'],
'audio' => ['mp3', 'wav', 'ogg', 'm4a'],
'archives' => ['zip', 'rar', '7z', 'tar', 'gz'],
'code' => ['php', 'js', 'css', 'html', 'py', 'java', 'cpp']
];
public function __construct($adapter) {
$this->adapter = $adapter;
add_action('wp_ajax_classify_files', [$this, 'ajax_classify_files']);
add_action('add_attachment', [$this, 'auto_classify_new_file']);
}
public function classify_file($file_path, $file_name) {
$extension = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));
// 根据扩展名分类
foreach ($this->categories as $category => $extensions) {
if (in_array($extension, $extensions)) {
return $category;
}
}
// 使用MIME类型进一步分类
$mime_type = $this->get_mime_type($file_path);
if ($mime_type) {
return $this->classify_by_mime_type($mime_type);
}
return 'other';
}
private function classify_by_mime_type($mime_type) {
$mime_categories = [
'image/' => 'images',
'application/pdf' => 'documents',
'application/msword' => 'documents',
'application/vnd.openxmlformats-officedocument' => 'documents',
'video/' => 'videos',
'audio/' => 'audio',
'application/zip' => 'archives',
'application/x-rar-compressed' => 'archives',
'text/' => 'documents'
];
foreach ($mime_categories as $prefix => $category) {
if (strpos($mime_type, $prefix) === 0) {
return $category;
}
}
return 'other';
}
public function auto_classify_new_file($attachment_id) {
$file_path = get_attached_file($attachment_id);
$file_name = basename($file_path);
$category = $this->classify_file($file_path, $file_name);
// 保存分类信息
update_post_meta($attachment_id, '_file_category', $category);
// 如果是图片,提取更多信息
if ($category === 'images') {
$this->extract_image_metadata($attachment_id, $file_path);
}
}
private function extract_image_metadata($attachment_id, $file_path) {
$metadata = [];
// 获取EXIF数据
if (function_exists('exif_read_data') && in_array(strtolower(pathinfo($file_path, PATHINFO_EXTENSION)), ['jpg', 'jpeg'])) {
$exif = @exif_read_data($file_path);
if ($exif) {
if (isset($exif['DateTimeOriginal'])) {
$metadata['taken_date'] = $exif['DateTimeOriginal'];
}
if (isset($exif['GPSLatitude']) && isset($exif['GPSLongitude'])) {
$metadata['gps'] = $this->convert_gps($exif['GPSLatitude'], $exif['GPSLongitude']);
}
if (isset($exif['Make'])) {
$metadata['camera_make'] = $exif['Make'];
}
if (isset($exif['Model'])) {
$metadata['camera_model'] = $exif['Model'];
}
}
}
// 获取图片尺寸
$image_size = getimagesize($file_path);
if ($image_size) {
$metadata['dimensions'] = [
'width' => $image_size[0],
'height' => $image_size[1]
];
$metadata['mime_type'] = $image_size['mime'];
}
// 计算文件哈希
$metadata['file_hash'] = md5_file($file_path);
// 保存元数据
update_post_meta($attachment_id, '_image_metadata', $metadata);
}
private function convert_gps($gps_lat, $gps_lon) {
// 将GPS坐标转换为十进制
$lat_degrees = count($gps_lat) > 0 ? $this->gps_to_degrees($gps_lat) : 0;
$lon_degrees = count($gps_lon) > 0 ? $this->gps_to_degrees($gps_lon) : 0;
// 确定半球
$lat_direction = ($gps_lat['GPSLatitudeRef'] == 'S') ? -1 : 1;
$lon_direction = ($gps_lon['GPSLongitudeRef'] == 'W') ? -1 : 1;
return [
'lat' => $lat_degrees * $lat_direction,
'lon' => $lon_degrees * $lon_direction
];
}
private function gps_to_degrees($gps_coordinate) {
$degrees = count($gps_coordinate) > 0 ? $this->gps_coordinate_to_number($gps_coordinate[0]) : 0;
$minutes = count($gps_coordinate) > 1 ? $this->gps_coordinate_to_number($gps_coordinate[1]) : 0;
$seconds = count($gps_coordinate) > 2 ? $this->gps_coordinate_to_number($gps_coordinate[2]) : 0;
return $degrees + ($minutes / 60) + ($seconds / 3600);
}
private function gps_coordinate_to_number($coordinate_part) {
$parts = explode('/', $coordinate_part);
if (count($parts) <= 0) {
return 0;
}
if (count($parts) == 1) {
return $parts[0];
}
return floatval($parts[0]) / floatval($parts[1]);
}
public function ajax_classify_files() {
check_ajax_referer('file_classifier', 'nonce');
$file_ids = array_map('intval', $_POST['file_ids']);
$results = [];
foreach ($file_ids as $file_id) {
$file = get_post($file_id);
if (!$file || $file->post_type != 'attachment') {
continue;
}
$file_path = get_attached_file($file_id);
$category = $this->classify_file($file_path, $file->post_title);
// 更新分类
update_post_meta($file_id, '_file_category', $category);
$results[] = [
'id' => $file_id,
'name' => $file->post_title,
'category' => $category,
'icon' => $this->get_category_icon($category)
];
}
wp_send_json_success([
'results' => $results,
'total' => count($results)
]);
}
private function get_category_icon($category) {
$icons = [
'images' => 'dashicons-format-image',
'documents' => 'dashicons-media-document',
'videos' => 'dashicons-format-video',
'audio' => 'dashicons-format-audio',
'archives' => 'dashicons-media-archive',
'code' => 'dashicons-editor-code',
'other' => 'dashicons-media-default'
];
return isset($icons[$category]) ? $icons[$category] : $icons['other'];
}
}
4.4 文件分享与协作工具
<?php
/**
* 文件分享与协作工具
*/
class File_Sharing_Tool {
private $adapter;
private $share_expiry_days = 7;
public function __construct($adapter) {
$this->adapter = $adapter;
add_action('wp_ajax_create_file_share', [$this, 'ajax_create_share']);
add_action('wp_ajax_revoke_file_share', [$this, 'ajax_revoke_share']);
add_action('wp', [$this, 'handle_shared_file_access']);
}
public function create_share_link($file_id, $options = []) {
global $wpdb;
// 验证文件存在且用户有权限
$file = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}cloud_files WHERE id = %d",
$file_id
));
if (!$file) {
