typecho附件上传需php底层(upload_max_filesize、post_max_size、client_max_body_size)、后台白名单(allowedattachmenttypes)及插件钩子(uploadhandle)三重校验缺一不可,仅改其一无效。

Typecho 限制附件上传格式和大小,必须同时配置 PHP 底层参数 + Typecho 后台设置 + 插件级校验,三者缺一不可。只改其中一项,必然失效。
PHP.ini 和 Nginx 配置是硬性门槛,不达标请求根本到不了 Typecho
用户上传文件时,如果超过 upload_max_filesize 或 post_max_size,PHP 直接返回 413 Request Entity Too Large 错误,Typecho 根本收不到请求。Nginx 还要额外检查 client_max_body_size(宝塔面板里叫「上传大小限制」)。
- 三者必须满足:
client_max_body_size≥post_max_size≥upload_max_filesize,建议统一设为20M - 修改后必须重启服务:宝塔中点「重载配置」或执行
sudo systemctl restart nginx php-fpm - 验证是否生效:上传一个略超限的文件,看报错是 Nginx 的 413 还是 Typecho 后台的「文件过大」提示——前者说明底层没调好
Typecho 后台「设置 - 评论/附件」里的选项只控制白名单,不校验大小
Typecho 原生只校验 MIME 类型白名单,靠的是 $options->allowedAttachmentTypes 这个配置项(不是 allowedUploadFiles 或其他名字)。它返回一个数组,比如 ['jpg', 'png', 'pdf', 'zip'],Typecho 会用 finfo_file() 检查文件真实类型,不是只看后缀。
- 后台设置页面填的「允许上传的文件类型」,实际存进数据库就是这个数组,大小写敏感,不能带点(写
.jpg会失败) - 这个配置对大小完全无约束,哪怕你设成
1KB,只要类型在白名单里,20MB 的 PNG 也能传上去 - 升级到 Typecho 1.3.0 后,该配置仍有效,但注意:插件若自己读取配置,必须用
$options->allowedAttachmentTypes,别手误写错字段名
真正可靠的大小+类型双校验,得靠插件钩子拦截
Typecho 的 Widget_Upload 类提供 uploadHandle 钩子,是唯一能做上传前校验的地方。官方不内置大小检查,必须自己加逻辑。
- 典型做法是在插件中注册钩子:
Typecho_Plugin::factory('Widget_Upload')->uploadHandle = array('MyPlugin', 'checkBeforeUpload'); - 在
checkBeforeUpload方法里,先用$_FILES['file']['size']比对阈值,再用pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION)提取扩展名,与白名单比对 - 注意:Typecho 1.3.0 后,上传临时文件路径可能变化,别直接操作
$_FILES['file']['tmp_name'],优先用$file->getStream()获取流对象 - 校验失败必须抛出异常(如
throw new Typecho_Widget_Exception(_t('文件超出大小限制'))),否则会被静默忽略
最容易被忽略的一点:Typecho 的附件校验不处理「伪造后缀」的恶意文件。比如把 shell.php 改成 shell.jpg,只要 MIME 检测通过(image/jpeg),就会入库。真要防住,得在钩子里加二进制头检测,例如用 finfo_open(FILEINFO_MIME_TYPE) 读取真实类型,再和白名单比对。











