Mini Kabibi Habibi
<?php
/**
* This file is part of PHPWord - A pure PHP library for reading and writing
* word processing documents.
*
* PHPWord is free software distributed under the terms of the GNU Lesser
* General Public License version 3 as published by the Free Software Foundation.
*
* For the full copyright and license information, please read the LICENSE
* file that was distributed with this source code. For the full list of
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
*
* @see https://github.com/PHPOffice/PHPWord
*
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
*/
namespace PhpOffice\PhpWord\Reader;
use Exception;
use PhpOffice\PhpWord\Element\AbstractElement;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Reader\Word2007\AbstractPart;
use PhpOffice\PhpWord\Shared\XMLReader;
use PhpOffice\PhpWord\Shared\ZipArchive;
/**
* Reader for Word2007.
*
* @since 0.8.0
*
* @todo watermark, checkbox, toc
* @todo Partly done: image, object
*/
class Word2007 extends AbstractReader implements ReaderInterface
{
/**
* Loads PhpWord from file.
*
* @param string $docFile
*
* @return \PhpOffice\PhpWord\PhpWord
*/
public function load($docFile)
{
$phpWord = new PhpWord();
$relationships = $this->readRelationships($docFile);
$commentRefs = [];
$steps = [
[
'stepPart' => 'document',
'stepItems' => [
'styles' => 'Styles',
'numbering' => 'Numbering',
],
],
[
'stepPart' => 'main',
'stepItems' => [
'officeDocument' => 'Document',
'core-properties' => 'DocPropsCore',
'extended-properties' => 'DocPropsApp',
'custom-properties' => 'DocPropsCustom',
],
],
[
'stepPart' => 'document',
'stepItems' => [
'endnotes' => 'Endnotes',
'footnotes' => 'Footnotes',
'settings' => 'Settings',
'comments' => 'Comments',
],
],
];
foreach ($steps as $step) {
$stepPart = $step['stepPart'];
$stepItems = $step['stepItems'];
if (!isset($relationships[$stepPart])) {
continue;
}
foreach ($relationships[$stepPart] as $relItem) {
$relType = $relItem['type'];
if (isset($stepItems[$relType])) {
$partName = $stepItems[$relType];
$xmlFile = $relItem['target'];
$part = $this->readPart($phpWord, $relationships, $commentRefs, $partName, $docFile, $xmlFile);
$commentRefs = $part->getCommentReferences();
}
}
}
return $phpWord;
}
/**
* Read document part.
*
* @param array<string, array<string, null|AbstractElement>> $commentRefs
*/
private function readPart(PhpWord $phpWord, array $relationships, array $commentRefs, string $partName, string $docFile, string $xmlFile): AbstractPart
{
$partClass = "PhpOffice\\PhpWord\\Reader\\Word2007\\{$partName}";
if (!class_exists($partClass)) {
throw new Exception(sprintf('The part "%s" doesn\'t exist', $partClass));
}
/** @var AbstractPart $part Type hint */
$part = new $partClass($docFile, $xmlFile);
$part->setImageLoading($this->hasImageLoading());
$part->setRels($relationships);
$part->setCommentReferences($commentRefs);
$part->read($phpWord);
return $part;
}
/**
* Read all relationship files.
*
* @param string $docFile
*
* @return array
*/
private function readRelationships($docFile)
{
$relationships = [];
// _rels/.rels
$relationships['main'] = $this->getRels($docFile, '_rels/.rels');
// word/_rels/*.xml.rels
$wordRelsPath = 'word/_rels/';
$zip = new ZipArchive();
if ($zip->open($docFile) === true) {
for ($i = 0; $i < $zip->numFiles; ++$i) {
$xmlFile = $zip->getNameIndex($i);
if ((substr($xmlFile, 0, strlen($wordRelsPath))) == $wordRelsPath && (substr($xmlFile, -1)) != '/') {
$docPart = str_replace('.xml.rels', '', str_replace($wordRelsPath, '', $xmlFile));
$relationships[$docPart] = $this->getRels($docFile, $xmlFile, 'word/');
}
}
$zip->close();
}
return $relationships;
}
/**
* Get relationship array.
*
* @param string $docFile
* @param string $xmlFile
* @param string $targetPrefix
*
* @return array
*/
private function getRels($docFile, $xmlFile, $targetPrefix = '')
{
$metaPrefix = 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/';
$officePrefix = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/';
$rels = [];
$xmlReader = new XMLReader();
$xmlReader->getDomFromZip($docFile, $xmlFile);
$nodes = $xmlReader->getElements('*');
foreach ($nodes as $node) {
$rId = $xmlReader->getAttribute('Id', $node);
$type = $xmlReader->getAttribute('Type', $node);
$target = $xmlReader->getAttribute('Target', $node);
$mode = $xmlReader->getAttribute('TargetMode', $node);
// Remove URL prefixes from $type to make it easier to read
$type = str_replace($metaPrefix, '', $type);
$type = str_replace($officePrefix, '', $type);
$docPart = str_replace('.xml', '', $target);
// Do not add prefix to link source
if ($type != 'hyperlink' && $mode != 'External') {
$target = $targetPrefix . $target;
}
// Push to return array
$rels[$rId] = ['type' => $type, 'target' => $target, 'docPart' => $docPart, 'targetMode' => $mode];
}
ksort($rels);
return $rels;
}
}