最近項目中需要用到在線編輯Office文檔。最后找來找去發現有個免費的控件“點聚WebOffice”。經過兩天的測試發現還不錯。雖然里面也有些不完善的地方。先說一下不足吧,想用的同學可以斟酌。
1、在Widnows 7 x64下運行不穩定,經常會導致ie瀏覽器崩潰。
2、打開的本地文件不能是2007新格式的文檔,如:docx/xlsx。如果打開一個docx的文檔,然后保存到服務器端時會發現沒有任何數據(使用PHP時,查看$_FILES)。
3、客戶端安裝的即便是Office2010,通過控件新建一個文檔,然后保存到服務器端時,格式還是2003以前的文檔格式。即后綴還是使用doc/xls。
4、客戶端安裝的Office最好是完整版的,不要安裝精簡版的。會導致打不開應用程序(官方的QQ群里有些同學提出的此bug)。
5、控件不支持https。
下面是我使用PHP時的demo,此demo是根據官方提供的asp版來修改的,僅做了項目中用到的一部分,如:新建與編輯文檔。
1、首先看一下目錄結構:
在站點的根目錄下weboffice_v6.0.5.0.cab是必須的,這樣的話,當客戶端沒有安裝控件時,我們就可以直接通過讓瀏覽器下載此文件來安裝。
2、開始編寫demo.php頁面,此頁面有3個按鈕:新建Word文檔、新建Excel文檔、刷新服務器端文件列表。
刷新服務器端文件列表按鈕的作用是獲取我們保存的文檔列表,即uploadfiles目錄下面的所有的文檔。
當單擊新建時會通過一個隱藏的form表單來打開一個新的頁面(webOffice.php),通過GET方式傳遞fileType參數。fileType值為:doc或xls。
通過單擊服務器端文件列表右側的編輯按鈕道理相同,僅傳遞的參數有所不同。編輯文件時只需要傳遞fileName即可。

1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 5 <title>WebOffice Demo</title> 6 <script type="text/javascript"> 7 function editFile(path) { 8 var f = document.myForm; 9 f.action = 'webOffice.php?fileName=' + path; 10 f.target = '_blank'; 11 f.submit(); 12 } 13 14 function createFile(type) { 15 var f = document.myForm; 16 f.action = 'webOffice.php?fileType=' + type; 17 f.target = '_blank'; 18 f.submit(); 19 } 20 </script> 21 </head> 22 23 <body> 24 <form name="myForm" action="webOffice.php" method="post"> 25 <input type="hidden" id="fileName" name="fileName" /> 26 <input type="button" id="newDoc" name="newDoc" value="新建Word文檔" onclick="createFile('doc')" /> 27 <input type="button" id="newDoc" name="newDoc" value="新建Excel文檔" onclick="createFile('xls')" /> 28 </form> 29 <form action="?" method="post"> 30 <input type="submit" id="getFiles" name="getFiles" value="刷新服務器端文件列表" /> 31 </form> 32 <table border="1" width="400" cellspacing="0" cellpadding="0"> 33 <tr> 34 <th>文件名稱</th> 35 <th width=60>操作</th> 36 </tr> 37 <?php 38 if ($_POST['getFiles'] != '') { 39 $files = array(); 40 $path = dirname(__FILE__) . "/uploadfiles"; 41 42 if ($handle = opendir($path)) { 43 while (false !== ($file = readdir($handle))) { 44 $ext = substr($file, -3); 45 46 if ($ext == 'doc' || $ext == 'xls') { 47 // 如果服務器是Windows,文件名稱需要轉換成UTF-8 48 $files[] = $_ENV['OS'] == 'Windows_NT' ? iconv('GB18030', 'UTF-8//IGNORE', $file) : $file; 49 } 50 } 51 closedir($handle); 52 } 53 54 if (count($files) > 0) { 55 foreach ($files as $file) { 56 echo "<tr><td>$file</td><td><input type='button' value='編輯' onclick='editFile(\"" . $file . "\")' /></td>"; 57 } 58 } 59 } 60 ?> 61 </table> 62 </body> 63 </html>
3、編寫webOffice.php頁面。首先要嵌入webOffice控件,可以通過script標簽來插入,官方提供的這個js文件其實很簡單,就是輸出一個object標簽對象。在這里面需要注意的是控件的高度,最好不要使用100%而是使用一個固定的值,如果使用百分比,那么控件所屬的容器就要指定高度。
1 var s = "" 2 s += "<object id=WebOffice1 height=586 width='100%' style='LEFT: 0px; TOP: 0px' classid='clsid:E77E049B-23FC-4DB8-B756-60529A35FAD5' codebase=weboffice_v6.0.5.0.cab#Version=6,0,5,0>" 3 s +="<param name='_ExtentX' value='6350'><param name='_ExtentY' value='6350'>" 4 s +="</OBJECT>" 5 document.write(s)
嵌入控件之后要監聽控件的NotifyCtrlReady事件,官方提供的方式是使用script標簽的方式來監聽,而不是通過attachEvent的方式,標簽方式有一個優點即可以不必將代碼寫在嵌入控件之后,我們可以將其放在head部分。
1 <SCRIPT LANGUAGE=javascript FOR=WebOffice1 EVENT=NotifyCtrlReady> 2 <!-- 3 var fn = '<?php echo $fileName; ?>'; 4 5 if (fn) { 6 fn = './uploadfiles/' + fn; 7 } 8 9 // 在裝載完Weboffice(執行<object>...</object>)控件后執行 "WebOffice1_NotifyCtrlReady"方法 10 WebOffice1_NotifyCtrlReady(fn, "<?php echo $fileType; ?>"); 11 //--> 12 </SCRIPT>
這個事件也就是調用WebOffice1_NotifyCtrlReady函數,而這個函數的作用則是根據fileName來判斷是新建一個文檔還是打開一個文檔。
1 /** 2 * 控件初始化WebOffice方法 3 * @param {String} fileName 要打開的文件名稱 4 * @param {String} fileType 要打開的文件類型,doc/ 5 */ 6 function WebOffice1_NotifyCtrlReady(fileName, fileType) { 7 var office = document.all.WebOffice1; 8 if (fileName) { 9 office.LoadOriginalFile(fileName, fileType); 10 } else { 11 office.LoadOriginalFile("", fileType); 12 } 13 }
最后一步也就是如何保存到服務器端。要將文檔保存到服務器端需要分四步走。
第一步,初始化HTTP。office.HttpInit();
第二步,由於weboffice的提交數據跟平常的form表單的提交沒什么區別,因此我們可以在此進行附加一些其他的數據,如文件名。office.HttpAddPostString("fileName", fileName);
第三步,將我們需要保存的文檔附加進來。office.HttpAddPostCurrFile("docContent", '');第二個參數就是以什么文件名傳遞給服務器,直接傳遞一個空字符串即可。
第四步,將數據提交到一個php接收頁。office.HttpPost("./resources/php/upload.php");
這四步,除了第二步之外其他的三步都是必不可少的。
下面是webOffice.php頁面的完整代碼:

1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 5 <title>Office在線編輯器</title> 6 </head> 7 <?php 8 $fileName = $_GET['fileName']; 9 10 $fileType = $_GET['fileType']; 11 12 if ($fileType == '') { 13 $fileType = strtolower(substr($fileName, -3)) == 'doc' ? 'doc' : 'xls'; 14 } 15 ?> 16 <script type="text/javascript"> 17 /** 18 * 控件初始化WebOffice方法 19 * @param {String} fileName 要打開的文件名稱 20 * @param {String} fileType 要打開的文件類型,doc/ 21 */ 22 function WebOffice1_NotifyCtrlReady(fileName, fileType) { 23 var office = document.all.WebOffice1; 24 if (fileName) { 25 office.LoadOriginalFile(fileName, fileType); 26 } else { 27 office.LoadOriginalFile("", fileType); 28 } 29 } 30 31 // 關閉頁面時調用此函數,關閉文件 32 function window_onunload() { 33 document.all.WebOffice1.Close(); 34 } 35 36 function SaveDoc() { 37 var fileType = '<?php echo $fileType; ?>', 38 fileName = document.myForm.fileName.value, 39 office = document.all.WebOffice1; 40 41 if (!~fileName.indexOf('.' + fileType)) { fileName += '.' + fileType; } 42 43 office.HttpInit(); 44 45 // 添加相應的Post元素 46 office.HttpAddPostString("fileName", fileName); 47 48 office.HttpAddPostCurrFile("docContent", ''); // 上傳文件 49 50 var result = office.HttpPost("./resources/php/upload.php"); 51 52 if("OK" == result){ 53 alert("文件上傳成功"); 54 window.close(); 55 }else 56 alert("文件上傳失敗") 57 } 58 59 </script> 60 <SCRIPT LANGUAGE=javascript FOR=WebOffice1 EVENT=NotifyCtrlReady> 61 <!-- 62 var fn = '<?php echo $fileName; ?>'; 63 64 if (fn) { 65 fn = './uploadfiles/' + fn; 66 } 67 68 // 在裝載完Weboffice(執行<object>...</object>)控件后執行 "WebOffice1_NotifyCtrlReady"方法 69 WebOffice1_NotifyCtrlReady(fn, "<?php echo $fileType; ?>"); 70 //--> 71 </SCRIPT> 72 73 <body onunload="window_onunload()"> 74 <form name="myForm" method="post"> 75 <label for="fileName">文件名:</label> 76 <input type="text" id="fileName" name="fileName" value="<?php echo $fileName; ?>" /> 77 <input type="submit" id="saveFile" name="saveFile" value="保存文件到服務器" onclick="SaveDoc()" /> 78 </form> 79 <script src="resources/js/LoadWebOffice.js"></script> 80 </body> 81 </html>
4、編寫upload.php頁面。即接收上傳的文件並且保存到uploadfiles目錄下。大家還是直接看代碼吧,php上傳沒什么可說的,很簡單,不像是ASP那么麻煩。
在upload.php頁面中用到了一個uf.class.php類,我簡單的封裝的一個上傳類。

1 <?php 2 /** 3 * PHP上傳文件 4 * 公開屬性,overwrite,默認true 5 */ 6 class uploadFile { 7 private $name; // 上傳表單的name 8 private $fileName; // 文件名 9 private $uploadDir; // 文件存放目錄 10 private $type; // 允許上傳的文件類型 11 public $overwrite; // 是否覆蓋已存在的文件 12 13 function __construct() { 14 $this->name = 'file'; 15 $this->fileName = ''; 16 $this->uploadDir = 'D:/Codes/WebOffice/uploadfiles/'; 17 $this->type = array("xlsx", "doc", "docx", "xls"); 18 $this->overwrite = true; 19 } 20 21 /** 22 * 檢測文件后綴 23 * @param {String} $f 要檢測的文件名稱 24 */ 25 public function fileExt($f) { 26 return substr(strrchr($f, '.'), 1); 27 } 28 29 /** 30 * 設置上傳表單的name 31 * @param {String} $n 表單的name 32 */ 33 public function setName($n) { 34 if ($n == '') { 35 return false; 36 } else { 37 $this->name = $n; 38 } 39 } 40 41 /** 42 * 設置文件名 43 * @param {String} $fn 文件名 44 */ 45 public function setFileName($fn) { 46 if ($fn == '') { 47 return false; 48 } 49 $this->fileName = $fn; 50 return true; 51 } 52 53 /** 54 * 設置文件存放目錄 55 * @param {String} $p 文件存放目錄 56 */ 57 public function setPath($p) { 58 if ($p == '') { 59 return false; 60 } 61 $this->uploadDir = $p; 62 return true; 63 } 64 65 /** 66 * 設置允許上傳的文件格式 67 * @param {Array} $t 文件格式數組 68 */ 69 public function setFileType($t) { 70 if (is_array($t)) { 71 $this->type = $t; 72 return true; 73 } else { 74 return false; 75 } 76 } 77 78 /** 79 * 上傳文件 80 */ 81 public function upload() { 82 if ($this->fileName == '') { 83 $this->fileName = $_FILES[$this->name]['name']; 84 } 85 86 //判斷文件類型 87 /*if(!in_array(strtolower($this->fileExt($_FILES[$this->name]['name'])), $this->type)) { 88 echo "<script>alert('您只能上傳以下類型文件: ".implode(",",$this->type)."');</script>"; 89 return ''; 90 } else {*/ 91 $uploadfile = $this->uploadDir.$this->fileName; 92 93 if (!$this->overwrite && file_exists($uploadfile)) { 94 /*echo "<script>alert('文件已經存在!');</script>";*/ 95 return ''; 96 } 97 98 if (move_uploaded_file($_FILES[$this->name]['tmp_name'], $uploadfile)) { 99 /*echo "<script>alert('上傳成功!');</script>";*/ 100 return $uploadfile; 101 } 102 /*}*/ 103 } 104 } 105 ?>
1 <?php 2 require_once('uf.class.php'); 3 $upload = new uploadFile(); 4 $upload->setName('docContent'); 5 if ($_ENV['OS'] != 'Windows_NT') { 6 $upload->setPath('/var/ins-g/webOffice/uploadfiles/'); 7 } 8 $upload->setFileName($_POST['fileName']); 9 $result = $upload->upload(); 10 11 echo "OK"; 12 ?>
5、如果有同學跟我一樣,項目是跑在https下,但此控件又不支持https,所以我們還是創建一個虛擬主機來專門的跑這個在線編輯。這也是沒有辦法的辦法。
找到apache的配置文件httpd.conf。在最后添加以下幾行配置信息。
Listen 88 <VirtualHost *:88> DocumentRoot /var/ins-g/webOffice SSLEngine off </VirtualHost>
Documentroot的路徑即為插件程序所在的目錄。SSLEngine off即關閉ssl而用http來訪問。
還要注意要設置uploadfiles目錄有可寫的權限。
一切就緒后重啟apache即可。
完整的示例與官方開發文檔可以單擊下面的鏈接進行下載。
http://pan.baidu.com/netdisk/singlepublic?fid=759613_3581574499