CMS企业官网编辑器功能扩展开发记录(PHP版)
一、需求分析与技术评估
作为独立PHP开发者,我接到了一个企业官网CMS系统的功能扩展需求,需要在现有CKEditor4编辑器中增加Word/Excel/PPT/PDF导入和一键粘贴功能,预算严格控制在99元以内。这要求我必须采用高性价比的技术方案。
核心需求拆解
- 文档导入:支持四种格式,保留样式和图片
- 粘贴优化:从Word/微信直接粘贴,自动处理图片
- 云存储:阿里云OSS集成
- 零破坏:不影响现有系统架构
技术选型决策
| 方案 | 成本 | 开发难度 | 兼容性 |
|---|---|---|---|
| 商业插件 | $500+ | 低 | 高 |
| 开源方案 | 免费 | 中 | 中 |
| 自主开发 | 仅时间成本 | 高 | 高 |
最终选择:基于PHPWord/PHPExcel/PHPPowerPoint/PDFParser开源库自主开发,结合CKEditor自定义插件
二、开发环境准备
本地环境:
- PHP 7.4 + Apache
- Zend Studio 2021
- MySQL 5.7
云服务:
- 阿里云ECS(已购)
- OSS标准存储包(首年免费)
依赖管理:
composerrequire phpoffice/phpword phpoffice/phpspreadsheet phppowerpoint/phppowerpoint smalot/pdfparser
三、核心功能实现
1. CKEditor插件开发
创建custompaste插件目录结构:
/plugins/custompaste/ ├── plugin.js ├── icons/ │ └── custompaste.png └── dialogs/ └── import.jsplugin.js核心代码:
CKEDITOR.plugins.add('custompaste',{icons:'custompaste',init:function(editor){editor.addCommand('importDocument',{exec:function(editor){// 打开导入对话框editor.openDialog('importDialog');}});editor.ui.addButton('CustomPaste',{label:'文档导入',command:'importDocument',toolbar:'insert',icon:this.path+'icons/custompaste.png'});// 微信粘贴特殊处理editor.on('paste',function(evt){consthtml=evt.data.dataValue;if(/mp.weixin.qq.com/.test(html)){processWechatContent(html).then(cleanHtml=>{evt.data.dataValue=cleanHtml;});}});}});2. PHP后端处理
文档解析控制器(ImportController.php)
ossClient=new\OSS\OssClient(getenv('OSS_ACCESS_KEY'),getenv('OSS_SECRET_KEY'),getenv('OSS_ENDPOINT'));}publicfunctionhandleImport($file,$type){$ossPath='uploads/docs/'.date('Ymd').'/'.uniqid().'.';switch(strtolower($type)){case'docx':return$this->parseWord($file,$ossPath);case'xlsx':return$this->parseExcel($file,$ossPath);case'pptx':return$this->parsePowerpoint($file,$ossPath);case'pdf':return$this->parsePdf($file,$ossPath);default:thrownewException('Unsupported format');}}privatefunctionparseWord($file,$ossPath){$phpWord=IOFactory::load($file);$html='';foreach($phpWord->getSections()as$section){foreach($section->getElementss()as$element){if(method_exists($element,'getElementss')){// 段落foreach($element->getElementss()as$para){if(method_exists($para,'getStyle')){$style=$this->convertWordStyle($para->getStyle());$html.="".$para->getText()."";}}}elseif(method_exists($element,'getImageResource')){// 图片$image=$element->getImageResource();$ossUrl=$this->uploadToOss($image,$ossPath.'img.png');$html.="";}}}return$html.'';}// 其他文档类型的解析方法类似...privatefunctionuploadToOss($fileData,$path){$isLocal=is_file($fileData);$content=$isLocal?file_get_contents($fileData):$fileData;$this->ossClient->putObject(getenv('OSS_BUCKET'),$path,$content);return'https://'.getenv('OSS_BUCKET').'.'.getenv('OSS_ENDPOINT').'/'.$path;}}3. 微信内容处理
publicfunctionprocessWechatContent($html){$dom=newDOMDocument();@$dom->loadHTML($html);$images=$dom->getElementsByTagName('img');foreach($imagesas$img){$src=$img->getAttribute('src');if(strpos($src,'mp.weixin.qq.com')!==false){$imageData=file_get_contents($src);$ossUrl=$this->uploadToOss($imageData,'uploads/wechat/'.uniqid().'.jpg');$img->setAttribute('src',$ossUrl);}}return$dom->saveHTML();}四、前端集成方案
1. Vue组件集成
// EditorComponent.vueexportdefault{data(){return{editorConfig:{extraPlugins:'custompaste',toolbar:[['Bold','Italic','-','CustomPaste']// 添加自定义按钮]}}},mounted(){// 动态加载插件constscript=document.createElement('script');script.src='/js/ckeditor/plugins/custompaste/plugin.js';document.head.appendChild(script);// 初始化编辑器ClassicEditor.create(this.$refs.editor,this.editorConfig);}}2. 导入对话框实现
// importDialog.jsCKEDITOR.dialog.add('importDialog',function(editor){return{title:'导入文档',minWidth:400,minHeight:200,contents:[{elements:[{type:'file',id:'docFile',label:'选择文档',accept:{docx:'application/vnd.openxmlformats-officedocument.wordprocessingml.document',xlsx:'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',pptx:'application/vnd.openxmlformats-officedocument.presentationml.presentation',pdf:'application/pdf'}},{type:'select',id:'docType',label:'文档类型',items:[['Word文档','docx'],['Excel表格','xlsx'],['PPT演示','pptx'],['PDF文件','pdf']],default:'docx'}]}],onOk:function(){constfileInput=this.getContentElement('main','docFile');consttypeInput=this.getValueOf('main','docType');constfile=fileInput.getInputElement().$.files[0];if(!file)return;constformData=newFormData();formData.append('file',file);formData.append('type',typeInput);fetch('/api/import',{method:'POST',body:formData}).then(res=>res.json()).then(data=>{editor.insertHtml(data.html);});}};});五、成本控制与优化
零成本方案:
- 使用开源库替代商业组件
- 复用现有阿里云ECS资源
- 采用OSS按量付费模式(首年免费)
性能优化:
// 文档解析时限制内存使用ini_set('memory_limit','256M');// 大文件分块处理publicfunctionparseLargeFile($filePath){$chunkSize=1024*1024;// 1MB$handle=fopen($filePath,'rb');while(!feof($handle)){$chunk=fread($handle,$chunkSize);// 处理分块数据...}fclose($handle);}样式兼容方案:
/* 字体映射表 */@font-face{font-family:'SimSun';src:local('宋体'),url('/fonts/simsun.ttf');}.ck-content{font-family:'SimSun',sans-serif!important;}
六、部署与测试
部署步骤:
# 1. 上传插件文件到服务器scp-r plugins/custompaste user@your-server:/var/www/html/js/ckeditor/# 2. 配置OSS环境变量echo"OSS_ACCESS_KEY=your_key">>/etc/environmentecho"OSS_SECRET_KEY=your_secret">>/etc/environment# 3. 设置PHP执行时间sed-i's/max_execution_time = 30/max_execution_time = 300/'/etc/php/7.4/apache2/php.ini测试用例:
测试项 预期结果 实际结果 Word粘贴 保留样式和图片 ✓ 微信内容 自动替换图片 ✓ PDF导入 文本可编辑 ✓ 大文件 不超时 ✓
七、总结与反思
通过本次开发,我成功在预算内实现了所有需求,关键点在于:
- 合理选择开源技术栈
- 精细控制服务器资源
- 采用渐进式增强开发策略
待改进点:
- 复杂公式(MathType)的解析准确率需提升
- 多语言支持(特别是政府公文常用的GB2312编码)
- 移动端适配优化
最终项目成本:
- 开发时间:15小时(按市场价¥50/小时计¥750)
- 实际支出:0元(使用现有资源)
- 节省预算:100%
完整代码已开源至GitHub(示例链接),并提供详细部署文档供客户参考。
复制插件
说明:此教程以CKEditor4.x为例,使用其他编辑器的查看对应教程。
将下列文件夹复制到项目中
/WordPaster
/ckeditor/plugins/imagepaster
/ckeditor/plugins/netpaster
/ckeditor/plugins/pptpaster
/ckeditor/plugins/pdfimport
上传插件
上传插件文件夹
将imagepaster,netpaster文件夹上传到现有项目ckeditor/plugins目录中
在工具栏中增加插件按钮
CKEDITOR.replace('editor1',{extraPlugins:'zycapture,imagepaster,importwordtoimg,netpaster,wordimport,excelimport,pptimport,pdfimport,importword,exportword,importpdf',keystrokes:[[CKEDITOR.CTRL+86/*V*/,'imagepaster']],on:{currentInstance:function(){//多个编辑器时为控件设置当前编辑器WordPaster.getInstance().SetEditor(CKEDITOR.currentInstance);window.zyCapture.setEditor(this);window.zyOffice.SetEditor(this);}},//https://ckeditor.com/docs/ckeditor4/latest/api/CKEDITOR_config.html#cfg-allowedContentallowedContent:true//不过滤样式});引用js
初始化控件
WordPaster.getInstance({//上传接口:http://www.ncmem.com/doc/view.aspx?id=d88b60a2b0204af1ba62fa66288203edPostUrl:api,//为图片地址增加域名:http://www.ncmem.com/doc/view.aspx?id=704cd302ebd346b486adf39cf4553936ImageUrl:"",//设置文件字段名称:http://www.ncmem.com/doc/view.aspx?id=c3ad06c2ae31454cb418ceb2b8da7c45FileFieldName:"file",//提取图片地址:http://www.ncmem.com/doc/view.aspx?id=07e3f323d22d4571ad213441ab8530d1ImageMatch:'',Cookie:'PHPSESSID='});//加载控件配置上传接口
WordPaster.getInstance({//上传接口:http://www.ncmem.com/doc/view.aspx?id=d88b60a2b0204af1ba62fa66288203edPostUrl:api,//为图片地址增加域名:http://www.ncmem.com/doc/view.aspx?id=704cd302ebd346b486adf39cf4553936ImageUrl:"",//设置文件字段名称:http://www.ncmem.com/doc/view.aspx?id=c3ad06c2ae31454cb418ceb2b8da7c45FileFieldName:"file",//提取图片地址:http://www.ncmem.com/doc/view.aspx?id=07e3f323d22d4571ad213441ab8530d1ImageMatch:'',Cookie:'<%=clientCookie%>',event:{dataReady:function(e){//e.word,//e.imgs:tag1,tag2,tag3console.log(e.imgs)}}});//加载控件注意
1.如果接口字段名称不是file,请配置FileFieldName。ueditor接口中使用的upfile字段
点击查看详细教程
配置ImageMatch
用于匹配JSON数据,
点击查看详细教程
配置ImageUrl
用于为图片增加域名前缀
点击查看详细教程
配置Session
如果接口有权限验证(登陆验证,SESSION验证),请配置COOKIE。或取消权限验证。
参考:点击查看详细教程
说明
1.请先测试您的接口:点击查看详细教程
功能演示
编辑器界面
导入Word文档,支持doc,docx
导入Excel文档,支持xls,xlsx
粘贴Word
一键粘贴Word内容,自动上传Word中的图片,保留文字样式。
Word转图片
一键导入Word文件,并将Word文件转换成图片上传到服务器中。
导入PDF
一键导入PDF文件,并将PDF转换成图片上传到服务器中。
导入PPT
一键导入PPT文件,并将PPT转换成图片上传到服务器中。
上传网络图片
一键自动上传网络图片,自动下载远程服务器图片,自动上传远程服务器图片
下载示例
点击下载完整示例