Yii 官方擴充庫的 KindEditor 版本較舊,本文提供一套完整可用的自訂擴充包,包含主 Widget(KEditor)、檔案管理 Action(KEditorManage)、上傳處理 Action(KEditorUpload),支援圖片/影音/檔案上傳、伺服器瀏覽、自訂工具欄、字數統計等功能。
protected/extensions/KEditor/
├── KEditor.php # 主 Widget(繼承 CWidget)
├── KEditorManage.php # 檔案管理 Action(繼承 CAction)
├── KEditorUpload.php # 上傳處理 Action(繼承 CAction)
└── keSource/ # KindEditor 4.x 源碼
├── kindeditor.js
├── kindeditor-min.js
├── themes/default/default.css
├── plugins/
└── lang/zh_TW.js
class KEditor extends CWidget {
public $model;
public $name;
public $properties = array(); // KindEditor 配置
public $textareaOptions = array(); // textarea 屬性
private $_baseUrl;
public function init() {
if ($this->name === null) throw new CException('name 屬性必填');
$this->_baseUrl = Yii::app()->assetManager->publish(dirname(__FILE__).'/keSource');
$cs = Yii::app()->clientScript;
$cs->registerCssFile($this->_baseUrl.'/themes/default/default.css');
$cs->registerScriptFile($this->_baseUrl.'/'.(YII_DEBUG?'kindeditor.js':'kindeditor-min.js'));
}
public function run() {
$options = $this->getKeProperties(); // 過濾允許的配置鍵
$js = "KindEditor.ready(function(K) {
var editor_{$this->id} = K.create('#{$this->id}', " . CJavaScript::encode($options) . ");
});";
Yii::app()->clientScript->registerScript('KE_'.$this->name, $js, CClientScript::POS_HEAD);
$taOptions = $this->getTextareaOptions();
$taOptions['name'] = CHtml::resolveName($this->model, $this->name);
$this->id = $taOptions['id'] = CHtml::getIdByName($taOptions['name']);
echo CHtml::activeTextArea($this->model, $this->name, $taOptions);
}
// 靜態方法:取得上傳路徑/URL(支援參數覆蓋)
public static function getUploadPath() {
if (isset(Yii::app()->params['uploadPath'])) {
return Yii::getPathOfAlias('webroot') . str_replace('/', DIRECTORY_SEPARATOR, Yii::app()->params['uploadPath']);
}
return Yii::app()->assetManager->getPublishedPath(dirname(__FILE__).'/keSource') . '/upload';
}
public static function getUploadUrl() {
if (isset(Yii::app()->params['uploadPath'])) {
return Yii::app()->baseUrl . Yii::app()->params['uploadPath'];
}
return Yii::app()->assetManager->publish(dirname(__FILE__).'/keSource') . '/upload';
}
// ... getKeProperties(), getTextareaOptions() 過濾白名單鍵值
}
class KEditorUpload extends CAction {
public function run() {
$dir = isset($_GET['dir']) ? $_GET['dir'] : 'file';
$extMap = array(
'image' => array('gif','jpg','jpeg','png','bmp'),
'flash' => array('swf','flv'),
'media' => array('swf','flv','mp3','wav','wma','wmv','mid','avi','mpg','asf','rm','rmvb'),
'file' => array('doc','docx','xls','xlsx','ppt','htm','html','txt','zip','rar','gz','bz2'),
);
if (!isset($extMap[$dir])) {
echo CJSON::encode(array('error'=>1,'message'=>'目錄錯誤'));
return;
}
$file = CUploadedFile::getInstanceByName('imgFile');
if ($file) {
$ext = strtolower($file->extensionName);
if (!in_array($ext, $extMap[$dir])) {
echo CJSON::encode(array('error'=>1,'message'=>'副檔名不允許:'.implode(',',$extMap[$dir])));
return;
}
$dateDir = date('Ymd');
$savePath = KEditor::getUploadPath() . "/$dir/$dateDir";
if (!is_dir($savePath)) mkdir($savePath, 0777, true);
$fileName = date('His') . '_' . rand(10000,99999) . ".$ext";
$file->saveAs("$savePath/$fileName");
echo CJSON::encode(array('error'=>0,'url'=>KEditor::getUploadUrl()."/$dir/$dateDir/$fileName"));
} else {
echo CJSON::encode(array('error'=>1,'message'=>'未收到檔案'));
}
}
}
掃描上傳目錄,回傳 KindEditor 要求的 JSON 結構(含 moveup_dir_path、current_dir_path、file_list 等),支援分類瀏覽、排序、縮圖預覽。(程式碼較長,核心邏輯:DirectoryIterator 掃描 → 過濾副檔名 → 組裝 JSON → CJSON::encode 輸出)。
'params' => array(
'adminEmail' => 'webmaster@example.com',
'uploadPath' => '/uploads', // 實體路徑:/var/www/app/uploads
),
class DefaultController extends Controller {
public function actions() {
return array(
'upload' => 'application.extensions.KEditor.KEditorUpload',
'manageJson' => 'application.extensions.KEditor.KEditorManage',
);
}
}
widget('ext.KEditor.KEditor', array(
'model' => $model,
'name' => 'content',
'properties' => array(
'uploadJson' => '/admin/default/upload',
'fileManagerJson' => '/admin/default/manageJson',
'allowFileManager' => true,
'newlineTag' => 'br',
'width' => '100%',
'height' => '400px',
'resizeType' => 1,
'items' => array(
'source', '|', 'undo', 'redo', '|', 'preview', 'print', '|',
'cut', 'copy', 'paste', 'plainpaste', 'wordpaste', '|',
'justifyleft', 'justifycenter', 'justifyright', 'justifyfull', '|',
'insertorderedlist', 'insertunorderedlist', 'indent', 'outdent', '|',
'formatblock', 'fontname', 'fontsize', '|',
'forecolor', 'hilitecolor', 'bold', 'italic', 'underline', 'strikethrough', '|',
'image', 'flash', 'media', 'table', 'hr', 'emoticons', 'link', 'unlink', '|',
'fullscreen', 'about'
),
'afterCreate' => 'js:function() { updateCount(this); }',
'afterChange' => 'js:function() { updateCount(this); }',
),
'textareaOptions' => array('style' => 'width:100%;height:400px;'),
)); ?>
| KindEditor 原生參數 | Widget properties 鍵 | 說明 |
|---|---|---|
| uploadJson | uploadJson | 上傳端點 URL |
| fileManagerJson | fileManagerJson | 檔案管理端點 URL |
| allowFileManager | allowFileManager | 啟用檔案管理按鈕 |
| afterCreate | afterCreate | 初始化完成回調,JS 代碼需加 js: 前綴 |
| items | items | 工具欄按鈕陣列 |
| resizeType | resizeType | 0=不調整, 1=縱向, 2=雙向 |
這套 KEditor 擴充包將 KindEditor 完整封裝為 Yii Widget,實現零侵入式整合:視圖一行調用、配置陣列化、上傳管理 Action 化。建議專案直接複製 extensions/KEditor/ 目錄,根據業務調整 items 工具欄與 extMap 副檔名白名單即可投入生產使用。