2012年6月14日 星期四

CKEditor上整合CKFinder (使用ASP.NET VB語言)

FCKediotr 從改版並重新命名為 CKEditor 後,原本在文字編輯器上插入本地圖片的功能被拿掉了
image

現在要使用本地上傳的話,需要使用額外的插件 CKFinder,上下圖比較一下,使用後「瀏覽伺服器」「上傳」二個功能才可以打開
image

底下就紀錄一下怎麼實現這個功能,實作的內容
在VISUAL STUDIO 2010 裡,整合 CKEditor.NET 3.6.2 與 CKFinder 2.2.1 (建置的web 平台是vb語言)


STEP 1  下載及安裝

下載及安裝 CKEditor.NET 3.6.2 的方式,dnowba 在前二篇文章提過了就不贅述
ASP.NET 上使用免費的文字編輯器CKEditor
在ASP.NET (使用VB語言) 修改 CKEdtior

下載及安裝 CKFinder 2.2.1:
到官網下載檔案:http://ckfinder.com/download ,記得要下的是asp.net的專屬版本image

下載後,將整個資料夾解壓縮到網站的根目錄下,如下圖,特別注意,如果不想要自已修改一些路徑的話,ckeditor 和 ckfinder 二個資料夾建議放在同一層級裡。目錄下的「_sample」是範本可以刪除,「_source」是源始碼,如果不需要重新編譯的話,那麼刪除也沒關係。
image

再來就是引用參照檔:加入成為控制項的方法除了「在visual studio裡的工具箱右鍵選擇項目」外,「直接把ckfinder.bin 拖曳到工具箱」也可行。
image


step 2 設置上傳目錄

這個是最煩人的地方了,在不同的程式語言裡表達路徑的方式本來就不一樣,而路徑又分成絕對和相對路徑,很多安裝出現錯誤訊息大部分都是沒有指對路徑所導致,CKFinder預設上傳的目錄是使用"/ckfinder/userfiles/"目錄,如果要修改的話,修改 ckfinder/config.ascx 檔案,如以下程式碼,如果我們設置了一個名為xexe的網站,那麼路徑設置最好是完整一些,路徑的後頭別忘了加"/"表示在此目錄下放置。

// The base URL used to reach files in CKFinder through the browser.
 // 上傳資料放置的網路路徑
BaseUrl = "~/ckfinder/userfiles/";
// The phisical directory in the server where the file will end up. If
// blank, CKFinder attempts to resolve BaseUrl.
// 上傳資料放置的實體路徑,如果空白不填,那麼系統會嘗試反解網路路徑以取得實體路徑。
BaseDir = "C:/inetpub/wwwroot/xexe/ckfinder/userfiles/";


step 3 設置安全性

如下圖,設置好安全性的話,權限不足的人無法使用上傳功能,可以避免被不肖人士侵入網站,步驟有二:
image

1. 檢查上載目錄權限,必須有寫入的權限。如下圖,在ckfinder 資料夾下(或者是自行設一個供上傳的資料夾) 設定安全性,給IUSR_<ServerName>角色寫入(完全控制) 的權限。提醒,不要在整個網站目錄上開可寫的權限,除了上傳目錄是寫入外,上層的目錄只要能讀取能列表就好了;另外,也請不要開一個使用者everyone 然後給個完全控制,這樣不需要通過瀏覽器就可以輕易到你的網站故作非為了。
image

2、修改 ckfinder/config.ascx 檔案,如下,把第15行的註解拿掉就可以了,程式碼
return ( Session[ "IsAuthorized" ] != null && (bool)Session[ "IsAuthorized" ] == true ); 意思就是用session值來判斷使用者的權限。

public override bool CheckAuthentication()
	{
		// WARNING : DO NOT simply return "true". By doing so, you are allowing
		// "anyone" to upload and list the files in your server. You must implement
		// some kind of session validation here. Even something very simple as...   
		//
		//		return ( Session[ "IsAuthorized" ] != null && (bool)Session[ "IsAuthorized" ] == true );
		//
		// ... where Session[ "IsAuthorized" ] is set to "true" as soon as the
		// user logs on your system.

		 //return false;
        return (Session["IsAuthorized"] != null && (bool)Session["IsAuthorized"] == true);
        //return true;
	}

我們在放置ckfinder的網頁,load事件裡加個驗證的方法,例如「如果帳號密碼正確的話,session(“IsAuthorized”)就設定為true,就可以達到一定的安全程度了,建議千萬不要把上面的參數設成 return true,這樣就是「來者不拒」了,也別像下面那樣在頁面上「門戶洞開」。
image

3. 最好的方法其實跳出錯誤訊息還是不妥,個人認為沒有權限的話,應該連頁面都不給他看到,直接讓網頁重新導向redirect到另一個畫面,或是把ckfinder這個控件給visible,不過後來想想,如果是整合到ckedtior裡,那麼有可能我們會有讓使用者只可以寫文章貼連結圖床的位置,而不能把圖片存在server裡。


step 4 把ckfinder 整合到 ckeditor 裡

方法有二種,擇一使用:
1、修改 ckediotr/config.js
在CKEDITOR.editorConfig = function (config)  底下加入行2~行7的程式碼,這樣就可以啟用ckeditor的filebrowser檔案瀏覽的按鈕,connector.aspx 和 ckfinder.html  都是ckfinder 解譯的重要編碼,所以導向路徑要和你安裝ckfinder的路徑一致。

CKEDITOR.editorConfig = function (config) {
    config.filebrowserBrowseUrl = 'ckfinder/ckfinder.html';
    config.filebrowserImageBrowseUrl = 'ckfinder/ckfinder.html?Type=Images';
    config.filebrowserFlashBrowseUrl = 'ckfinder/ckfinder.html?Type=Flash';
    config.filebrowserUploadUrl = 'ckfinder/core/connector/aspx/connector.aspx?command=QuickUpload&type=Files';
    config.filebrowserImageUploadUrl = 'ckfinder/core/connector/aspx/connector.aspx?command=QuickUpload&type=Images';
    config.filebrowserFlashUploadUrl = 'ckfinder/core/connector/aspx/connector.aspx?command=QuickUpload&type=Flash';
};

第1種方式適合全域性的調用,意思就是網站上所有使用ckeditor的都會啟用ckfinder ,都可以透過文字編輯器的插入圖片功能「間接」使用檔案上傳。

2、在頁面程式碼onload的階段載入啟用,一樣注意路徑問題

Protected Overrides Sub OnLoad(e As EventArgs)
          Dim _FileBrowser As New CKFinder.FileBrowser
        _FileBrowser.BasePath = "ckfinder/"
        _FileBrowser.SetupCKEditor(CKEditorControl1)
    End Sub

第2種方式適合用在「某頁面的CKEDITOR開放檔案上傳功能,另一個有ckeditor 頁面就不需要。」這個時候在頁面上寫上段程式碼。

個人認為第二種比較適當。


可能出現的錯誤及解決方法:

1. 在使用檔案上傳的功能時,出現「無法載入型別:'CKFinder.Connector.Connector'」的錯誤,錯誤圖片及訊息如下:
image

Server Error in '/' Application.
Parser Error
Description: An error occurred during the parsing of a resource required to service this request. Please review the following specific parse error details and modify your source file appropriately. 

Parser Error Message: Could not load type 'CKFinder.Connector.Connector'.

Source Error: 


Line 1: <%@ Page Language="c#" Inherits="CKFinder.Connector.Connector" Trace="false" AutoEventWireup="false" %> Line 2: <%@ Register Src="../../../config.ascx" TagName="Config" TagPrefix="CKFinder" %>
Line 3: <%--

Source File: /ckfinder/core/connector/aspx/connector.aspx Line: 1 

Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.237

解決方式:

(1)一開始我以為是 framework 版本的問題,以前曾經有過經驗是VISUAL STUDIO 2005開發的網站/專案 (是framework 2.0)要移到VISUAL STUDIO 2010 (預設是framework 4.0執行)。不過後來從以下幾點澄清了這個誤解:
查了一下 CKFinder 官網並沒有特別提到CKFinder 是用什麼framework環境開發,再檢查一下開放源始碼裡雖使用到framework裡的函數(就是用using來取得一些framework已經定義好的命名空間),但並沒有錯誤(在開發環境下debug一下就知道了)
後來證實了一下,在IIS裡把應用程式集區改為原來的defaultAppPool。網站裡web.config也改了編譯方式,結果還是一樣。
image

(2) 再來就把錯誤訊息給po到google上,看看是不是有解決的solution,大部分的訊息都是說沒有引用 ckfinder.dll 導致找不到 'CKFinder.Connector.Connector' ,這個自然不用求證,有放就是有放,再重放一次結果也一樣,除非官方發出來的bin檔是有問題的(那麼應該這麼專業的coding應該會很快釋出修正,這個版本發出也3個多月了)。尤其像這種已經包起來的bin檔我們也沒法子自行修改,dnowba有試著把「_resorce資料夾」的資料「ckfinder\_source\CKFinder.Net.csproj」重新編譯,還是沒結果。

(3) 一開始測試的時候,我都是在client 端測試 (這種檔案需要上傳到server的,我通常都直接找台client來試,比較不會出錯),因為前面我想到編譯的問題,所以想會不會改了一些檔案後,還需要重新編譯一次,就是重新啟動一次IIS (突發奇想,到了這邊完全沒理論的亂試了),索性就重新啟動IIS,然後在SERVER端開了個簡易的IIS PORT來測試,沒想到在client端執行不了的程式,在server竟然跑起來了…
這個地方我先想到的是「防火牆」的問題,會不會ckfinder 要配合一些特定的port才能上傳檔案,這個想法雖然白痴但是我還是試了…邊試邊想自已真的白痴,如果port鎖住了那麼出現的錯誤「HTTP 404 - 找不到檔案」之類的訊息吧,沒道理看得到網頁。
好了,我還是看看家裡分享器中虛擬伺服器的狀況,再把windows server 和clinet端的軟體防火牆全給關了…結論就是還是白忙一場。

(4) 最後…最後…我終於解決了,這個解決方式真的是始料未及啊,下圖裡,我把我的web站台整個設成應用程式(因為我整個網頁都是用互動式寫的,全都要runat server),然後我在使用ckfinder的時候,也很直覺的把ckfinder這個資料夾轉換成應用程式了,就是這個「多此一舉」,讓我折騰了二天…
image

唉…iis的錯誤訊息真的是很妙,「無法載入型別」和「多此一舉」到底有什麼關係。

2.在瀏覽器上chrome 可能會看不到上傳的頁面:


為ckfinder 加入plugin 插件

插件的功能是官方開發ckfinder時關注的重點之一,官方的想法是希望透過開源的方式,加入更多的第三方開發者來豐富ckfinder的功能,所以利用插件的方式,每個插件的編譯碼各自獨立,只要在ckfinder的地方導入編譯碼路徑就能實現,官方提供了三個範例供參考,在下載ckfinder裡面的plugins資料夾裡,這三個功能都還不錯,dnowba 學藝不精,javascript 只看得懂幾個字的程度談不上開發,這裡就只是介紹一下這三個還不賴的範例,最後告訴大家怎麼「啟用」

1、第一個範例插件:這個plugin 名為「fileeditor」,針對某些文件 (例如txt、html、js、php ),可以進行「在線編輯」

如果上傳的文件符合要求的格式時,在檔案上右鍵選單,上頭就會多一個「edit」的選項。
 image

選擇edit時,就會出現編輯視窗
官方是說會有「程式碼高亮顯示」的功能,我目前測試的xml檔沒看到,看來只限於html, .js, .php 這三個檔案。
image

底下就是上傳html,編輯時就有高亮顯示,下圖另外又反應了文字編碼的問題…
image

2、 第二個範例插件:這個plugin 名為「imageresize」,功能是可以設定圖片大小,一般來說這種功能是有上傳圖片還沒到伺服端前,這個「imageresize」則是針對已上傳的圖片(已經在server端)

如下圖,如果是圖片格式的檔案,在圖上右鍵會看到「resize」的選項
image

點選後resize的選項可以有幾種small、mediun、large三種固定格式,若都不合意就自訂長寬。
image

重設大小後,系統是用另存新檔的方式,不是直接覆蓋。
image

3、第三個範例插件:這個plugin 名為「watermark」,就是為上傳的圖片檔案自動加上一個浮水印。

如下圖右下角的地方,浮水印的圖是直接嵌在圖片上,不是另存一份有浮水印的圖檔
image

上面這三個功能可以說是在server端裡實現的,雖然我不知道是不是真的 ( 嗯,如果client 的使用者有權限去使用server端裡的這些資源,那會不會有有心人士利用這個來攻擊server服務器。比方說上傳圖片後一直用機器人程式「resize」,加重server的負擔來達到癱瘓主機的目的。)  好的,話雖如此,我還是要說明一下怎麼「啟用」這幾個附加功能。

ckfinder/config.ascx 裡頭,加入以下程式碼

		// Optional: enable extra plugins (remember to copy .dll files first).
        // 啟用三個附加的功能:FileEditor
		Plugins = new string[] {
			 "CKFinder.Plugins.FileEditor, CKFinder_FileEditor",
			 "CKFinder.Plugins.ImageResize, CKFinder_ImageResize",
			 "CKFinder.Plugins.Watermark, CKFinder_Watermark"
		};
		// Settings for extra plugins.
        //// 下面是設定調整圖片大小ImageResize plugin的參數,設定三種定制大小的長、寬
		PluginSettings = new Hashtable();
		PluginSettings.Add("ImageResize_smallThumb", "90x90" );
		PluginSettings.Add("ImageResize_mediumThumb", "120x120" );
		PluginSettings.Add("ImageResize_largeThumb", "180x180" );
		// Name of the watermark image in plugins/watermark folder
        // 下面是設定浮水印Watermark plugin的參數,包含浮水印圖片名稱、靠右間距、靠下間距、浮水印品質、透明度)
		PluginSettings.Add("Watermark_source", "logo.gif" );
		PluginSettings.Add("Watermark_marginRight", "5" );
		PluginSettings.Add("Watermark_marginBottom", "5" );
		PluginSettings.Add("Watermark_quality", "90" );
		PluginSettings.Add("Watermark_transparency", "80" );

接下來把函式庫給加到bin資料夾去,三個插件各自有各自的bin檔,路徑位置不多說,看圖對照吧。
image


其他功能的調整設定

CKFinder 除了搭配 CKEditor 使用外,其實也可以獨立當作檔案管理的介面,官方也有包成一個控制項來使用,頁面上要使用的話,就是直接把這個控件拉到頁面上就可以了。所以可以整個當作web界面的檔案總管,功能算是措措有餘了。像下圖dnowba就故意把文字編輯器和ckfinder的界面分別開來。在插入圖片時其實就可以先參照位置。image

ckfinder的主要設定參數都放在ckfinder/config.ascx 檔案
官方在這個參數設定檔案已經有很貼心的加註設定要點了,這裡dnowba 照著順序,把官方的說明給中文化,略解釋註解在程式碼中:

		// Thumbnail settings.
        //預覽縮圖功能設定
		// "Url" is used to reach the thumbnails with the browser, while "Dir"
		// points to the physical location of the thumbnail files in the server.
		Thumbnails.Url = BaseUrl + "_thumbs/";
		if ( BaseDir != "" ) {
			Thumbnails.Dir = BaseDir + "_thumbs/";
		}
		Thumbnails.Enabled = true;
		Thumbnails.DirectAccess = false;
		Thumbnails.MaxWidth = 100;
		Thumbnails.MaxHeight = 100;
		Thumbnails.Quality = 80;

		// Set the maximum size of uploaded images. If an uploaded image is
		// larger, it gets scaled down proportionally. Set to 0 to disable this
		// feature.
        //設定上傳圖片檔案的最大值,如果上傳圖檔太大的話也會自動降級,如果不需要限制大小的話,就設定為0
		Images.MaxWidth = 1600;
		Images.MaxHeight = 1200;
		Images.Quality = 80;

		// Indicates that the file size (MaxSize) for images must be checked only
		// after scaling them. Otherwise, it is checked right after uploading.
        // 在上傳圖檔前是否檢查圖片大小
		CheckSizeAfterScaling = true;

		// Increases the security on an IIS web server.
		// If enabled, CKFinder will disallow creating folders and uploading files whose names contain characters
		// that are not safe under an IIS 6.0 web server.
        // 增加IIS的安全性,禁止上傳的檔案、資料夾命名含有特定符號
		DisallowUnsafeCharacters = true;

		// Due to security issues with Apache modules, it is recommended to leave the
		// following setting enabled. It can be safely disabled on IIS.
        // 這個和APACHE有關,如果是使用IIS架站的話就不用理他
		ForceSingleExtension = true;

		// For security, HTML is allowed in the first Kb of data for files having the
		// following extensions only.
        // 允許 HTML 上可直讀的文件檔案名 (而且可以用現有的IIS 解譯)
		HtmlExtensions = new string[] { "html", "htm", "xml", "js" };

		// Folders to not display in CKFinder, no matter their location. No
		// paths are accepted, only the folder name.
		// The * and ? wildcards are accepted.
        // 也是安全性的設定,不懂就用預設的吧
		HideFolders = new string[] { ".svn", "CVS" };

		// Files to not display in CKFinder, no matter their location. No
		// paths are accepted, only the file name, including extension.
		// The * and ? wildcards are accepted.
        // 也是安全性的設定,不懂就用預設的吧
		HideFiles = new string[] { ".*" };

		// Perform additional checks for image files.
		SecureImageUploads = true;

		// The session variable name that CKFinder must use to retrieve the
		// "role" of the current user. The "role" is optional and can be used
		// in the "AccessControl" settings (bellow in this file).
        //設置使用者權限,可將使用者分成若干群組來分別控制他們的使用權限。
        // session名稱如下
		RoleSessionVar = "CKFinder_UserRole";

		// ACL (Access Control) settings. Used to restrict access or features
		// to specific folders.
		// Several "AccessControl.Add()" calls can be made, which return a
		// single ACL setting object to be configured. All properties settings
		// are optional in that object.
		// Subfolders inherit their default settings from their parents' definitions.
		//
		//	- The "Role" property accepts the special "*" value, which means
		//	  "everybody".
		//	- The "ResourceType" attribute accepts the special value "*", which
		//	  means "all resource types".
		AccessControl acl = AccessControl.Add();
		acl.Role = "*";
		acl.ResourceType = "*";
		acl.Folder = "/";

		acl.FolderView = true;
		acl.FolderCreate = true;
		acl.FolderRename = true;
		acl.FolderDelete = true;

		acl.FileView = true;
		acl.FileUpload = true;
		acl.FileRename = true;
		acl.FileDelete = true;

		// Resource Type settings.
		// A resource type is nothing more than a way to group files under
		// different paths, each one having different configuration settings.
		// Each resource type name must be unique.
		// When loading CKFinder, the "type" querystring parameter can be used
		// to display a specific type only. If "type" is omitted in the URL,
		// the "DefaultResourceTypes" settings is used (may contain the
		// resource type names separated by a comma). If left empty, all types
		// are loaded.
        // 設置可上傳檔案的檔案類型,分為Files、Images、Flash三資料夾,各自設定可以上傳的格式
        // 名稱需注意大小寫,例如若設定可上傳DOC,那格式為doc的檔案將不可以上傳

		DefaultResourceTypes = "";

		ResourceType type;

		type = ResourceType.Add( "Files" );
		type.Url = BaseUrl + "files/";
		type.Dir = BaseDir == "" ? "" : BaseDir + "files/";
		type.MaxSize = 0;
		type.AllowedExtensions = new string[] { "7z", "aiff", "asf", "avi", "bmp", "csv", "doc", "docx", "fla", "flv", "gif", "gz", "gzip", "jpeg", "jpg", "mid", "mov", "mp3", "mp4", "mpc", "mpeg", "mpg", "ods", "odt", "pdf", "png", "ppt", "pptx", "pxd", "qt", "ram", "rar", "rm", "rmi", "rmvb", "rtf", "sdc", "sitd", "swf", "sxc", "sxw", "tar", "tgz", "tif", "tiff", "txt", "vsd", "wav", "wma", "wmv", "xls", "xlsx", "zip","html","htm" };
		type.DeniedExtensions = new string[] { };

		type = ResourceType.Add( "Images" );
		type.Url = BaseUrl + "images/";
		type.Dir = BaseDir == "" ? "" : BaseDir + "images/";
		type.MaxSize = 0;
		type.AllowedExtensions = new string[] { "bmp", "gif", "jpeg", "jpg", "png" };
		type.DeniedExtensions = new string[] { };

		type = ResourceType.Add( "Flash" );
		type.Url = BaseUrl + "flash/";
		type.Dir = BaseDir == "" ? "" : BaseDir + "flash/";
		type.MaxSize = 0;
		type.AllowedExtensions = new string[] { "swf", "flv" };
		type.DeniedExtensions = new string[] { };
	}

最後再提醒大家,CKFinder、CKEditor 有分多個應用版本,本篇是asp.net的應用,如果你使用不同版本,還是請參考原廠的說明為主。

沒有留言:

張貼留言

Related Posts Plugin for WordPress, Blogger...
// Dnow Function