1<?php 2 3namespace dokuwiki\plugin\wordimport\docx; 4 5use splitbrain\PHPArchive\Zip; 6 7/** 8 * The main DOCX object 9 * 10 * This class is the main entry point for importing a DOCX file into DokuWiki. It handles extracting the 11 * document and offers access to its contents. 12 */ 13class DocX 14{ 15 /** @var string The temporary directory where the DOCX is extracted */ 16 protected $tmpdir; 17 /** @var Relationships Relationship references*/ 18 protected $relationships; 19 /** @var Numbering Numbering definitions for lists */ 20 protected $numbering; 21 /** @var Styles Style definitions */ 22 protected $styles; 23 /** @var Document The main document */ 24 protected $document; 25 /** @var string|null The page id to which this docx is imported */ 26 protected $pageId; 27 /** @var array The plugin configuration */ 28 protected $config; 29 30 /** 31 * Create a new DOCX object 32 * 33 * @param string $docx path to the DOCX file 34 * @param array $config the plugin configuration 35 */ 36 public function __construct(string $docx, array $config) 37 { 38 $zip = new Zip(); 39 $zip->open($docx); 40 41 $this->tmpdir = io_mktmpdir(); 42 $zip->extract($this->tmpdir); 43 $zip->close(); 44 45 $this->config = $config; 46 } 47 48 /** 49 * Import the DOCX into DokuWiki 50 * 51 * @param string $pageid the page id to import the document into 52 * @throws \Exception 53 */ 54 public function import($pageid) 55 { 56 if (auth_quickaclcheck(getNS($pageid) . ':*') < AUTH_DELETE) { 57 throw new \Exception('You do not have enough permission to import into this namespace'); 58 } 59 60 $this->pageId = $pageid; 61 if (checklock($pageid)) throw new \Exception('page is currently locked'); 62 lock($pageid); 63 64 $doc = $this->getDocument(); 65 saveWikiText($pageid, (string)$doc, 'Imported from DOCX'); 66 67 unlock($pageid); 68 } 69 70 /** 71 * Parse and access the document 72 * 73 * @return Document 74 */ 75 public function getDocument(): Document 76 { 77 if (!$this->document) $this->document = new Document($this); 78 return $this->document; 79 } 80 81 /** 82 * Parse and access the list number definitions 83 * 84 * @return Numbering 85 * @internal 86 */ 87 public function getNumbering(): Numbering 88 { 89 if (!$this->numbering) $this->numbering = new Numbering($this); 90 return $this->numbering; 91 } 92 93 /** 94 * Parse and access the relationships 95 * 96 * @return Relationships 97 * @internal 98 */ 99 public function getRelationships(): Relationships 100 { 101 if (!$this->relationships) $this->relationships = new Relationships($this); 102 return $this->relationships; 103 } 104 105 /** 106 * Parse and access the style information 107 * 108 * @return Styles 109 * @internal 110 */ 111 public function getStyles(): Styles 112 { 113 if (!$this->styles) $this->styles = new Styles($this); 114 return $this->styles; 115 } 116 117 /** 118 * The page id to which this docx is imported. Used for media imports 119 * 120 * Important: this will return null if this is not called within a import process 121 * 122 * @return string|null 123 * @internal 124 */ 125 public function getPageId(): ?string 126 { 127 return $this->pageId; 128 } 129 130 /** 131 * Load a file from the extracted docx 132 * 133 * @param string $file document relative path to the file to load 134 * @return \SimpleXMLElement 135 * @throws \Exception when the file does not exist 136 * @internal 137 */ 138 public function loadXMLFile($file) 139 { 140 $file = $this->getFilePath($file); 141 return simplexml_load_file($file); 142 } 143 144 /** 145 * Get the full path to a file within the doc 146 * 147 * @param string $relative document relative path 148 * @return string 149 * @throws \Exception when the file does not exist 150 * @internal 151 */ 152 public function getFilePath($relative): string 153 { 154 $file = $this->tmpdir . '/' . $relative; 155 156 if (!file_exists($file)) { 157 throw new \Exception('File not found: ' . $file); 158 } 159 160 return $file; 161 } 162 163 /** 164 * Get a configuration value 165 * 166 * @param string $key 167 * @param mixed $default default value if the key is not set 168 * @return mixed 169 * @internal 170 */ 171 public function getConf($key, $default = null) 172 { 173 return $this->config[$key] ?? $default; 174 } 175 176 /** 177 * Cleanup the temporary directory 178 */ 179 public function __destruct() 180 { 181 io_rmdir($this->tmpdir, true); 182 if ($this->pageId) unlock($this->pageId); 183 } 184} 185