将Base64字符串转为WordPress附件时重复上传问题排查与修复
问题分析与修复方案
问题根源
你的代码每次调用都会直接生成新文件并插入媒体库,核心原因有两个:
- 缺少重复内容校验:没有检查当前Base64对应的图片是否已经上传过,仅靠
microtime()生成不同文件名,导致WordPress判定为新文件。 - MIME类型提取逻辑脆弱:用固定长度的
substr截取MIME类型,遇到jpeg这类长度不同的类型会出错。
修复步骤与代码修改
1. 新增内容哈希校验逻辑
通过计算解码后图片内容的MD5哈希,作为唯一标识来检查媒体库中是否存在相同图片。
2. 优化MIME类型提取
从Base64字符串的头部正确解析MIME类型,避免硬编码索引的问题。
3. 存储哈希到附件元数据
上传成功后将哈希值存为附件的自定义字段,方便后续校验查询。
修改后的完整Catalog类代码:
<?php class Catalog { public function uploadBase64Image() { // Base64字符串示例 $base64_img = include 'testbase64.php'; // 1. 解析Base64内容与MIME类型 $image_parts = explode(";base64,", $base64_img); $image_type = explode(':', $image_parts[0])[1]; // 正确提取image/png、image/jpeg等 $mime = explode('/', $image_type)[1]; $decoded = base64_decode($image_parts[1]); // 2. 生成图片内容的唯一哈希(核心校验依据) $content_hash = md5($decoded); // 3. 检查媒体库中是否已有相同哈希的附件 $existing_attach = get_posts([ 'post_type' => 'attachment', 'meta_key' => '_image_content_hash', 'meta_value' => $content_hash, 'posts_per_page' => 1, 'fields' => 'ids', 'post_status' => 'inherit' ]); if (!empty($existing_attach)) { // 已存在,直接返回已有附件ID return $existing_attach[0]; } // 4. 不存在则执行上传流程 $upload_dir = wp_upload_dir(); $upload_path = str_replace('/', DIRECTORY_SEPARATOR, $upload_dir['path']) . DIRECTORY_SEPARATOR; $title = "test"; $filename = $title . '.' . $mime; // 用内容哈希替代microtime,保证相同内容的文件名一致 $hashed_filename = $content_hash . '_' . $filename; $upload_file = file_put_contents($upload_path . $hashed_filename, $decoded); if (!$upload_file) { // 文件写入失败,返回错误(可根据需求自定义处理) return false; } $attachment = [ 'post_mime_type' => $image_type, // 用正确解析的MIME类型 'post_title' => preg_replace('/\.[^.]+$/', '', basename($hashed_filename)), 'post_content' => '', 'post_status' => 'inherit', 'guid' => $upload_dir['url'] . '/' . basename($hashed_filename) ]; $attach_id = wp_insert_attachment($attachment, $upload_dir['path'] . '/' . $hashed_filename); require_once ABSPATH . 'wp-admin/includes/image.php'; $attach_data = wp_generate_attachment_metadata($attach_id, $upload_dir['path'] . '/' . $hashed_filename); wp_update_attachment_metadata($attach_id, $attach_data); // 5. 将内容哈希存入附件元数据,供后续校验使用 update_post_meta($attach_id, '_image_content_hash', $content_hash); return $attach_id; } }
额外注意事项
你的调用代码挂载在init钩子上,每次前端页面加载都会触发,即使图片已经上传过。如果只是测试用,可以添加执行次数限制,比如:
function testCatalog() { if (!is_admin() && !get_option('catalog_image_uploaded')) { $catalog = new Catalog(); $attach_id = $catalog->uploadBase64Image(); // 标记已上传,避免重复触发 update_option('catalog_image_uploaded', true); return $attach_id; } } add_action('init', 'testCatalog');
测试完成后记得移除这个限制,或者根据实际业务逻辑调整触发时机。
内容的提问来源于stack exchange,提问作者benjah
相关产品推荐
相关产品推荐

