Word2007.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. <?php
  2. /**
  3. * This file is part of PHPWord - A pure PHP library for reading and writing
  4. * word processing documents.
  5. *
  6. * PHPWord is free software distributed under the terms of the GNU Lesser
  7. * General Public License version 3 as published by the Free Software Foundation.
  8. *
  9. * For the full copyright and license information, please read the LICENSE
  10. * file that was distributed with this source code. For the full list of
  11. * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
  12. *
  13. * @see https://github.com/PHPOffice/PHPWord
  14. * @copyright 2010-2018 PHPWord contributors
  15. * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
  16. */
  17. namespace PhpOffice\PhpWord\Reader;
  18. use PhpOffice\PhpWord\PhpWord;
  19. use PhpOffice\PhpWord\Shared\XMLReader;
  20. use PhpOffice\PhpWord\Shared\ZipArchive;
  21. /**
  22. * Reader for Word2007
  23. *
  24. * @since 0.8.0
  25. * @todo watermark, checkbox, toc
  26. * @todo Partly done: image, object
  27. */
  28. class Word2007 extends AbstractReader implements ReaderInterface
  29. {
  30. /**
  31. * Loads PhpWord from file
  32. *
  33. * @param string $docFile
  34. * @return \PhpOffice\PhpWord\PhpWord
  35. */
  36. public function load($docFile)
  37. {
  38. $phpWord = new PhpWord();
  39. $relationships = $this->readRelationships($docFile);
  40. $steps = array(
  41. array('stepPart' => 'document', 'stepItems' => array(
  42. 'styles' => 'Styles',
  43. 'numbering' => 'Numbering',
  44. )),
  45. array('stepPart' => 'main', 'stepItems' => array(
  46. 'officeDocument' => 'Document',
  47. 'core-properties' => 'DocPropsCore',
  48. 'extended-properties' => 'DocPropsApp',
  49. 'custom-properties' => 'DocPropsCustom',
  50. )),
  51. array('stepPart' => 'document', 'stepItems' => array(
  52. 'endnotes' => 'Endnotes',
  53. 'footnotes' => 'Footnotes',
  54. 'settings' => 'Settings',
  55. )),
  56. );
  57. foreach ($steps as $step) {
  58. $stepPart = $step['stepPart'];
  59. $stepItems = $step['stepItems'];
  60. if (!isset($relationships[$stepPart])) {
  61. continue;
  62. }
  63. foreach ($relationships[$stepPart] as $relItem) {
  64. $relType = $relItem['type'];
  65. if (isset($stepItems[$relType])) {
  66. $partName = $stepItems[$relType];
  67. $xmlFile = $relItem['target'];
  68. $this->readPart($phpWord, $relationships, $partName, $docFile, $xmlFile);
  69. }
  70. }
  71. }
  72. return $phpWord;
  73. }
  74. /**
  75. * Read document part.
  76. *
  77. * @param \PhpOffice\PhpWord\PhpWord $phpWord
  78. * @param array $relationships
  79. * @param string $partName
  80. * @param string $docFile
  81. * @param string $xmlFile
  82. */
  83. private function readPart(PhpWord $phpWord, $relationships, $partName, $docFile, $xmlFile)
  84. {
  85. $partClass = "PhpOffice\\PhpWord\\Reader\\Word2007\\{$partName}";
  86. if (class_exists($partClass)) {
  87. /** @var \PhpOffice\PhpWord\Reader\Word2007\AbstractPart $part Type hint */
  88. $part = new $partClass($docFile, $xmlFile);
  89. $part->setRels($relationships);
  90. $part->read($phpWord);
  91. }
  92. }
  93. /**
  94. * Read all relationship files
  95. *
  96. * @param string $docFile
  97. * @return array
  98. */
  99. private function readRelationships($docFile)
  100. {
  101. $relationships = array();
  102. // _rels/.rels
  103. $relationships['main'] = $this->getRels($docFile, '_rels/.rels');
  104. // word/_rels/*.xml.rels
  105. $wordRelsPath = 'word/_rels/';
  106. $zip = new ZipArchive();
  107. if ($zip->open($docFile) === true) {
  108. for ($i = 0; $i < $zip->numFiles; $i++) {
  109. $xmlFile = $zip->getNameIndex($i);
  110. if ((substr($xmlFile, 0, strlen($wordRelsPath))) == $wordRelsPath && (substr($xmlFile, -1)) != '/') {
  111. $docPart = str_replace('.xml.rels', '', str_replace($wordRelsPath, '', $xmlFile));
  112. $relationships[$docPart] = $this->getRels($docFile, $xmlFile, 'word/');
  113. }
  114. }
  115. $zip->close();
  116. }
  117. return $relationships;
  118. }
  119. /**
  120. * Get relationship array
  121. *
  122. * @param string $docFile
  123. * @param string $xmlFile
  124. * @param string $targetPrefix
  125. * @return array
  126. */
  127. private function getRels($docFile, $xmlFile, $targetPrefix = '')
  128. {
  129. $metaPrefix = 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/';
  130. $officePrefix = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/';
  131. $rels = array();
  132. $xmlReader = new XMLReader();
  133. $xmlReader->getDomFromZip($docFile, $xmlFile);
  134. $nodes = $xmlReader->getElements('*');
  135. foreach ($nodes as $node) {
  136. $rId = $xmlReader->getAttribute('Id', $node);
  137. $type = $xmlReader->getAttribute('Type', $node);
  138. $target = $xmlReader->getAttribute('Target', $node);
  139. $mode = $xmlReader->getAttribute('TargetMode', $node);
  140. // Remove URL prefixes from $type to make it easier to read
  141. $type = str_replace($metaPrefix, '', $type);
  142. $type = str_replace($officePrefix, '', $type);
  143. $docPart = str_replace('.xml', '', $target);
  144. // Do not add prefix to link source
  145. if ($type != 'hyperlink' && $mode != 'External') {
  146. $target = $targetPrefix . $target;
  147. }
  148. // Push to return array
  149. $rels[$rId] = array('type' => $type, 'target' => $target, 'docPart' => $docPart, 'targetMode' => $mode);
  150. }
  151. ksort($rels);
  152. return $rels;
  153. }
  154. }