php - 如何在 Linux 上获取 Word 文档中的页数?

标签 php ms-word

我看到了这个问题PHP - Get number of pages in a Word document .我还需要确定给定 word 文件 (doc/docx) 的页数。我试图调查 phplivedocx/ZF(@hobodave 链接到原始帖子答案中的内容),但我在那里失去了手脚。我也不能使用任何外部网络服务(比如 DOC2PDF 站点,然后计算 PDF 版本中的页面,等等...)。

简单地说:是否有任何 php 代码(使用 ZF 或 PHP 中的任何其他代码,不包括 COM 对象或其他执行文件,例如“AbiWord”;我使用的是共享 Linux 服务器,没有 exec 或类似函数), 求word文件的页数?

编辑:即将支持的Word版本是Microsoft-Word 2003 & 2007。

最佳答案

获取 docx 文件的页数非常简单:

function get_num_pages_docx($filename)
{
    $zip = new ZipArchive();

    if($zip->open($filename) === true)
    {  
        if(($index = $zip->locateName('docProps/app.xml')) !== false)
        {
            $data = $zip->getFromIndex($index);
            $zip->close();

            $xml = new SimpleXMLElement($data);
            return $xml->Pages;
        }

        $zip->close();
    }

    return false;
}

对于 97-2003 格式,这当然具有挑战性,但绝不是不可能的。页数存储在文档的 SummaryInformation 部分,但由于文件的 OLE 格式,很难找到它。结构定义得非常彻底(虽然在我看来很糟糕)here更简单 here .我今天看了一个小时,但没看多远! (不是我习惯的抽象级别),但输出十六进制以更好地理解结构:

function get_num_pages_doc($filename) 
{
    $handle = fopen($filename, 'r');
    $line = @fread($handle, filesize($filename));

    echo '<div style="font-family: courier new;">';

        $hex = bin2hex($line);
        $hex_array = str_split($hex, 4);
        $i = 0;
        $line = 0;
        $collection = '';
        foreach($hex_array as $key => $string)
        {
            $collection .= hex_ascii($string);
            $i++;

            if($i == 1)
            {
                echo '<b>'.sprintf('%05X', $line).'0:</b> ';
            }

            echo strtoupper($string).' ';

            if($i == 8)
            {
                echo ' '.$collection.' <br />'."\n";
                $collection = '';
                $i = 0;

                $line += 1;
            }
        }

    echo '</div>';

    exit();
}

function hex_ascii($string, $html_safe = true)
{
    $return = '';

    $conv = array($string);
    if(strlen($string) > 2)
    {
        $conv = str_split($string, 2);
    }

    foreach($conv as $string)
    {
        $num = hexdec($string);

        $ascii = '.';
        if($num > 32)
        {   
            $ascii = unichr($num);
        }

        if($html_safe AND ($num == 62 OR $num == 60))
        {
            $return .= htmlentities($ascii);
        }
        else
        {
            $return .= $ascii;
        }
    }

    return $return;
}

function unichr($intval)
{
    return mb_convert_encoding(pack('n', $intval), 'UTF-8', 'UTF-16BE');
}

它将输出代码,您可以在其中找到以下部分:

007000: 0500 5300 7500 6D00 6D00 6100 7200 7900 ..S.u.m.m.a.r.y.
007010: 4900 6E00 6600 6F00 7200 6D00 6100 7400 I.n.f.o.r.m.a.t.
007020: 6900 6F00 6E00 0000 0000 0000 0000 0000 i.o.n...........
007030: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 

这将允许您查看引用信息,例如:

007040: 2800 0201 FFFF FFFF FFFF FFFF FFFF FFFF (...ÿÿÿÿÿÿÿÿÿÿÿÿ
007050: 0000 0000 0000 0000 0000 0000 0000 0000 ................
007060: 0000 0000 0000 0000 0000 0000 0000 0000 ................
007070: 0000 0000 2500 0000 0010 0000 0000 0000 ....%...........

这将允许您确定所描述的属性:

_ab = ("SummaryInformation") 
_cb = 0028
_mse = 02 (STGTY_STREAM) 
_bflags = 01 (DE_BLACK) 
_sidLeftSib = FFFF FFFF 
_sidRightSib = FFFF FFFF (none) 
_sidChild = FFFF FFFF (n/a for STGTY_STREAM) 
_clsid = 0000 0000 0000 0000 0000 0000 0000 0000 (n/a) 
_dwUserFlags = 0000 0000 (n/a) 
_time[0] = CreateTime = 0000 0000 0000 0000 (n/a) 
_time[1] = ModifyTime = 0000 0000 0000 0000 (n/a)
_startSect = 0000 0000 
_ulSize = 0000 1000 
_dptPropType = 0000 (n/a)

这将使您找到相关的代码部分,将其解压缩并获取页码。当然,这是我没有时间处理的难点,但应该能为您指明正确的方向。

M$ 并不容易!

关于php - 如何在 Linux 上获取 Word 文档中的页数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8986067/

相关文章:

php - 是否可以显示这样的表格?

php - PCRE正则表达式非连续重复

php - 如何在使用 MySQL 的子查询中执行 LEFT JOIN 两个表并从主查询中排除多行?

php - 如何将 MySQL 表转储到文件然后读取它并使用它代替数据库本身?

javascript - 如何在 MS Word 2013 中使用 String.replace() 方法而不弄乱空白段落和对象标识符?

Emacs - 如何避免或替换错误的字符编码?

php - 使用 PHP 重命名上传的文件,但保留扩展名

text - Word - 如何将文本粘贴到页面底部

excel - 从 Word 调用 Excel VBA

Word 中的 VBA : Programmatically add content control with a style