php解析word,得到文檔中的圖片

背景

前段時間在寫一個功能:用原生php將得到word中的內容並導入到網站系統中。由於文檔中存在公式,圖片,表格等,所以寫的比較麻煩。php

 

思路

大致思路是先將word中格式爲doc的文檔轉化爲docx,用預處理程序將文檔中的公式轉化爲swf圖片格式,將word轉化爲xml格式,在得到xml中的內容轉化爲json格式。html

 

預備知識

1. 理解xml基礎java

xml是一種可擴展標記語言,是互聯網數據傳輸的重要工具,xml能夠實現跨互聯網平臺而不受編程語言和操做系統的限制,能夠說是一個擁有互聯網最高級別通行證的數據攜帶者。node

xml是當前處理結構化文檔信息中的技術,有助於在服務器之間穿梭結構化出具,使得開發工做者能夠更加方便的控制數據的存儲和傳輸web

xml用於標記電子文件使其具備結構性的標記語言,可用來標記數據,定義數據類型,是一種容許用戶對本身的標記語言進行定義的源語言。它是標準通用語言的子集,很是適合web傳輸。編程

具體的詳解能夠看這裏:https://blog.csdn.net/com_ma/article/details/73277535json

 

2. word的兩種不一樣的存儲方式服務器

word文檔的兩種存儲格式:doc和docxdom

doc:習慣上被稱爲word,採用二進制存儲數據編程語言

docx:也就是word2007,採用xml存儲數據

那麼後綴明明是docx格式的,爲何成xml格式了?

選擇一個test.docx,將後綴名改成.zip,而後進行解壓,獲得下面的目錄結構:

 

因此你認爲的docx文檔,實際上是一個壓縮文件~

 

3. 瞭解DOM和PHP DOM XML解析

DOM提供了針對html和xml文檔的標準對象集,以及用於訪問和操做這些文檔的標準接口。XML DOM是爲文檔定義標準的對象集。使用PHP DOM擴展能夠實現PHP對DOM樹的一系列操做。

使用PHP DOM讀取一個XML文檔:

test.xml:

<?xml version="1.0" encoding="utf-8"?>
<teststore>
<test>
    <name>php dom test</name>
    <author>test-one</author>
</test>
<test>
    <title>php dom test 2</title>
    <author>test-two</author>
</test>
</teststore>

test.php:

<?php
    $doc = new DOMDocument();
    $doc->load("test.xml");
    //獲取標籤對象
    $book=$doc->getElementsByTagName("test");
    //輸出第一個中的值
    echo $book->item(0)->nodeValue;

    echo "<br>----------------<br>";

    $title=$doc->getElementsByTagName("name");
    echo $title->item(0)->nodeValue;

    echo "<br>----------------<br>";
    //遍歷全部book標籤中的內容
    foreach ($book as $note)
    {
        echo $note->nodeValue;
        echo "<br>";
    }

結果:

 

 

4. word中xml的定義格式

word中的數據是怎麼定義的呢??

咱們只會介紹連個l兩個文件/文件夾:

一個文件是word/document.xml,這個文件定義了word整個文檔的內容。

另外一個文件夾是word/media,這個文件夾存放着文檔的多媒體內容,換句話說文檔中全部的圖片,音頻視頻都是在這個文件夾下存放。

 

document.ml中的總體結構定義:

<w:document mc:ignorable="w14 w15 wp14" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" xmlns:wpscustomdata="http://www.wps.cn/officeDocument/2013/wpsCustomData">
    <w:body>
        <w:p>
            <w:ppr>
                <w:pstyle w:val="2">
                </w:pstyle>
                <w:keepnext w:val="0">
                </w:keepnext>
                <w:keeplines w:val="0">
                </w:keeplines>
                <w:widowcontrol>
                </w:widowcontrol>
                <w:suppresslinenumbers w:val="0">
                </w:suppresslinenumbers>
                <w:pbdr>
                    <w:top w:color="auto" w:space="0" w:sz="0" w:val="none">
                    </w:top>
                    <w:left w:color="auto" w:space="0" w:sz="0" w:val="none">
                    </w:left>
                    <w:bottom w:color="auto" w:space="0" w:sz="0" w:val="none">
                    </w:bottom>
                    <w:right w:color="auto" w:space="0" w:sz="0" w:val="none">
                    </w:right>
                </w:pbdr>

 

文檔段落內容:

<w:p>
            <w:ppr>
                <w:pstyle w:val="2">
                </w:pstyle>
                <w:keepnext w:val="0">
                </w:keepnext>
                <w:keeplines w:val="0">
                </w:keeplines>
                <w:widowcontrol>
                </w:widowcontrol>
                <w:suppresslinenumbers w:val="0">
                </w:suppresslinenumbers>
                <w:pbdr>
                    <w:top w:color="auto" w:space="0" w:sz="0" w:val="none">
                    </w:top>
                    <w:left w:color="auto" w:space="0" w:sz="0" w:val="none">
                    </w:left>
                    <w:bottom w:color="auto" w:space="0" w:sz="0" w:val="none">
                    </w:bottom>
                    <w:right w:color="auto" w:space="0" w:sz="0" w:val="none">
                    </w:right>
                </w:pbdr>
                <w:shd w:fill="FAFAFA" w:val="clear">
                </w:shd>
                <w:spacing w:after="150" w:afterautospacing="0" w:before="150" w:beforeautospacing="0" w:line="378" w:linerule="atLeast">
                </w:spacing>
                <w:ind w:firstline="0" w:left="0" w:right="0">
                </w:ind>
                <w:rpr>
                    <w:rfonts w:ascii="Verdana" w:cs="Verdana" w:hansi="Verdana" w:hint="default">
                    </w:rfonts>
                    <w:i w:val="0">
                    </w:i>
                    <w:caps w:val="0">
                    </w:caps>
                    <w:color w:val="404040">
                    </w:color>
                    <w:spacing w:val="0">
                    </w:spacing>
                    <w:sz w:val="21">
                    </w:sz>
                    <w:szcs w:val="21">
                    </w:szcs>
                </w:rpr>
            </w:ppr>
            <w:r>
                <w:rpr>
                    <w:rfonts w:ascii="Verdana" w:cs="Verdana" w:hansi="Verdana" w:hint="default">
                    </w:rfonts>
                    <w:i w:val="0">
                    </w:i>
                    <w:caps w:val="0">
                    </w:caps>
                    <w:color w:val="404040">
                    </w:color>
                    <w:spacing w:val="0">
                    </w:spacing>
                    <w:sz w:val="21">
                    </w:sz>
                    <w:szcs w:val="21">
                    </w:szcs>
                    <w:bdr w:color="auto" w:space="0" w:sz="0" w:val="none">
                    </w:bdr>
                    <w:shd w:fill="FAFAFA" w:val="clear">
                    </w:shd>
                </w:rpr>
                <w:t>
                    做者: Test
                </w:t>
            </w:r>
        </w:p>

 

圖片內容定義:

<w:r>
                <w:rpr>
                    <w:rfonts w:ascii="Verdana" w:cs="Verdana" w:hansi="Verdana" w:hint="default">
                    </w:rfonts>
                    <w:i w:val="0">
                    </w:i>
                    <w:caps w:val="0">
                    </w:caps>
                    <w:color w:val="404040">
                    </w:color>
                    <w:spacing w:val="0">
                    </w:spacing>
                    <w:sz w:val="21">
                    </w:sz>
                    <w:szcs w:val="21">
                    </w:szcs>
                    <w:bdr w:color="auto" w:space="0" w:sz="0" w:val="none">
                    </w:bdr>
                    <w:shd w:fill="FAFAFA" w:val="clear">
                    </w:shd>
                </w:rpr>
                <w:drawing>
                    <wp:inline distb="0" distl="114300" distr="114300" distt="0">
                        <wp:extent cx="5543550" cy="5543550">
                        </wp:extent>
                        <wp:effectextent b="0" l="0" r="0" t="0">
                        </wp:effectextent>
                        <wp:docpr descr="IMG_256" id="1" name="Picture 1">
                        </wp:docpr>
                        <wp:cnvgraphicframepr>
                            <a:graphicframelocks nochangeaspect="1" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
                            </a:graphicframelocks>
                        </wp:cnvgraphicframepr>
                        <a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
                            <a:graphicdata uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
                                <pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
                                    <pic:nvpicpr>
                                        <pic:cnvpr descr="IMG_256" id="1" name="Picture 1">
                                        </pic:cnvpr>
                                        <pic:cnvpicpr>
                                            <a:piclocks nochangeaspect="1">
                                            </a:piclocks>
                                        </pic:cnvpicpr>
                                    </pic:nvpicpr>
                                    <pic:blipfill>
                                        <a:blip r:embed="rId4">
                                        </a:blip>
                                        <a:stretch>
                                            <a:fillrect>
                                            </a:fillrect>
                                        </a:stretch>
                                    </pic:blipfill>
                                    <pic:sppr>
                                        <a:xfrm>
                                            <a:off x="0" y="0">
                                            </a:off>
                                            <a:ext cx="5543550" cy="5543550">
                                            </a:ext>
                                        </a:xfrm>
                                        <a:prstgeom prst="rect">
                                            <a:avlst>
                                            </a:avlst>
                                        </a:prstgeom>
                                        <a:nofill>
                                        </a:nofill>
                                        <a:ln w="9525">
                                            <a:nofill>
                                            </a:nofill>
                                        </a:ln>
                                    </pic:sppr>
                                </pic:pic>
                            </a:graphicdata>
                        </a:graphic>
                    </wp:inline>
                </w:drawing>
            </w:r>

 

結論:

<w:document>  定義整個文檔的開始

    <w:body>    document的子節點,文檔的主體內容

        <w:p>    body的子節點,一個段落,就是word文檔中的段落

           <w:r>    p元素的子節點,一個Run定義了段落中具備相同格式的一段內容

                <w:t>    Run元素節點的子節點,就是文檔的內容

                <w:drawing>    run元素的子節點,定義了一張圖片

                    <w:inline>    drawing子節點,具體應用沒有研究

                    <a:graphic>     定義了圖片內容

                        <pic:blipfill>    graphic文檔的子節點,定義了圖片內容的索引.

 

具體的說,若是用java,那麼XWPF解析docx文檔就是作xml文檔解析,得到全部的節點並轉換成更好用的屬性提供API進行使用,在java中poi能根據這個名稱拿到圖片相對應的資源,而獲取圖片位置的關鍵也就是這裏。

 

 

可是很不幸,我用的是php~~~因此咱們須要經過php的相關接口手動實現得到圖片.

 

下面說一下個人具體思路:經過PHP的內置DOMDocument接口得到docx文檔的xml節點,遍歷xml節點找到保存圖片的節點元素,向下遍歷圖片節點扎到r:embed索引的值。由於docx文檔是一個壓縮包格式,因此經過PHP內置接口ZipArchive接口遍歷該docx文檔(實質就是遍歷.zip壓縮包),經過索引找到對應的圖片,轉換成二進制數據,在拼接img標籤顯示格式爲base64的圖片數據。

轉換成xml:

    private $rels_xml;
    private $doc_xml;
    
    private function readZipPart($filename) {
        $zip = new ZipArchive();
        $_xml = 'word/document.xml';
        $_xml_rels = 'word/_rels/document.xml.rels';
        if (true === $zip->open($filename)) {
            if (($index = $zip->locateName($_xml)) !== false) {
                $xml = $zip->getFromIndex($index);
            }
            $zip->close();
        } else die('non zip file');
        
        if (true === $zip->open($filename)) {
            if (($index = $zip->locateName($_xml_rels)) !== false) {
                $xml_rels = $zip->getFromIndex($index);                    
            }
            $zip->close();
        } else die('non zip file');
        
        $this->doc_xml = new DOMDocument();
        $this->doc_xml->encoding = mb_detect_encoding($xml);
        $this->doc_xml->preserveWhiteSpace = false;
        $this->doc_xml->formatOutput = true;
        $this->doc_xml->loadXML($xml);
        $this->doc_xml->saveXML();
        
        $this->rels_xml = new DOMDocument();
        $this->rels_xml->encoding = mb_detect_encoding($xml);
        $this->rels_xml->preserveWhiteSpace = false;
        $this->rels_xml->formatOutput = true;
        $this->rels_xml->loadXML($xml_rels);
        $this->rels_xml->saveXML();
        
    }

 

判斷是否爲圖片節點:

if($paragraph->name === 'w:drawing') {
    (strstr($ts,'…封…') != false || strstr($ts,'…線…') != false) ? $t .= '' : $t .= $this->analysisDrawing($paragraph);
}

 

得到圖片索引:

    private function analysisDrawing(&$drawingXml) {
        while($drawingXml->read()) {
            if ($drawingXml->nodeType == XMLREADER::ELEMENT && $drawingXml->name === 'a:blip') {
                $rId = $drawingXml->getAttribute('r:embed');
                $rIdIndex = substr($rId,3);
                return $this->checkImageFormating($rIdIndex);
            }
        }
    }

 

顯示壓縮包中圖片文件:

    private function checkImageFormating($rIdIndex) {

        $imgname = 'word/media/image'.($rIdIndex-8);
        $zipfileName =  __DIR__.DIRECTORY_SEPARATOR.'b'.DIRECTORY_SEPARATOR.'test.docx';
        $zip=zip_open($zipfileName);
        while($zip_entry = zip_read($zip)) {//讀依次讀取包中的文件
            $file_name=zip_entry_name($zip_entry);//獲取zip中的文件名
            if(strstr($file_name,$imgname) != '' ) {
                $a = ($rIdIndex-8 < 10) ? mb_substr($file_name,mb_strlen($imgname,"utf-8"),1, 'utf-8') : '';    
                if($rIdIndex-8 < 10 && $a != '.') continue;
                if ($enter_zp = zip_entry_open($zip, $zip_entry, "r")) {  //讀取包中文件
                    $ext = pathinfo(zip_entry_name ($zip_entry),PATHINFO_EXTENSION);//獲取圖片文件擴展名
                    $content = zip_entry_read($zip_entry,zip_entry_filesize($zip_entry));//讀取文件二進制數據
                    return sprintf('<img src="data:image/%s;base64,%s">', $ext, base64_encode($content));//利用base64_encode函數轉換讀取到的二進制數據並輸入輸出到頁面中
                }
                zip_entry_close($zip_entry); //關閉zip中打開的項目 
            }
        }
        zip_close($zip);//關閉zip文件   
    }
相關文章
相關標籤/搜索