Html转Word

需求

将富文本编辑后的HTML代码片段转换为Word文件,替换Word文件模板变量,加盖章,生成并打包下载

摘要

在尝试使用PHPWord进行转换后,生成的Word文件没有样式,使用原生生成方式PHPWord则无法打开文件,因此转换思路如下

  1. 先将HTML代码块格式化为可导出的Word格式(视图、保留样式)
  2. 替换HTML内模板参数为变量
  3. 添加印章变量
  4. 打包zip下载(此处生成了多个文件所以多了一步打包zip)

工具类代码

<?php

namespace app\common\utils;

/**
 * 自定义 HTML与Word操作类处理
 * @author Teanxo
 */
class Html2Word
{
    private $html;

    private $htmlTagTemp = <<<HTML
<html xmlns:v='urn:schemas-microsoft-com:vml'xmlns:o='urn:schemas-microsoft-com:office:office'xmlns:w='urn:schemas-microsoft-com:office:word'xmlns:m='http://schemas.microsoft.com/office/2004/12/omml'xmlns='http://www.w3.org/TR/REC-html40'>
HTML;

    /**
     * html字符内 挂载到header标签内的模板
     * @var string
     */
    private $headerTmp = <<<HTML
<!--[if gte mso 9]><xml><w:WordDocument><w:View>Print</w:View><w:TrackMoves>false</w:TrackMoves><w:TrackFormatting/><w:ValidateAgainstSchemas/><w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid><w:IgnoreMixedContent>false</w:IgnoreMixedContent><w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText><w:DoNotPromoteQF/><w:LidThemeOther>EN-US</w:LidThemeOther><w:LidThemeAsian>ZH-CN</w:LidThemeAsian><w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript><w:Compatibility><w:BreakWrappedTables/><w:SnapToGridInCell/><w:WrapTextWithPunct/><w:UseAsianBreakRules/><w:DontGrowAutofit/><w:SplitPgBreakAndParaMark/><w:DontVertAlignCellWithSp/><w:DontBreakConstrainedForcedTables/><w:DontVertAlignInTxbx/><w:Word11KerningPairs/><w:CachedColBalance/><w:UseFELayout/></w:Compatibility><w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel><m:mathPr><m:mathFont m:val='Cambria Math'/><m:brkBin m:val='before'/><m:brkBinSub m:val='--'/><m:smallFrac m:val='off'/><m:dispDef/><m:lMargin m:val='0'/> <m:rMargin m:val='0'/><m:defJc m:val='centerGroup'/><m:wrapIndent m:val='1440'/><m:intLim m:val='subSup'/><m:naryLim m:val='undOvr'/></m:mathPr></w:WordDocument></xml><![endif]-->
HTML;

    /**
     * 当有一些不是成员变量的时候
     * 需要指定一个对象 才可对特殊变量进行高级赋值操作
     * 代替适配器,使用动态调用方式
     * $operationInstance->$func($sourceData)
     * @var null
     */
    private $operationInstance = null;


    /**
     * 将一个HTML字符串格式为可导出Word的数据
     */
    public function replaceHTML()
    {
        // 判断字符串中是否存在HTML标签
        $htmlIndex = strpos($this->html, "<html");


        if ($htmlIndex !== false) {
            $htmlEndIndex = stripos($this->html, ">");
            // 删除HTML开始头部标签
            $endHtml = substr($this->html, $htmlEndIndex + 1);
            $this->html = $this->htmlTagTemp . $endHtml;
        } else {
            $this->html = $this->htmlTagTemp . $this->html . "</html>";
        }


        // 判断字符串中是否存在header标签
        $headerIndex = stripos($this->html, "<head>");
        $hRepIndex = stripos($this->html, "<!--[if gte mso 9]>");

        // header标签 且定义插入标签不存在时候执行
        if ($headerIndex !== false && $hRepIndex === false) {
            // 拿到meta标签开始位置
            $startIndex = stripos($this->html, "<meta");

            // 必须匹配到meta结束标签才能执行
            preg_match_all('/<meta(.*)$/m', $this->html, $matches);
            if (count($matches) > 0) {

                // 拿到head结束标签位置
                $lastMetaStr = end($matches[0]);
                $lastIndex = strpos($this->html, $lastMetaStr);
                $endIndex = $lastIndex + strlen($lastMetaStr);

                // 为header插入word导出所需标签
                $startHtmlStr = substr($this->html, 0, $lastIndex);
                $endHhtmlStr = substr($this->html, $endIndex);

                // 为head拼接指定标签
                $this->html = $startHtmlStr . $this->headerTmp . $endHhtmlStr;

            }

        } else if ($headerIndex === false) {
            // header标签不存在 那么创建

            // 拿到meta标签开始位置
            $startIndex = stripos($this->html, "<meta");
            // 拿到meta标签结束位置
            preg_match_all('/<meta(.*)$/m', $this->html, $matches);
            if (count($matches) > 0) {
                // 拿到head结束标签位置
                $lastMetaStr = end($matches[0]);
                $lastIndex = strpos($this->html, $lastMetaStr);
                $endIndex = $lastIndex + strlen($lastMetaStr);

                $startHtmlStr = substr($this->html, 0, $lastIndex);
                $endHhtmlStr = substr($this->html, $endIndex);

                // 为head拼接指定标签
                $this->html = $startHtmlStr . "<head>" . $this->headerTmp . "</head>" . $endHhtmlStr;


            }
        }
        return $this;
    }

    /**
     * 将模板化的HTML变量  替换
     * @param array $tmpVar 示例 ['模板名称 例如:项目名称'=>'字段名称']
     * @param array $sourceData 示例 ['字段名称'=>'字段值']
     * @return $this
     */
    public function variables(array $tmpVar, array $sourceData)
    {
        foreach ($tmpVar as $key => $value) {
            if (is_string($value) && isset($sourceData[$value])) {
                $this->variable('$(' . $key . ')', $sourceData[$value]);
            } else if (is_array($value) && key_exists("func", $value)) {
                $func = $value['func'];
                $this->html = str_replace('$(' . $key . ')', $this->operationInstance->$func($sourceData), $this->html);
            }
        }
        return $this;
    }

    /**
     * 单个模板变量赋值
     * @param string $tmpName
     * @param $val
     */
    public function variable(string $tmpName, $val)
    {
        $this->html = str_replace($tmpName, $val, $this->html);
        return $this;
    }

    /**
     * 将变量以正则表达式形式进行赋值
     * @param $pattern
     * @param $val
     */
    public function pregMatchVariable($pattern, $val)
    {
        $this->html = preg_replace($pattern, $val, $this->html);
        return $this;
    }


    /**
     * 写入Word文件
     * @param string $fileName 文件路径
     * @return void
     */
    public function writeWord(string $fileName)
    {
        $writefile = fopen($fileName, 'wb') or die("创建文件失败"); //wb以二进制写入
        fwrite($writefile, $this->html);
        fclose($writefile);
        file_put_contents($fileName, $this->html);
    }

    /**
     * 挂载HTML数据
     * @param mixed $html
     */
    public function setHtml(string $html)
    {
        $this->html = $html;
        return $this;
    }

    /**
     * 获取HTML数据
     * @return string
     */
    public function getHtml()
    {
        return $this->html;
    }

    /**
     * @param  $operationInstance
     */
    public function setOperationInstance($operationInstance)
    {
        $this->operationInstance = new $operationInstance();
        return $this;
    }


}

使用方法

$html2Word = new Html2Word();

// 一些示例数据
$configs = array(
	'项目名称' => 'product_name',
	'项目别名' => 'product_as',
	// 当此处设置为 array时 且存在func属性,那么会执行 Html2WordOperation类中的seal方法,也就是setOperationInstance时传入的类
	'盖章' => [
		'func' => 'seal'
	]
);


$variableData = array(
	'product_name' => '小米手机',
	'product_as' => '小米'
);

$html2Word->setOperationInstance(Html2WordOperation::class) // 传入自定义操作类
          ->setHtml($productTemplateinfo['content']) // 挂载HTML代码片段
          ->replaceHTML() // 整理为可导出Word格式
          ->variables($configs, $variableData) // 将HTML代码模板的变量转为实际参数
          ->pregMatchVariable('/人民币【.*万元整+/', $amountText) // 正则表达式变量赋值
          ->writeWord($filePath) // 导出文件;

Html2WordOperation类示例
/**
 * 对转换中变量进行特殊方法处理
 */
class Html2WordOperation
{
    /**
     * 生成盖章
     * @param $sourceData 同等variableData
     * @return string
     */
    public function seal($sourceData)
    {
        $seal = $sourceData['seal'];
        // 读取盖章数据
        return <<<HTML
<img src="$seal" style="width: 100px;height: 100px;margin-top: 15px;" />
HTML;

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飞鱼三两只

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值