* @copyright Copyright (C) 2021-2022, Sylvain Lelièvre * @license GNU General Public License, version 3 * @link https://deltacms.fr/ * * Delta was created from version 11.2.00.24 of ZwiiCMS * @author Rémi Jean * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez * @copyright Copyright (C) 2018-2021, Frédéric Tempez */ class form extends common { const VERSION = '4.0'; const REALNAME = 'Formulaire'; const DELETE = true; const UPDATE = '0.0'; const DATADIRECTORY = ''; // Contenu localisé inclus par défaut (page.json et module.json) public static $actions = [ 'config' => self::GROUP_MODERATOR, 'update' => self::GROUP_MODERATOR, 'data' => self::GROUP_MODERATOR, 'delete' => self::GROUP_MODERATOR, 'deleteall' => self::GROUP_MODERATOR, 'index' => self::GROUP_VISITOR, 'export2csv' => self::GROUP_MODERATOR, 'output2csv' => self::GROUP_MODERATOR ]; public static $data = []; public static $pages = []; public static $pagination; // Objets const TYPE_MAIL = 'mail'; const TYPE_SELECT = 'select'; const TYPE_TEXT = 'text'; const TYPE_TEXTAREA = 'textarea'; const TYPE_DATETIME = 'date'; const TYPE_CHECKBOX = 'checkbox'; const TYPE_LABEL = 'label'; const TYPE_FILE = 'file'; const ITEMSPAGE = 10; public static $types = [ self::TYPE_LABEL => 'Etiquette', self::TYPE_TEXT => 'Champ texte', self::TYPE_TEXTAREA => 'Grand champ texte', self::TYPE_MAIL => 'Champ mail', self::TYPE_SELECT => 'Sélection', self::TYPE_CHECKBOX => 'Case à cocher', self::TYPE_DATETIME => 'Date', self::TYPE_FILE => 'fichier' ]; public static $types_en = [ self::TYPE_LABEL => 'Label', self::TYPE_TEXT => 'Text field', self::TYPE_TEXTAREA => 'Large text field', self::TYPE_MAIL => 'Mail field', self::TYPE_SELECT => 'Selection', self::TYPE_CHECKBOX => 'Check box', self::TYPE_DATETIME => 'Date', self::TYPE_FILE => 'file' ]; public static $listUsers = [ ]; public static $signature = [ 'text' => 'Nom du site', 'logo' => 'Logo du site' ]; public static $signature_en = [ 'text' => 'Name of the site', 'logo' => 'Website logo' ]; public static $logoWidth = [ '40' => '40%', '60' => '60%', '80' => '80%', '100' => '100%' ]; public static $maxSizeUpload = [ '100000' => '100Ko', '200000' => '200Ko', '500000' => '500Ko', '1000000' => '1Mo', '2000000' => '2Mo', '5000000' => '5Mo' ]; /** * Mise à jour du module */ public function update() { if( null === $this->getData(['module', $this->getUrl(0), 'config', 'maxSizeUpload'])) $this->setData(['module', $this->getUrl(0), 'config', 'maxSizeUpload', '500000']); } /** * Configuration */ public function config() { // Lexique $text = []; $val = $this->getData(['config', 'i18n', 'langAdmin']); switch ($val) { case 'fr' : $text[0] = 'Modifications enregistrées'; $text[1] = 'Configuration du module'; break; case 'en' : $text[0] = 'Saved changes'; $text[1] = 'Module configuration'; break; } // Liste des utilisateurs $userIdsFirstnames = helper::arrayCollumn($this->getData(['user']), 'firstname'); ksort($userIdsFirstnames); self::$listUsers [] = ''; foreach($userIdsFirstnames as $userId => $userFirstname) { self::$listUsers [] = $userId; } // Soumission du formulaire if($this->isPost()) { // Configuration $this->setData([ 'module', $this->getUrl(0), 'config', [ 'button' => $this->getInput('formConfigButton'), 'captcha' => $this->getInput('formConfigCaptcha', helper::FILTER_BOOLEAN), 'group' => $this->getInput('formConfigGroup', helper::FILTER_INT), 'user' => self::$listUsers [$this->getInput('formConfigUser', helper::FILTER_INT)], 'mail' => $this->getInput('formConfigMail') , 'pageId' => $this->getInput('formConfigPageIdToggle', helper::FILTER_BOOLEAN) === true ? $this->getInput('formConfigPageId', helper::FILTER_ID) : '', 'subject' => $this->getInput('formConfigSubject'), 'replyto' => $this->getInput('formConfigMailReplyTo', helper::FILTER_BOOLEAN), 'signature' => $this->getInput('formConfigSignature'), 'logoUrl' => $this->getInput('formConfigLogo'), 'logoWidth' => $this->getInput('formConfigLogoWidth'), 'maxSizeUpload' => $this->getInput('formConfigMaxSize') ] ]); // Génération des données vides if ($this->getData(['module', $this->getUrl(0), 'data']) === null) { $this->setData(['module', $this->getUrl(0), 'data', []]); } // Génération des champs $inputs = []; foreach($this->getInput('formConfigPosition', null) as $index => $position) { $inputs[] = [ 'name' => htmlspecialchars_decode($this->getInput('formConfigName[' . $index . ']'),ENT_QUOTES), 'position' => helper::filter($position, helper::FILTER_INT), 'required' => $this->getInput('formConfigRequired[' . $index . ']', helper::FILTER_BOOLEAN), 'type' => $this->getInput('formConfigType[' . $index . ']'), 'values' => $this->getInput('formConfigValues[' . $index . ']') ]; } $this->setData(['module', $this->getUrl(0), 'input', $inputs]); // Valeurs en sortie $this->addOutput([ 'notification' => $text[0], 'redirect' => helper::baseUrl() . $this->getUrl(), 'state' => true ]); } // Liste des pages foreach($this->getHierarchy(null, false) as $parentPageId => $childrenPageIds) { self::$pages[$parentPageId] = $this->getData(['page', $parentPageId, 'title']); foreach($childrenPageIds as $childKey) { self::$pages[$childKey] = '    ' . $this->getData(['page', $childKey, 'title']); } } // Valeurs en sortie $this->addOutput([ 'title' => $text[1], 'vendor' => [ 'html-sortable', 'flatpickr' ], 'view' => 'config' ]); } /** * Données enregistrées */ public function data() { // Lexique $text = []; $val = $this->getData(['config', 'i18n', 'langAdmin']); switch ($val) { case 'fr' : $text[0] = 'Données enregistrées'; break; case 'en' : $text[0] = 'Registered data'; break; } $data = $this->getData(['module', $this->getUrl(0), 'data']); if($data) { // Pagination $pagination = helper::pagination($data, $this->getUrl(),self::ITEMSPAGE); // Liste des pages self::$pages = $pagination['pages']; // Inverse l'ordre du tableau $dataIds = array_reverse(array_keys($data)); $data = array_reverse($data); // Données en fonction de la pagination for($i = $pagination['first']; $i < $pagination['last']; $i++) { $content = ''; foreach($data[$i] as $input => $value) { $content .= $input . ' : ' . $value . '
'; } self::$data[] = [ $content, template::button('formDataDelete' . $dataIds[$i], [ 'class' => 'formDataDelete buttonRed', 'href' => helper::baseUrl() . $this->getUrl(0) . '/delete/' . $dataIds[$i] . '/' . $_SESSION['csrf'], 'value' => template::ico('cancel') ]) ]; } } // Valeurs en sortie $this->addOutput([ 'title' => $text[0], 'view' => 'data' ]); } /** * Export CSV * @author Frédéric Tempez * @copyright Copyright (C) 2018-2021, Frédéric Tempez */ public function export2csv() { // Lexique $text = []; $val = $this->getData(['config', 'i18n', 'langAdmin']); switch ($val) { case 'fr' : $text[0] = 'Action non autorisée'; $text[1] = 'Export CSV effectué dans le gestionnaire de fichiers
sous le nom '; $text[2] = 'Aucune donnée à exporter'; break; case 'en' : $text[0] = 'Action not allowed'; $text[1] = 'CSV export performed in the file manager under the name '; $text[2] = 'No data to export'; break; } // Jeton incorrect if ($this->getUrl(2) !== $_SESSION['csrf']) { // Valeurs en sortie $this->addOutput([ 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/data', 'notification' => $text[0] ]); } else { $data = $this->getData(['module', $this->getUrl(0), 'data']); if ($data !== []) { $csvfilename = 'data-'.date('dmY').'-'.date('hm').'-'.rand(10,99).'.csv'; if (!file_exists(self::FILE_DIR.'source/data')) { mkdir(self::FILE_DIR.'source/data', 0755); } $fp = fopen(self::FILE_DIR.'source/data/'.$csvfilename, 'w'); fputcsv($fp, array_keys($data[1]), ';','"'); foreach ($data as $fields) { fputcsv($fp, $fields, ';','"'); } fclose($fp); // Valeurs en sortie $this->addOutput([ 'notification' => $text[1].$csvfilename, 'redirect' => helper::baseUrl() . $this->getUrl(0) .'/data', 'state' => true ]); } else { $this->addOutput([ 'notification' => $text[2], 'redirect' => helper::baseUrl() . $this->getUrl(0) .'/data' ]); } } } /** * Suppression */ public function deleteall() { // Lexique $text = []; $val = $this->getData(['config', 'i18n', 'langAdmin']); switch ($val) { case 'fr' : $text[0] = 'Action non autorisée'; $text[1] = 'Données supprimées'; $text[2] = 'Aucune donnée à supprimer'; break; case 'en' : $text[0] = 'Unauthorised action'; $text[1] = 'Data deleted'; $text[2] = 'No data to be deleted'; break; } // Jeton incorrect if ($this->getUrl(2) !== $_SESSION['csrf']) { // Valeurs en sortie $this->addOutput([ 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/data', 'notification' => $text[0] ]); } else { $data = ($this->getData(['module', $this->getUrl(0), 'data'])); if (count($data) > 0 ) { // Suppression multiple for ($i = 1; $i <= count($data) ; $i++) { echo $this->deleteData(['module', $this->getUrl(0), 'data', $i]); } // Valeurs en sortie $this->addOutput([ 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/data', 'notification' => $text[1], 'state' => true ]); } else { // Valeurs en sortie $this->addOutput([ 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/data', 'notification' => $text[2] ]); } } } /** * Suppression */ public function delete() { // Lexique $text = []; $val = $this->getData(['config', 'i18n', 'langAdmin']); switch ($val) { case 'fr' : $text[0] = 'Action non autorisée'; $text[1] = 'Donnée supprimée'; break; case 'en' : $text[0] = 'Unauthorised action'; $text[1] = 'Data deleted'; break; } // Jeton incorrect if ($this->getUrl(3) !== $_SESSION['csrf']) { // Valeurs en sortie $this->addOutput([ 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/data', 'notification' => $text[0] ]); } else { // La donnée n'existe pas if($this->getData(['module', $this->getUrl(0), 'data', $this->getUrl(2)]) === null) { // Valeurs en sortie $this->addOutput([ 'access' => false ]); } // Suppression else { $this->deleteData(['module', $this->getUrl(0), 'data', $this->getUrl(2)]); // Valeurs en sortie $this->addOutput([ 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/data', 'notification' => $text[1], 'state' => true ]); } } } /** * Accueil */ public function index() { // Mise à jour du module $this->update(); // Lexique $text = []; $val = $this->getData(['config', 'i18n', 'langAdmin']); switch ($val) { case 'fr' : $text[0] = 'Incorrect'; $text[1] = 'Nouveau message en provenance de votre site'; $text[2] = 'Nouveau message en provenance de la page "'; $text[3] = 'Formulaire soumis'; $text[4] = 'La pièce jointe n\'est pas une image'; $text[5] = '?'; $text[6] = 'La taille du fichier excède '; $text[7] = 'L\'extension du fichier doit être jpg, jpeg, png ou gif'; $text[8] = 'Erreur pendant le téléversement du fichier'; $text[9] = 'échec le message n\'est pas envoyé car '; break; case 'en' : $text[0] = 'Incorrect'; $text[1] = 'New message from your site'; $text[2] = 'New message from the page "'; $text[3] = 'Form submitted'; $text[4] = 'File is not an image'; $text[5] = '?'; $text[6] = 'File size exceeds '; $text[7] = 'The file extension must be jpg, jpeg, png or gif'; $text[8] = 'Error while uploading file' ; $text[9] = 'failure, the message is not sent because '; break; } // Soumission du formulaire if($this->isPost()) { // Check la captcha if( $this->getData(['module', $this->getUrl(0), 'config', 'captcha']) // AND $this->getInput('formcaptcha', helper::FILTER_INT) !== $this->getInput('formcaptchaFirstNumber', helper::FILTER_INT) + $this->getInput('formcaptchaSecondNumber', helper::FILTER_INT)) AND password_verify($this->getInput('formCaptcha', helper::FILTER_INT), $this->getInput('formCaptchaResult') ) === false ) { self::$inputNotices['formCaptcha'] = $text[0]; } // Préparation le contenu du mail $data = []; $replyTo = null; $content = ''; // $notice concerne la pièce jointe $notice = ''; foreach($this->getData(['module', $this->getUrl(0), 'input']) as $index => $input) { // Filtre la valeur switch($input['type']) { case self::TYPE_MAIL: $filter = helper::FILTER_MAIL; $this->setData(['module', $this->getUrl(0), 'draft', 'mail', $this->getInput('formInput[' . $index . ']')]); break; case self::TYPE_TEXTAREA: $filter = helper::FILTER_STRING_LONG; $this->setData(['module', $this->getUrl(0), 'draft', 'textarea', $this->getInput('formInput[' . $index . ']')]); break; case self::TYPE_DATETIME: $filter = helper::FILTER_STRING_SHORT; // Mettre TYPE_DATETIME pour récupérer un TIMESTAMP $this->setData(['module', $this->getUrl(0), 'draft', 'datetime', $this->getInput('formInput[' . $index . ']')]); break; case self::TYPE_CHECKBOX: $filter = helper::FILTER_BOOLEAN; $this->setData(['module', $this->getUrl(0), 'draft', 'checkbox', $this->getInput('formInput[' . $index . ']')]); break; case self::TYPE_SELECT: $this->setData(['module', $this->getUrl(0), 'draft', 'select', $this->getInput('formInput[' . $index . ']')]); break; case self::TYPE_TEXT: $this->setData(['module', $this->getUrl(0), 'draft', 'text', $this->getInput('formInput[' . $index . ']')]); break; default: $filter = helper::FILTER_STRING_SHORT; } $value = $this->getInput('formInput[' . $index . ']', $filter, $input['required']) === true ? 'X' : $this->getInput('formInput[' . $index . ']', $filter, $input['required']); // premier champ email ajouté au mail en reply si option active if ($this->getData(['module', $this->getUrl(0), 'config', 'replyto']) === true && $input['type'] === 'mail') { $replyTo = $value; } // Traitement de la pièce jointe, fichier avec extension valide de taille maximum $sizeMax // Fichier chargé dans site/file/uploads/ et effacé après l'envoi du mail if( $input['type'] === 'file'){ $target_dir = self::FILE_DIR.'uploads'; $sizeMax = $this->getData(['module', $this->getUrl(0), 'config', 'maxSizeUpload']); $extensions_valides = array( 'jpg' , 'jpeg' , 'gif' , 'png'); $extensions_images = array( 'jpg' , 'jpeg' , 'gif' , 'png' ); $file_name = basename($_FILES["fileToUpload"]["name"]); if( $_FILES["fileToUpload"]["error"] === 0){ if($file_name !== '' && $file_name !== null){ if( ! is_dir( $target_dir )) mkdir( $target_dir, 0744); // Copie du fichier .htaccess depuis module/form/ressource copy('./module/form/ressource/.htaccess', $target_dir.'/.htaccess'); $target_file = $target_dir .'/'. $file_name; $imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION)); // Vérification que la pièce jointe est une image quand son extension est celle d'une image if( $_FILES["fileToUpload"]["tmp_name"] !== '' && $_FILES["fileToUpload"]["tmp_name"] !== null && in_array($imageFileType,$extensions_images)){ $check = getimagesize($_FILES["fileToUpload"]["tmp_name"]); if($check === false) $notice = $text[4]; } // Vérification de la taille du fichier if ($_FILES["fileToUpload"]["size"] > $sizeMax) $notice = $text[6].intval($sizeMax/1000).' Ko'; // Vérification des types de fichiers autorisés if( ! in_array($imageFileType,$extensions_valides) ) $notice = $text[7]; // Upload du fichier if ($notice === '') { if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) { $value = $file_name; } else { $notice = $text[8]; } } } } else { switch($_FILES["fileToUpload"]["error"]) { case 2 : $notice = $text[6].' MAX_FILE_SIZE : 5Mo'; break; default: $notice = $text[8]; } } } // Préparation des données pour la création dans la base $data[$this->getData(['module', $this->getUrl(0), 'input', $index, 'name'])] = $value; // Préparation des données pour le mail $content .= '' . $this->getData(['module', $this->getUrl(0), 'input', $index, 'name']) . ' : ' . $value . '
'; } // Si absence d'erreur sur la pièce jointe if( $notice === ''){ // Crée les données $this->setData(['module', $this->getUrl(0), 'data', helper::increment(1, $this->getData(['module', $this->getUrl(0), 'data'])), $data]); $sent = true; // Emission du mail // Rechercher l'adresse en fonction du mail $singleuser = $this->getData(['user', $this->getData(['module', $this->getUrl(0), 'config', 'user']), 'mail']); $singlemail = $this->getData(['module', $this->getUrl(0), 'config', 'mail']); $group = $this->getData(['module', $this->getUrl(0), 'config', 'group']); // Verification si le mail peut être envoyé if( self::$inputNotices === [] && ( $group > 0 || $singleuser !== '' || $singlemail !== '' ) ) { // Utilisateurs dans le groupe $to = []; if ($group > 0){ foreach($this->getData(['user']) as $userId => $user) { if($user['group'] >= $group) { $to[] = $user['mail']; } } } // Utilisateur désigné if (!empty($singleuser)) { $to[] = $singleuser; } // Mail désigné if (!empty($singlemail)) { $to[] = $singlemail; } if($to) { // Sujet du mail $subject = $this->getData(['module', $this->getUrl(0), 'config', 'subject']); if($subject === '') { $subject = $text[1]; } // Envoi le mail $sent = $this->sendMail( $to, $subject, $text[2] . $this->getData(['page', $this->getUrl(0), 'title']) . '" :

' . $content, $replyTo, $file_name ); } } // Nettoyage du dossier self::FILE_DIR.uploads $FilesUpload = glob( self::FILE_DIR.'uploads/*'); foreach($FilesUpload as $file) { if(is_file($file)) unlink($file); } // Redirection $redirect = helper::baseUrl() . $this->getUrl(0); if ( $this->getData(['module', $this->getUrl(0), 'config', 'pageId']) !== '') $redirect = helper::baseUrl() . $this->getData(['module', $this->getUrl(0), 'config', 'pageId']); // Effacement des données provisoires $this->setData(['module', $this->getUrl(0), 'draft', '']); } else { $sent = false; $redirect = helper::baseUrl() . $this->getUrl(0); } // Passage de la langue d'administration à flatpickr $lang_flatpickr = 'fr'; if( $this->getData(['config', 'i18n', 'langAdmin']) ==='en'){ $lang_flatpickr = 'default'; } ?> addOutput([ 'notification' => ($sent === true ? $text[3] : $notice), 'redirect' => $redirect, 'state' => ($sent === true ? true : false), 'vendor' => [ 'flatpickr' ], ]); } // Passage de la langue d'administration à flatpickr $lang_flatpickr = 'fr'; if( $this->getData(['config', 'i18n', 'langAdmin']) ==='en'){ $lang_flatpickr = 'default'; } ?> addOutput([ 'showBarEditButton' => true, 'showPageContent' => true, 'view' => 'index', 'vendor' => [ 'flatpickr' ], ]); } }