1<?php 2/** 3 * Action Plugin 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Greg BELLAMY <garlik.crx@gmail.com> [Gag] 7 * @author José Torrecilla <qky669@gmail.com> 8 * @version 0.11beta 9 */ 10// must be run within Dokuwiki 11if(!defined('DOKU_INC')) die(); 12if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN', DOKU_INC . 'lib/plugins/'); 13 14class action_plugin_odtplus2dw extends DokuWiki_Action_Plugin { 15 16 /** 17 * Registers a callback function for a given event 18 */ 19 function register(Doku_Event_Handler $controller) { 20 // File Parser hook 21 $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, '_parser', array()); 22 // Display form hook before the wiki page (on top); Maybe create a param to display the form after the page 23 $controller->register_hook('TPL_ACT_RENDER', 'BEFORE', $this, '_render', array()); 24 $controller->register_hook('TEMPLATE_PAGETOOLS_DISPLAY', 'BEFORE', $this, 'addbutton', array()); 25 //Add MENU_ITEMS_ASSEMBLY 26 $controller->register_hook('MENU_ITEMS_ASSEMBLY', 'AFTER', $this, 'addsvgbutton', array()); 27 } 28 29 /** 30 * Add 'import'-button to menu 31 * 32 * @param Doku_Event $event 33 * @param mixed $param not defined 34 */ 35 public function addsvgbutton(&$event, $param) { 36 global $conf; 37 38 if($event->data['view'] == 'page') { 39 array_push($event->data['items'],new \dokuwiki\plugin\odtplus2dw\MenuItem()); 40 } 41 } 42 43 44 /** 45 * Add 'import'-button to pagetools 46 * 47 * @param Doku_Event $event 48 * @param mixed $param not defined 49 */ 50 public function addbutton(&$event, $param) { 51 global $ID, $REV, $conf; 52 53 if($this->getConf('showimportbutton') && $event->data['view'] == 'main') { 54 $params = array('do' => 'odtplus2dw'); 55 if($REV) { 56 $params['rev'] = $REV; 57 } 58 59 $event->data['items'] = array_slice($event->data['items'], 0, -1, true) + 60 array('import_file' => 61 '<li>' 62 .'<a href='.wl($ID, $params).' class="action import_file" rel="nofollow" title="'.$this->getLang('import_button').'">' 63 .'<span>'.$this->getLang('import_button').'</span>' 64 .'</a>' 65 .'</li>') + 66 array_slice($event->data['items'], -1, 1, true); 67 } 68 } 69 70 function _render(&$event, $param) { 71 ### _render : displays the upload form in the pages according to authorized action 72 # INPUT : it's a dokuwiki event function 73 # OUTPUT : void 74 # DISPLAY : upload form 75 global $ID, $lang; 76 // Check if the current action is in the action allow table 77 if ( strpos( $this->getConf('formDisplayRule'), $event->data) === false ) return; 78 // Check if the page exists 79 if ( page_exists( $ID ) && $event->data != "odtplus2dw" ) return; 80 if ( page_exists( $ID ) ) echo p_render('xhtml',p_get_instructions( $this->getLang( 'formPageExistMessage' ) ), $info ); 81 // Check auth user can edit this page 82 if ( auth_quickaclcheck( $ID ) < AUTH_EDIT ) return; 83 // If all check is ok, display the form 84 $message = $this->getConf('formIntroMessage'); 85 if ( $message == 'default' ) $message = $this->getLang('formIntroMessage'); 86 if ($message) echo p_render('xhtml',p_get_instructions($message),$info); 87 // FIXME create the form with dokuwiki method ? 88 echo '<form method="post" action="" enctype="multipart/form-data"> 89 <fieldset> 90 <legend>'.$this->getLang('formLegend').'</legend> 91 <input type="hidden" name="MAX_FILE_SIZE" value="'.$this->getConf('formMaxFileSize').'"/> 92 <input type="hidden" name="do" value="odtplus2dw"/> 93 <input type="hidden" name="id" value="'.$ID.'"/> 94 <input type="file" name="userFile"/> 95 <input type="submit" value="'.$lang['btn_upload'].'"/> 96 </fieldset> 97 </form>'; 98 if ( $event->data == 'odtplus2dw' ) $event->preventDefault(); 99 } 100 101 function _parser(&$event, $param) { 102 ### _parser : check if a file migth be uploaded, then call the odtplus2dw converter 103 # INPUT : it's a dokuwiki event function 104 # OUTPUT : void 105 106 // Check action is odt2dw 107 if ( $event->data != 'odtplus2dw' ) return; 108 109 ###Preparation of the message renderer 110 //Set the debug lvl 111 $this->debug = $this->getConf( 'debugLvl' ); 112 //If used, open the logFile 113 if ( $this->debug >= 2 ) { 114 $this->logFile = $this->getConf( 'logFile' ); 115 if ( isset( $this->logFile ) ) if ( file_exists( dirname( $this->logFile ) ) || mkdir( dirname( $this->logFile ) ) ) { 116 if ( ! ( $this->logFileHandle = @fopen( $this->logFile, 'a' ) ) ) unset( $this->logFileHandle, $this->logFile ); 117 } else unset( $this->logFile ); 118 if ( ! isset( $this->logFileHandle ) ) $this->_msg( 'er_logFile' ); 119 } 120 ### 121 122 // Check upload file defined 123 $retour = false; 124 if ( $_FILES['userFile'] ) { 125 // If parse work, change action to defined one in conf/local.php file 126 $retour = $this->_odtplus2dw(); 127 # Delete temp file 128 $this->_purge_env(); 129 } 130 //if the file is correctly parsed, change the action to the action defined in the conf 131 //otherwise the action stay odt2dw -> the display form hook will be call by render trigger 132 if ( $retour === true ) { 133 $event->data = $this->getConf('parserPostDisplay'); 134 } else { 135 $event->preventDefault(); 136 } 137 138 ### Clear the message renderer 139 // Close the log file if used 140 if ( isset( $this->logFileHandle ) ) @fclose( $this->logFileHandle ); 141 ### 142 } 143 144 function _odtplus2dw() { 145 ### _odtplus2dw : Translate a supported file into dokuwiki syntax 146 # OUTPUT : 147 # * true -> process successfully finished 148 # * false -> something wrong; using _msg to display what's wrong 149 150 global $ID, $conf; 151 152 //Table use to convert urn to url -> without this, xslProc won't parse correctly 153 //Table corrigeant les attributs de la racine du fichier content.xml : urn -> url 154 $this->conversion = array( 155 "xmlns:office" => "http://openoffice.org/2000/office", 156 "xmlns:style" => "http://openoffice.org/2000/style", 157 "xmlns:text" => "http://openoffice.org/2000/text", 158 "xmlns:table" => "http://openoffice.org/2000/table", 159 "xmlns:draw" => "http://openoffice.org/2000/drawing", 160 "xmlns:fo" => "http://www.w3.org/1999/XSL/Format", 161 "xmlns:xlink" => "http://www.w3.org/1999/xlink", 162 "xmlns:dc" => "http://purl.org/dc/elements/1.1/", 163 "xmlns:meta" => "http://openoffice.org/2000/meta", 164 "xmlns:number" => "http://openoffice.org/2000/datastyle", 165 "xmlns:svg" => "http://www.w3.org/2000/svg", 166 "xmlns:chart" => "http://openoffice.org/2000/chart", 167 "xmlns:dr3d" => "http://openoffice.org/2000/dr3d", 168 "xmlns:math" => "http://www.w3.org/1998/Math/MathML", 169 "xmlns:form" => "http://openoffice.org/2000/form", 170 "xmlns:script" => "http://openoffice.org/2000/script", 171 "xmlns:config" => "http://openoffice.org/2001/config", 172 "xmlns:ooo" => "http://openoffice.org/2004/office", 173 "xmlns:ooow" => "http://openoffice.org/2004/writer", 174 "xmlns:oooc" => "http://openoffice.org/2004/calc", 175 "xmlns:dom" => "http://www.w3.org/2001/xml-events", 176 "xmlns:xforms" => "http://www.w3.org/2002/xforms", 177 "xmlns:xsd" => "http://www.w3.org/2001/XMLSchema", 178 "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance", 179 "xmlns:rpt" => "http://openoffice.org/2005/report", 180 "xmlns:of" => "urn:oasis:names:tc:opendocument:xmlns:of:1.2", 181 "xmlns:xhtml" => "http://www.w3.org/1999/xhtml", 182 "xmlns:grddl" => "http://www.w3.org/2003/g/data-view#", 183 "xmlns:tableooo" => "http://openoffice.org/2009/table", 184 "xmlns:css3t" => "http://www.w3.org/TR/css3-text/" 185 ); 186 // urn wont be/need to convert -- keep for further odt file version 187 // "xmlns:field" => "urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0", 188 //"xmlns:formx" => "urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0", 189 // CONSTANT : Content file extract from the odt file 190 $this->xmlFile = "content.xml"; 191 192 ### Check parameter ### 193 194 // Page receive content 195 if ( ! $this->pageName = $ID ) return $this->_msg('er_id'); 196 $this->nsName = getNS($this->pageName); 197 // Check right to change the page 198 if ( page_exists($ID) ) { 199 if ( auth_quickaclcheck($ID) < AUTH_EDIT ) return $this->_msg('er_acl_edit'); 200 } else { 201 if ( auth_quickaclcheck($ID) < AUTH_CREATE ) return $this->_msg('er_acl_create'); 202 } 203 204 // Check the file uploaded 205 if ( ! $this->_checkUploadFile() ) return $this->_msg('er_checkUploadResult'); 206 207 // Check the xslFile 208 if ( ! $this->getConf( 'parserXslFile' ) ) return $this->_msg('er_xslFile_notset'); 209 $this->xslFile = DOKU_PLUGIN.'odtplus2dw/'.$this->getConf('parserXslFile'); 210 if ( ! file_exists($this->xslFile) ) return $this->_msg('er_xslFile_exists'); 211 if ( ! is_file($this->xslFile) ) return $this->_msg('er_xslFile_isfile'); 212 213 // Class Control 214 if ( ! class_exists( "XSLTProcessor" ) ) return $this->_msg('er_class_xsltProcessor'); 215 if ( ! class_exists( "ZipArchive" ) ) return $this->_msg('er_class_zipArchive'); 216 if ( ! class_exists( "DOMDocument" ) ) return $this->_msg('er_class_domDocument'); 217 // Create instance of needed class 218 $this->XSLT = new XSLTProcessor; 219 $this->ZIP = new ZipArchive; 220 $this->XSL = new DOMDocument; 221 $this->XML = new DOMDocument; 222 223 // Load the xslFile 224 if ( ! ($this->XSL->load( $this->xslFile ) ) ) return $this->_msg('er_loadXsl'); 225 // Build the xsl processor 226 if ( ! $this->_set_xsltProcessor() ) return $this->_msg('er_xsltProc'); 227 // Extract content file from odt file 228 if ( ! $this->_unzip( $this->xmlFile ) ) return $this->_msg('er_file_unzip'); 229 // Load the xmlFile 230 if ( ! $this->XML->load($this->uploadDir.'/'.$this->xmlFile) ) return $this->_msg('er_loadXml'); 231 if ( ! $this->racine = $this->XML->getElementsByTagName('document-content')->item(0) ) return $this->_msg('er_invalidRoot'); 232 // Correction for urn bug 233 foreach ( $this->conversion as $attr => $value ) if ( $this->racine->hasAttribute($attr) ) $this->racine->setAttributeNS( "http://www.w3.org/2000/xmlns/", $attr, $value ); 234 // Transformation du fichier XML 235 $this->result = '====== '.basename($this->odtFileName,'.odt').' ====== 236'; 237 if ( $this->getConf('parserLinkToOriginalFile') && auth_quickaclcheck($ID) >= AUTH_UPLOAD ) $this->result .= '<sub>{{'.$this->userFileName.'|'.$this->getLang('parserOriginalFile').'}}</sub> 238 239'; 240 241 ### Parameters have been checked successfully ### 242 243 244 // Set specific time out to parse the odt file into dw syntax 245 set_time_limit( $this->getConf('parserCoreTimeOut') ); 246 // Parse the content - This is the CORE 247 if ( ! $tmp = html_entity_decode($this->XSLT->transformToDoc( $this->XML )->saveHTML(), ENT_COMPAT, 'UTF-8') ) return $this->_msg('er_transform'); 248 $this->result .= $tmp; 249 // Set the time out to default 250 set_time_limit(30); 251 // Extract and store image files from odt file to Dokuwiki mediaManager 252 $this->_parse_image(); 253 254 // Store the result 255 if ( ! $this->_apply_result() ) return $this->_msg('er_apply'); 256 257 return true; 258 } 259 260 function _msg( $message, $type=null, $force=false ) { 261 ### _msg : display message using the debugLvl value 262 # $message : mixed : 263 # * string : key for $this->getLang() function 264 # * array : 265 # $message[0] : string : key for $this->getLang() function 266 # $message[1] : string : additional information 267 # $type : integer : (check the dokuwiki msg function) 268 # * -1 : error message 269 # * 0 : normal message 270 # * 1 : info message 271 # if type == null, the first 3 char of the key define the message type 272 # * er_ : -1 273 # * ok_ : 1 274 # * otherwise : 0 275 # $force : boolean : force displaying the message without checking debugLvl 276 # OUTPUT : 277 # * true -> display a normal message 278 # * false -> display an error message 279 # DISPLAY : call dokuwiki msg function 280 if ( is_array( $message ) ) { 281 $output = $message[0]; 282 } else { 283 $output = $message; 284 } 285 // If output is empty, crash with error display; 286 if ( ! $output ) die( $this->getLang( 'er_msg_nomessage' ) ); 287 if ( is_null( $type ) ) { 288 $val = substr( $output, 0, strpos( $output, '_' )+1 ); 289 switch ($val) { 290 case 'er_' : 291 $err = -1; 292 break; 293 case 'ok_' : 294 $err = 1; 295 break; 296 default : 297 $err = 0; 298 } 299 } else { 300 if ( $type < -1 || $type > 1 ) return false; 301 $err = $type; 302 } 303 // Dev debugging mode; manually set to 4; this dirtily display some informations 304 if ( $this->debug > 3 ) echo '<p>message : '.$message.' |output : '.$output.' |val : '.$val.' |err : '.$err.'</p>'; 305 306 // Debug = 0 => No message 307 if ( !$force && $this->debug == 0 ) return ( $err == -1 ? false : true ); 308 309 // Debug < 3 => Only error message; If it s not an error message, message return true; 310 if ( !$force && $err != -1 && $this->debug < 3 ) return true; 311 // Otherwise display the message 312 $content = $output.' : '.$this->getLang( $output ).( is_array( $message ) ? ' : '.$message[1] : '' ); 313 msg( 'odtplus2dw : '.$content, $err ); 314 if ( isset( $this->logFileHandle ) ) fwrite( $this->logFileHandle, date(DATE_ATOM).':'.$_SERVER['REMOTE_USER'].':'.$content.' 315' ); 316 // If error message, return false 317 if ( $err == -1 ) return false; 318 // Otherwise return true; 319 return true; 320 } 321 322 323 324 function _checkUploadFile() { 325 ### _checkUploadFile : group all process about the uploadFile, like uploadStatus, file format, move it in a working directory, etc. ### 326 # OUTPUT : 327 # * true -> process successfully 328 # * false -> something wrong; using _msg to display what's wrong 329 // Check a file will be upload 330 if ( ! $_FILES['userFile'] ) return $this->_msg('er_file_miss'); 331 // Check the file status 332 if ( $_FILES['userFile']['error'] > 0 ) return $this->_msg( array( 'er_file_upload', $_FILES['userFile']['error'] ) ); 333 // Check the file has an authorized mimetype 334 if ( $this->getConf( 'parserMimeTypeAuthorized' ) != "" && strpos( $this->getConf( 'parserMimeTypeAuthorized' ), $_FILES['userFile']['type'] ) === false ) return $this->_msg( array( 'er_file_format', $_FILES['userFile']['type'] ) ); 335 336 // Create an unique temp work dir name 337 while ( file_exists( $this->uploadDir = $this->getConf( 'parserUploadDir' ).rand( 10000, 100000 ) ) ) {}; 338 // Create the directory 339 if ( ! mkdir( $this->uploadDir, 0777, true ) ) return $this->_msg( 'er_file_tmpDir' ); 340 // Chmod. Maybe not required, but we keep it beacause using soffice sometimes is not easy... 341 chmod( $this->uploadDir, 0777 ); 342 // Move the upload file into the work directory 343 $this->userFileName = $_FILES['userFile']['name']; 344 $this->userFile = $this->uploadDir.'/'.$this->userFileName; 345 if ( ! move_uploaded_file( $_FILES['userFile']['tmp_name'], $this->userFile ) ) return $this->_msg('er_file_getFromDownload'); 346 347 // Pandoc/SOffice support: Set odtFile/odtFileName to be the same as userFile/userFileName. 348 // Will change later if neccesary 349 $this->odtFileName = substr($this->userFileName, 0); 350 $this->odtFile = substr($this->userFile, 0); 351 352 // Add Pandoc support 353 if ( $this->getConf( 'parserMimeTypePandoc' ) != "" && strpos( $this->getConf( 'parserMimeTypePandoc' ), $_FILES['userFile']['type'] ) !== false ) { 354 355 $this->_prepareOdtFileName(); 356 357 $output = array(); 358 // Conversion to odt file 359 exec( 'pandoc -s -w odt -o "' . $this->odtFile . '" "' . $this->userFile . '"', $output, $return_var ); 360 } 361 362 // Add SOffice support 363 if ( $this->getConf( 'parserMimeTypeSOffice' ) != "" && strpos( $this->getConf( 'parserMimeTypeSOffice' ), $_FILES['userFile']['type'] ) !== false ) { 364 365 $this->_prepareOdtFileName(); 366 367 $output = array(); 368 // Conversion to odt file 369 exec( 'cd ' . $this->uploadDir . ' && sudo soffice --nofirststartwizard --headless --convert-to odt:"writer8" "' . $this->userFileName . '"', $output, $return_var ); 370 } 371 372 // All upload file checking are OK 373 return true; 374 } 375 376 function _prepareOdtFileName() { 377 // Change original extension to ".odt" 378 $info = pathinfo($this->userFile); 379 $this->odtFileName = $info['filename'] . '.odt'; 380 $this->odtFile = $this->uploadDir.'/'. $this->odtFileName; 381 } 382 383 function _purge_env() { 384 ### _purge_env : clean the system from temporary file ### 385 # OUTPUT : 386 # void 387 # Display some error message if something wrong in the delete process (might delete the file manually) 388 389 // Perhaps this would not be needed if use temp dir. 390 // No timeOut : the cleanning process wont be interrupted. 391 set_time_limit(0); 392 // use @ to catch the system error message 393 // If exists, delete the download file 394 if ( file_exists( $this->odtFile ) ) if ( ! @unlink( $this->odtFile ) ) $this->_msg( array( 'er_pg_file', $this->odtFile ) ); 395 if ( file_exists( $this->userFile ) ) if ( ! @unlink( $this->userFile ) ) $this->_msg( array( 'er_pg_file', $this->userFile ) ); 396 // Delete each file extracted for the uploaded file 397 if ( $this->file_extract ) foreach ($this->file_extract as $file) if ( file_exists( $file ) ) if ( ! @unlink( $file ) ) $this->_msg( array( 'er_pg_file', $file ) ); 398 // Delete each image than would be renamed and not moved to the wiki 399 if ( $this->file_import ) foreach ( $this->file_import as $file ) if ( file_exists( $this->uploadDir.'/'.$this->pictpath.'/'.$file ) ) if ( ! @unlink( $this->uploadDir.'/'.$this->pictpath.'/'.$file ) ) $this->_msg( array( 'er_pg_file', $this->uploadDir.'/'.$this->pictpath.'/'.$file ) ); 400 // Delete the Pictures directory 401 if ( file_exists( $this->uploadDir.'/'.$this->pictpath) ) if ( ! @rmdir( $this->uploadDir.'/'.$this->pictpath ) ) $this->_msg( array( 'er_pg_dir', $this->uploadDir.'/'.$this->pictpath ) ); 402 // Than delete the temporary directory 403 if ( file_exists( $this->uploadDir ) ) if ( ! @rmdir( $this->uploadDir ) ) $this->_msg( array( 'er_pg_dir', $this->uploadDir ) ); 404 // Set back default timeOut 405 set_time_limit(30); 406 } 407 408 function _set_xsltProcessor(){ 409 ### _set_xsltProcessor : set all xslt param regarding the dokuwiki plugin installed ### 410 # OUTPUT : 411 # * true -> process successfully 412 # * false -> something wrong; using _msg to display what's wrong 413 # _msg info report ( debugLvl >= 2 ) display message about active plugin 414 415 // Gag : I think it s a Nasty way to check plugin - must be rewriten but i don t know how 416 $tmp_plugin_lst = plugin_list(); 417 if ( ! $this->XSLT->importStylesheet( $this->XSL ) ) return $this->_msg('er_xslt_invalid'); 418 foreach ( array('numberedheadings') as $param ) if ( array_search( $param, $tmp_plugin_lst ) !== false ) { 419 if ( ! $this->XSLT->setParameter( '', $param, '1' ) ) return $this->_msg( array( 'inf_xslt_param', $param ), -1 ); 420 // _msg info report 421 $this->_msg( array( 'ok_infoPlugin', $param ), 1 ); 422 } 423 // 424 foreach ( array('subtable_message') as $lang_elt ) if ( ! $this->XSLT->setParameter( '', $lang_elt, $this->getLang('xsl_'.$lang_elt ) ) ) $this->_msg( array( 'inf_xslt_lang', $param ), 0 ); 425 return true; 426 } 427 428 function _apply_result() { 429 ### _apply_result : store the content in dokuwiki page and the attache file (img) in dokuwiki media 430 # OUTPUT : 431 # * true -> process successfully 432 # * false -> something wrong; using _msg to display what's wrong 433 global $INFO; 434 // Save the content in data/page 435 saveWikiText( $this->pageName, $this->result, $this->getLang( 'parserSummary' ).$this->userFileName ); 436 if ( ! page_exists($this->pageName) ) return $this->_msg('er_apply_content'); 437 // Check if the user could upload file (ACL : permission lvl 8) 438 if ( auth_quickaclcheck($ID) >= AUTH_UPLOAD ) { 439 // Import the image file in the mediaManager (data/media) 440 $destDir = mediaFN( $this->nsName ); 441 if ( ! ( file_exists( $destDir ) || mkdir( $destDir, 0777, true ) ) ) return $this->_msg( array( 'er_apply_dirCreate' ) ); 442 if ( $this->file_import ) foreach ( $this->file_import as $pict ) { 443 $destFile = mediaFN( $this->nsName.':'.$pict ); 444 list( $ext, $mime ) = mimetype( $this->uploadDir.'/'.$this->pictpath.'/'.$pict ); 445 if ( media_upload_finish($this->uploadDir.'/'.$this->pictpath.'/'.$pict, $destFile, $this->nsName, $mime, @file_exists($destFile), 'rename' ) != $this->nsName ) return $this->_msg( array( 'er_apply_img', $this->uploadDir.'/'.$this->pictpath.'/'.$pict ) ); 446 } 447 // Keep the original file (import the upload file in the mediaManager) 448 $destFile = mediaFN( $this->nsName.':'.$this->userFileName ); 449 list( $ext, $mime ) = mimetype( $this->uploadDir.'/'.$this->userFileName ); 450 if ( media_upload_finish($this->uploadDir.'/'.$this->userFileName, $destFile, $this->nsName, $mime, @file_exists($destFile), 'rename' ) != $this->nsName ) return $this->_msg( array( 'er_apply_file' ) ); 451 } else { 452 // If not allowed to upload, display a message. 453 $this->_msg( 'inf_acl_upload', 0, true ); 454 } 455 # Refresh info about the current page (see doku.php where $INFO is initiate) - Needed for edit or preview "parserPostDisplay" option 456 $INFO = pageinfo(); 457 return true; 458 } 459 460 function _parse_image() { 461 ### _parse_image : search dokuwiki img markup in $this->result than extract the img file and rename it to easier name ### 462 # OUTPUT : 463 # void 464 # using _msg to display each img file wont be process successfully 465 466 global $ID; 467 $imgs = array(); 468 if ( preg_match_all( '|{{((?:[^/}]+/)*[^/}]+)/([0-9a-zA-Z]+)(\.[a-z]+)(\?[0-9]+(?:x[0-9]+)?)?}}|', $this->result, $imgs, PREG_SET_ORDER ) ) { 469 if ( auth_quickaclcheck( $ID ) < AUTH_UPLOAD ) return $this->_msg( 'er_acl_upload' ); 470 $this->err['ok'] = array(); 471 foreach ( $imgs as $key => $value ) { 472 set_time_limit(20); 473 $this->pictpath = $value[1]; 474 $pict = $value[2].$value[3]; 475 $ext = $value[3]; 476 $other = $value[4]; 477 if ( $this->_unzip($this->pictpath.'/'.$pict) ) { 478 # Do not overwrite existing images 479 # Hash to see if files are identical, prevents multiple files with same content but different names in media manager 480 $newFileHash = hash_file('sha512', $this->uploadDir.'/'.$this->pictpath.'/'.$pict); 481 $newFileName = ''; 482 do { 483 $newFileName = noNS($this->pageName).'_image_'.$key.$ext; 484 $existingFile = mediaFN( $this->nsName.':'.$newFileName); 485 $key = $key + 1; 486 } while ( file_exists( $existingFile ) && hash_file('sha512', $existingFile) != $newFileHash ); 487 488 if ( rename( $this->uploadDir.'/'.$this->pictpath.'/'.$pict, $this->uploadDir.'/'.$this->pictpath.'/'.$newFileName ) ) { 489 $this->result = str_replace( '{{'.$this->pictpath.'/'.$pict.$other.'}}' , '{{'.$newFileName.$other.'}}' , $this->result ); 490 $this->file_import[] = $newFileName; 491 if ( $this->debug ) $this->err['ok'][] = $pict.' : '.$newFileName; 492 } else $this->err[$pict] = 'rename'; 493 } else $this->err[$pict] = 'unzip'; 494 } 495 } 496 if ( $this->err ) foreach ( $this->err as $key => $value ) { 497 switch ( $key ) { 498 case 'ok': 499 foreach ( $value as $msg ) $this->_msg( array( 'ok_img', $msg ) ); 500 break; 501 default : 502 // $value E ( rename, unzip) => er_img_rename, er_img_unzip 503 $this->_msg( array( 'er_img_'.$value, $key ) ); 504 } 505 } 506 } 507 508 function _unzip( $entrie ) { 509 ### _unzip : extract $entrie file from $this->odtFile to $this->uploadDir using $this->ZIP object instance of ZipArchive Class ### 510 # $entrie : string : fullFileName (with the internal path in the archive) 511 # OUTPUT : 512 # * true -> extraction ok 513 # * false -> something wrong; using _msg to display what's wrong 514 515 if ( ! $this->ZIP ) return $this->_msg('er_unzip_object'); 516 if ( ! file_exists( $this->odtFile ) ) return $this->_msg('er_unzip_nofile'); 517 if ( ! ( $this->ZIP->open( $this->odtFile ) === true ) ) return $this->_msg( 'er_unzip_open' ); 518 $res = $this->ZIP->extractTo( $this->uploadDir, $entrie ); 519 $this->ZIP->close(); 520 if ( ! $res ) return $this->_msg( array( 'er_unzip_error', $entrie ) ); 521 $this->file_extract[] = $this->uploadDir.'/'.$entrie; 522 return $this->_msg( array( 'ok_unzip', $entrie ) ); 523 } 524 525} 526