modele=$modele; $structure=json_decode(json_encode((array)simplexml_load_file($modele)),1); // nettoyage de l'attribut du tag de base après récupération du type $this->type=$structure['@attributes']['type']; // la cle de tri est l'attribut de cle, sinon le premier tag de type texte $this->cle=$structure['@attributes']['cle']; // dupliquer la structure dans le contenu $this->contenu=$structure; unset($this->contenu['@attributes']); foreach($this->contenu as $cle => $valeur){ if(empty($this->cle) && $valeur['@attributes']['type']=="text"){ $this->cle =$cle; } $this->contenu[$cle]['contenu']=""; } $this->hydrate=false; $this->messages=array(); //print_r($this->contenu); } // fonction de lecture d'un xml // reçoit le nom, et va récupérer // le xml grace à la constante d'adresse du dossier // dans le fichier de configuration public function lire_xml($fichier){ $this->fichier=$fichier; $this->fichier_seul=fichier_seul($fichier); $tempcontenu=json_decode(json_encode((array)simplexml_load_file($fichier,'SimpleXMLElement', LIBXML_NOCDATA)),1); unset($tempcontenu['@attributes']); // transformation éventuelle de l'array pour complaire à la structure // hydrater la structure par le contenu foreach($this->contenu as $cle => $valeur){ if(isset($tempcontenu[$cle])){ $this->contenu[$cle]['contenu']=$tempcontenu[$cle]; // supprimer cette clé du contenu // pour pouvoir dans un deuxième temps // ajouter les contenus éventuellement ajoutés librement // sans référence dans la définition du xml unset($tempcontenu[$cle]); } else { $this->contenu[$cle]['contenu']=""; } } // ajouter les champs trouvé hors définition dans le contenu // par exemple contenu du truc foreach($tempcontenu as $cle => $valeur){ $this->contenu[$cle]['@attributes']['type']='unknow'; $this->contenu[$cle]['@attributes']['titre']=$cle; if(is_array($tempcontenu[$cle])){ foreach($tempcontenu[$cle] as $ar_item){ $this->contenu[$cle]['contenu'][]=$ar_item; } } else { $this->contenu[$cle]['contenu']=$tempcontenu[$cle]; } } $this->hydrate=true; } //sur base de la structure de $contenu, écrit le formulaire public function ecrit_xml(){ $doc = new DOMDocument(); $doc->formatOutput = true; $doc->encoding = "UTF-8"; $item = $doc->createElement('item'); $item->setAttribute('type', $this->type); foreach($this->contenu as $tag => $contenu){ // print_r($contenu); if(is_array($contenu['contenu'])){ // type "multiple", prendre chaque item pour le rentrer foreach($contenu['contenu'] as $e){ $elem = $doc->createElement( $tag ); $ct = $elem->ownerDocument->createCDATASection($e); $elem->appendChild($ct); $item->appendChild( $elem ); } } else { // contenu unique, créer un noeud if($contenu['contenu']!=""){ $elem = $doc->createElement( $tag ); $ct = $elem->ownerDocument->createCDATASection($contenu['contenu']); $elem->appendChild($ct); $item->appendChild( $elem ); } } } $doc->appendChild( $item ); fix_exists_dir(CHEMIN.DOSSIER_XML); $r=$doc->save($this->fichier); if($r==true){ $this->messages[]="enregistrement réussi de ".$this->fichier; } else { $this->messages[]="échec de l'enregistrement de ".$this->fichier; } } // renvoie tout le contenu dans un array public function get_contenu(){ return $this->contenu; } // renvoie tout le contenu dans un array public function get_contenu_simple(){ $retour=array(); foreach ($this->contenu as $champ => $contenu){ if (!$this->is_tag_empty($champ)){ $retour[$champ]=$this->get($champ); } } return $retour; } // renvoie le contenu dans un array, moins une exclude list public function get_partial_contenu($exclus=array()){ $base_contenu =$this->contenu; if(is_array($exclus)){ foreach($exclus as $tag){ unset($base_contenu[$tag]); } } else { unset($base_contenu[$exclus]); } return $base_contenu; } public function get_liste_pour_attribut($attribut,$valeur,$exclude){ $retour=array(); foreach($this->contenu as $tag => $contenu){ //print_r($contenu['@attributes']); if(isset($contenu['@attributes'][$attribut]) && !in_array($tag,$exclude)){ if($contenu['@attributes'][$attribut]==$valeur){ $retour[]=$tag; } } } return $retour; } // renvoir le contenu total d'un tag public function get_contenu_tag($tag){ //$retour=$this->contenu[$tag]["@attributes"]; $this->contenu[$tag]; //return $retour; } public function get_tag_attribute($tag,$attribute,$defaut=""){ //print_r($this->contenu[$tag]['@attributes']); if(isset($this->contenu[$tag]['@attributes'][$attribute])){ return $this->contenu[$tag]['@attributes'][$attribute]; //echo "il y a attribut"; } else { return $defaut; } //return $retour; } // renvoie le contenu d'un tag // avec filtrage éventuel public function get($tag, $defaut="", $filtrage=false){ $retour=""; if(isset($this->contenu[$tag])){ // attention un tag peut être présent mais vide // dans ce cas il se présente en array if(!is_array($this->contenu[$tag]['contenu'])){ $retour=$this->contenu[$tag]['contenu']; } else { if(count($this->contenu[$tag]['contenu'])){ $retour = $this->contenu[$tag]['contenu']; } } } if($retour==""){ return $defaut; } else { // voir si le filtrage s'applique // si on est face à un array, appliquer le filtre sur chaque élément return $retour; } } // renvoie le contenu du tag en un array public function get_tag_array($tag){ $contenu=$this->contenu[$tag]['contenu']; if(is_array($contenu)){ if(trim(implode("",$contenu))==""){ return array(); } else { return $contenu; } } else { if(trim($contenu)==""){ return array(); } else { return array( $contenu ); } } return false; } // renvoie le nombre d'éléments contenus public function get_tag_nb($tag){ if(!isset($this->contenu[$tag]) || !isset($this->contenu[$tag]['contenu'])){ return 0; } if(is_string($this->contenu[$tag]['contenu'])){ return 1; } return count($this->contenu[$tag]['contenu']); } public function set($tag, $contenu){ if(isset($this->contenu[$tag])){ $this->contenu[$tag]['contenu']=$contenu; } } // afficher le tag de maniere standard // avec un label, les contenus et le filtrage spécifié public function display_tag($tag,$class_replace="",$filter_replace=""){ if($this->is_tag_empty($tag)){ return ""; } // okay, quelque chose à afficher // label si le contenu n'est pas de type texte $retour="
"; $type=$this->get_tag_attribute($tag,"type"); if($type !="text"){ $retour.=""; } $contenu=$this->get($tag); // transformer les éléments uniques en array if(!is_array($contenu)){ $contenu=array(0=>$contenu); } $nb=count($contenu); $classnth="grid1"; if($nb == 2 ) { $classnth="grid2"; } else if($nb >= 3 ){ $classnth="grid3"; } $retour.="
"; // affichage de chaque item foreach($contenu as $pc){ switch($type){ case "image": $retour.= "
"; break; case "file": $ext = strtolower(pathinfo($pc, PATHINFO_EXTENSION)); switch($ext){ case "mp4": case "ogg": case "webm": $retour.=""; break; case "mp3": case "ogg": $retour.=""; break; default: $retour.=""; break; } break; default: $retour.="
".nl2br($this->appliquer_filtre($tag,$pc))."
"; break; } } $retour.="
"; return $retour; } // Creation du formulaire /*
We'll never share your email with anyone else.
*/ public function deployer_formulaire($action=array()){ // action : action= nom de l'action, bouton=texte du bouton, titre=entete // entete du formulaire $this->form="
"; if(isset($action['titre'])){ $this->form .= "
\n

".$action['titre']."

\n
\n"; } if(isset($action['addtop'])){ $this->form .= $action['addtop']; } $this->form .="type."\" method=\"post\" enctype=\"multipart/form-data\" class=\"pb-3\">"; $this->form .=""; foreach($this->contenu as $tag => $champ){ // champs à exclure sur demande if(isset($action['exclure_champ'])){ if(in_array($tag,$action['exclure_champ'])){ continue; } } // prendre le contenu et en faire un array // si l'array est vide, lui donner un contenu vide // foreach sur les contenus // ajouter le bouton plus si on est en multi // démarrer le filedset, afficher le label $this->form .= "
\n"; $this->form .="\n"; $contenus=$this->get_tag_array($tag); // si le tag est vide, mettre un contenu pour afficher le champ if(empty($contenus)){ $contenus=array(0 => ""); } if($this->is_tag_multiple($tag)){ // champ multiple $multiple=true; $this->form .="
\n"; // cas particulier des files: il faut toujours un input if(($champ['@attributes']['type']=='file' || $champ['@attributes']['type']=='image') && !$this->is_tag_empty($tag)){ $contenus[]=""; } } else { $multiple=false; $this->form .="
\n"; } // foreach sur les contenus du tag foreach($contenus as $contenu){ switch($champ['@attributes']['type']) { case 'image': $this->form .= $this->form_part_image($tag, $champ, $contenu, $multiple); break; case 'file': $this->form .= $this->form_part_file($tag, $champ, $contenu, $multiple); break; default: $this->form .= $this->form_part_input($tag, $champ, $contenu, $multiple); break; } } $this->form .="
\n"; // le bouton "plus" if($multiple){ $this->form .= "
\n"; } $this->form .= "
\n"; } if(!isset($action['no_submit'])){ $this->form .= "form .=$action['submit']; } else { $this->form .= "Envoyer"; } $this->form .= "\">\n"; } $this->form .= "\n"; if(isset($action['delete'])){ $this->form .= "
"; $this->form .=""; $this->form .="
Supprimer
"; $this->form .= ""; $this->form .= "
"; } $this->form.="
"; if(isset($action['addbottom'])){ $this->form .= $action['addbottom']; } return $this->form; } private function form_part_image($tag, $champ, $contenu, $multiple){ $code=""; if($multiple){ $add="[]"; $addclass="col-12 col-sm-6 mb-1";} else { $add="";$addclass="col-12"; } if(!empty($contenu)) { $ext = pathinfo(DOSSIER_FICHIERS.$contenu, PATHINFO_EXTENSION); switch ($ext){ case 'jpg': case'gif': case 'png': $url_item=""; $code .="
"; $code .= ""; $code .= "
"; $code .= ""; $code .=""; $code .= "
"; break; } } else { $this->form .= "
"; } return $code; } private function form_part_file($tag, $champ, $contenu, $multiple){ $code=""; if($multiple){ $add="[]"; } else { $add=""; } if(!empty($contenu)) { // creer un hash pour placer dans le value le type et le tag // pour un meilleur process $ext = pathinfo(DOSSIER_FICHIERS.$contenu, PATHINFO_EXTENSION); $icones=array( "pdf"=>"far fa-file-pdf", "zip" =>"far fa-file-archive", "mp3" => "far fa-file-audio", "mp4" => "far fa-file-video", "ogg" => "far fa-file-video", "defaut" => "far fa-file" ); if(isset($icones[$ext])){ $icon_class=$icones[$ext]; } else { $icon_class=$icones['defaut']; } $code .= "
".fichier_seul(DOSSIER_FICHIERS.$contenu)."
"; } else { $this->form .= "
"; } return $code; } // sous fonction de déployer formulaire, crée un élément particulier // ancien value_html_part private function form_part_input($titre, $champ, $contenu, $multiple){ $code=""; if(isset($champ['@attributes']['class'])) { $addclass=" ".$champ['@attributes']['class']; } else { $addclass=""; } if($multiple){ $add="[]"; } else { $add=""; } switch($champ['@attributes']['type']) { case 'select': $options=explode("|",$champ['@attributes']['value']); $code .= "
\n"; break; case 'radio': $options=explode("|",$champ['@attributes']['value']); $code .="
"; foreach($options as $option){ $code .= "\n"; } $code .="
"; break; case 'textarea': $code .= "
\n"; break; default: $code .= "
\n"; break; } return $code; } public function traiter_formulaire($ecrire=false){ //unset($_POST['valider']); $retour="none"; if(isset($_POST['action'])){ if($_POST['action']=="supprimer"){ $this->supprimer_xml(); return "delete"; } // d'abord les suppressions de document // virer les docs, puis les virer du $_POST // ici il faudrait checker si il y a suppression de document. // les documents sont signalé par un bouton checkbox avec leur nom // les supprimer avant toute chose et les retirer de la liste de $this->contenu $retour="update"; // ne pas injecter le bouton du form dans le xml ! unset($_POST['action']); unset($_POST['submit']); // bouton du form, pas utile // traitement des fichiers à supprimer $this->traiter_uploads_delete(); foreach($_POST as $cle => $valeur){ // pre-traitement: soit c'est un champ unique, // du coup passer l'array éventuel à champ // soit c'est un multiple, vider les elements de liste vides if(isset($this->contenu[$cle]['@attributes']['multiple'])) { if(is_array($valeur)){ for($i=count($valeur)-1;$i>=0;$i--){ if(empty($valeur[$i])){ unset($valeur[$i]); // virer si c'est vide } } } } else { if(is_array($valeur)){ $valeur=$valeur[0]; // ne prendre que le premier } } //if(!empty($valeur) && !is_array($valeur)){ $this->contenu[$cle]['contenu']=$valeur; //} // supprimer cette clé du contenu // pour pouvoir dans un deuxième temps // ajouter les contenus éventuellement ajoutés librement // sans référence dans la définition du xml unset($_POST[$cle]); } $this->traiter_uploads(); // si c'est un nouveau xml, lui donner un nom if($this->hydrate==false){ $this->fichier=CHEMIN.DOSSIER_XML.date("YmdHis")."_".$this->nettoie_lien($this->get('titre'))."_".hash('adler32', date("Y-m-d H:i:s")).".xml"; $this->fichier_seul=fichier_seul($this->fichier); $retour="insert"; } if($ecrire){ $this->ecrit_xml(); } } return $retour; } // supprimer les fichiers demandés private function traiter_uploads_delete(){ if(isset($_POST['doc-delete'])){ foreach($_POST['doc-delete'] as $num => $doc){ $elem=explode("|",$doc); // rechercher le bon element // si c'est un contenu unique (pas un array, supprimer l'élément) if(!is_array($this->contenu[$elem[0]]['contenu'])){ unset($this->contenu[$elem[0]]); @unlink(CHEMIN.DOSSIER_FICHIERS.$elem[1]); } else { // plusieurs éléments dans contenu ! for($i = count($this->contenu[$elem[0]]['contenu'])-1; $i>=0;$i--){ if($this->contenu[$elem[0]]['contenu'][$i]==$elem[1]){ unset($this->contenu[$elem[0]]['contenu'][$i]); @unlink(CHEMIN.DOSSIER_FICHIERS.$elem[1]); $this->contenu[$elem[0]]['contenu'] = array_values($this->contenu[$elem[0]]['contenu']); } } } } unset ($_POST['doc-delete']); } } // traiter les imports de fichier // hydrate contenu avec private function traiter_uploads(){ // ne pas oublier de virer les documents supprimés fix_exists_dir(CHEMIN.DOSSIER_FICHIERS); //print_r($_FILES); foreach($_FILES as $tag => $fichiers){ // 1) vérifier que le tag est associé à un fichier ou une image if($this->contenu[$tag]['@attributes']['type']!='file' && $this->contenu[$tag]['@attributes']['type']!='image'){ $this->messages[] = "Ce fichier n'est associé à aucun tag"; continue; } // 2) vérifier si ce qui est reçu est un array ou un seul élément // comparer avc le description du tag (multiple ou pas) if(is_array($fichiers['name'])){ // 2-1) passer en revue l'array foreach($fichiers['name'] as $num => $c){ $piece=array( "name" => $fichiers['name'][$num], "tmp_name" => $fichiers['tmp_name'][$num], "size" => $fichiers['size'][$num], ); $this->traiter_upload_piece($tag,$piece,$num); } } else if(!is_array($fichiers['name'])){ // 2-2) traitement de la piece unique $this->traiter_upload_piece($tag,$fichiers,0); } else { $this->messages[] = "Un problème avec $tag "; } } //print_r($this->messages); } // traiter_upload_piece reçoit un tag et des fichiers // compare les fichiers aux extensions autorisées // si un zip est reçu et que zip n'est pas dans les extensions, // le décompresser et regarder ce qu'il y a dedans qui correspond aux extensions // // reecrire cette fonction et son parent // Le parent analyse $_FILES tag par tag // regarde si le tag est actuellement vide // si le tag est multiple // ensuite vérifie le file // si c'est ok déplace le fichier (verifie les doublons) vers le dossier des fichires // et envoie vers sous fonction pour ajouter au tag avec son nom correct // private function traiter_upload_piece($tag,$piece,$num){ if(empty($piece['name'])){ return false; } $ext_ok=explode(",",$this->contenu[$tag]['@attributes']['allow']); $ext = strtolower(pathinfo($piece['name'], PATHINFO_EXTENSION)); if($ext=="jpeg"){ $ext="jpg"; // virer les ext en jpeg } if(!in_array($ext,$ext_ok) || empty($piece['name'])){ $this->messages[] = "Ce fichier n'a pas la bonne extension ou fichier absent"; return false; } $fileParts = pathinfo($piece['name']); $nom_seul=$this->stripAccents($fileParts['filename']); if(file_exists(CHEMIN.DOSSIER_FICHIERS.$nom_seul.".".$ext)){ $ad= hash('adler32', date("Y-m-d H:i:s")); $nom_seul=$nom_seul."_".$ad; // ce serait mieux entre le nom et l'extension } if(!move_uploaded_file($piece['tmp_name'], CHEMIN.DOSSIER_FICHIERS.$nom_seul.".".$ext)){ $this->messages[]="Impossible de déplacer le fichier vers ".DOSSIER_FICHIERS; return false; } // recuperer les contenus précédents en array // le contenu à la base peut être vide, ou ne contenir qu'un élément en string if($this->is_tag_empty($tag)){ // tag vide, ajouter l'element $this->set($tag,$nom_seul.".".$ext); } else { if($this->is_tag_multiple($tag)){ if(is_string($this->contenu[$tag]['contenu'])){ $this->contenu[$tag]['contenu']=array($this->contenu[$tag]['contenu']); } $this->contenu[$tag]['contenu'][]=$nom_seul.".".$ext; } else { $this->set($tag,$nom_seul.".".$ext); } } $this->messages[]="fichier envoyé avec succès vers ".DOSSIER_FICHIERS; } public function supprimer_xml(){ // supprimer le xml //echo "supprimer ".$this->fichier; unlink($this->fichier); // supprimer les documents attachés foreach($this->get_contenu() as $elem){ if($elem['@attributes']['type']=="file" || $elem['@attributes']['type']=="image"){ $c=$elem['contenu']; if(!is_array($c)){$c=array($c);} foreach($c as $f){ if($f){ unlink(CHEMIN.DOSSIER_FICHIERS.$f); } if($elem['@attributes']['type']=="image"){ // eliminer les vignettes de l'image ! } } } } } /* Petites fonctions diverses - - - - - - - - */ public function is_tag_empty($tag){ $contenu=$this->contenu[$tag]['contenu']; if(is_array($contenu)){ if(trim(implode("",$contenu))==""){ return true; } } else { if(trim($contenu)==""){ return true; } } return false; } public function is_tag_multiple($tag){ if(isset($this->contenu[$tag]['@attributes']['multiple'])){ if($this->contenu[$tag]['@attributes']['multiple']=="oui"){ return true; } } return false; } // transforme un lien en un truc uniquement constitué de lettres public function nettoie_lien($texte){ $texte = preg_replace("#[^a-zA-Z]#", "", $texte); return $texte; } // retire tous les caractères qui peuvent poser problème à l'enregistrement public function stripAccents($string){ $transliterator = Transliterator::createFromRules(':: Any-Latin; :: Latin-ASCII; :: NFD; :: [:Nonspacing Mark:] Remove; :: Lower(); :: NFC;', Transliterator::FORWARD); return $transliterator->transliterate($string); /* $str = htmlentities($string, ENT_NOQUOTES, 'UTF-8'); $str = preg_replace('#Ç#', 'C', $str); $str = preg_replace('#ç#', 'c', $str); $str = preg_replace('#è|é|ê|ë#', 'e', $str); $str = preg_replace('#È|É|Ê|Ë#', 'E', $str); $str = preg_replace('#à|á|â|ã|ä|å#', 'a', $str); $str = preg_replace('#@|À|Á|Â|Ã|Ä|Å#', 'A', $str); $str = preg_replace('#ì|í|î|ï#', 'i', $str); $str = preg_replace('#Ì|Í|Î|Ï#', 'I', $str); $str = preg_replace('#ð|ò|ó|ô|õ|ö#', 'o', $str); $str = preg_replace('#Ò|Ó|Ô|Õ|Ö#', 'O', $str); $str = preg_replace('#ù|ú|û|ü#', 'u', $str); $str = preg_replace('#Ù|Ú|Û|Ü#', 'U', $str); $str = preg_replace('#ý|ÿ#', 'y', $str); $str = preg_replace('#Ý#', 'Y', $str); $str = preg_replace('#\&([A-za-])(?:acute|cedil|circ|grave|ring|tilde|uml)\;#', '\1', $str); $str = strtolower(str_replace(" ","_",$str)); $str = str_replace(array("#","'",'"'),"",$str); return $str; */ } public function file_icon($fichier){ $icones=array( "mp4"=>"far fa-file-video", "ogg"=>"far fa-file-video", "mp3"=>"far fa-file-audio", "pdf"=>"far fa-file-pdf", "zip" =>"far fa-file-archive", "tif"=>"far fa-file-image", "defaut" => "far fa-file", ); $ext = pathinfo($fichier, PATHINFO_EXTENSION); if(isset($icones[$ext])){ $icon_class=$icones[$ext]; } else { $icon_class=$icones['defaut']; } return ""; } public function appliquer_filtre($tag,$contenu){ switch ($this->get_tag_attribute($tag,"filtre_display","")){ case "lien": if (filter_var($contenu, FILTER_VALIDATE_URL)) { $p=parse_url($contenu); return "Lien vers ".$p['host'].""; } else { return $contenu; } break; default: return $contenu; break; } } } ?>