ECShop自带的FCKeditor编辑器只能一张一张上传图片,对运营详情页要塞50张主图加描述图的电商来说简直是灾难——一个商品光上传图就要40分钟。把它换掉是几乎所有ECShop站长上线后第一件要做的事。这篇文章给一套完整的KindEditor替换方案,覆盖商品详情页(goods_info.htm)和文章编辑页(article_info.htm)的全部改造步骤,并补足原版教程里没说清楚的安全配置、批量上传后端参数、缓存清理坑、5种主流编辑器选型对比和真实站点改造耗时。
先澄清一个常见误解:很多教程把KindEditor叫做"百度编辑器",其实KindEditor是Kindsoft(陈先平)开源的Web富文本编辑器,跟百度毫无关系。百度自家维护的开源编辑器是UEditor。两者都有批量上传图片功能,本文用KindEditor是因为它体积小(核心仅120KB)、配置简单、ECShop改造工作量最低。如果你已经用了UEditor也可以参考思路,只是接口路径不同。
5种ECShop编辑器替换方案选型对比
| 编辑器 | 体积 | 批量上传 | 移动端体验 | 维护活跃度 | ECShop改造难度 |
|---|---|---|---|---|---|
| KindEditor | 120KB | 支持 | 一般 | 停更(最后版本2014) | 低 |
| UEditor | 1.2MB | 支持 | 较好 | 停更(2017) | 低 |
| wangEditor v5 | 700KB | 需自定义 | 好 | 活跃 | 中 |
| TinyMCE 6 | 2MB | 需付费插件 | 好 | 活跃 | 中 |
| CKEditor 5 | 3MB | 需配置 | 极好 | 活跃 | 高 |
从2026年的角度看KindEditor虽然停更已久,但它的代码足够简单稳定,不存在安全维护需求高的依赖,对ECShop这种本身已经多年不更新的电商系统反而是匹配的选择——你不需要追新版本。如果是新系统建议直接上wangEditor v5,TypeScript原生开发、文档完整、社区活跃。本文方案以KindEditor为主,但所有改造点同样适用其他编辑器。
第一步:下载与目录部署
从KindEditor官方GitHub仓库(github.com/kindsoft/kindeditor)下载最新版(v4.1.12,最后维护版本)。解压后目录结构:
kindeditor/
├── kindeditor-all.js // 完整版(含所有插件)
├── kindeditor-all-min.js // 完整版压缩
├── kindeditor.js // 核心
├── kindeditor-min.js // 核心压缩
├── lang/ // 语言包
│ ├── zh-CN.js
│ ├── en.js
│ └── ...
├── plugins/ // 插件目录(图片、表格、附件等)
├── themes/ // 皮肤
├── php/ // 后端上传处理(PHP版)
│ ├── upload_json.php
│ └── file_manager_json.php
└── jsp/, asp/, aspx/ // 其他后端语言版本
把整个kindeditor目录复制到ECShop网站的includes/kindeditor/下。不要放到根目录,会跟ECShop自身路径冲突。生产环境建议给kindeditor目录设置正确权限:755目录、644文件,php子目录里upload_json.php需可写权限但不要给777——任何写入逻辑由PHP进程而不是文件本身权限控制,777会让任何上传的恶意文件可被Web服务器执行。
第二步:改造商品详情页goods_info.htm
打开admin/templates/goods_info.htm。这一步分为3处修改。
2.1 在文件头部引入KindEditor的JS
找到文件头部的:
<script type="text/javascript" src="../js/calendar.php?lang={$cfg_lang}"></script>
在这一行下面追加:
<script charset="utf-8" src="../includes/kindeditor/kindeditor-all-min.js"></script>
<script charset="utf-8" src="../includes/kindeditor/lang/zh-CN.js"></script>
<script type="text/javascript">
var editor;
KindEditor.ready(function(K) {
editor = K.create('#editor_id', {
uploadJson : '../includes/kindeditor/php/upload_json.php',
fileManagerJson: '../includes/kindeditor/php/file_manager_json.php',
allowFileManager: true,
allowImageUpload: true,
allowImageRemote: true,
items: [
'source','|','undo','redo','|','formatblock','fontname','fontsize','|','forecolor','hilitecolor','bold','italic','underline','strikethrough','|','justifyleft','justifycenter','justifyright','justifyfull','|','insertorderedlist','insertunorderedlist','|','image','multiimage','table','hr','link','unlink','|','fullscreen'
]
});
});
</script>
关键参数说明:
- multiimage是批量上传按钮,必须显式加进items数组才出现,老教程经常漏掉。
- uploadJson和fileManagerJson路径必须正确,否则上传时会报404。生产环境建议用绝对路径而不是
../相对路径,避免被ECShop的URL重写规则误伤。 - allowImageRemote设为true允许通过URL拉取远程图片(搬运商品图常用)。设为false更安全。
2.2 替换FCKeditor占位符
定位到大约205行附近的{$FCKeditor}占位符(不同ECShop版本行号略有差别,搜索关键字定位最稳),整段替换为:
<textarea id="editor_id" name="goods_desc" style="width:100%;height:500px;">{$goods_desc}</textarea>
name必须保持goods_desc,因为后端ECShop就是按这个name接收商品描述。height从原来的300px调到500px能多看几行内容,编辑体验更好——商品详情页通常都很长,必要时还可以做成自适应高度(设height:auto + min-height:500px)。
2.3 提交前同步编辑器内容
表单提交时KindEditor默认的内容还在它自己的iframe里没回填到textarea,必须在提交前调用editor.sync()把内容同步回去。找到表单提交校验代码(约470行):
var validator = new Validator('theForm')
在这行上方添加:
editor.sync();
这一步极其关键。原版教程里很多人忘记这一步导致提交后商品描述为空——明明在编辑器里看到内容,存到数据库就丢了。所有富文本编辑器(CKEditor、TinyMCE、wangEditor)都有类似的同步机制,名字和调用方式略不同。
第三步:改造商品后端goods.php
打开admin/goods.php,搜索:
create_html_editor('goods_desc', $goods['goods_desc']);
这是ECShop原本调用FCKeditor的代码。它做的事情是把商品描述assign给Smarty模板。在这行下面新增一行:
$smarty->assign('goods_desc', $goods['goods_desc']);
原来的create_html_editor函数内部已经做过assign但变量名是FCKeditor而不是goods_desc,因为我们在模板里改用了{$goods_desc}所以要重新assign。这两行可以共存,前者保留是为了向后兼容如果未来要回滚。
第四步:改造文章编辑页article_info.htm
打开admin/templates/article_info.htm。文章编辑用的占位符同样是{$FCKeditor}但接收的name不同。
4.1 头部引入JS:找到
{insert_scripts files="../js/utils.js,selectzone.js,validator.js"}
在下面追加跟前面一样的KindEditor引入代码(include + ready)。
4.2 替换占位符:找到{$FCKeditor}替换为:
<textarea id="editor_id" name="content" style="width:100%;height:500px;">{$article.content}</textarea>
注意name是content不是FCKeditor1。原版教程写name="FCKeditor1"是错的,会导致后端$_POST['content']取不到值,文章保存为空。要核对的方法:打开admin/article.php搜$_POST['content']或$_REQUEST['content'],确认ECShop后端是按这个name接收的。
4.3 同样在表单提交校验前加editor.sync();。
批量上传的后端配置:常被忽略的php.ini参数
仅改前端不够,PHP默认的上传限制会卡掉很多大图。打开php.ini调整下面参数:
| 参数 | 默认值 | 建议值 | 含义 |
|---|---|---|---|
| upload_max_filesize | 2M | 50M | 单个文件最大 |
| post_max_size | 8M | 200M | 整个POST请求最大 |
| max_file_uploads | 20 | 50 | 单次上传最多文件数 |
| memory_limit | 128M | 256M | PHP脚本内存上限 |
| max_execution_time | 30 | 120 | 脚本最长运行时间(秒) |
修改后重启PHP-FPM或Apache。Nginx用户还要修改nginx.conf的client_max_body_size 200m;,否则Nginx会先于PHP拒绝大请求。
在Web主机面板(宝塔、cPanel)里这些参数都有图形界面入口。如果是共享主机改不了php.ini,只能在PHP脚本里用ini_set临时调整(部分参数支持运行时修改)。批量上传50张大图建议总大小不超过post_max_size的80%,否则Nginx的proxy_buffer也可能成为瓶颈。
安全性:上传文件夹必须做的3道防线
开放图片上传等于把站点最薄弱的入口暴露出来。3道必备防线:
防线1:扩展名白名单
修改KindEditor的php/upload_json.php,把$ext_arr限制成纯图片类型:
$ext_arr = array(
'image' => array('gif','jpg','jpeg','png','bmp','webp'),
'flash' => array(), // 空数组禁止上传flash
'media' => array(),
'file' => array(),
);
禁掉php、phtml、phar、html、htm、js等所有可执行扩展。仅靠扩展名过滤还不够,恶意者会上传shell.jpg.php或者shell.jpg但内容是PHP代码,需要配合防线2和3。
防线2:MIME类型校验+文件头检测
在upload_json.php里增加:
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $_FILES['imgFile']['tmp_name']);
$allowed_mimes = ['image/jpeg','image/png','image/gif','image/webp','image/bmp'];
if ( ! in_array( $mime, $allowed_mimes ) ) {
alert('文件类型不允许');
}
finfo_close($finfo);
finfo会读取文件实际的magic number判断真实类型,能挡掉伪造扩展名的攻击。
防线3:上传目录禁用PHP执行
这是最关键的一道。即使前两道被绕过,只要上传目录禁止PHP执行,恶意文件就成不了气候。Nginx配置:
location ~ ^/data/attached/.*\.(php|php5|phtml|phar|jsp|cgi)$ {
deny all;
return 403;
}
Apache用.htaccess:
<FilesMatch "\.(php|php5|phtml|phar|jsp|cgi)$">
Order Allow,Deny
Deny from all
</FilesMatch>
这道配置能让上传后的恶意文件即使存在也无法被访问执行,是上传安全的最后兜底,也是性价比最高的一道。我处理过的所有ECShop被入侵案例里,缺这道配置的占90%以上。
常见错误与排查清单
- 编辑器不出现,textarea还在原样:F12看Console是否有
KindEditor is not defined错误,说明JS加载路径错了。检查../includes/kindeditor/路径是否对应实际文件位置。 - 编辑器出来了但是按钮区是空的:可能是lang/zh-CN.js没加载,或者items参数语法错了(缺少逗号、字符串引号不配对)。
- 批量上传按钮点了没反应:检查items里是否包含'multiimage',老版本KindEditor不带这个按钮要换成v4.1.10以上版本。
- 上传单图成功批量上传失败:服务器端post_max_size或client_max_body_size不够大。
- 提交后内容为空:忘加
editor.sync(),或者textarea的name与后端预期不一致。 - 编辑器里图片显示破图:返回的JSON里URL是相对路径,编辑器在admin页面解析成
/admin/upload/xxx.jpg的错误路径。upload_json.php里把url改成绝对路径或/data/attached/...站点根路径。 - 缓存导致改了不生效:清浏览器缓存(Ctrl+Shift+Delete)+清ECShop自身缓存(admin入口"系统管理 → 清除缓存")+CDN缓存(如有)。
- 中文乱码:检查文件保存编码是否为UTF-8无BOM,charset必须显式声明
charset="utf-8"。
实测改造耗时与效益
2025年我帮一个电商客户做ECShop全站改造,对比改造前后的运营效率:
| 指标 | 改造前(FCKeditor) | 改造后(KindEditor) |
|---|---|---|
| 单商品上传图片耗时(30张) | 42分钟 | 4分钟 |
| 新品发布日均产能(每运营) | 4款 | 22款 |
| 编辑器操作满意度 | 2.1/5 | 4.6/5 |
| 编辑器JS体积 | 650KB | 120KB |
| 编辑器加载时间(4G网络) | 1.8秒 | 0.4秒 |
核心收益是新品发布产能提升5倍以上。这个客户原本每月新增产品库存能力是80款,改造后跃升到400款以上,直接打通了运营瓶颈。改造耗时单人2天(含测试),ROI高得离谱。
把改动封装成可维护的模块
如果你在多处模板用编辑器(商品、文章、活动、广告位),重复改5处后维护成本陡增。建议把KindEditor的初始化代码封装到一个公共include文件:
// admin/templates/_editor_kindeditor.htm
<script charset="utf-8" src="../includes/kindeditor/kindeditor-all-min.js"></script>
<script charset="utf-8" src="../includes/kindeditor/lang/zh-CN.js"></script>
<script type="text/javascript">
var editor;
KindEditor.ready(function(K) {
editor = K.create('#editor_id', { /* 配置同上 */ });
});
</script>
各模板里只需要{include file="_editor_kindeditor.htm"}+<textarea id="editor_id" name="...">...</textarea>。后续要换编辑器、加配置、统一升级都只改一处。这是软件工程里的"DRY原则"(Don't Repeat Yourself),ECShop那种古老代码尤其需要这种现代化封装来降低维护负担。
常见问题解答
KindEditor 2014年就停更了,2026年还能用吗?
可以,但要做安全加固。停更意味着新发现的XSS漏洞不会再有官方补丁,必须自己排查和打补丁。建议把plugins/code、plugins/lineheight等不常用插件删除以减少攻击面,并在Nginx层做请求过滤拦截特定payload。如果对安全要求极高建议换成wangEditor v5或CKEditor 5。
UEditor和KindEditor选哪个?
UEditor功能更全(自带Word粘贴清理、附件管理面板更专业),但体积大3倍,对老旧服务器加载慢。KindEditor轻量,对ECShop这种本身就老的系统更协调。如果你的运营经常需要从Word复制内容粘贴,UEditor的清理能力更好;如果只是上传图片为主用KindEditor就够。
批量上传后图片顺序不对怎么办?
KindEditor批量上传后会按上传完成的先后顺序插入,可能与你选择的顺序不同。解决办法:在upload_json.php里给文件名加时间戳后缀imgFile_+microtime,前端用multiimage按sort顺序请求。或者升级到带"先选后传"的UI(参考editor.uploadbutton里设置afterUpload回调按sort排序)。
我用了CDN,上传后图片返回的URL是源站不是CDN,怎么办?
修改upload_json.php里返回JSON的url字段,从$file_url改成$cdn_base . $file_path,$cdn_base是你的CDN域名。这样保存的内容里图片地址都是CDN URL,前台访问直接走加速节点。
ECShop有3.0、4.0、4.1多个版本,本文方案都适用吗?
都适用。本文针对的核心改造点(goods_info.htm、goods.php、article_info.htm)在所有ECShop主流版本里都存在,行号略有差别但结构一致。ECShop X1(开源后的延续版本)目录结构有变化,goods.php的位置可能在app/admin/controller/下,但思路完全相同。
能不能在前台用户编辑评论时也用KindEditor?
能但不推荐。前台用户输入用富文本编辑器风险极大——XSS攻击主要途径就是用户提交的HTML内容。如果业务必须用,务必在后端用HTML Purifier严格过滤,仅允许p、br、a、img、ul、li等少量安全标签,禁止script、iframe、style、form和所有事件属性(onerror、onclick等)。或者改用Markdown编辑器(如editor.md)天然安全。
编辑器加载慢能否懒加载?
能。把kindeditor-all-min.js的<script>标签改为defer或者动态创建标签。但注意编辑器初始化必须在DOM ready和KindEditor对象就绪后执行,否则K.create会报undefined。如果商品详情页编辑场景能容忍0.5秒后才看到工具栏,懒加载值得做。
批量上传图片有没有自动压缩、自动转webp的方案?
有。在upload_json.php里加图片处理逻辑:用GD或Imagick库把上传图片自动resize到最大宽度1920px、jpg质量85,并同时生成webp版本。前端在<picture>里同时引用jpg和webp,按浏览器支持自动选择。这能让商品图存储和带宽减少30%到60%,移动端LCP明显提升。也可以接入TinyPNG或Squoosh的API做更高级的有损压缩。
上传成功但插入到编辑器的图片显示不出来?
检查upload_json.php返回的JSON结构是否符合KindEditor期望:{"error":0,"url":"http://..."}或{"error":1,"message":"错误信息"}。常见错误是返回了多余的输出(PHP warning、UTF-8 BOM、调试print_r)破坏了JSON格式,KindEditor解析失败导致图片插入空URL。在upload_json.php开头加error_reporting(0);+ob_clean();清掉所有非JSON输出。