'Macros disponibles :', 'style' => array( 'bold' => true, 'font-size' => 16 ) ); foreach($dataset as $macro => $infos) { $rows[] = array( 'content' => ($infos['type']=='list') ? '{{#'.$macro.'}}{{/'.$macro.'}} : '.$infos['desc'] : '{{'.$macro.'}} : '.$infos['desc'] ); } $temp_file = tempnam(sys_get_temp_dir(), mt_rand(0,10000)); self::write($temp_file, $rows); $stream = file_get_contents($temp_file); unlink($temp_file); return $stream; } /** ROOT **/ //Fichier [Content_Types].xml public static function content_types(){ return ' '; } /** DOCPROPS **/ //Fichier docProps/app.xml public static function app(){ return ' 0100Microsoft Office Word011falseTitre1false0falsefalse16.0000'; } //Fichier docProps/core.xml public static function core(){ global $myUser; return ' '.$myUser->fullName().''.$myUser->fullName().'1'.date('Y-m-d').'T'.date('H:i:s').'Z'.''.date('Y-m-d').'T'.date('H:i:s').'Z'.''; } /** _RELS **/ //Fichier _rels/.rels public static function single_rels(){ return ' '; } /** WORD **/ //Fichier word/_rels/document.xml.rels public static function word_rels(){ return ' '; } //Fichier word/webSettings.xml public static function web_settings(){ return ' '; } //Fichier word/settings.xml public static function settings(){ return ' '; } //Fichier word/fontTable.xml public static function font_table(){ return ' '; } //créée le document d'exemple public static function document($rows){ $stream = ' '; foreach($rows as $row){ $stream .= ''; if(isset($row['style'])) { $stream .= ''; foreach ($row['style'] as $property => $value) { $stream .= self::custom_style_map($property, $value); } $stream .= ''; } $stream .= ''. htmlspecialchars($row['content'], ENT_COMPAT).''; $stream .= ''; } $stream .= ''; return $stream; } //Retourne les différentes balises de style public static function custom_style_map($property=null, $value=null){ $stdFontSize = 22; //11pt * 2 $stdColor = '000000'; $stdHighlight = 'none'; $stdHighlightColors= array('black','blue','cyan','green','magenta','red','yellow','white','darkBlue','darkCyan','darkGreen','darkMagenta','darkRed','darkYellow','darkGray','lightGray'); $basic = array( 'bold' => array('tag'=>''), 'italic' => array('tag'=>''), 'underline' => array('tag'=>''), 'strike' => array('tag'=>''), 'caps' => array('tag'=>''), ); if(isset($value)){ $advanced = array( 'font-size' => array('tag'=>''), 'color' => array('tag'=>''), 'highlight' => array('tag'=>'') ); } $styles = array_merge($basic, $advanced); return isset($property) && isset($styles[$property]) ? $styles[$property]['tag'] : ''; } //Crée un fichier Word (format .docx) au chemin //$path indiqué avec les données $rows fournies //en paramètres /** Tableau de données attendu : * $rows = array( * 0 => array( * 'content' => 'Macros disponibles :', * 'style' => array( * 'bold' => true, * 'font-size' => 16 * ) * ), * 1 => array( * 'content' => '[programme.date]' * ), * 2 => array( * 'content' => '[programme.heure]' * ) * ); * * Chaque entrée dans $rows correspond à une ligne (paragraphe) sur le fichier **/ public static function write($path, $rows){ $docx = new ZipArchive(); if(file_exists($path)) unlink($path); $docx->open($path, ZipArchive::CREATE); //root $docx->addFromString('[Content_Types].xml', self::content_types()); //_rels folder $docx->addFromString('_rels/.rels', self::single_rels()); //docProps folder $docx->addFromString('docProps/app.xml', self::app()); $docx->addFromString('docProps/core.xml', self::core()); //word folder $docx->addFromString('word/_rels/document.xml.rels', self::word_rels()); $docx->addFromString('word/document.xml', self::document($rows)); $docx->addFromString('word/fontTable.xml', self::font_table()); $docx->addFromString('word/settings.xml', self::settings()); $docx->addFromString('word/webSettings.xml', self::web_settings()); $docx->close(); } public function parse($filePath){ $this->zip = new ZipArchive(); $res = $this->zip->open($filePath); if($res !== TRUE) throw new Exception('Impossible d\'ouvrir le ZIP, code:' . $res); $this->body = self::strip($this->zip->getFromName('word/document.xml')); $this->footer = self::strip($this->zip->getFromName('word/footer1.xml')); $this->header = self::strip($this->zip->getFromName('word/header1.xml')); $this->relationships = $this->zip->getFromName('word/_rels/document.xml.rels'); } public function add_image($tag, $img, $return=false){ //Unité utilisé en OOXML, 1px = 9525 EMU $emu = 9525; $pathParts = explode(SLASH, $img); $imgParts = explode('.', end($pathParts)); preg_match('/(jpg|jpeg|png)/', end($imgParts), $ext); $ext = $ext[0]; $imgParts[array_search(end($imgParts), $imgParts)] = $ext; $cType = in_array($ext, array('jpg', 'jpeg')) ? 'jpeg' : $ext; $pathParts[array_search(end($pathParts), $pathParts)] = implode('.', $imgParts); $imgUrl = implode(SLASH, $pathParts); $img = strpos($imgUrl, __ROOT__) !== false ? $img : __ROOT__.$imgUrl; //Récupération taille image list($width, $height) = getimagesize($img); $mimeTypes = $this->zip->getFromName('[Content_Types].xml', 0, ZipArchive::OVERWRITE); if(strrpos($mimeTypes, '') === false) { $mimeTypes = str_replace('', '', $mimeTypes); // $mimeTypes = str_replace('', '', $mimeTypes); $this->zip->addFromString('[Content_Types].xml', $mimeTypes); } $i = 100; $uid = 'img'.$i; while(strpos($this->relationships, 'Id="'.$uid.'"') !== false){ $i++; $uid = 'img'.$i; } $this->zip->addFile($img, 'word/media/'.$uid.'.'.$ext); $rel = ''; $this->relationships = str_replace('',$rel.'',$this->relationships); $xmlPic = ''; $this->body = str_replace('{{'.$tag.'}}',$xmlPic, $this->body); if($return){ $datas['picture'] = $xmlPic; $datas['cType'] = $mimeTypes; return $datas; } } //crée le document final avec les tags remplacés public static function from_template($source, $data, $return){ $destination = File::dir().'tmp'.SLASH.'template.'.time().'-'.rand(0,100).'.docx'; $source = File::dir().$source; copy($source,$destination); $docx = new self(); $docx->parse($destination); foreach($data as $tag => $value){ if(is_array($value)){ $docx->body = preg_replace_callback('#\{\{\#'.$tag.'\}\}(.*)\{\{\/'.$tag.'\}\}#si', function ($match) use($value, $docx) { $content = ''; foreach($value as $line){ $bloc = $match[1]; foreach($line as $subTag=>$subValue){ if(substr($subValue,0,2)=='::' && strpos($bloc, '{{'.$subTag.'}}') !== false) { $picDatas = $docx->add_image($subTag, substr($subValue,2), true); $bloc = str_replace('{{'.$subTag.'}}',$picDatas['picture'],$bloc); continue; } $subValue = self::convert_text_format($subValue); $bloc = str_replace('{{'.$subTag.'}}',$subValue,$bloc); } $content .=$bloc; } return $content; },$docx->body); continue; } if(substr($value,0,2)=='::'){ $docx->add_image($tag, substr($value,2)); continue; } $value = self::convert_text_format($value); $docx->body = str_replace('{{'.$tag.'}}',$value,$docx->body); $docx->footer = str_replace('{{'.$tag.'}}',$value,$docx->footer); $docx->header = str_replace('{{'.$tag.'}}',$value,$docx->header); } //conditions - if $ifRegex = '/\{\{\#([^\/\:\#}]*)\}\}(.*?)\{\{\/\1\}\}/is'; $docx->body = preg_replace_callback($ifRegex,function($matches) use ($data) { $key = $matches[1]; $docx->body = $matches[2]; return !isset($data[$key]) || (!is_array($data[$key]) && empty($data[$key])) || (is_array($data[$key]) && count($data[$key])==0) ?'':$docx->body; },$docx->body); //conditions - else $elseRegex = '/\{\{\^([^\/\:\#}]*)\}\}(.*?)\{\{\/\1\}\}/is'; $docx->body = preg_replace_callback($elseRegex,function($matches) use ($data) { $key = $matches[1]; $docx->body = $matches[2]; return (isset($data[$key]) && !is_array($data[$key]) && !empty($data[$key])) || (is_array($data[$key]) && count($data[$key])>0) ?'':$docx->body; },$docx->body); $docx->save(); $docx->close(); if($return!='stream') return $destination; $stream = file_get_contents($destination); unlink($destination); return $stream; } public static function convert_text_format($value){ //Remplace les

et les
par les w:br word $value = str_replace(array('
','

','

','
    '),'',$value); //todo ameliorable $value = str_replace(array('
  • '),' - ',$value); $value = str_replace(array('
  • '),'',$value); $value = str_replace('
','',$value); //todo - $value = preg_replace('|([^<]*)|is', '$1', $value); //Remplace les & par des & $value = str_replace(array('&'), array('&'), $value); //remplace les balises non word (ne commencant pas par ]*)>|is', '<$1>', $value); return $value; } //Ajoute au fichier les différentes modifications effectuées public function save(){ $this->zip->addFromString('word/document.xml', $this->body); if(!empty($this->header)) $this->zip->addFromString('word/header1.xml', $this->header); if(!empty($this->footer)) $this->zip->addFromString('word/footer1.xml', $this->footer); $this->zip->addFromString('word/_rels/document.xml.rels', $this->relationships); } //Ferme le fichier public function close(){ $this->zip->close(); } public static function strip($content){ $content = preg_replace_callback( '#\{\{([^\]]+)\}\}#U', function ($match) { return strip_tags($match[0]); }, $content ); return $content; } } ?>