目的
用户上传DOC,DOCX等文件格式后,能够在线查看到文件的内容。
想法
WORD文件内容是富文本,可以转换成HTML格式后表现出来,或者转换成PDF格式,然后通过pdf.js来实现在线阅读。
实现
由于后端环境是Windows,脚本语言为PHP, 因此可以使用PHP的COM组件来调用OpenOffice 或者 MS Word 来实现该格式转换问题。
准备
1. 安装OpenOffice 或者 MS Word 程序
OpenOffice可以在这里下载。
2. 打开COM
注意:COM组件只试用于Windows版本下的PHP,需要PHP5及.Net runtime.
PHP 5.3.15/5.4.5
需在php.ini
手动打开php_com_dotnet.dll
,此前版本默认已经打开。
另外,您可能还需要打开com.allow_dcom
, 具体配置如下:
extension=php_com_dotnet.dll...[COM]
...; allow Distributed-COM calls
; http://php.net/com.allow-dcomcom.allow_dcom = true
; autoregister constants of a components typlib on com_load()
; http://php.net/com.autoregister-typelibcom.autoregister_typelib = true
使用MS Word来转换
PHP代码:
<?phptry{
$word = new COM("word.application") or die("Unable to instanciate Word");
echo "Strat...\n"; // set it to 1 to see the MS Word window (the actual opening of the document) $word->Visible = 0; // recommend to set to 0, disables alerts like "Do you want MS Word to be the default .. etc" $word->DisplayAlerts = 0; // open the word 2007-2013 document $word->Documents->Open(realpath("in.docx")); // save it as word 2003 // $word->ActiveDocument->SaveAs('newdocument.pdf'); // convert word 2007-2013 to PDF $word->ActiveDocument->ExportAsFixedFormat("F:\\Tools\\Program Handle\\WAMP\\www\\wordConvertor\\output.pdf", 17, false, 0, 0, 0, 0, 7, true, true, 2, true, true, false); // quit the Word process $word->Quit(false); // clean up unset($word); echo "Done!";}catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";}
?>
如果您遇到以下类似的错误, 并确认MS Word已经安装好:
PHP Fatal error: Uncaught exception 'com_exception' with message 'Source: Microsoft Word
Description: This command is not available because no document is open.'
请尝试这样解决(建议先尝试方法二):
方法一:
- 开始
- Win+R 运行
- 输入
dcomcnfg
- Press OK
- 展开 Component Services
- 展开 Computers
- 右键 My Computer,点击”Properties”
- Default Properties选项卡
- 确认勾选Enable COM Internet Services on this computer 和Enable Distributed COM
- 设置 Default Authentication Level 为 Default
- 设置 Default Impersonation Level 为 Identify
- COM Security tab 选项卡
- Access Permissions area, 点击 Edit Limits…
- 确认ANONYMOUS LOGIN 下允许 remote access
- 点击 Add…
- 在 “Enter object names to select” 文本框内输入 “Everyone”
- 允许Everyone 有 Local Access 和 Remote Access
- 点击确认
- 同样在Access Permissions 区域,点击
Edit Default
- 确认允许 SELF and SYSTEM 有 remote access
- 点击
Add...
重复步骤 16 and 17 - 点击确认
- 在Launch and Activation
Permissions区域下点击
Edit Limits...
- 确认允许Administrator user 有 remote launch 和 remote activation的权限
- 如果Everyone用户组在这里不存在,请重复步骤16,17
- 允许Everyone group有local launch, remote launch, local activation,和 remote activation权限.
- 点击确认
- 同样在Launch and Activation
Permissions区域下,点击
Edit Default...
- 确认Administrator, INTERACTIVE, 和 SYSTEM用户组有 remote launch 和 remote activation 的权利.
- 重复步骤16 和 17 以创建Everyone用户组
- 允许Everyone group有local launch, remote launch, local activation,和 remote activation权限.
ci_dcomcnfg_1
同时,确认php.ini
中的com.allow_dcom
已经打开。重启后再试,如果问题依旧,请继续以下步骤:
- 依次点击Console Root -> Component Services -> Computers ->
My Computer -> DCOM Config,
在此处找到
Microsoft Word 97 - 2003 Document
(如果没有找到,请尝试方法二). - 右键属性.
- Security
选项卡中确认
Launch and Activation Permissions
,Access Permissions
,Configuration permissions
已经勾选为Default
. - 在
Identity
选项卡中选择The interactive user
或者指定一个Admin用户, 通常它可能是The launching user
.
方法二:
- Win + R 打开运行;
- 输入
mmc -32
,按下OK; - 在新弹出的窗口中点击 File -> Add/Remove Sanp-in (或者Ctrl + M);
- 在新窗口中的左侧找到Component Services, 添加,确认;
- 依次点击Console Root -> Component Services -> Computers ->
My Computer -> DCOM Config,
在此处找到
Microsoft Word 97 - 2003 Document
. - 右键
Microsoft Word 97 - 2003 Document
,选择Property
, 在Identity
选项卡中选择The interactive user
或者指定一个Admin用户, 通常它可能是The launching user
.
ci_dcomcnfg_2
使用OpenOffice来转换
启动OpenOffice服务
两种方式,方式一比较简便。
确认是否已经开启参考以下命令来获取回复:
netstat -nao|findstr -c":8100"
其中8100应该改为您自行设定OpenOffice服务端口。
方式一
假设您的OpenOffce安装在C:\Program Files (x86)\OpenOffice 4\program\soffice.exe
,在CMD中输入以下命令:
"C:\Program Files (x86)\OpenOffice 4\program\soffice.exe" -headless -accept="socket,host=127.0.0.1,port=8100;urp;" -nofirststartwizard
方式二
- 创建文件夹在该路径上 C:, 把srvany.exe复制到里面去. 该文件从Windows Server 2003 Resource Kit提取.
- 打开CMD(管理员模式). 运行一下命令.
C:\Windows\system32>sc create "ooservice" binPath= "\"C:\Utils\srvany.exe\"" DisplayName= "OpenOffice Server" start= auto
[SC] CreateService SUCCESS
- 打开注册表编辑器(Win + R, 输入regedit). 寻找到HKEY_LOCAL_MACHINE.
- 创建一个新的 key,名为
Parameters
. - 在
Parameters
这个Key中, 创建一个名为Application
的String,其值如下:
"C:\Program Files (x86)\OpenOffice 4\program\soffice.exe" -headless -accept="socket,host=127.0.0.1,port=8100;urp;" -nofirststartwizard
Note: Update path to open office as necessary.
- 最后您的注册表大概类似于这个样子:
- 在
Control Panel
->Administrative Tools
->Services
中找到Open Office Server
并开启. - 使用上述的netstat -nao|findstr -c”:8100”命令确认是否已经开启.
成功后回复如下:
C:\Windows\system32>netstat -nao|findstr -c":8100"
TCP 127.0.0.1:8100 0.0.0.0:0 LISTENING 6016
PHP代码
<?phpfunction MakePropertyValue($name, $value,$osm){
$oStruct = $osm->Bridge_GetStruct("com.sun.star.beans.PropertyValue");
$oStruct->Name = $name;
$oStruct->Value = $value;
return $oStruct;
}
function word2pdf($doc_url, $output_url){
// Invoke the OpenOffice.org service manager $osm = new COM("com.sun.star.ServiceManager") or die ("Please be sure that OpenOffice.org is installed.\n");
// Set the application to remain hidden to avoid flashing the document onscreen $args = array(MakePropertyValue("Hidden",true,$osm));
// Launch the desktop $top = $osm->createInstance("com.sun.star.frame.Desktop");
// Load the .doc file, and pass in the "Hidden" property from above $oWriterDoc = $top->loadComponentFromURL($doc_url,"_blank", 0, $args);
// Set up the arguments for the PDF output $export_args = array(MakePropertyValue("FilterName","writer_pdf_Export",$osm));
// Write out the PDF $oWriterDoc->storeToURL($output_url,$export_args);
$oWriterDoc->close(true);
}
try{
echo "Strat...\n"; $doc_file = 'file:///F:/Tools/Program Handle/WAMP/www/wordConvertor/in.docx' ;
$output_file = 'file:///F:/Tools/Program Handle/WAMP/www/wordConvertor/out.pdf';
word2pdf($doc_file, $output_file);
echo "Done!";}catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";}
?>
问题及注意
1.程序长时间卡在new COM("com.XXXXX")
这一行
由于实际上是调用MS WORD或者OpenOffice来完成的功能,因此调试时,可以利用任务管理器查看相关进程,防止因为错误的代码/环境重复打开多个进程而得不到关闭,导致后面的测试也出错。
此外,还可以调短php.ini
中的max_execution_time
,个人感觉3s内无响应就该去再做检查了.
参考
https://www.getfilecloud.com/supportdocs/display/cloud/Running+Openoffice+as+a+service+in+Windows
http://www.figured-it-out.com/figured-out.php?sid=24
http://stackoverflow.com/questions/12104775/cant-open-word-doc-with-com-in-php