在搭建带富文本编辑器的网站时,图片上传是绕不开的功能。前端常见的做法是把图片转成base64字符串随文本内容一起提交,或者单独用FormData以二进制文件形式上传。php后端需要根据这两种不同入参,分别写接收与存储逻辑,并把图片保存到服务器目录,最终向前端返回可访问的url,供编辑器插入使用。

一、前端两种图片提交方式
大多数现代富文本编辑器,例如常见的开源组件,在用户粘贴截图时会自动把图片编码为base64格式,嵌入到HTML的img标签的src属性里。这种方式对前端来说最简单,不需要额外请求,但会导致报文体积明显变大,且php接收后要从长字符串里剥离数据头并解码。
另一种方式是编辑器触发单独的上传事件,前端构造FormData对象,把选中的文件以multipart/form-data格式发给后端接口。此时php可以通过全局变量$_FILES直接拿到临时文件信息,处理起来更直观,也方便做大小与类型限制。理解这两种差异,才能写出兼容的后台逻辑。
1.1 base64方式的前端示例
下面是一段简化版的前端代码,把图片转成base64并提交给php。注意实际项目中往往只在保存文章时才一起发,或者先抽出来单独传。
// 假设从编辑区拿到包含base64的图片HTML片段
var imgTag = '<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+M8AAAMBAQAY3Y2wAAAAAElFTkSuQmCC">';
// 提取base64部分并提交
var base64Data = imgTag.match(/base64,([^"]+)/)[1];
fetch('/upload_base64.php', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({image: base64Data, ext: 'png'})
});
1.2 文件方式的前端示例
使用FormData上传则更标准,也不需要自己处理编码。以下代码把文件对象追加到表单里:
var fileInput = document.querySelector('input[type=file]');
var formData = new FormData();
formData.append('image', fileInput.files[0]);
fetch('/upload_file.php', {
method: 'POST',
body: formData
});
二、php接收base64图片并存储
当php收到json里的base64字段,先用file_get_contents从php://input读取原始体,再json_decode拿到数据。关键是要过滤掉可能存在的换行与空格,并用base64_decode还原为二进制。之后校验扩展名,生成基于时间与随机数的文件名,写入上传目录。
存储路径建议放在web根目录外的子文件夹或通过路由暴露,避免脚本被执行。下面示例把图片存到uploads目录,并返回完整url。注意要处理解码失败与写文件权限问题。
2.1 完整php代码
<?php
// 接收base64图片并保存
$raw = file_get_contents('php://input');
$data = json_decode($raw, true);
if (!isset($data['image']) || !isset($data['ext'])) {
http_response_code(400);
echo json_encode(['error' => '缺少参数']);
exit;
}
$ext = preg_replace('/[^a-zA-Z]/', '', $data['ext']);
$allowed = ['png', 'jpg', 'jpeg', 'gif'];
if (!in_array(strtolower($ext), $allowed)) {
http_response_code(415);
echo json_encode(['error' => '不支持的类型']);
exit;
}
$binary = base64_decode(str_replace(' ', '+', $data['image']));
if ($binary === false) {
http_response_code(400);
echo json_encode(['error' => '解码失败']);
exit;
}
$dir = __DIR__ . '/uploads/';
if (!is_dir($dir)) {
mkdir($dir, 0755, true);
}
$filename = date('YmdHis') . '_' . mt_rand(1000, 9999) . '.' . $ext;
$path = $dir . $filename;
if (file_put_contents($path, $binary) === false) {
http_response_code(500);
echo json_encode(['error' => '写入失败']);
exit;
}
$url = 'https://ipipp.com/uploads/' . $filename;
echo json_encode(['url' => $url]);
2.2 代码要点说明
上述代码用preg_replace限制扩展名只能是字母,防止传入php等危险后缀。base64_decode前把空格替换为加号,是因为部分前端在长串里加了空格换行,会导致解码出错。
返回的url使用了示例域名ipipp.com,实际部署时改成你自己的站点域名与路径即可。若上传目录不在web可访问位置,需要额外写读取接口把文件流输出。
三、php接收文件形式上传
通过$_FILES接收是php最基础的能力。编辑器用FormData发来的文件会出现在$_FILES['image']中,包含name、type、tmp_name、error、size五个字段。我们要先判断error是否为0,再校验大小和真实类型,最后用move_uploaded_file移到目标目录。
相比base64,文件上传不会让请求体膨胀数倍,也更容易在nginx或php.ini层做上传限制。下面是对应实现。
3.1 完整php代码
<?php
// 接收表单文件上传
if (!isset($_FILES['image']) || $_FILES['image']['error'] !== UPLOAD_ERR_OK) {
http_response_code(400);
echo json_encode(['error' => '上传错误']);
exit;
}
$tmp = $_FILES['image']['tmp_name'];
$size = $_FILES['image']['size'];
if ($size > 2 * 1024 * 1024) {
http_response_code(413);
echo json_encode(['error' => '文件过大']);
exit;
}
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $tmp);
finfo_close($finfo);
$map = [
'image/png' => 'png',
'image/jpeg' => 'jpg',
'image/gif' => 'gif'
];
if (!array_key_exists($mime, $map)) {
http_response_code(415);
echo json_encode(['error' => '类型不允许']);
exit;
}
$dir = __DIR__ . '/uploads/';
if (!is_dir($dir)) {
mkdir($dir, 0755, true);
}
$filename = date('YmdHis') . '_' . mt_rand(1000, 9999) . '.' . $map[$mime];
$dest = $dir . $filename;
if (!move_uploaded_file($tmp, $dest)) {
http_response_code(500);
echo json_encode(['error' => '移动失败']);
exit;
}
$url = 'https://ipipp.com/uploads/' . $filename;
echo json_encode(['url' => $url]);
3.2 安全与类型校验
代码中使用finfo_file读取临时文件的真实MIME,而不是信任前端给的type,这样可以避免把伪装成图片的脚本存进来。move_uploaded_file是php专门处理上传文件的函数,会检查文件是否来自合法上传请求。
若你的编辑器支持同时粘贴与选择上传,可以写一个统一入口,先判断是否有$_FILES再决定是否走base64分支,从而复用存储与返回逻辑。
四、返回url与编辑器对接
无论哪种方式,php最终都返回了包含url的json。前端在fetch的then里解析后,把url替换回编辑器内容中的临时标识,或者插入新的img标签。富文本编辑器通常提供setContent或execCommand接口来完成这一步。
建议后端返回相对路径或完整域名视前端部署而定。如果使用了cdn,只需把uploads目录同步或挂载到cdn源站,url换成cdn地址即可,php代码无需大改。
4.1 前端插入返回url
fetch('/upload_file.php', {method:'POST', body: formData})
.then(r => r.json())
.then(res => {
if (res.url) {
// 假定编辑器暴露了插入图片方法
editor.insertImage(res.url);
}
});
4.2 常见故障排查
若返回404,先确认uploads目录有web访问权限且url路径正确。若图片损坏,多为base64解码前未处理空格或数据头未去净。若大图失败,检查php.ini里的post_max_size与upload_max_filesize。
把两种接收方式都封装成独立函数,并在入口根据content-type或参数分流,是保持代码清晰的做法。这样后续增加鉴权或水印处理也只需改一处。
phpbase64_uploadrich_text_editor修改时间:2026-08-08 23:45:39