1. 问题
实现一个功能:导出pdf。
网上有很多种办法来导出pdf,但是我选择了wkhtmltopdf。wkhtmltopdf是需要安装在操作系统的软件,导出效率可观。
系统现状:
- 思路:在centos安装wkhtmltopdf然后通过php调用命令来处理。
但是发现,系统环境原因,不能调用操作系统的wkhtmltopdf来导出,这就是本次处理最大的问题所在。只能异步处理,写个shell脚本来调用,在用php脚本来检测是否成功。
- 实现:
- 定时脚本1:php脚本,检测到有需要导出pdf的任务的时候,通过smarty来生成静态html,存到目录A。
- 定时脚本2:shell脚本,检测到目录A有html时,将html生成为pdf,存到目录B,并删除目录A的html。
- 定时脚本3:php脚本,检测到目录B有文件时,将该文件转存到目录C,并删除目录B原来的pdf。
简易代码如下:
# 脚本1<?phpob_start();$smarty = new \package\template\Smarty($config);$smarty->assign('data', $r);$smarty->show($template_dir.'template_index.html',false);$content = ob_get_clean();$template_dir = $main_data . 'report/project/html/';$html_file = $template_dir.$id.'_'.$data_id.'.html';file_put_contents($html_file,$content);
# 脚本2for file in $(ls | grep "^[0-9]*_[0-9]*.html$")dopdf_name="${file%%.*}"pdf_header="${pdf_name}header.html"pdf_file_path="${pdf_path}${pdf_name}.pdf"`/usr/local/bin/wkhtmltopdf --header-html "${pdf_header}" --footer-html tmplate_footer.html "${file}" "${pdf_file_path}"`# 判断文件是否生成成功,是则删除htmlif [ -f "${pdf_file_path}" ];thenrm "${file}"rm "${pdf_header}"fidone
# 脚本3
<?
$data = scandir($pre_pdf_dir);
foreach ($data as $f) {
}
- 调试:
出现一个问题:一直推送同一个pdf给人员,而且该pdf乱码。调试发现,因为脚本2没有把html删除,但是为什么没有删除呢?
原因:脚本2在导出大文件的时候,先生成文件名,所以当脚本3检测到目录B有文件生成,就把文件推送出去了,并且删除掉原文件,导致脚本2发现导出pdf失败了,就没有删除掉html,然后就无限循环,这就是问题的整个过程。
解决:
- 脚本3检测文件时识别后缀为非pdf时不处理。
在运行脚本2的生成过程中,将要生成的文件后缀改成非pdf,等生成完成后再改回pdf后缀。
# 脚本2 for file in $(ls | grep "^[0-9]*_[0-9]*.html$") do pdf_name="${file%%.*}" pdf_header="${pdf_name}header.html" pdf_file_path="${pdf_path}${pdf_name}.pdf" # 临时文件 pdf_tmp="${pdf_file_path}.tmp" `/usr/local/bin/wkhtmltopdf --header-html "${pdf_header}" --footer-html tmplate_footer.html "${file}" "${pdf_tmp}"` # 判断文件是否生成成功,则文件改名,删除html if [ -f "${pdf_tmp}" ];then # 临时文件改名为pdf mv "${pdf_tmp}" "${pdf_file_path}" # 删除html rm "${file}" rm "${pdf_header}" fi done# 脚本3 <? $data = scandir($pre_pdf_dir); foreach ($data as $f) { $info = pathinfo($f); // 判断是否生成完成pdf,如果后缀不是pdf则文件未生成完成 if ($info['extension'] != 'pdf') continue; }
- 由于程序设计时没有做更多的可靠性处理,导致一个环节出错,就可能出现不可预料的错误。此程序有改进空间,比如记录推送次数,推送失败就做出进一步的处理。
