[置顶] PHP生成word的三种方式
摘要:
最近工作遇到关于生成word的问题
现在总结一下生成word的三种方法。
btw:好像在博客园发表博客只要是标题带PHP的貌似点击量都不是很高(哥哥我标题还是带上PHP了),不知道为什么,估计博客园以net技术为主吧,这让我等PHP草民情何以堪情何以堪。。牢骚发完了,正式写博客吧
正文
PHP生成word原理
- 利用windows下面的 com组件
- 利用PHP将内容写入doc文件之中
具体实现:
-
利用windows下面的 com组件
原理:com作为PHP的一个扩展类,安装过office的服务器会自动调用word.application的com,可以自动生成文档,PHP官方文档手册:http://www.php.net/manual/en/class.com.php
使用官方实例:
<pre><?php // starting word $word = new COM( "word.application" )
or die ( "Unable to instantiate Word" ); echo "Loaded Word, version {$word->Version}\n" ; //bring it to front $word ->Visible = 1; //open an empty document $word ->Documents->Add(); //do some weird stuff $word ->Selection->TypeText( "This is a test..." ); $word ->Documents[1]->SaveAs( "Useless test.doc" ); //closing word $word ->Quit(); //free the object $word = null; ?> |
个人建议:com实例后的方法都需要查找官方文档才知道什么意思,编辑器没有代码提示,非常不方便,另外这个效率也不是很高,不推荐使用
利用PHP将内容写入doc文件之中
这个方法又可以分为两种方法
- 生成mht格式(和HTML很相似)写入word
- 纯HTML格式写入word
-
生成mht格式(和HTML很相似)写入word
这个方法主要参看:http://www.cnitblog.com/CoffeeCat/archive/2008/08/07/47753.html
/** * 根据HTML代码获取word文档内容 * 创建一个本质为mht的文档,该函数会分析文件内容并从远程下载页面中的图片资源 * 该函数依赖于类MhtFileMaker * 该函数会分析img标签,提取src的属性值。但是,src的属性值必须被引号包围,否则不能提取 * * @param string $content HTML内容 * @param string $absolutePath 网页的绝对路径。如果HTML内容里的图片路径为相对路径,那么就需要填写这个参数,来让该函数自动填补成绝对路径。这个参数最后需要以/结束 * @param bool $isEraseLink 是否去掉HTML内容中的链接 */ function getWordDocument( $content
, $absolutePath = "" ,
$isEraseLink = true ) { $mht = new MhtFileMaker(); if ( $isEraseLink ) $content = preg_replace( '/<a\s*.*?\s*>(\s*.*?\s*)<\/a>/i'
, '$1' , $content );
//去掉链接 $images = array (); $files = array (); $matches = array (); //这个算法要求src后的属性值必须使用引号括起来 if ( preg_match_all( '/<img[.\n]*?src\s*?=\s*?[\"\'](.*?)[\"\'](.*?)\/>/i' , $content
, $matches ) ) { $arrPath = $matches [1]; for ( $i =0; $i < count ( $arrPath ); $i ++) { $path = $arrPath [ $i ]; $imgPath = trim( $path
); if ( $imgPath
!= "" ) { $files [] = $imgPath ; { //绝对链接,不加前缀 } else { $imgPath = $absolutePath . $imgPath ; } $images [] = $imgPath ; } } } $mht ->AddContents( "tmp.html" , $mht ->GetMimeType( "tmp.html" ), $content ); for ( $i =0; $i < count ( $images ); $i ++) { $image = $images [ $i ]; if ( @ fopen ( $image
, 'r' ) ) { $imgcontent = @ file_get_contents (
$image ); if ( $content
) $mht ->AddContents( $files [ $i ], $mht ->GetMimeType( $image ), $imgcontent ); } else { echo "file:" . $image . " not exist!<br />" ; } } return $mht ->GetFile(); } |
这个函数的主要功能其实就是分析HTML代码中的所有图片地址,并且依次下载下来。获取到了图片的内容以后,调用MhtFileMaker类,将图片添加到mht文件中。具体的添加细节,封装在MhtFileMaker类中了。
-
使用方法:远程调用
url= http://www.***.com;$content = file_get_contents($url);$fileContent = getWordDocument($content,"http://www.yoursite.com/Music/etc/");$fp = fopen("test.doc", 'w');fwrite($fp, $fileContent);fclose($fp);
其中,$content变量应该是HTML源代码,后面的链接应该是能填补HTML代码中图片相对路径的URL地址
-
本地生成调用:
header(“Cache-Control: no-cache, must-revalidate”);
header(“Pragma: no-cache”);
$wordStr = ‘PHP淮北的个人网站–PHP10086.com’;
$fileContent = getWordDocument($wordStr);
$fileName = iconv(“utf-8″, “GBK”, ‘PHP淮北’ . ‘_’. $intro . ‘_’ . rand(100, 999));
header(“Content-Type: application/doc”);
header(“Content-Disposition: attachment; filename=” . $fileName . “.doc”);
echo $fileContent;
注意,在使用这个函数之前,您需要先包含类MhtFileMaker,这个类可以帮助我们生成Mht文档。
<?php /*********************************************************************** Class: Mht File Maker Version: 1.2 beta Date: 02/11/2007 Author: Wudi <wudicgi@yahoo.de> Description: The class can make .mht file. ***********************************************************************/ class MhtFileMaker{ var $config = array (); var $headers = array (); var $headers_exists =
array (); var $files = array (); var $boundary ; var $dir_base ; var $page_first ; function MhtFile( $config
= array ()){ } function SetHeader( $header ){ $this ->headers[] = $header ; $key = strtolower ( substr ( $header , 0,
strpos ( $header , ':' ))); $this ->headers_exists[ $key ] = TRUE; } function SetFrom( $from ){ $this ->SetHeader( "From: $from" ); } function SetSubject( $subject ){ $this ->SetHeader( "Subject: $subject" ); } function SetDate( $date
= NULL, $istimestamp = FALSE){ if ( $date
== NULL) { $date = time(); } if ( $istimestamp
== TRUE) { $date = date ( 'D, d M Y H:i:s O' ,
$date ); } $this ->SetHeader( "Date: $date" ); } function SetBoundary( $boundary
= NULL){ if ( $boundary
== NULL) { $this ->boundary = '--'
. strtoupper (md5(mt_rand())) . '_MULTIPART_MIXED' ; } else { $this ->boundary = $boundary ; } } function SetBaseDir( $dir ){ $this ->dir_base = str_replace ( "\\" ,
"/" , realpath ( $dir )); } function SetFirstPage( $filename ){ $this ->page_first = str_replace ( "\\" ,
"/" , realpath ( "{$this->dir_base}/$filename" )); } function AutoAddFiles(){ if (!isset( $this ->page_first)) { exit ( 'Not set the first page.' ); } $filepath = str_replace ( $this ->dir_base,
'' , $this ->page_first); $this ->AddFile( $this ->page_first,
$filepath , NULL); $this ->AddDir( $this ->dir_base); } function AddDir( $dir ){ $handle_dir = opendir( $dir ); while ( $filename
= readdir( $handle_dir )) { if (( $filename != '.' ) && ( $filename != '..' ) && ( "$dir/$filename" != $this ->page_first))
{ if ( is_dir ( "$dir/$filename" )) { $this ->AddDir( "$dir/$filename" ); } elseif ( is_file ( "$dir/$filename" )) { $filepath = str_replace ( $this ->dir_base,
'' , "$dir/$filename" ); $this ->AddFile( "$dir/$filename" ,
$filepath , NULL); } } } closedir ( $handle_dir ); } function AddFile( $filename ,
$filepath = NULL, $encoding = NULL){ if ( $filepath
== NULL) { $filepath = $filename ; } $mimetype = $this ->GetMimeType( $filename ); $filecont = file_get_contents ( $filename ); $this ->AddContents( $filepath ,
$mimetype , $filecont ,
$encoding ); } function AddContents( $filepath ,
$mimetype , $filecont ,
$encoding = NULL){ if ( $encoding
== NULL) { $filecont = chunk_split ( base64_encode ( $filecont ), 76); $encoding = 'base64' ; } $this ->files[] = array ( 'filepath'
=> $filepath , 'mimetype' =>
$mimetype , 'filecont' =>
$filecont , 'encoding' =>
$encoding ); } function CheckHeaders(){ if (! array_key_exists ( 'date' ,
$this ->headers_exists)) { $this ->SetDate(NULL, TRUE); } if ( $this ->boundary == NULL) { $this ->SetBoundary(); } } function CheckFiles(){ if ( count ( $this ->files) == 0) { return FALSE; } else { return TRUE; } } function GetFile(){ $this ->CheckHeaders(); if (! $this ->CheckFiles()) { exit ( 'No file was added.' ); } $contents = implode( "\r\n" ,
$this ->headers); $contents .= "\r\n" ; $contents .= "MIME-Version: 1.0\r\n" ; $contents .= "Content-Type: multipart/related;\r\n" ; $contents .= "\tboundary=\"{$this->boundary}\";\r\n" ; $contents .= "\ttype=\""
. $this ->files[0][ 'mimetype' ] .
"\"\r\n" ; $contents .= "X-MimeOLE: Produced By Mht File Maker v1.0 beta\r\n" ; $contents .= "\r\n" ; $contents .= "This is a multi-part message in MIME format.\r\n" ; $contents .= "\r\n" ; foreach ( $this ->files
as $file ) { $contents .= "--{$this->boundary}\r\n" ; $contents .= "Content-Type: $file[mimetype]\r\n" ; $contents .= "Content-Transfer-Encoding: $file[encoding]\r\n" ; $contents .= "Content-Location: $file[filepath]\r\n" ; $contents .= "\r\n" ; $contents .= $file [ 'filecont' ]; $contents .= "\r\n" ; } $contents .= "--{$this->boundary}--\r\n" ; return $contents ; } function MakeFile( $filename ){ $contents = $this ->GetFile(); $fp = fopen ( $filename ,
'w' ); fwrite( $fp , $contents ); fclose( $fp ); } function GetMimeType( $filename ){ $pathinfo = pathinfo ( $filename ); switch ( $pathinfo [ 'extension' ]) { case 'htm' :
$mimetype = 'text/html' ; break ; case 'html' :
$mimetype = 'text/html' ; break ; case 'txt' :
$mimetype = 'text/plain' ; break ; case 'cgi' :
$mimetype = 'text/plain' ; break ; case 'php' :
$mimetype = 'text/plain' ; break ; case 'css' :
$mimetype = 'text/css' ; break ; case 'jpg' :
$mimetype = 'image/jpeg' ; break ; case 'jpeg' :
$mimetype = 'image/jpeg' ; break ; case 'jpe' :
$mimetype = 'image/jpeg' ; break ; case 'gif' :
$mimetype = 'image/gif' ; break ; case 'png' :
$mimetype = 'image/png' ; break ; default : $mimetype
= 'application/octet-stream' ; break ; } return $mimetype ; } } ?> |
点评:这种方法的缺点是不支持批量生成,因为一个页面只能有一个header,(无论远程使用还是本地生成声明header页面只能输出一个header),即使你循环生成,结果还是只有一个word生成(当然你可以修改上面的方式来实现)
2.纯HTML格式写入word
原理:
利用ob_start把html页面先存储起来(解决一下页面多个header问题,可以批量生成),然后在写入doc文档内容利用
代码:
<?php class word { function start() { ob_start(); echo '<html xmlns:o= "urn:schemas-microsoft-com:office:office" xmlns:w= "urn:schemas-microsoft-com:office:word" } function save( $path ) { echo "</html>" ; $data = ob_get_contents(); ob_end_clean(); $this ->wirtefile ( $path , $data ); } function wirtefile ( $fn , $data ) { $fp = fopen ( $fn , "wb" ); fwrite( $fp , $data ); fclose( $fp ); } } $html = ' <table width=600 cellpadding= "6" cellspacing= "1"
bgcolor= "#336699" > <tr bgcolor= "White" > <td>PHP10086</td> </tr> <tr bgcolor= "red" > <td>PHP10086</td> </tr> <tr bgcolor= "White" > <td colspan=2 > PHP10086<br> 最靠谱的PHP技术博客分享网站 </td> </tr> </table> '; //批量生成 for ( $i =1; $i <=3; $i ++){ $word = new word(); $word ->start(); //$html = "aaa".$i; $wordname = 'PHP淮北的个人网站--PHP10086.com' . $i . ".doc" ; echo $html ; $word ->save( $wordname ); ob_flush(); //每次执行前刷新缓存 flush (); } |
个人点评:这种方法效果最好,原因有两个:
第一代码比较简洁,很容易理解,第二种支持批量生成word且下载(这个很重要)
第三支持完整的html代码
看一下效果:
生成了三个word文档:并且内容支持完整的html代码显示,第三种方法强烈推荐