'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 '
Normal.dotm0100Microsoft 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|gif)/', 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;
}
}
?>