ZwiiCMS/core/core.php

2952 lines
101 KiB
PHP
Raw Normal View History

2018-04-02 08:29:19 +02:00
<?php
/**
* This file is part of Zwii.
*
* For full copyright and license information, please see the LICENSE
* file that was distributed with this source code.
*
* @author Rémi Jean <remi.jean@outlook.com>
* @copyright Copyright (C) 2008-2018, Rémi Jean
* @license GNU General Public License, version 3
* @link http://zwiicms.com/
*/
class common {
const DISPLAY_RAW = 0;
const DISPLAY_JSON = 1;
const DISPLAY_LAYOUT_BLANK = 2;
const DISPLAY_LAYOUT_MAIN = 3;
const DISPLAY_LAYOUT_LIGHT = 4;
const GROUP_BANNED = -1;
const GROUP_VISITOR = 0;
const GROUP_MEMBER = 1;
const GROUP_MODERATOR = 2;
const GROUP_ADMIN = 3;
2018-11-13 13:27:37 +01:00
const ZWII_VERSION = '8.4.0';
2018-04-02 08:29:19 +02:00
public static $actions = [];
public static $coreModuleIds = [
'config',
'install',
'maintenance',
'page',
'sitemap',
'theme',
'user'
];
private $data = [];
private $defaultData = [
'config' => [
'analyticsId' => '',
'autoBackup' => true,
'cookieConsent' => true,
'favicon' => 'favicon.ico',
'homePageId' => 'accueil',
'maintenance' => false,
'metaDescription' => 'Zwii est un CMS sans base de données qui permet à ses utilisateurs de créer et gérer facilement un site web sans aucune connaissance en programmation.',
'social' => [
'facebookId' => '',
'googleplusId' => '',
'instagramId' => '',
'pinterestId' => '',
'twitterId' => '',
'youtubeId' => ''
],
'timezone' => 'Europe/Paris',
2018-10-06 05:46:07 +02:00
'title' => 'Zwii, votre site en quelques clics !',
2018-10-06 06:19:54 +02:00
'ItemsperPage' => 10
2018-04-02 08:29:19 +02:00
],
'core' => [
'dataVersion' => 0,
'lastBackup' => 0,
'lastClearTmp' => 0
],
'page' => [
'accueil' => [
// menu image
'typeMenu' => 'text',
'iconUrl' => '',
'disable' => false,
// menu image
'content' => "<h3>Bienvenue sur votre nouveau site Zwii !</h3>\r\n<p><strong>Un email contenant le récapitulatif de votre installation vient de vous être envoyé.</strong></p>\r\n<p>Connectez-vous dès maintenant à votre espace membre afin de créer un site à votre image ! Vous allez pouvoir personnaliser le thème, créer des pages, ajouter des utilisateurs et bien plus encore !</p>\r\n<p>Si vous avez besoin d'aide ou si vous cherchez des informations sur Zwii, n'hésitez pas à jeter un œil à notre <a title=\"Forum\" href=\"http://forum.zwiicms.com/\">forum</a>.</p>",
'hideTitle' => false,
'metaDescription' => '',
'metaTitle' => '',
'moduleId' => '',
2018-10-23 10:21:57 +02:00
'modulePosition' => 'bottom',
2018-04-02 08:29:19 +02:00
'parentPageId' => '',
'position' => 1,
'group' => self::GROUP_VISITOR,
'targetBlank' => false,
'title' => 'Accueil'
],
'enfant' => [
// menu image
'typeMenu' => 'text',
'iconUrl' => '',
'disable' => false,
// menu image
'content' => "<p>Vous pouvez assigner des parents à vos pages afin de mieux organiser votre menu !</p>\r\n<div class=\"row\">\r\n<div class=\"col4\">\r\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam interdum, neque non vulputate hendrerit, arcu turpis dapibus nisl, id scelerisque metus lectus vitae nisi. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec feugiat dolor et turpis finibus condimentum. Cras sit amet ligula sagittis justo.</p>\r\n</div>\r\n<div class=\"col4\">\r\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam interdum, neque non vulputate hendrerit, arcu turpis dapibus nisl, id scelerisque metus lectus vitae nisi. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec feugiat dolor et turpis finibus condimentum. Cras sit amet ligula sagittis justo.</p>\r\n</div>\r\n<div class=\"col4\">\r\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam interdum, neque non vulputate hendrerit, arcu turpis dapibus nisl, id scelerisque metus lectus vitae nisi. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec feugiat dolor et turpis finibus condimentum. Cras sit amet ligula sagittis justo.</p>\r\n</div>\r\n</div>",
'hideTitle' => false,
'metaDescription' => '',
'metaTitle' => '',
'moduleId' => '',
2018-10-23 10:21:57 +02:00
'modulePosition' => 'bottom',
2018-04-02 08:29:19 +02:00
'parentPageId' => 'accueil',
'position' => 1,
'group' => self::GROUP_VISITOR,
'targetBlank' => false,
'title' => 'Enfant'
],
'cachee' => [
// menu image
'typeMenu' => 'text',
'iconUrl' => '',
'disable' => false,
// menu image
'content' => "<p>Cette page n'est visible que par les membres de votre site !</p>\r\n<div class=\"row\">\r\n<div class=\"col6\">\r\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam interdum, neque non vulputate hendrerit, arcu turpis dapibus nisl, id scelerisque metus lectus vitae nisi. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec feugiat dolor et turpis finibus condimentum. Cras sit amet ligula sagittis justo.</p>\r\n</div>\r\n<div class=\"col6\">\r\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam interdum, neque non vulputate hendrerit, arcu turpis dapibus nisl, id scelerisque metus lectus vitae nisi. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec feugiat dolor et turpis finibus condimentum. Cras sit amet ligula sagittis justo.</p>\r\n</div>r\n</div>",
'hideTitle' => false,
'metaDescription' => '',
'metaTitle' => '',
'moduleId' => '',
'parentPageId' => '',
2018-10-23 10:21:57 +02:00
'modulePosition' => 'bottom',
2018-04-02 08:29:19 +02:00
'position' => 2,
'group' => self::GROUP_MEMBER,
'targetBlank' => false,
'title' => 'Cachée'
],
'blog' => [
2018-09-09 18:51:24 +02:00
2018-04-02 08:29:19 +02:00
'typeMenu' => 'text',
'iconUrl' => '',
2018-09-09 18:51:24 +02:00
'disable' => false,
2018-04-02 08:29:19 +02:00
'content' => "<p>Cette page contient une instance du module de blog. Cliquez sur un article afin de le lire et de poster des commentaires.</p>",
'hideTitle' => false,
'metaDescription' => '',
'metaTitle' => '',
'moduleId' => 'blog',
2018-10-23 10:21:57 +02:00
'modulePosition' => 'bottom',
2018-04-02 08:29:19 +02:00
'parentPageId' => '',
'position' => 3,
'group' => self::GROUP_VISITOR,
'targetBlank' => false,
'title' => 'Blog'
],
'galeries' => [
// menu image
'typeMenu' => 'text',
'iconUrl' => '',
'disable' => false,
// menu image
'content' => "<p>Cette page contient une instance du module de galeries photos. Cliquez sur la galerie ci-dessous afin de voir les photos qu'elle contient.</p>",
'hideTitle' => false,
'metaDescription' => '',
'metaTitle' => '',
'moduleId' => 'gallery',
2018-10-23 10:21:57 +02:00
'modulePosition' => 'bottom',
2018-04-02 08:29:19 +02:00
'parentPageId' => '',
'position' => 4,
'group' => self::GROUP_VISITOR,
'targetBlank' => false,
'title' => 'Galeries'
],
'site-de-zwii' => [
// menu image
'typeMenu' => 'text',
'iconUrl' => '',
'disable' => false,
// menu image
'content' => "",
'hideTitle' => false,
'metaDescription' => '',
'metaTitle' => '',
'moduleId' => 'redirection',
2018-10-23 10:21:57 +02:00
'modulePosition' => 'bottom',
2018-04-02 08:29:19 +02:00
'parentPageId' => '',
'position' => 5,
'group' => self::GROUP_VISITOR,
'targetBlank' => true,
'title' => 'Site de Zwii'
],
'contact' => [
// menu image
'typeMenu' => 'text',
'iconUrl' => '',
'disable' => false,
// menu image
'content' => "<p>Cette page contient un exemple de formulaire conçu à partir du module de génération de formulaires. Il est configuré pour envoyer les données saisies par mail aux administrateurs du site.</p>",
'hideTitle' => false,
'metaDescription' => '',
'metaTitle' => '',
'moduleId' => 'form',
2018-10-23 10:21:57 +02:00
'modulePosition' => 'bottom',
2018-04-02 08:29:19 +02:00
'parentPageId' => '',
'position' => 6,
'group' => self::GROUP_VISITOR,
'targetBlank' => false,
'title' => 'Contact'
]
],
'module' => [
'blog' => [
'mon-premier-article' => [
'closeComment' => false,
'comment' => [
'58e11d09e5aff' => [
'author' => 'Rémi',
'content' => 'Article bien rédigé et très pertinent, bravo !',
'createdOn' => 1421786100,
'userId' => ''
]
],
'content' => "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In a placerat metus. Morbi luctus laoreet dolor et euismod. Phasellus eget eros ac eros pretium tincidunt. Sed maximus magna lectus, non vestibulum sapien pretium maximus. Donec convallis leo tortor. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras convallis lacus eu risus gravida varius. Etiam mattis massa vitae eros placerat bibendum.</p>\r\n<p>Vivamus tempus magna augue, in bibendum quam blandit at. Morbi felis tortor, suscipit ut ipsum ut, volutpat consectetur orci. Nulla tincidunt quis ligula non viverra. Sed pretium dictum blandit. Donec fringilla, nunc at dictum pretium, arcu massa viverra leo, et porta turpis ipsum eget risus. Quisque quis maximus purus, in elementum arcu. Donec nisi orci, aliquam non luctus non, congue volutpat massa. Curabitur sed risus congue, porta arcu vel, tincidunt nisi. Duis tincidunt quam ut velit maximus ornare. Nullam sagittis, ante quis pharetra hendrerit, lorem massa dapibus mi, a hendrerit dolor odio nec augue. Nunc sem nisl, tincidunt vitae nunc et, viverra tristique diam. In eget dignissim lectus. Nullam volutpat lacus id ex dapibus viverra. Pellentesque ultricies lorem ut nunc elementum volutpat. Cras id ultrices justo.</p>\r\n<p>Phasellus nec erat leo. Praesent at sem nunc. Vestibulum quis condimentum turpis. Cras semper diam vitae enim fringilla, ut fringilla mauris efficitur. In nec porttitor urna. Nam eros leo, vehicula eget lobortis sed, gravida id mauris. Nulla bibendum nunc tortor, non bibendum justo consectetur vel. Phasellus nec risus diam. In commodo tellus nec nulla fringilla, nec feugiat nunc consectetur. Etiam non eros sodales, sodales lacus vel, finibus leo. Quisque hendrerit tristique congue. Phasellus nec augue vitae libero elementum facilisis. Mauris pretium ornare nisi, non scelerisque velit consectetur sit amet.</p>",
'picture' => 'galerie/landscape/meadow.jpg',
2018-04-02 08:29:19 +02:00
'publishedOn' => 1420903200,
'state' => true,
'title' => 'Mon premier article',
'userId' => '' // Géré au moment de l'installation
],
'mon-deuxieme-article' => [
'closeComment' => false,
'comment' => [],
'content' => "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam lobortis eros pharetra metus rutrum pretium et sagittis mauris. Donec commodo venenatis sem nec suscipit. In tempor sollicitudin scelerisque. Etiam quis nibh eleifend, congue nisl quis, ultricies ipsum. Integer at est a eros vulputate pellentesque eu vitae tellus. Nullam suscipit quam nisl. Vivamus dui odio, luctus ac fringilla ultrices, eleifend vel sapien. Integer sem ex, lobortis eu mattis eu, condimentum non libero. Aliquam non porttitor elit, eu hendrerit neque. Praesent tortor urna, tincidunt sed dictum id, rutrum tempus sapien.</p>\r\n<p>Donec accumsan ante ac odio laoreet porttitor. Pellentesque et leo a leo scelerisque mattis id vel elit. Quisque egestas congue enim nec semper. Morbi mollis nibh sapien. Nunc quis fringilla lorem. Donec vel venenatis nunc. Donec lectus velit, tempor sit amet dui sed, consequat commodo enim. Nam porttitor neque semper, dapibus nunc bibendum, lobortis urna. Morbi ullamcorper molestie lectus a elementum. Curabitur eu cursus orci, sed tristique justo. In massa lacus, imperdiet eu elit quis, consectetur maximus magna. Integer suscipit varius ante vitae egestas. Morbi scelerisque fermentum ipsum, euismod faucibus mi tincidunt id. Sed at consectetur velit. Ut fermentum nunc nibh, at commodo felis lacinia nec.</p>\r\n<p>Nullam a justo quis lectus facilisis semper eget quis sem. Morbi suscipit erat sem, non fermentum nunc luctus vel. Proin venenatis quam ut arcu luctus efficitur. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nam sollicitudin tristique nunc nec convallis. Maecenas id tortor semper, tempus nisl laoreet, cursus lacus. Aliquam sagittis est in leo congue, a pharetra felis aliquet. Nulla gravida lobortis sapien, quis viverra enim ullamcorper sed. Donec ultrices sem eu volutpat dapibus. Nam euismod, tellus eu congue mollis, massa nisi finibus odio, vitae porta arcu urna ac lorem. Sed faucibus dignissim pretium. Pellentesque eget ante tellus. Pellentesque a elementum odio, sit amet vulputate diam. Lorem ipsum dolor sit amet, consectetur adipiscing elit. In hendrerit consequat dolor, malesuada pellentesque tellus molestie non. Aenean quis purus a lectus pellentesque laoreet.</p>",
'picture' => 'galerie/landscape/desert.jpg',
2018-04-02 08:29:19 +02:00
'publishedOn' => 1421748000,
'state' => true,
'title' => 'Mon deuxième article',
'userId' => '' // Géré au moment de l'installation
],
'mon-troisieme-article' => [
'closeComment' => true,
'comment' => [],
'content' => "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut ut tempus nibh. Cras eget iaculis justo, ac laoreet lacus. Nunc tellus nulla, auctor id hendrerit eu, pellentesque in sapien. In hac habitasse platea dictumst. Aliquam leo urna, hendrerit id nunc eget, finibus maximus dolor. Sed rutrum sapien consectetur, tincidunt nulla at, blandit quam. Duis ex enim, vehicula vel nisi vitae, lobortis volutpat nisl. Vivamus enim libero, euismod nec risus vel, interdum placerat elit. In cursus sapien condimentum dui imperdiet, sed lobortis ante consectetur. Maecenas hendrerit eget felis non consequat.</p>\r\n<p>Nullam nec risus non velit efficitur tempus eget tincidunt mauris. Etiam venenatis leo id justo sagittis, commodo dignissim sapien tristique. Vivamus finibus augue malesuada sapien gravida rutrum. Integer mattis lectus ac pulvinar scelerisque. Integer suscipit feugiat metus, ac molestie odio suscipit eget. Fusce at elit in tellus venenatis finibus id sit amet magna. Integer sodales luctus neque blandit posuere. Cras pellentesque dictum lorem eget vestibulum. Quisque vitae metus non nisi efficitur rhoncus ut vitae ipsum. Donec accumsan massa at est faucibus lacinia. Quisque imperdiet luctus neque eu vestibulum. Phasellus pellentesque felis ligula, id imperdiet elit ultrices eu.</p>",
'picture' => 'galerie/landscape/iceberg.jpg',
2018-04-02 08:29:19 +02:00
'publishedOn' => 1423154400,
'state' => true,
'title' => 'Mon troisième article',
'userId' => '' // Géré au moment de l'installation
]
],
'galeries' => [
'beaux-paysages' => [
'config' => [
'name' => 'Beaux paysages',
'directory' => 'site/file/source/galerie/landscape'
2018-04-02 08:29:19 +02:00
],
'legend' => [
'desert.jpg' => 'Un désert',
'iceberg.jpg' => 'Un iceberg',
'meadow.jpg' => 'Une prairie'
]
],
'espace' => [
'config' => [
'name' => 'Espace',
'directory' => 'site/file/source/galerie/space'
2018-04-02 08:29:19 +02:00
],
'legend' => [
'earth.jpg' => 'La Terre et la Lune',
'cosmos.jpg' => 'Le cosmos',
'nebula.jpg' => 'Une nébuleuse'
]
]
],
'site-de-zwii' => [
'url' => 'http://zwiicms.com/',
'count' => 0
],
'contact' => [
'config' => [
'button' => '',
'capcha' => true,
'group' => self::GROUP_ADMIN,
'pageId' => '',
'subject' => ''
],
'data' => [],
'input' => [
[
'name' => 'Adresse mail',
'position' => 1,
'required' => true,
'type' => 'mail',
'values' => ''
],
[
'name' => 'Sujet',
'position' => 2,
'required' => true,
'type' => 'text',
'values' => ''
],
[
'name' => 'Message',
'position' => 3,
'required' => true,
'type' => 'textarea',
'values' => ''
]
]
]
],
'user' => [],
'theme' => [
'body' => [
'backgroundColor' => 'rgba(236, 239, 241, 1)',
'image' => '',
'imageAttachment' => 'scroll',
'imageRepeat' => 'no-repeat',
'imagePosition' => 'top center',
'imageSize' => 'auto'
],
'button' => [
'backgroundColor' => 'rgba(74, 105, 189, 1)'
],
'footer' => [
'backgroundColor' => 'rgba(255, 255, 255, 1)',
'copyrightAlign' => 'center',
'height' => '10px',
'loginLink' => true,
'margin' => false,
'position' => 'site',
'socialsAlign' => 'center',
'text' => '',
'textAlign' => 'center',
2018-09-09 21:28:05 +02:00
'textColor' => 'rgba(33, 34, 35, 1)',
'copyrightPosition' => '3',
'textPosition' => '2',
'socialsPosition' => '1'
2018-04-02 08:29:19 +02:00
],
'header' => [
'backgroundColor' => 'rgba(255, 255, 255, 1)',
'font' => 'Oswald',
'fontSize' => '2em',
'fontWeight' => 'normal',
'height' => '150px',
'image' => '',
'imagePosition' => 'center center',
'imageRepeat' => 'no-repeat',
'margin' => false,
'position' => 'site',
'textAlign' => 'center',
'textColor' => 'rgba(33, 34, 35, 1)',
'textHide' => false,
'textTransform' => 'none',
2018-09-09 11:47:24 +02:00
'linkHome' => 'false',
'imageContainer' => 'auto'
2018-04-02 08:29:19 +02:00
],
'link' => [
'textColor' => 'rgba(74, 105, 189, 1)'
],
'menu' => [
'backgroundColor' => 'rgba(74, 105, 189, 1)',
'fontSize' => '1em',
'fontWeight' => 'normal',
'height' => '15px 10px',
'loginLink' => true,
'margin' => false,
'position' => 'site-second',
'textAlign' => 'left',
'textColor' => 'rgba(255, 255, 255, 1)',
'textTransform' => 'none'
],
'site' => [
'backgroundColor' => 'rgba(255, 255, 255, 1)',
'radius' => '0',
'shadow' => '0',
'width' => '1170px'
],
'text' => [
'font' => 'Open+Sans',
'fontSize' => '14px',
'textColor' => 'rgba(33, 34, 35, 1)'
],
'title' => [
'font' => 'Oswald',
'fontWeight' => 'normal',
'textColor' => 'rgba(74, 105, 189, 1)',
'textTransform' => 'none'
]
]
];
private $hierarchy = [
'all' => [],
'visible' => []
];
private $input = [
'_COOKIE' => [],
'_POST' => []
];
public static $inputBefore = [];
public static $inputNotices = [];
public $output = [
'access' => true,
'content' => '',
'display' => self::DISPLAY_LAYOUT_MAIN,
'metaDescription' => '',
'metaTitle' => '',
'notification' => '',
'redirect' => '',
'script' => '',
'showBarEditButton' => false,
'showPageContent' => false,
'state' => false,
'style' => '',
'title' => null, // Null car un titre peut être vide
// Trié par ordre d'exécution
'vendor' => [
'jquery',
'normalize',
'lity',
'filemanager',
// 'flatpickr', Désactivé par défaut
// 'tinycolorpicker', Désactivé par défaut
// 'tinymce', Désactivé par défaut
// 'codemirror', // Désactivé par défaut
'tippy',
'zwiico'
],
'view' => ''
];
public static $groups = [
self::GROUP_BANNED => 'Banni',
self::GROUP_VISITOR => 'Visiteur',
self::GROUP_MEMBER => 'Membre',
self::GROUP_MODERATOR => 'Modérateur',
self::GROUP_ADMIN => 'Administrateur'
];
public static $groupEdits = [
self::GROUP_BANNED => 'Banni',
self::GROUP_MEMBER => 'Membre',
self::GROUP_MODERATOR => 'Modérateur',
self::GROUP_ADMIN => 'Administrateur'
];
public static $groupNews = [
self::GROUP_MEMBER => 'Membre',
self::GROUP_MODERATOR => 'Modérateur',
self::GROUP_ADMIN => 'Administrateur'
];
public static $groupPublics = [
self::GROUP_VISITOR => 'Visiteur',
self::GROUP_MEMBER => 'Membre',
self::GROUP_MODERATOR => 'Modérateur',
self::GROUP_ADMIN => 'Administrateur'
];
public static $timezone;
private $url = '';
private $user = [];
/**
* Constructeur commun
*/
public function __construct() {
// Extraction des données http
if(isset($_POST)) {
$this->input['_POST'] = $_POST;
}
if(isset($_COOKIE)) {
$this->input['_COOKIE'] = $_COOKIE;
}
// Génère le fichier de donnée
if(file_exists('site/data/data.json') === false) {
$this->setData([$this->defaultData]);
$this->saveData();
chmod('site/data/data.json', 0755);
}
// Import des données
if($this->data === []) {
// Trois tentatives
for($i = 0; $i < 3; $i++) {
$this->setData([json_decode(file_get_contents('site/data/data.json'), true)]);
if($this->data) {
break;
}
elseif($i === 2) {
exit('Unable to read data file.');
}
// Pause de 10 millisecondes
usleep(10000);
}
}
// Mise à jour
$this->update();
// Utilisateur connecté
if($this->user === []) {
$this->user = $this->getData(['user', $this->getInput('ZWII_USER_ID')]);
}
// Construit la liste des pages parents/enfants
if($this->hierarchy['all'] === []) {
$pages = helper::arrayCollumn($this->getData(['page']), 'position', 'SORT_ASC');
// Parents
foreach($pages as $pageId => $pagePosition) {
if(
// Page parent
$this->getData(['page', $pageId, 'parentPageId']) === ""
// Ignore les pages dont l'utilisateur n'a pas accès
AND (
$this->getData(['page', $pageId, 'group']) === self::GROUP_VISITOR
OR (
$this->getUser('password') === $this->getInput('ZWII_USER_PASSWORD')
AND $this->getUser('group') >= $this->getData(['page', $pageId, 'group'])
)
)
) {
if($pagePosition !== 0) {
$this->hierarchy['visible'][$pageId] = [];
}
$this->hierarchy['all'][$pageId] = [];
}
}
// Enfants
foreach($pages as $pageId => $pagePosition) {
if(
// Page parent
$parentId = $this->getData(['page', $pageId, 'parentPageId'])
// Ignore les pages dont l'utilisateur n'a pas accès
AND (
(
$this->getData(['page', $pageId, 'group']) === self::GROUP_VISITOR
AND $this->getData(['page', $parentId, 'group']) === self::GROUP_VISITOR
)
OR (
$this->getUser('password') === $this->getInput('ZWII_USER_PASSWORD')
AND $this->getUser('group') >= $this->getData(['page', $parentId, 'group'])
AND $this->getUser('group') >= $this->getData(['page', $pageId, 'group'])
)
)
) {
if($pagePosition !== 0) {
$this->hierarchy['visible'][$parentId][] = $pageId;
}
$this->hierarchy['all'][$parentId][] = $pageId;
}
}
}
// Construit l'url
if($this->url === '') {
if($url = $_SERVER['QUERY_STRING']) {
$this->url = $url;
}
else {
$this->url = $this->getData(['config', 'homePageId']);
}
}
}
/**
* Ajoute les valeurs en sortie
* @param array $output Valeurs en sortie
*/
public function addOutput($output) {
$this->output = array_merge($this->output, $output);
}
/**
* Ajoute une notice de champ obligatoire
* @param string $key Clef du champ
*/
public function addRequiredInputNotices($key) {
// La clef est un tableau
if(preg_match('#\[(.*)\]#', $key, $secondKey)) {
$firstKey = explode('[', $key)[0];
$secondKey = $secondKey[1];
if(empty($this->input['_POST'][$firstKey][$secondKey])) {
common::$inputNotices[$firstKey . '_' . $secondKey] = 'Obligatoire';
}
}
// La clef est une chaine
elseif(empty($this->input['_POST'][$key])) {
common::$inputNotices[$key] = 'Obligatoire';
}
}
/**
* Check du token CSRF (true = bo
*/
public function checkCSRF() {
return ((empty($_POST['csrf']) OR hash_equals($_SESSION['csrf'], $_POST['csrf']) === false) === false);
}
/**
* Supprime des données
* @param array $keys Clé(s) des données
*/
public function deleteData($keys) {
switch(count($keys)) {
case 1 :
unset($this->data[$keys[0]]);
break;
case 2:
unset($this->data[$keys[0]][$keys[1]]);
break;
case 3:
unset($this->data[$keys[0]][$keys[1]][$keys[2]]);
break;
case 4:
unset($this->data[$keys[0]][$keys[1]][$keys[2]][$keys[3]]);
break;
case 5:
unset($this->data[$keys[0]][$keys[1]][$keys[2]][$keys[3]][$keys[4]]);
break;
case 6:
unset($this->data[$keys[0]][$keys[1]][$keys[2]][$keys[3]][$keys[4]][$keys[5]]);
break;
case 7:
unset($this->data[$keys[0]][$keys[1]][$keys[2]][$keys[3]][$keys[4]][$keys[5]][$keys[6]]);
break;
}
}
/**
2018-11-13 13:27:37 +01:00
* Récupérer une copie d'écran du site Web pour le tag image si le fichier n'existe pas
* En local, copie du site décran de ZwiiCMS
*/
public function makeImageTag () {
if (!file_exists('site/file/source/screenshot.png'))
{
if ( strpos(helper::baseUrl(false),'localhost') > 0 OR strpos(helper::baseUrl(false),'127.0.0.1') > 0) {
$site = 'https://ZwiiCMS.com'; } else {
$site = helper::baseUrl(false); }
2018-11-13 13:27:37 +01:00
$googlePagespeedData = file_get_contents('https://www.googleapis.com/pagespeedonline/v2/runPagespeed?url='. $site .'&screenshot=true');
$googlePagespeedData = json_decode($googlePagespeedData, true);
$screenshot = $googlePagespeedData['screenshot']['data'];
$screenshot = str_replace(array('_','-'),array('/','+'),$screenshot);
$data = 'data:image/jpeg;base64,'.$screenshot;
$data = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $data));
file_put_contents( 'site/file/source/screenshot.png',$data);
}
}
2018-04-02 08:29:19 +02:00
/**
* Accède aux données
* @param array $keys Clé(s) des données
* @return mixed
*/
public function getData($keys = null) {
// Retourne l'ensemble des données
if($keys === null) {
return $this->data;
}
// Décent dans les niveaux de la variable $data
$data = $this->data;
foreach($keys as $key) {
// Si aucune donnée n'existe retourne null
if(isset($data[$key]) === false) {
return null;
}
// Sinon décent dans les niveaux
else {
$data = $data[$key];
}
}
// Retourne les données
return $data;
}
/**
* Accède à la liste des pages parents et de leurs enfants ou aux enfants d'une page parent
* @param int $parentId Id de la page parent
* @param bool $onlyVisible Affiche seulement les pages visibles
* @return array
*/
public function getHierarchy($parentId = null, $onlyVisible = true) {
$hierarchy = $onlyVisible ? $this->hierarchy['visible'] : $this->hierarchy['all'];
// Enfants d'un parent
if($parentId) {
if(array_key_exists($parentId, $hierarchy)) {
return $hierarchy[$parentId];
}
else {
return [];
}
}
// Parents et leurs enfants
else {
return $hierarchy;
}
}
/**
* Accède à une valeur des variables http (ordre de recherche en l'absence de type : _COOKIE, _POST)
* @param string $key Clé de la valeur
* @param int $filter Filtre à appliquer à la valeur
* @param bool $required Champ requis
* @return mixed
*/
public function getInput($key, $filter = helper::FILTER_STRING_SHORT, $required = false) {
// La clef est un tableau
if(preg_match('#\[(.*)\]#', $key, $secondKey)) {
$firstKey = explode('[', $key)[0];
$secondKey = $secondKey[1];
foreach($this->input as $type => $values) {
// Champ obligatoire
if($required) {
$this->addRequiredInputNotices($key);
}
// Check de l'existence
// Également utile pour les checkboxs qui ne retournent rien lorsqu'elles ne sont pas cochées
if(
array_key_exists($firstKey, $values)
AND array_key_exists($secondKey, $values[$firstKey])
) {
// Retourne la valeur filtrée
if($filter) {
return helper::filter($this->input[$type][$firstKey][$secondKey], $filter);
}
// Retourne la valeur
else {
return $this->input[$type][$firstKey][$secondKey];
}
}
}
}
// La clef est une chaine
else {
foreach($this->input as $type => $values) {
// Champ obligatoire
if($required) {
$this->addRequiredInputNotices($key);
}
// Check de l'existence
// Également utile pour les checkboxs qui ne retournent rien lorsqu'elles ne sont pas cochées
if(array_key_exists($key, $values)) {
// Retourne la valeur filtrée
if($filter) {
return helper::filter($this->input[$type][$key], $filter);
}
// Retourne la valeur
else {
return $this->input[$type][$key];
}
}
}
}
// Sinon retourne null
return helper::filter(null, $filter);
}
/**
* Accède à une partie l'url ou à l'url complète
* @param int $key Clé de l'url
* @return string|null
*/
public function getUrl($key = null) {
// Url complète
if($key === null) {
return $this->url;
}
// Une partie de l'url
else {
$url = explode('/', $this->url);
return array_key_exists($key, $url) ? $url[$key] : null;
}
}
/**
* Accède à l'utilisateur connecté
* @param int $key Clé de la valeur
* @return string|null
*/
public function getUser($key) {
if(is_array($this->user) === false) {
return false;
}
elseif($key === 'id') {
return $this->getInput('ZWII_USER_ID');
}
elseif(array_key_exists($key, $this->user)) {
return $this->user[$key];
}
else {
return false;
}
}
/**
* Check qu'une valeur est transmise par la méthode _POST
* @return bool
*/
public function isPost() {
return ($this->checkCSRF() AND $this->input['_POST'] !== []);
}
/**
* Enregistre les données
*/
public function saveData() {
// Trois tentatives
for($i = 0; $i < 3; $i++) {
if(file_put_contents('site/data/data.json', json_encode($this->getData()), LOCK_EX) !== false) {
break;
}
// Pause de 10 millisecondes
usleep(10000);
}
}
/**
* Envoi un mail
* @param string|array $to Destinataire
* @param string $subject Sujet
* @param string $content Contenu
* @return bool
*/
public function sendMail($to, $subject, $content) {
// Layout
ob_start();
include 'core/layout/mail.php';
$layout = ob_get_clean();
// Mail
$mail = new PHPMailer;
$mail->CharSet = 'UTF-8';
$host = str_replace('www.', '', $_SERVER['HTTP_HOST']);
$mail->setFrom('no-reply@' . $host, $this->getData(['config', 'title']));
$mail->addReplyTo('no-reply@' . $host, $this->getData(['config', 'title']));
if(is_array($to)) {
foreach($to as $userMail) {
$mail->addAddress($userMail);
}
}
else {
$mail->addAddress($to);
}
$mail->isHTML(true);
$mail->Subject = $subject;
$mail->Body = $layout;
$mail->AltBody = strip_tags($content);
if($mail->send()) {
return true;
}
else {
return $mail->ErrorInfo;
}
}
/**
* Insert des données
* @param array $keys Clé(s) des données
*/
public function setData($keys) {
switch(count($keys)) {
case 1:
$this->data = $keys[0];
break;
case 2:
$this->data[$keys[0]] = $keys[1];
break;
case 3:
$this->data[$keys[0]][$keys[1]] = $keys[2];
break;
case 4:
$this->data[$keys[0]][$keys[1]][$keys[2]] = $keys[3];
break;
case 5:
$this->data[$keys[0]][$keys[1]][$keys[2]][$keys[3]] = $keys[4];
break;
case 6:
$this->data[$keys[0]][$keys[1]][$keys[2]][$keys[3]][$keys[4]] = $keys[5];
break;
case 7:
$this->data[$keys[0]][$keys[1]][$keys[2]][$keys[3]][$keys[4]][$keys[5]] = $keys[6];
break;
}
}
/**
* Mises à jour
*/
private function update() {
// Version 8.1.0
if($this->getData(['core', 'dataVersion']) < 810) {
$this->setData(['config', 'timezone', 'Europe/Paris']);
$this->setData(['core', 'dataVersion', 810]);
$this->saveData();
}
// Version 8.2.0
if($this->getData(['core', 'dataVersion']) < 820) {
$this->setData(['theme', 'body', 'backgroundColor', 'rgba(236, 239, 241, 1)']);
$this->setData(['theme', 'site', 'backgroundColor', 'rgba(255, 255, 255, 1)']);
$this->setData(['theme', 'text', 'fontSize', '14px']);
$this->setData(['theme', 'text', 'textColor', 'rgba(33, 34, 35, 1)']);
$this->setData(['theme', 'menu', 'fontSize', '1em']);
$this->setData(['theme', 'menu', 'textColor', 'rgba(255, 255, 255, 1)']);
$this->setData(['theme', 'header', 'fontSize', '2em']);
$this->setData(['theme', 'footer', 'textColor', 'rgba(33, 34, 35, 1)']);
$this->setData(['core', 'dataVersion', 820]);
$this->saveData();
}
// Version 8.2.2
if($this->getData(['core', 'dataVersion']) < 822) {
$this->setData(['config', 'maintenance', false]);
$this->setData(['core', 'dataVersion', 822]);
$this->saveData();
}
// Version 8.2.6
if($this->getData(['core', 'dataVersion']) < 826) {
$this->setData(['theme','header','linkHome',false]);
$this->setData(['core', 'dataVersion', 826]);
$this->SaveData();
}
2018-09-09 11:47:24 +02:00
// Version 8.3.13
if($this->getData(['core', 'dataVersion']) < 8313) {
$this->setData(['theme','header','imageContainer','auto']);
$this->setData(['core', 'dataVersion', 8313]);
$this->SaveData();
}
2018-11-13 13:27:37 +01:00
// Version 8.4.0
if($this->getData(['core', 'dataVersion']) < 840) {
2018-09-09 21:28:05 +02:00
$this->setData(['theme','footer','socialsPosition','1']);
$this->setData(['theme','footer','textPosition','2']);
$this->setData(['theme','footer','copyrightPosition','3']);
2018-10-06 05:46:07 +02:00
$this->setData(['config','ItemsperPage','10']);
2018-11-13 13:27:37 +01:00
$this->setData(['core', 'dataVersion', 840]);
2018-09-09 21:28:05 +02:00
$this->SaveData();
}
2018-04-02 08:29:19 +02:00
}
}
class core extends common {
/**
* Constructeur du coeur
*/
public function __construct() {
parent::__construct();
// Token CSRF
if(empty($_SESSION['csrf'])) {
$_SESSION['csrf'] = bin2hex(openssl_random_pseudo_bytes(32));
}
// Fuseau horaire
self::$timezone = $this->getData(['config', 'timezone']); // Utile pour transmettre le timezone à la classe helper
date_default_timezone_set(self::$timezone);
// Supprime les fichiers temporaires
$lastClearTmp = mktime(0, 0, 0);
if($lastClearTmp > $this->getData(['core', 'lastClearTmp']) + 86400) {
$iterator = new DirectoryIterator('site/tmp/');
foreach($iterator as $fileInfos) {
if($fileInfos->isFile() AND $fileInfos->getBasename() !== '.gitkeep') {
@unlink($fileInfos->getPathname());
}
}
// Date de la dernière suppression
$this->setData(['core', 'lastClearTmp', $lastClearTmp]);
// Enregistre les données
$this->saveData();
}
// Backup automatique des données
$lastBackup = mktime(0, 0, 0);
if(
$this->getData(['config', 'autoBackup'])
AND $lastBackup > $this->getData(['core', 'lastBackup']) + 86400
AND $this->getData(['user']) // Pas de backup pendant l'installation
) {
// Copie du fichier de données
copy('site/data/data.json', 'site/backup/' . date('Y-m-d', $lastBackup) . '.json');
// Date du dernier backup
$this->setData(['core', 'lastBackup', $lastBackup]);
// Enregistre les données
$this->saveData();
// Supprime les backups de plus de 30 jours
$iterator = new DirectoryIterator('site/backup/');
foreach($iterator as $fileInfos) {
if(
$fileInfos->isFile()
AND $fileInfos->getBasename() !== '.htaccess'
AND $fileInfos->getMTime() + (86400 * 30) < time()
) {
@unlink($fileInfos->getPathname());
}
}
}
// Crée le fichier de personnalisation avancée
if(file_exists('site/data/custom.css') === false) {
file_put_contents('site/data/custom.css', file_get_contents('core/module/theme/resource/custom.css'));
chmod('site/data/custom.css', 0755);
}
// Crée le fichier de personnalisation
if(file_exists('site/data/theme.css') === false) {
file_put_contents('site/data/theme.css', '');
chmod('site/data/theme.css', 0755);
}
// Check la version
$cssVersion = preg_split('/\*+/', file_get_contents('site/data/theme.css'));
if(empty($cssVersion[1]) OR $cssVersion[1] !== md5(json_encode($this->getData(['theme'])))) {
// Version
$css = '/*' . md5(json_encode($this->getData(['theme']))) . '*/';
// Import des polices de caractères
$css .= '@import url("https://fonts.googleapis.com/css?family=' . $this->getData(['theme', 'text', 'font']) . '|' . $this->getData(['theme', 'title', 'font']) . '|' . $this->getData(['theme', 'header', 'font']) . '");';
// Fond du site
$colors = helper::colorVariants($this->getData(['theme', 'body', 'backgroundColor']));
$css .= 'body{background-color:' . $colors['normal'] . ';font-family:"' . str_replace('+', ' ', $this->getData(['theme', 'text', 'font'])) . '",sans-serif}';
if($themeBodyImage = $this->getData(['theme', 'body', 'image'])) {
$css .= 'body{background-image:url("../file/source/' . $themeBodyImage . '");background-position:' . $this->getData(['theme', 'body', 'imagePosition']) . ';background-attachment:' . $this->getData(['theme', 'body', 'imageAttachment']) . ';background-size:' . $this->getData(['theme', 'body', 'imageSize']) . ';background-repeat:' . $this->getData(['theme', 'body', 'imageRepeat']) . '}';
}
// Site
$colors = helper::colorVariants($this->getData(['theme', 'link', 'textColor']));
$css .= 'a{color:' . $colors['normal'] . '}';
$css .= 'a:hover{color:' . $colors['darken'] . '}';
$css .= 'body,.row > div{font-size:' . $this->getData(['theme', 'text', 'fontSize']) . '}';
$css .= 'body,.block h4,input[type=\'email\'],input[type=\'text\'],input[type=\'password\'],.inputFile,select,textarea,.inputFile,.button.buttonGrey,.button.buttonGrey:hover{color:' . $this->getData(['theme', 'text', 'textColor']) . '}';
$css .= '.container{max-width:' . $this->getData(['theme', 'site', 'width']) . '}';
$css .= '#site{background-color:' . $this->getData(['theme', 'site', 'backgroundColor']) . ';border-radius:' . $this->getData(['theme', 'site', 'radius']) . ';box-shadow:' . $this->getData(['theme', 'site', 'shadow']) . ' #212223}';
$colors = helper::colorVariants($this->getData(['theme', 'button', 'backgroundColor']));
$css .= '.speechBubble,.button,.button:hover,button[type=\'submit\'],.pagination a,.pagination a:hover,input[type=\'checkbox\']:checked + label:before,input[type=\'radio\']:checked + label:before,.helpContent{background-color:' . $colors['normal'] . ';color:' . $colors['text'] . '}';
$css .= '.helpButton span{color:' . $colors['normal'] . '}';
$css .= 'input[type=\'text\']:hover,input[type=\'password\']:hover,.inputFile:hover,select:hover,textarea:hover{border-color:' . $colors['normal'] . '}';
$css .= '.speechBubble:before{border-color:' . $colors['normal'] . ' transparent transparent transparent}';
$css .= '.button:hover,button[type=\'submit\']:hover,.pagination a:hover,input[type=\'checkbox\']:not(:active):checked:hover + label:before,input[type=\'checkbox\']:active + label:before,input[type=\'radio\']:checked:hover + label:before,input[type=\'radio\']:not(:checked):active + label:before{background-color:' . $colors['darken'] . '}';
$css .= '.helpButton span:hover{color:' . $colors['darken'] . '}';
$css .= '.button:active,button[type=\'submit\']:active,.pagination a:active{background-color:' . $colors['veryDarken'] . '}';
$colors = helper::colorVariants($this->getData(['theme', 'title', 'textColor']));
$css .= 'h1,h2,h3,h4,h5,h6{color:' . $colors['normal'] . ';font-family:"' . str_replace('+', ' ', $this->getData(['theme', 'title', 'font'])) . '",sans-serif;font-weight:' . $this->getData(['theme', 'title', 'fontWeight']) . ';text-transform:' . $this->getData(['theme', 'title', 'textTransform']) . '}';
// Bannière
$colors = helper::colorVariants($this->getData(['theme', 'header', 'backgroundColor']));
if($this->getData(['theme', 'header', 'margin'])) {
if($this->getData(['theme', 'menu', 'position']) === 'site-first') {
$css .= 'header{margin:0 20px}';
}
else {
$css .= 'header{margin:20px 20px 0 20px}';
}
}
2018-09-09 11:47:24 +02:00
$css .= 'header{background-size:' . $this->getData(['theme','header','imageContainer']).'}';
2018-04-02 08:29:19 +02:00
$css .= 'header{background-color:' . $colors['normal'] . ';height:' . $this->getData(['theme', 'header', 'height']) . ';line-height:' . $this->getData(['theme', 'header', 'height']) . ';text-align:' . $this->getData(['theme', 'header', 'textAlign']) . '}';
2018-09-09 11:47:24 +02:00
// Modif CrowueWeb pour la bannière
$css .= '@media (max-width: 767px) {header{height:' . $this->getData(['theme', 'header', 'height'])/2 . 'px;line-height:' . $this->getData(['theme', 'header', 'height'])/2 . 'px;}}';
// Fin modif Croque Web
2018-04-02 08:29:19 +02:00
if($themeHeaderImage = $this->getData(['theme', 'header', 'image'])) {
$css .= 'header{background-image:url("../file/source/' . $themeHeaderImage . '");background-position:' . $this->getData(['theme', 'header', 'imagePosition']) . ';background-repeat:' . $this->getData(['theme', 'header', 'imageRepeat']) . '}';
}
$colors = helper::colorVariants($this->getData(['theme', 'header', 'textColor']));
$css .= 'header span{color:' . $colors['normal'] . ';font-family:"' . str_replace('+', ' ', $this->getData(['theme', 'header', 'font'])) . '",sans-serif;font-weight:' . $this->getData(['theme', 'header', 'fontWeight']) . ';font-size:' . $this->getData(['theme', 'header', 'fontSize']) . ';text-transform:' . $this->getData(['theme', 'header', 'textTransform']) . '}';
// Menu
$colors = helper::colorVariants($this->getData(['theme', 'menu', 'backgroundColor']));
$css .= 'nav,nav a{background-color:' . $colors['normal'] . '}';
$css .= 'nav a,#toggle span,nav a:hover{color:' . $this->getData(['theme', 'menu', 'textColor']) . '}';
$css .= 'nav a:hover{background-color:' . $colors['darken'] . '}';
$css .= 'nav a.active{background-color:' . $colors['veryDarken'] . '}';
$css .= '#menu{text-align:' . $this->getData(['theme', 'menu', 'textAlign']) . '}';
if($this->getData(['theme', 'menu', 'margin'])) {
if(
$this->getData(['theme', 'menu', 'position']) === 'site-first'
OR $this->getData(['theme', 'header', 'position']) === 'body'
) {
$css .= 'nav{margin:20px 20px 0 20px}';
}
else {
$css .= 'nav{margin:0 20px 0}';
}
}
$css .= '#toggle span,#menu a{padding:' . $this->getData(['theme', 'menu', 'height']) . ';font-weight:' . $this->getData(['theme', 'menu', 'fontWeight']) . ';font-size:' . $this->getData(['theme', 'menu', 'fontSize']) . ';text-transform:' . $this->getData(['theme', 'menu', 'textTransform']) . '}';
// Pied de page
$colors = helper::colorVariants($this->getData(['theme', 'footer', 'backgroundColor']));