commit 3393ebe2afcb1920964f2a0d09441c456a725de3 Author: Fred Tempez Date: Tue Sep 5 15:21:01 2023 +0200 Init avec suppression de la langue étrangère du site en cours diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7bce42d --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +core/class/phpmailer/.DS_Store +site/.DS_Store +site/data/* +site/tmp/* +site/backup/* +site/file/* +site/i18n/*.json +.DS_Store +core/vendor/tinymce/link_list.json +robots.txt +sitemap.xml diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..9bd3ba5 --- /dev/null +++ b/.htaccess @@ -0,0 +1,36 @@ +# Active la compression GZIP - option Apache + + mod_gzip_on Yes + mod_gzip_dechunk Yes + mod_gzip_item_include file \.(html?|txt|css|js|php|pl)$ + mod_gzip_item_include handler ^cgi-script$ + mod_gzip_item_include mime ^text\.* + mod_gzip_item_include mime ^application/x-javascript.* + mod_gzip_item_exclude mime ^image\.* + mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.* + + +# Active la compression DEFLATE - option Apache + + AddOutputFilterByType DEFLATE text/plain + AddOutputFilterByType DEFLATE text/html + AddOutputFilterByType DEFLATE text/xml + AddOutputFilterByType DEFLATE text/shtml + AddOutputFilterByType DEFLATE text/css + AddOutputFilterByType DEFLATE application/xml + AddOutputFilterByType DEFLATE application/xhtml+xml + AddOutputFilterByType DEFLATE application/rss+xml + AddOutputFilterByType DEFLATE application/javascript + AddOutputFilterByType DEFLATE application/x-javascript + + +# Bloque l'accès à la liste des fichiers +Options -Indexes + +# Désactive l'option de substitution automatique + + Options -MultiViews + + +# ne pas supprimer la ligne URL rewriting ! +# URL rewriting diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 0000000..825c32f --- /dev/null +++ b/CHANGES.md @@ -0,0 +1 @@ +# Changelog diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..35c5730 --- /dev/null +++ b/LICENSE @@ -0,0 +1 @@ +Cette œuvre est mise à disposition sous licence Attribution - Pas d'Utilisation Commerciale - Pas de Modification 4.0 International. Pour voir une copie de cette licence, visitez http://creativecommons.org/licenses/by-nc-nd/4.0/ ou écrivez à Creative Commons, PO Box 1866, Mountain View, CA 94042, USA. \ No newline at end of file diff --git a/LISEZMOI.md b/LISEZMOI.md new file mode 100644 index 0000000..8a800e9 --- /dev/null +++ b/LISEZMOI.md @@ -0,0 +1,113 @@ +# ZwiiLMS 0.0.01 + +Zwii est un CMS sans base de données (flat-file) qui permet de créer et gérer facilement un site web sans aucune connaissance en programmation. + +ZwiiCMS a été créé par un développeur de talent, [Rémi Jean](https://remijean.fr/). Il est désormais maintenu par Frédéric Tempez. + +[Site](http://zwiicms.fr/) - [Forum](http://forum.zwiicms.com/) - [Version initiale](https://github.com/remijean/ZwiiCMS/) - [GitHub](https://github.com/fredtempez/ZwiiCMS) + +## Configuration recommandée + +* PHP 7.2 ou plus +* Support de .htaccess + +## Licence + +Cette œuvre est mise à disposition sous licence Attribution - Pas d'utilisation Commerciale - Pas de Modification 4.0 International. + +Pour voir une copie de cette licence, visitez http://creativecommons.org/licenses/by-nc-nd/4.0/ ou écrivez à Creative Commons, PO Box 1866, Mountain View, CA 94042, USA. + +## Téléchargement de ZwiiCMS + +Pour télécharger la dernière version publiée, rendez-vous : +- sur [la page des mises à jour](https://forge.chapril.org/ZwiiCMS-Team/ZwiiCMS/releases) +- ou sur [la page de téléchargement du site](https://zwiicms.fr/telechargement) + + +## Installation + +Décompressez l'archive de Zwii et téléversez son contenu à la racine de votre serveur ou dans un sous-répertoire. C'est tout ! + +Vous trouverez de plus amples explications, en particulier pour une installation chez Free, dans la rubrique "Téléchargements" du forum. + + +## Procédures de mise à jour + +A l'occasion de l'installation d'une verion majeure, il est recommandé de réaliser une copie de sauvegarde. + +### Automatique + +* Connectez-vous à votre site. +* Si une mise à jour est disponible, elle vous est proposée dans la barre d'administration. +* Cliquez sur le bouton "Mettre à jour". + +### Manuelle + +* Sauvegardez l'intégralité de votre site, spécialement le répertoire "site". +* Décompressez la nouvelle version sur votre ordinateur. +* Transférez son contenu sur votre serveur en activant le remplacement des fichiers. + + +## Arborescence générale + +*Légende : [R] Répertoire - [F] Fichier* + +```text +[R] core Cœur du système + [R] class Classes + [R] layout Mise en page + [R] module Modules du cœur + [R] vendor Librairies extérieures + [F] core.js.php Cœur javascript + [F] core.php Cœur PHP + +[R] module Modules de page + [R] blog Blog + [R] form Gestionnaire de formulaires + [R] gallery Galerie + [R] news Nouvelles + [R] redirection Redirection + +[R] site Contenu du site + [R] backup Sauvegardes automatiques + [R] i18N Langues de l'interface de Zwii + [R] data Répertoire des données + [R] fr Dossier localisé + [F] page.json Données des pages + [F] module.json Données des modules de pages + [F] local.json Données du site propres à la langue + [F] .default Indicateur de la langue de site par défaut + [R] content Dossier des contenus de page + [F] accueil.html Exemple contenu de la page d'accueil + [R] fonts Dossier contenant les fontes installées + [F] font.html Fichier contenant les appels des fontes à charger sur cdnFonts + [F] fonts.css Fichier contenant la feuille de style liée aux polices de caractères locales + [F] fontes.woff Fichiers locaux des fontes (woff, etc..) + [R] modules Personnalisation des modules ou données propres + [F] admin.css Thème des pages d'administration + [F] admin.json Données de thème des pages d'administration + [F] blacklist.json Journalisation des tentatives de connexion avec des comptes inconnus + [F] config.json Configuration du site + [F] core.json Configuration du noyau + [F] custom.css Feuille de style de la personnalisation avancée + [F] font.json Descripteur des fontes personnalisées + [F] journal.log Journalisation des activités + [F] language.json Langues de l'interface + [F] profil.json Profils des utilisateurs + [F] theme.css Thème du site + [F] theme.json Données du site + [F] user.json Données des utilisateurs + [F] .backup Marqueur de la sauvegarde des fichiers si présent + [R] file Répertoire d'upload du gestionnaire de fichiers + [R] source Ressources diverses + [R] thumb Miniatures des images + [R] tmp Répertoire temporaire + +[F] index.php Fichier d'initialisation de ZwiiCMS +[F] robots.txt Filtrage des répertoires accessibles aux robots des moteurs de recherche +[F] sitemap.xml Plan du site +[F] sitemap.xml.gz Version compressée + +Le fichiers .htaccess contribuent à la sécurité en filtrant l'accès aux répertoires sensibles. + +``` diff --git a/core/class/.htaccess b/core/class/.htaccess new file mode 100644 index 0000000..3b355e3 --- /dev/null +++ b/core/class/.htaccess @@ -0,0 +1,3 @@ +# Bloque l'accès à la librairie +Order deny,allow +Deny from all \ No newline at end of file diff --git a/core/class/autoload.php b/core/class/autoload.php new file mode 100644 index 0000000..bf408d6 --- /dev/null +++ b/core/class/autoload.php @@ -0,0 +1,19 @@ + '']); + file_put_contents ('core/module/install/ressource/i18n/fr_FR.json', json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT), LOCK_EX); + } + */ + return (array_key_exists($text, core::$dialog) && !empty(core::$dialog[$text]) ? core::$dialog[$text] : $text); + } + + /** + * Formate la date avec le script strftime en UTF8 + * Date au format time() + * $format strftime + */ + public static function dateUTF8($format, $date) + { + require_once 'core/class/strftime/php-8.1-strftime.class.php'; + return mb_convert_encoding(\PHP81_BC\strftime($format, $date), 'UTF-8', mb_list_encodings()); + } + + /** + * Fonction pour assurer la traduction des messages + */ + public static function googleTranslate($to, $text) + { + if (!file_exists('site/i18n/' . $to . '.json')) { + file_put_contents('site/i18n/' . $to . '.json', json_encode([])); + } + if (!empty($text)) { + //Lecture des données en ligne + $data = json_decode(file_get_contents('site/i18n/' . $to . '.json'), true); + // Mode traduction + if ($to !== 'fr_FR') { + $arrayjson = json_decode(file_get_contents('https://clients5.google.com/translate_a/t?client=dict-chrome-ex&sl=auto&tl=' . $to . '&q=' . rawurlencode($text)), true); + $response = $arrayjson[0][0]; + // Captation + if ($data !== '') { + if (array_key_exists($text, $data)) { + $data[$text] = $response; + } else { + $data = array_merge($data, [$text => $response]); + } + } + // Mode alimentation des chaines + } else { + // Créer la variable + $data = array_merge($data, [$text => '']); + } + file_put_contents('site/i18n/' . $to . '.json', json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT), LOCK_EX); + + } + } + + + /** + * Récupérer l'adresse IP sans tenir compte du proxy + * @param integer Niveau d'anonymat 0 aucun, 1 octet à droite, etc.. + * @return string IP adress + * Cette fonction est utilisée par user + */ + + public static function getIp($anon = 4) + { + if (!empty($_SERVER['HTTP_CLIENT_IP'])) { + $ip = $_SERVER['HTTP_CLIENT_IP']; + } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { + $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; + } else { + $ip = $_SERVER['REMOTE_ADDR']; + } + + // Anonymiser l'adresse IP v4 + $d = array_slice(explode('.', $ip), 0, $anon); + $d = implode('.', $d); + $j = array_fill(0, 4 - $anon, 'x'); + $k = implode('.', $j); + $ip = count($j) == 0 ? $d : $d . '.' . $k; + return $ip; + } + + /** + * Fonction pour récupérer le numéro de version en ligne et le catalogue des modules + * @param string $url à récupérer + * @return mixed données récupérées + */ + + public static function getUrlContents($url) + { + // Ejecter free.fr + if (strpos(self::baseUrl(), 'free.fr') > 0) { + return false; + } + if ( + function_exists('file_get_contents') && + ini_get('allow_url_fopen') + ) { + $url_get_contents_data = @file_get_contents($url); // Masque un warning éventuel + } elseif (function_exists('curl_version')) { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_HEADER, 0); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_URL, $url); + $url_get_contents_data = curl_exec($ch); + curl_close($ch); + } elseif ( + function_exists('fopen') && + function_exists('stream_get_contents') && + ini_get('allow_url_fopen') + ) { + $handle = fopen($url, "r"); + $url_get_contents_data = stream_get_contents($handle); + } else { + $url_get_contents_data = false; + } + return $url_get_contents_data; + } + + /** + * Retourne les valeurs d'une colonne du tableau de données + * @param array $array Tableau cible + * @param string $column Colonne à extraire + * @param string $sort Type de tri à appliquer au tableau (SORT_ASC, SORT_DESC, ou null) + * @return array + */ + public static function arraycolumn($array, $column, $sort = null) + { + $newArray = []; + if (empty($array) === false) { + $newArray = array_map(function ($element) use ($column) { + return $element[$column]; + }, $array); + switch ($sort) { + case 'SORT_ASC': + asort($newArray); + break; + case 'SORT_DESC': + arsort($newArray); + break; + } + } + return $newArray; + } + + /** + * Compatibilité avec les anciens modules + */ + public static function arrayCollumn($array, $column, $sort = null) + { + return (helper::arrayColumn($array, $column, $sort)); + } + + + + /** + * Génère un backup des données de site + * @param string $folder dossier de sauvegarde + * @param array $exclude dossier exclus + * @return string nom du fichier de sauvegarde + */ + + public static function autoBackup($folder, $filter = ['backup', 'tmp']) + { + // Creation du ZIP + $baseName = str_replace('/', '', helper::baseUrl(false, false)); + $baseName = empty($baseName) ? 'ZwiiCMS' : $baseName; + $fileName = $baseName . '-backup-' . date('Y-m-d-H-i-s', time()) . '.zip'; + $zip = new ZipArchive(); + $zip->open($folder . $fileName, ZipArchive::CREATE | ZipArchive::OVERWRITE); + $directory = 'site/'; + //$filter = array('backup','tmp','file'); + $files = new RecursiveIteratorIterator( + new RecursiveCallbackFilterIterator( + new RecursiveDirectoryIterator( + $directory, + RecursiveDirectoryIterator::SKIP_DOTS + ), + function ($fileInfo, $key, $iterator) use ($filter) { + return $fileInfo->isFile() || !in_array($fileInfo->getBaseName(), $filter); + } + ) + ); + foreach ($files as $name => $file) { + if (!$file->isDir()) { + $filePath = $file->getRealPath(); + $relativePath = substr($filePath, strlen(realpath($directory)) + 1); + $zip->addFile($filePath, $relativePath); + } + } + $zip->close(); + return ($fileName); + } + + + + /** + * Retourne la liste des modules installés dans un tableau composé + * du nom réel + * du numéro de version + */ + public static function getModules() + { + $modules = array(); + $dirs = array_diff(scandir('module'), array('..', '.')); + foreach ($dirs as $key => $value) { + // Dossier non vide + if (file_exists('module/' . $value . '/' . $value . '.php')) { + // Lire les constantes en gérant les erreurs de nom de classe + try { + $class_reflex = new \ReflectionClass($value); + $class_constants = $class_reflex->getConstants(); + // Constante REALNAME + if (array_key_exists('REALNAME', $class_constants)) { + $realName = $value::REALNAME; + } else { + $realName = ucfirst($value); + } + // Constante VERSION + if (array_key_exists('VERSION', $class_constants)) { + $version = $value::VERSION; + } else { + $version = '0.0'; + } + // Constante UPDATE + if (array_key_exists('UPDATE', $class_constants)) { + $update = $value::UPDATE; + } else { + $update = '0.0'; + } + // Constante DELETE + if (array_key_exists('DELETE', $class_constants)) { + $delete = $value::DELETE; + } else { + $delete = true; + } + // Constante DATADIRECTORY + if (array_key_exists('DATADIRECTORY', $class_constants)) { + $dataDirectory = $value::DATADIRECTORY; + } else { + $dataDirectory = ''; + } + // Affection + $modules[$value] = [ + 'name' => $value, + 'realName' => $realName, + 'version' => $version, + 'update' => $update, + 'delete' => $delete, + 'dataDirectory' => $dataDirectory + ]; + } catch (Exception $e) { + // on ne fait rien + } + } + } + return ($modules); + } + + + + /** + * Retourne true si le protocole est en TLS + * @return bool + */ + public static function isHttps() + { + if ( + (empty($_SERVER['HTTPS']) === false and $_SERVER['HTTPS'] !== 'off') + or $_SERVER['SERVER_PORT'] === 443 + ) { + return true; + } else { + return false; + } + } + + + /** + * Retourne l'URL de base du site + * @param bool $queryString Affiche ou non le point d'interrogation + * @param bool $host Affiche ou non l'host + * @return string + */ + public static function baseUrl($queryString = true, $host = true) + { + // Protocole + $protocol = helper::isHttps() === true ? 'https://' : 'http://'; + // Host + if ($host) { + $host = $protocol . $_SERVER['HTTP_HOST']; + } + // Pathinfo + $pathInfo = pathinfo($_SERVER['PHP_SELF']); + // Querystring + if ($queryString and helper::checkRewrite() === false) { + $queryString = '?'; + } else { + $queryString = ''; + } + return $host . rtrim($pathInfo['dirname'], ' ' . DIRECTORY_SEPARATOR) . '/' . $queryString; + } + + /** + * Check le statut de l'URL rewriting + * @return bool + */ + public static function checkRewrite() + { + // N'interroge que le serveur Apache + if (strpos($_SERVER["SERVER_SOFTWARE"], 'Apache') > 0) { + self::$rewriteStatus === false; + } elseif (self::$rewriteStatus === null) { + // Ouvre et scinde le fichier .htaccess + $htaccess = explode('# URL rewriting', file_get_contents('.htaccess')); + // Retourne un boolean en fonction du contenu de la partie réservée à l'URL rewriting + //self::$rewriteStatus = (empty($htaccess[1]) === false); + self::$rewriteStatus = (strpos($htaccess[1], 'RewriteEngine on') > 0) ? true : false; + } + return self::$rewriteStatus; + } + + /** + * Renvoie le numéro de version de Zwii est en ligne + * @return string + */ + public static function getOnlineVersion($channel) + { + return (helper::getUrlContents(common::ZWII_UPDATE_URL . $channel . '/version')); + } + + + /** + * Check si une nouvelle version de Zwii est disponible + * @return bool + */ + public static function checkNewVersion($channel) + { + $version = helper::getOnlineVersion($channel); + if (!empty($version)) { + return ((version_compare(common::ZWII_VERSION, $version)) === -1); + } else { + return false; + } + } + + + /** + * Génère des variations d'une couleur + * @param string $rgba Code rgba de la couleur + * @return array + */ + public static function colorVariants($rgba) + { + preg_match('#\(+(.*)\)+#', $rgba, $matches); + $rgba = explode(', ', $matches[1]); + return [ + 'normal' => 'rgba(' . $rgba[0] . ',' . $rgba[1] . ',' . $rgba[2] . ',' . $rgba[3] . ')', + 'darken' => 'rgba(' . max(0, $rgba[0] - 15) . ',' . max(0, $rgba[1] - 15) . ',' . max(0, $rgba[2] - 15) . ',' . $rgba[3] . ')', + 'veryDarken' => 'rgba(' . max(0, $rgba[0] - 20) . ',' . max(0, $rgba[1] - 20) . ',' . max(0, $rgba[2] - 20) . ',' . $rgba[3] . ')', + 'text' => self::relativeLuminanceW3C($rgba) > .22 ? "#222" : "#DDD", + 'rgb' => 'rgb(' . $rgba[0] . ',' . $rgba[1] . ',' . $rgba[2] . ')', + 'invert' => 'rgba (' . + ($rgba[0] < 128 ? 255 : 0) . ',' . + ($rgba[1] < 128 ? 255 : 0) . ',' . + ($rgba[1] < 128 ? 255 : 0) . ',' . + ($rgba[0] < 128 ? 255 : 0) . ')' + ]; + } + + /** + * Supprime un cookie + * @param string $cookieKey Clé du cookie à supprimer + */ + public static function deleteCookie($cookieKey) + { + unset($_COOKIE[$cookieKey]); + setcookie($cookieKey, '', time() - 3600, helper::baseUrl(false, false), '', false, true); + } + + /** + * Filtre une chaîne en fonction d'un tableau de données + * @param string $text Chaîne à filtrer + * @param int $filter Type de filtre à appliquer + * @return string + */ + public static function filter($text, $filter) + { + $text = is_null($text) ? $text : trim($text); + switch ($filter) { + case self::FILTER_BOOLEAN: + $text = (bool) $text; + break; + case self::FILTER_DATETIME: + $timezone = new DateTimeZone(core::$timezone); + $date = new DateTime($text); + $date->setTimezone($timezone); + $text = (int) $date->format('U'); + break; + case self::FILTER_FLOAT: + $text = filter_var($text, FILTER_SANITIZE_NUMBER_FLOAT); + $text = (float) $text; + break; + case self::FILTER_ID: + $text = mb_strtolower($text, 'UTF-8'); + $text = strip_tags( + str_replace( + explode(',', 'á,à,â,ä,ã,å,ç,é,è,ê,ë,í,ì,î,ï,ñ,ó,ò,ô,ö,õ,ú,ù,û,ü,ý,ÿ,\',", '), + explode(',', 'a,a,a,a,a,a,c,e,e,e,e,i,i,i,i,n,o,o,o,o,o,u,u,u,u,y,y,-,-,-'), + $text + ) + ); + $text = preg_replace('/([^a-z0-9-])/', '', $text); + // Supprime les emoji + $text = preg_replace('/[[:^print:]]/', '', $text); + // Supprime les tirets en fin de chaine (emoji en fin de nom) + $text = rtrim($text, '-'); + // Cas où un identifiant est vide + if (empty($text)) { + $text = uniqid(''); + } + // Un ID ne peut pas être un entier, pour éviter les conflits avec le système de pagination + if (intval($text) !== 0) { + $text = '_' . $text; + } + break; + case self::FILTER_INT: + $text = (int) filter_var($text, FILTER_SANITIZE_NUMBER_INT); + break; + case self::FILTER_MAIL: + $text = filter_var($text, FILTER_SANITIZE_EMAIL); + break; + case self::FILTER_PASSWORD: + $text = password_hash($text, PASSWORD_BCRYPT); + break; + case self::FILTER_STRING_LONG: + $text = mb_substr(filter_var($text, FILTER_SANITIZE_FULL_SPECIAL_CHARS), 0, 500000); + break; + case self::FILTER_STRING_SHORT: + $text = mb_substr(filter_var($text, FILTER_SANITIZE_FULL_SPECIAL_CHARS), 0, 500); + break; + case self::FILTER_TIMESTAMP: + $text = date('Y-m-d H:i:s', $text); + break; + case self::FILTER_URL: + $text = filter_var($text, FILTER_SANITIZE_URL); + break; + } + return $text; + } + + /** + * Incrémente une clé en fonction des clés ou des valeurs d'un tableau + * @param mixed $key Clé à incrémenter + * @param array $array Tableau à vérifier + * @return string + */ + public static function increment($key, $array = []) + { + // Pas besoin d'incrémenter si la clef n'existe pas + if ($array === []) { + return $key; + } + // Incrémente la clef + else { + // Si la clef est numérique elle est incrémentée + if (is_numeric($key)) { + $newKey = $key; + while (array_key_exists($newKey, $array) or in_array($newKey, $array)) { + $newKey++; + } + } + // Sinon l'incrémentation est ajoutée après la clef + else { + $i = 2; + $newKey = $key; + while (array_key_exists($newKey, $array) or in_array($newKey, $array)) { + $newKey = $key . '-' . $i; + $i++; + } + } + return $newKey; + } + } + + /** + * Minimise du css + * @param string $css Css à minimiser + * @return string + */ + public static function minifyCss($css) + { + // Supprime les commentaires + $css = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $css); + // Supprime les tabulations, espaces, nouvelles lignes, etc... + $css = str_replace(["\r\n", "\r", "\n", "\t", ' ', ' ', ' '], '', $css); + $css = preg_replace(['(( )+{)', '({( )+)'], '{', $css); + $css = preg_replace(['(( )+})', '(}( )+)', '(;( )*})'], '}', $css); + $css = preg_replace(['(;( )+)', '(( )+;)'], ';', $css); + // Convertir les codes entités + $css = htmlspecialchars_decode($css); + // Supprime les balises HTML + $css = strip_tags($css); + // Retourne le css minifié + return $css; + } + + /** + * Minimise du js + * @param string $js Js à minimiser + * @return string + */ + public static function minifyJs($js) + { + // Supprime les commentaires + $js = preg_replace('/\\/\\*[^*]*\\*+([^\\/][^*]*\\*+)*\\/|\s*(?getUrl() + * @param string $item pagination nombre d'éléments par page + * @param null|int $sufix Suffixe de l'url + * @return array + */ + public static function pagination($array, $url, $item, $suffix = null) + { + // Scinde l'url + $url = explode('/', $url); + // Url de pagination + $urlPagination = is_numeric($url[count($url) - 1]) ? array_pop($url) : 1; + // Url de la page courante + $urlCurrent = implode('/', $url); + // Nombre d'éléments à afficher + $nbElements = count($array); + // Nombre de page + $nbPage = ceil($nbElements / $item); + // Page courante + $currentPage = is_numeric($urlPagination) ? self::filter($urlPagination, self::FILTER_INT) : 1; + // Premier élément de la page + $firstElement = ($currentPage - 1) * $item; + // Dernier élément de la page + $lastElement = $firstElement + $item; + $lastElement = ($lastElement > $nbElements) ? $nbElements : $lastElement; + // Mise en forme de la liste des pages + $pages = ''; + if ($nbPage > 1) { + for ($i = 1; $i <= $nbPage; $i++) { + $disabled = ($i === $currentPage) ? ' class="disabled"' : false; + $pages .= '' . $i . ''; + } + $pages = ''; + } + // Retourne un tableau contenant les informations sur la pagination + return [ + 'first' => $firstElement, + 'last' => $lastElement, + 'pages' => $pages + ]; + } + + /** + * Calcul de la luminance relative d'une couleur + */ + public static function relativeLuminanceW3C($rgba) + { + // Conversion en sRGB + $RsRGB = $rgba[0] / 255; + $GsRGB = $rgba[1] / 255; + $BsRGB = $rgba[2] / 255; + // Ajout de la transparence + $RsRGBA = $rgba[3] * $RsRGB + (1 - $rgba[3]); + $GsRGBA = $rgba[3] * $GsRGB + (1 - $rgba[3]); + $BsRGBA = $rgba[3] * $BsRGB + (1 - $rgba[3]); + // Calcul de la luminance + $R = ($RsRGBA <= .03928) ? $RsRGBA / 12.92 : pow(($RsRGBA + .055) / 1.055, 2.4); + $G = ($GsRGBA <= .03928) ? $GsRGBA / 12.92 : pow(($GsRGBA + .055) / 1.055, 2.4); + $B = ($BsRGBA <= .03928) ? $BsRGBA / 12.92 : pow(($BsRGBA + .055) / 1.055, 2.4); + return .2126 * $R + .7152 * $G + .0722 * $B; + } + + /** + * Retourne les attributs d'une balise au bon format + * @param array $array Liste des attributs ($key => $value) + * @param array $exclude Clés à ignorer ($key) + * @return string + */ + public static function sprintAttributes(array $array = [], array $exclude = []) + { + $exclude = array_merge( + [ + 'before', + 'classWrapper', + 'help', + 'label' + ], + $exclude + ); + $attributes = []; + foreach ($array as $key => $value) { + if (($value or $value === 0) and in_array($key, $exclude) === false) { + // Désactive le message de modifications non enregistrées pour le champ + if ($key === 'noDirty') { + $attributes[] = 'data-no-dirty'; + } + // Disabled + // Readonly + elseif (in_array($key, ['disabled', 'readonly'])) { + $attributes[] = sprintf('%s', $key); + } + // Autres + else { + $attributes[] = sprintf('%s="%s"', $key, $value); + } + } + } + return implode(' ', $attributes); + } + + /** + * Retourne un segment de chaîne sans couper de mot + * @param string $text Texte à scinder + * @param int $start (voir substr de PHP pour fonctionnement) + * @param int $length (voir substr de PHP pour fonctionnement) + * @return string + */ + public static function subword($text, $start, $length) + { + $text = trim($text); + if (strlen($text) > $length) { + $text = mb_substr($text, $start, $length); + $text = mb_substr($text, 0, min(mb_strlen($text), mb_strrpos($text, ' '))); + } + return $text; + } + + /** + * Cryptage + * @param string $key la clé d'encryptage + * @param string $string la chaine à coder + * @return string + */ + public static function encrypt($string, $key) + { + $encrypted = openssl_encrypt($string, "AES-256-CBC", $key, 0, substr(md5($key), 0, 16)); + return base64_encode($encrypted); + } + + /** + * Décryptage + * @param string $key la clé d'encryptage + * @param string $string la chaine à décoder + * @return string + */ + public static function decrypt($string, $key) + { + $decrypted = openssl_decrypt(base64_decode($string), "AES-256-CBC", $key, 0, substr(md5($key), 0, 16)); + return $decrypted; + } + +} \ No newline at end of file diff --git a/core/class/jsondb/Dot.class.php b/core/class/jsondb/Dot.class.php new file mode 100644 index 0000000..29b5dfa --- /dev/null +++ b/core/class/jsondb/Dot.class.php @@ -0,0 +1,477 @@ +data = $data; + } + } + + /** + * Get value of path, default value if path doesn't exist or all data + * + * @param array $array Source Array + * @param mixed|null $key Path + * @param mixed|null $default Default value + * @return mixed Value of path + */ + public static function getValue($array, $key, $default = null) + { + if (is_string($key)) { + // Iterate path + $keys = explode('.', $key); + foreach ($keys as $key) { + if (!isset($array[$key])) { + return $default; + } + $array = &$array[$key]; + } + // Get value + return $array; + } elseif (is_null($key)) { + // Get all data + return $array; + } + return null; + } + + /** + * Set value or array of values to path + * + * @param array $array Target array with data + * @param mixed $key Path or array of paths and values + * @param mixed|null $value Value to set if path is not an array + */ + public static function setValue(&$array, $key, $value) + { + if (is_string($key)) { + // Iterate path + $keys = explode('.', $key); + foreach ($keys as $key) { + if (!isset($array[$key]) || !is_array($array[$key])) { + $array[$key] = []; + } + $array = &$array[$key]; + } + // Set value to path + $array = $value; + } elseif (is_array($key)) { + // Iterate array of paths and values + foreach ($key as $k => $v) { + self::setValue($array, $k, $v); + } + } + } + + /** + * Add value or array of values to path + * + * @param array $array Target array with data + * @param mixed $key Path or array of paths and values + * @param mixed|null $value Value to set if path is not an array + * @param boolean $pop Helper to pop out last key if value is an array + */ + public static function addValue(&$array, $key, $value = null, $pop = false) + { + if (is_array($key)) { + // Iterate array of paths and values + foreach ($key as $k => $v) { + self::addValue($array, $k, $v); + } + } else { + // Iterate path + $keys = explode('.', (string)$key); + if ($pop === true) { + array_pop($keys); + } + foreach ($keys as $key) { + if (!isset($array[$key]) || !is_array($array[$key])) { + $array[$key] = []; + } + $array = &$array[$key]; + } + // Add value to path + $array[] = $value; + } + } + + /** + * Delete path or array of paths + * + * @param array $array Target array with data + * @param mixed $key Path or array of paths to delete + */ + public static function deleteValue(&$array, $key) + { + if (is_string($key)) { + // Iterate path + $keys = explode('.', $key); + $last = array_pop($keys); + foreach ($keys as $key) { + if (!isset($array[$key])) { + return; + } + $array = &$array[$key]; + } + if (isset($array[$last])) { + // Detele path + unset($array[$last]); + } + } elseif (is_array($key)) { + // Iterate array of paths + foreach ($key as $k) { + self::delete($k); + } + } + } + + + /** + * Get value of path, default value if path doesn't exist or all data + * + * @param mixed|null $key Path + * @param mixed|null $default Default value + * @return mixed Value of path + */ + public function get($key, $default = null, $asObject = false) + { + $value = self::getValue($this->data, $key, $default); + if ($asObject && is_array($value)) { + return new self($value); + } + + return $value; + } + + /** + * Set value or array of values to path + * + * @param mixed $key Path or array of paths and values + * @param mixed|null $value Value to set if path is not an array + * @return $this + */ + public function set($key, $value = null) + { + self::setValue($this->data, $key, $value); + return $this; + } + + /** + * Add value or array of values to path + * + * @param mixed $key Path or array of paths and values + * @param mixed|null $value Value to set if path is not an array + * @param boolean $pop Helper to pop out last key if value is an array + * @return $this + */ + public function add($key, $value = null, $pop = false) + { + self::addValue($this->data, $key, $value); + return $this; + } + + /** + * Check if path exists + * + * @param string $key Path + * @return boolean + */ + public function has($key) + { + $keys = explode('.', (string)$key); + $data = &$this->data; + foreach ($keys as $key) { + if (!isset($data[$key])) { + return false; + } + $data = &$data[$key]; + } + + return true; + } + + /** + * Delete path or array of paths + * + * @param mixed $key Path or array of paths to delete + * @return $this + */ + public function delete($key) + { + self::deleteValue($this->data, $key); + return $this; + } + + /** + * Increase numeric value + * + * @param string $key + * @param float $number + * @return float + */ + public function plus(string $key, float $number): float + { + $newAmount = $this->get($key, 0) + $number; + $this->set($key, $newAmount); + + return $newAmount; + } + + /** + * Reduce numeric value + * + * @param string $key + * @param float $number + * @return float + */ + public function minus(string $key, float $number): float + { + $newAmount = $this->get($key, 0) - $number; + $this->set($key, $newAmount); + + return $newAmount; + } + + /** + * Delete all data, data from path or array of paths and + * optionally format path if it doesn't exist + * + * @param mixed|null $key Path or array of paths to clean + * @param boolean $format Format option + */ + public function clear($key = null, $format = false) + { + if (is_string($key)) { + // Iterate path + $keys = explode('.', $key); + $data = &$this->data; + foreach ($keys as $key) { + if (!isset($data[$key]) || !is_array($data[$key])) { + if ($format === true) { + $data[$key] = []; + } else { + return; + } + } + $data = &$data[$key]; + } + // Clear path + $data = []; + } elseif (is_array($key)) { + // Iterate array + foreach ($key as $k) { + $this->clear($k, $format); + } + } elseif (is_null($key)) { + // Clear all data + $this->data = []; + } + } + + /** + * Set data + * + * @param array $data + */ + public function setData(array $data) + { + $this->data = $data; + } + + /** + * Set data as a reference + * + * @param array $data + */ + public function setDataAsRef(array &$data) + { + $this->data = &$data; + } + + /** + * @inheritDoc + */ + public function offsetSet($offset, $value): void + { + $this->set($offset, $value); + } + + /** + * @inheritDoc + */ + public function offsetExists($offset): bool + { + return $this->has($offset); + } + + /** + * @inheritDoc + */ + public function offsetGet($offset): mixed + { + return $this->get($offset); + } + + /** + * @inheritDoc + */ + public function offsetUnset($offset): void + { + $this->delete($offset); + } + + /** + * Magic methods + */ + public function __set($key, $value = null) + { + $this->set($key, $value); + } + + public function __get($key) + { + return $this->get($key); + } + + public function __isset($key) + { + return $this->has($key); + } + + public function __unset($key) + { + $this->delete($key); + } + + /** + * Check for emptiness + * + * @return bool + */ + public function isEmpty(): bool + { + return !(bool)count($this->data); + } + + /** + * Return all data as array + * + * @return array + */ + public function toArray(): array + { + return $this->data; + } + + /** + * Return as json string + * + * @return false|string + */ + public function toJson() + { + return json_encode($this->data, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT); + } + + /** + * @return string + */ + public function __toString(): string + { + return $this->toJson(); + } + + /** + * @return array + */ + public function __toArray(): array + { + return $this->toArray(); + } + + /** + * Return the current element + * @link https://php.net/manual/en/iterator.current.php + * @return mixed Can return any type. + * @since 5.0.0 + */ + public function current(): mixed + { + return current($this->data); + } + + /** + * Move forward to next element + * @link https://php.net/manual/en/iterator.next.php + * @return void Any returned value is ignored. + * @since 5.0.0 + */ + public function next(): void + { + next($this->data); + } + + /** + * Return the key of the current element + * @link https://php.net/manual/en/iterator.key.php + * @return mixed scalar on success, or null on failure. + * @since 5.0.0 + */ + public function key(): mixed + { + return key($this->data); + } + + /** + * Checks if current position is valid + * @link https://php.net/manual/en/iterator.valid.php + * @return bool The return value will be casted to boolean and then evaluated. + * Returns true on success or false on failure. + * @since 5.0.0 + */ + public function valid(): bool + { + $key = key($this->data); + return ($key !== NULL && $key !== FALSE); + } + + /** + * Rewind the Iterator to the first element + * @link https://php.net/manual/en/iterator.rewind.php + * @return void Any returned value is ignored. + * @since 5.0.0 + */ + public function rewind(): void + { + reset($this->data); + } + + /** + * @inheritDoc + */ + public function count(): int + { + return count($this->data); + } +} \ No newline at end of file diff --git a/core/class/jsondb/JsonDb.class.php b/core/class/jsondb/JsonDb.class.php new file mode 100644 index 0000000..8344c04 --- /dev/null +++ b/core/class/jsondb/JsonDb.class.php @@ -0,0 +1,161 @@ +config = array_merge([ + 'name' => 'data.json', + 'backup' => false, + 'dir' => getcwd() + ], $config); + $this->loadData(); + parent::__construct(); + } + + /** + * Reload data from file + * @return $this + */ + public function reload() + { + $this->loadData(true); + return $this; + } + + + /** + * Set value or array of values to path + * + * @param mixed $key Path or array of paths and values + * @param mixed|null $value Value to set if path is not an array + * @param bool $save Save data to database + * @return $this + */ + public function set($key, $value = null, $save = true) + { + parent::set($key, $value); + if ($save) + $this->save(); + return $this; + } + + /** + * Add value or array of values to path + * + * @param mixed $key Path or array of paths and values + * @param mixed|null $value Value to set if path is not an array + * @param boolean $pop Helper to pop out last key if value is an array + * @param bool $save Save data to database + * @return $this + */ + public function add($key, $value = null, $pop = false, $save = true) + { + parent::add($key, $value, $pop); + if ($save) + $this->save(); + return $this; + } + + /** + * Delete path or array of paths + * + * @param mixed $key Path or array of paths to delete + * @param bool $save Save data to database + * @return $thisurn $this + */ + public function delete($key, $save = true) + { + parent::delete($key); + if ($save) + $this->save(); + return $this; + } + + /** + * Delete all data, data from path or array of paths and + * optionally format path if it doesn't exist + * + * @param mixed|null $key Path or array of paths to clean + * @param boolean $format Format option + * @param bool $save Save data to database + * @return $this + */ + public function clear($key = null, $format = false, $save = true) + { + parent::clear($key, $format); + if ($save) + $this->save(); + return $this; + } + + + /** + * Local database upload + * @param bool $reload Reboot data? + * @return array|mixed|null + */ + protected function loadData($reload = false) + { + if ($this->data === null || $reload) { + $this->db = $this->config['dir'] . $this->config['name']; + if (!file_exists($this->db)) { + return null; // Rebuild database manage by CMS + } else { + if ($this->config['backup']) { + try { + //todo make backup of database + copy($this->config['dir'] . DIRECTORY_SEPARATOR . $this->config['name'], $this->config['dir'] . DIRECTORY_SEPARATOR . $this->config['name'] . '.backup'); + } catch (\Exception $e) { + + } + } + } + $this->data = json_decode(file_get_contents($this->db), true); + if (!$this->data === null) { + throw new \InvalidArgumentException('Database file ' . $this->db + . ' contains invalid json object. Please validate or remove file'); + } + } + return $this->data; + } + + /** + * Save database + */ + public function save() + { + //$v = json_encode($this->data, JSON_UNESCAPED_UNICODE ); + $v = json_encode($this->data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_FORCE_OBJECT); + $l = strlen($v); + $t = 0; + while ($t < 5) { + $w = file_put_contents($this->db, $v); // Multi user get a locker + if ($w == $l) { + break; + } + $t++; + } + if ($w !== $l) { + exit('Erreur d\'écriture, les données n\'ont pas été sauvegardées'); + } + + } +} \ No newline at end of file diff --git a/core/class/jsondb/LICENSE.md b/core/class/jsondb/LICENSE.md new file mode 100644 index 0000000..a3ecbe0 --- /dev/null +++ b/core/class/jsondb/LICENSE.md @@ -0,0 +1,19 @@ +Copyright (c) 2016-2017 Andrey Mistulov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/core/class/jsondb/README.md b/core/class/jsondb/README.md new file mode 100644 index 0000000..6656cd7 --- /dev/null +++ b/core/class/jsondb/README.md @@ -0,0 +1,269 @@ +# Dot - PHP dot notation array access +Based on [adbario/php-dot-notation](https://github.com/adbario/php-dot-notation) package + +Easy access to multidimensional arrays with dot notation. +With dot notation, your code is cleaner and handling deeper arrays is super easy. + +This class implements PHP's ArrayAccess class, so Dot object can also be used the same way as normal arrays with additional dot notation. + +With Dot you can change this: + +```php +echo $data['info']['home']['address']; +``` + +to this: + +```php +echo $data->get('info.home.address'); +``` + +or even this: + +```php +echo $data['info.home.address']; +``` + +## Installation + +Via composer: + +``` +composer require adbario/php-dot-notation +``` + +Or just copy the class file Dot.php and handle namespace yourself. + +#### With [Composer](https://getcomposer.org/): + +``` +composer require adbario/php-dot-notation +``` + +#### Manual installation: +1. Download the latest release +2. Extract the files into your project +3. require_once '/path/to/php-dot-notation/src/Dot.php'; + +## Usage + +This array will be used as a reference on this guide: + +```php +$array = [ + 'user' => [ + 'firstname' => 'John', + 'lastname' => 'Smith' + ], + 'info' => [ + 'kids' => [ + 0 => 'Laura', + 1 => 'Chris', + 2 => 'Little Johnny' + ], + 'home' => [ + 'address' => 'Rocky Road 3' + ] + ] +]; +``` + +### Create a Dot object + +To start with an empty array, just create a new Dot object: + +```php +$data = new \Adbar\Dot; +``` + +If you have an array already available, inject it to the Dot object: + +```php +$data = new \Adbar\Dot($array); +``` + +Set an array after creating the Dot object: + +```php +$data->setArray($array); +``` + +Set an array as a reference, and all changes will be made directly to the original array: + +```php +$data->setReference($array); +``` + +### Set a value + +Set i.e. a phone number in the 'home' array: + +```php +$data->set('info.home.tel', '09-123-456-789'); + +// Array style +$data['info.home.tel'] = '09-123-456-789'; +``` + +Set multiple values at once: + +```php +$data->set([ + 'user.haircolor' => 'blue', + 'info.home.address' => 'Private Lane 1' +]); +``` + +If the value already exists, Dot will override it with a new value. + +### Get a value + +```php +echo $data->get('info.home.address'); + +// Default value if the path doesn't exist +echo $data->get('info.home.country', 'some default value'); + +// Array style +echo $data['info.home.address']; +``` + +Get all the stored values: + +```php +$values = $data->all(); +`` + +Get a value from a path and remove it: + +```php +$address = $data->pull('home.address'); +``` + +Get all the stored values and remove them: + +```php +$values = $data->pull(); +``` + +### Add a value + +```php +$data->add('info.kids', 'Amy'); +``` + +Multiple values at once: + +```php +$data->add('info.kids', [ + 'Ben', 'Claire' +]); +``` + +### Check if a value exists + +```php +if ($data->has('info.home.address')) { + // Do something... +} + +// Array style +if (isset($data['info.home.address'])) { + // Do something... +} +``` + +### Delete a value + +```php +$data->delete('info.home.address'); + +// Array style +unset($data['info.home.address']); +``` + +Multiple values at once: + +```php +$data->delete([ + 'user.lastname', 'info.home.address' +]); +``` + +### Clear values + +Delete all the values from a path: + +```php +$data->clear('info.home'); +``` + +Clear multiple paths at once: + +```php +$data->clear([ + 'user', 'info.home' +]); +``` + +Clear all data: + +```php +$data->clear(); +``` + +### Sort the values + +You can sort the values of a given path or all the stored values. + +Sort the values of a path: + +```php +$kids = $data->sort('info.kids'); + +// Sort recursively +$info = $data->sort('info'); +``` + +Sort all the values + +```php +$sorted = $data->sort(); + +// Sort recursively +$sorted = $data->sort(); +``` + +### Magic methods + +Magic methods can be used to handle single level data (without dot notation). These examples are not using the same data array as examples above. + +Set a value: + +```php +$data->name = 'John'; +``` + +Get a value: + +```php +echo $data->name; +``` + +Check if a value exists: + +```php +if (isset($data->name)) { + // Do something... +} +``` + +Delete a value: + +```php +unset($data->name); +``` + +## License + +[MIT license](LICENSE.md) diff --git a/core/class/layout.class.php b/core/class/layout.class.php new file mode 100644 index 0000000..c6b0f56 --- /dev/null +++ b/core/class/layout.class.php @@ -0,0 +1,1310 @@ +core = $core; + } + + /** + * Affiche le consentement aux cookies + */ + public function showCookies() + { + // La gestion des cookies est externalisée + if ($this->getData(['config', 'cookieConsent']) === false) { + return; + } + // Le cookie est déjà validé + if ($this->getInput('ZWII_COOKIE_CONSENT') === 'true') { + return; + } + $item = '
'; + // Bouton de fermeture + $item .= '
'; + $item .= template::ico('cancel'); + $item .= '
'; + // Texte de la popup + $item .= '

' . $this->getData(['locale', 'cookies', 'titleLabel']) . '

'; + $item .= '

' . $this->getData(['locale', 'cookies', 'mainLabel']) . '

'; + // Formulaire de réponse + if ( + $this->getData(['locale', 'homePageId']) === $this->getUrl(0) + ) { + $item .= '
'; + } else { + $item .= ''; + } + $item .= '

'; + $item .= ''; + $item .= '
'; + // mentions légales si la page est définie + $legalPage = $this->getData(['locale', 'legalPageId']); + if ($legalPage !== 'none') { + $item .= '

' . $this->getData(['locale', 'cookies', 'linkLegalLabel']) . '

'; + } + $item .= '
'; + echo $item; + } + + /** + * Formate le contenu de la page selon les gabarits + * @param Page par defaut + */ + public function showMain() + { + echo '
'; + // Récupérer la config de la page courante + $blocks = is_null($this->getData(['page', $this->getUrl(0), 'block'])) ? '12' : $this->getData(['page', $this->getUrl(0), 'block']); + $blocks = explode('-', $blocks); + // Initialiser + $blockleft = ''; + $blockright = ''; + switch (sizeof($blocks)) { + case 1: // une colonne + $content = 'col' . $blocks[0]; + break; + case 2: // 2 blocs + if ($blocks[0] < $blocks[1]) { // détermine la position de la colonne + $blockleft = 'col' . $blocks[0]; + $content = 'col' . $blocks[1]; + } else { + $content = 'col' . $blocks[0]; + $blockright = 'col' . $blocks[1]; + } + break; + case 3: // 3 blocs + $blockleft = 'col' . $blocks[0]; + $content = 'col' . $blocks[1]; + $blockright = 'col' . $blocks[2]; + } + // Page pleine pour la configuration des modules et l'édition des pages sauf l'affichage d'un article de blog + $pattern = ['config', 'edit', 'add', 'comment', 'data']; + if ( + (sizeof($blocks) === 1 || + in_array($this->getUrl(1), $pattern)) + ) { // Pleine page en mode configuration + if ($this->getData(['page', $this->getUrl(0), 'navLeft']) === 'top' || $this->getData(['page', $this->getUrl(0), 'navRight']) === 'top') { + $this->showNavButtons('top'); + } + $this->showContent(); + if ($this->getData(['page', $this->getUrl(0), 'navLeft']) === 'bottom' || $this->getData(['page', $this->getUrl(0), 'navRight']) === 'bottom') { + $this->showNavButtons('bottom'); + } + } else { + echo '
'; + /** + * Barre gauche + */ + if ($blockleft !== '') { + echo '
"; + } + /** + * Contenu de page + */ + echo '
'; + $this->showNavButtons('top'); + $this->showContent(); + $this->showNavButtons('bottom'); + echo '
'; + /** + * Barre droite + */ + if ($blockright !== '') { + echo '
'; + } + echo '
'; + } + echo '
'; + } + + /** + * Affiche le contenu + * @param Page par défaut + */ + public function showContent() + { + + if ( + $this->core->output['title'] + and ($this->getData(['page', $this->getUrl(0)]) === null + or $this->getData(['page', $this->getUrl(0), 'hideTitle']) === false + or $this->getUrl(1) === 'config' + ) + ) { + echo '

' . $this->core->output['title'] . '

'; + } + + echo $this->core->output['content']; + } + + /** + * Affiche le pied de page + */ + public function showFooter() + { + // Déterminer la position + $positionFixed = ''; + if ( + $this->getData(['theme', 'footer', 'position']) === 'site' + // Affiche toujours le pied de page pour l'édition du thème + or ($this->getData(['theme', 'footer', 'position']) === 'hide' + and $this->getUrl(0) === 'theme' + ) + ) { + $position = 'site'; + } else { + $position = 'body'; + if ($this->getData(['theme', 'footer', 'fixed']) === true) { + $positionFixed = ' footerbodyFixed'; + } + // Sortir de la division précédente + echo ''; + } + + echo $this->getData(['theme', 'footer', 'position']) === 'hide' ? '