Init avec suppression de la langue étrangère du site en cours
This commit is contained in:
commit
3393ebe2af
11
.gitignore
vendored
Normal file
11
.gitignore
vendored
Normal file
@ -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
|
36
.htaccess
Normal file
36
.htaccess
Normal file
@ -0,0 +1,36 @@
|
||||
# Active la compression GZIP - option Apache
|
||||
<IfModule mod_gzip.c>
|
||||
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.*
|
||||
</IfModule>
|
||||
|
||||
# Active la compression DEFLATE - option Apache
|
||||
<IfModule mod_deflate.c>
|
||||
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
|
||||
</IfModule>
|
||||
|
||||
# Bloque l'accès à la liste des fichiers
|
||||
Options -Indexes
|
||||
|
||||
# Désactive l'option de substitution automatique
|
||||
<IfModule mod_negotiation.c>
|
||||
Options -MultiViews
|
||||
</IfModule>
|
||||
|
||||
# ne pas supprimer la ligne URL rewriting !
|
||||
# URL rewriting
|
1
CHANGES.md
Normal file
1
CHANGES.md
Normal file
@ -0,0 +1 @@
|
||||
# Changelog
|
1
LICENSE
Normal file
1
LICENSE
Normal file
@ -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.
|
113
LISEZMOI.md
Normal file
113
LISEZMOI.md
Normal file
@ -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.
|
||||
|
||||
```
|
3
core/class/.htaccess
Normal file
3
core/class/.htaccess
Normal file
@ -0,0 +1,3 @@
|
||||
# Bloque l'accès à la librairie
|
||||
Order deny,allow
|
||||
Deny from all
|
19
core/class/autoload.php
Normal file
19
core/class/autoload.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
class autoload {
|
||||
public static function autoloader () {
|
||||
require_once 'core/core.php';
|
||||
require_once 'core/class/router.class.php';
|
||||
require_once 'core/class/helper.class.php';
|
||||
require_once 'core/class/template.class.php';
|
||||
require_once 'core/class/layout.class.php';
|
||||
require_once 'core/class/sitemap/Runtime.class.php';
|
||||
require_once 'core/class/sitemap/FileSystem.class.php';
|
||||
require_once 'core/class/sitemap/SitemapGenerator.class.php';
|
||||
require_once 'core/class/phpmailer/PHPMailer.class.php';
|
||||
require_once 'core/class/phpmailer/Exception.class.php';
|
||||
require_once 'core/class/phpmailer/SMTP.class.php';
|
||||
require_once 'core/class/jsondb/Dot.class.php';
|
||||
require_once 'core/class/jsondb/JsonDb.class.php';
|
||||
}
|
||||
}
|
696
core/class/helper.class.php
Normal file
696
core/class/helper.class.php
Normal file
@ -0,0 +1,696 @@
|
||||
<?php
|
||||
|
||||
class helper
|
||||
{
|
||||
|
||||
/** Statut de la réécriture d'URL (pour éviter de lire le contenu du fichier .htaccess à chaque self::baseUrl()) */
|
||||
public static $rewriteStatus = null;
|
||||
|
||||
/** Filtres personnalisés */
|
||||
const FILTER_BOOLEAN = 1;
|
||||
const FILTER_DATETIME = 2;
|
||||
const FILTER_FLOAT = 3;
|
||||
const FILTER_ID = 4;
|
||||
const FILTER_INT = 5;
|
||||
const FILTER_MAIL = 6;
|
||||
const FILTER_PASSWORD = 7;
|
||||
const FILTER_STRING_LONG = 8;
|
||||
const FILTER_STRING_SHORT = 9;
|
||||
const FILTER_TIMESTAMP = 10;
|
||||
const FILTER_URL = 11;
|
||||
|
||||
|
||||
/**
|
||||
* Traduire le message dans la langue déterminée
|
||||
*/
|
||||
|
||||
public static function translate($text)
|
||||
{
|
||||
|
||||
// La traduction existe déjà dans le core
|
||||
/*
|
||||
if (array_key_exists($text, core::$dialog) === false && !empty($text)) {
|
||||
$dialogues = json_decode(file_get_contents('core/module/install/ressource/i18n/fr_FR.json' ), true);
|
||||
$data = array_merge($dialogues,[$text => '']);
|
||||
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*(?<![\:\=])\/\/.*/', '', $js);
|
||||
// Supprime les tabulations, espaces, nouvelles lignes, etc...
|
||||
$js = str_replace(["\r\n", "\r", "\t", "\n", ' ', ' ', ' '], '', $js);
|
||||
$js = preg_replace(['(( )+\))', '(\)( )+)'], ')', $js);
|
||||
// Retourne le js minifié
|
||||
return $js;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée un système de pagination (retourne un tableau contenant les informations sur la pagination (first, last, pages))
|
||||
* @param array $array Tableau de donnée à utiliser
|
||||
* @param string $url URL à utiliser, la dernière partie doit correspondre au numéro de page, par défaut utiliser $this->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 .= '<a href="' . helper::baseUrl() . $urlCurrent . '/' . $i . $suffix . '"' . $disabled . '>' . $i . '</a>';
|
||||
}
|
||||
$pages = '<div class="pagination">' . $pages . '</div>';
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
|
||||
}
|
477
core/class/jsondb/Dot.class.php
Normal file
477
core/class/jsondb/Dot.class.php
Normal file
@ -0,0 +1,477 @@
|
||||
<?php
|
||||
|
||||
namespace Prowebcraft;
|
||||
|
||||
use ArrayAccess;
|
||||
|
||||
/**
|
||||
* Dot Notation
|
||||
*
|
||||
* This class provides dot notation access to arrays, so it's easy to handle
|
||||
* multidimensional data in a clean way.
|
||||
*/
|
||||
class Dot implements \ArrayAccess, \Iterator, \Countable
|
||||
{
|
||||
|
||||
/** @var array Data */
|
||||
protected $data = [];
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array|null $data Data
|
||||
*/
|
||||
public function __construct(array $data = null)
|
||||
{
|
||||
if (is_array($data)) {
|
||||
$this->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);
|
||||
}
|
||||
}
|
161
core/class/jsondb/JsonDb.class.php
Normal file
161
core/class/jsondb/JsonDb.class.php
Normal file
@ -0,0 +1,161 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Andrey Mistulov
|
||||
* Company: Aristos
|
||||
* Date: 14.03.2017
|
||||
* Time: 15:25
|
||||
*/
|
||||
|
||||
namespace Prowebcraft;
|
||||
|
||||
/**
|
||||
* Class Data
|
||||
* @package Aristos
|
||||
*/
|
||||
class JsonDb extends \Prowebcraft\Dot
|
||||
{
|
||||
protected $db = '';
|
||||
protected $data = null;
|
||||
protected $config = [];
|
||||
|
||||
public function __construct($config = [])
|
||||
{
|
||||
$this->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');
|
||||
}
|
||||
|
||||
}
|
||||
}
|
19
core/class/jsondb/LICENSE.md
Normal file
19
core/class/jsondb/LICENSE.md
Normal file
@ -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.
|
269
core/class/jsondb/README.md
Normal file
269
core/class/jsondb/README.md
Normal file
@ -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)
|
1310
core/class/layout.class.php
Normal file
1310
core/class/layout.class.php
Normal file
File diff suppressed because it is too large
Load Diff
3
core/class/phpmailer/.htaccess
Normal file
3
core/class/phpmailer/.htaccess
Normal file
@ -0,0 +1,3 @@
|
||||
# Bloque l'accès à la librairie
|
||||
Order deny,allow
|
||||
Deny from all
|
40
core/class/phpmailer/Exception.class.php
Normal file
40
core/class/phpmailer/Exception.class.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHPMailer Exception class.
|
||||
* PHP Version 5.5.
|
||||
*
|
||||
* @see https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
|
||||
*
|
||||
* @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
|
||||
* @author Jim Jagielski (jimjag) <jimjag@gmail.com>
|
||||
* @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
|
||||
* @author Brent R. Matzelle (original founder)
|
||||
* @copyright 2012 - 2020 Marcus Bointon
|
||||
* @copyright 2010 - 2012 Jim Jagielski
|
||||
* @copyright 2004 - 2009 Andy Prevost
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
* @note This program is distributed in the hope that it will be useful - WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
namespace PHPMailer\PHPMailer;
|
||||
|
||||
/**
|
||||
* PHPMailer exception handler.
|
||||
*
|
||||
* @author Marcus Bointon <phpmailer@synchromedia.co.uk>
|
||||
*/
|
||||
class Exception extends \Exception
|
||||
{
|
||||
/**
|
||||
* Prettify error message output.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function errorMessage()
|
||||
{
|
||||
return '<strong>' . htmlspecialchars($this->getMessage(), ENT_COMPAT | ENT_HTML401) . "</strong><br />\n";
|
||||
}
|
||||
}
|
5126
core/class/phpmailer/PHPMailer.class.php
Normal file
5126
core/class/phpmailer/PHPMailer.class.php
Normal file
File diff suppressed because it is too large
Load Diff
1458
core/class/phpmailer/SMTP.class.php
Normal file
1458
core/class/phpmailer/SMTP.class.php
Normal file
File diff suppressed because it is too large
Load Diff
28
core/class/phpmailer/i18n/phpmailer.lang-de.php
Normal file
28
core/class/phpmailer/i18n/phpmailer.lang-de.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* German PHPMailer language file: refer to English translation for definitive list
|
||||
* @package PHPMailer
|
||||
*/
|
||||
|
||||
$PHPMAILER_LANG['authenticate'] = 'SMTP-Fehler: Authentifizierung fehlgeschlagen.';
|
||||
$PHPMAILER_LANG['connect_host'] = 'SMTP-Fehler: Konnte keine Verbindung zum SMTP-Host herstellen.';
|
||||
$PHPMAILER_LANG['data_not_accepted'] = 'SMTP-Fehler: Daten werden nicht akzeptiert.';
|
||||
$PHPMAILER_LANG['empty_message'] = 'E-Mail-Inhalt ist leer.';
|
||||
$PHPMAILER_LANG['encoding'] = 'Unbekannte Kodierung: ';
|
||||
$PHPMAILER_LANG['execute'] = 'Konnte folgenden Befehl nicht ausführen: ';
|
||||
$PHPMAILER_LANG['file_access'] = 'Zugriff auf folgende Datei fehlgeschlagen: ';
|
||||
$PHPMAILER_LANG['file_open'] = 'Dateifehler: Konnte folgende Datei nicht öffnen: ';
|
||||
$PHPMAILER_LANG['from_failed'] = 'Die folgende Absenderadresse ist nicht korrekt: ';
|
||||
$PHPMAILER_LANG['instantiate'] = 'Mail-Funktion konnte nicht initialisiert werden.';
|
||||
$PHPMAILER_LANG['invalid_address'] = 'Die Adresse ist ungültig: ';
|
||||
$PHPMAILER_LANG['invalid_hostentry'] = 'Ungültiger Hosteintrag: ';
|
||||
$PHPMAILER_LANG['invalid_host'] = 'Ungültiger Host: ';
|
||||
$PHPMAILER_LANG['mailer_not_supported'] = ' mailer wird nicht unterstützt.';
|
||||
$PHPMAILER_LANG['provide_address'] = 'Bitte geben Sie mindestens eine Empfängeradresse an.';
|
||||
$PHPMAILER_LANG['recipients_failed'] = 'SMTP-Fehler: Die folgenden Empfänger sind nicht korrekt: ';
|
||||
$PHPMAILER_LANG['signing'] = 'Fehler beim Signieren: ';
|
||||
$PHPMAILER_LANG['smtp_connect_failed'] = 'Verbindung zum SMTP-Server fehlgeschlagen.';
|
||||
$PHPMAILER_LANG['smtp_error'] = 'Fehler vom SMTP-Server: ';
|
||||
$PHPMAILER_LANG['variable_set'] = 'Kann Variable nicht setzen oder zurücksetzen: ';
|
||||
$PHPMAILER_LANG['extension_missing'] = 'Fehlende Erweiterung: ';
|
33
core/class/phpmailer/i18n/phpmailer.lang-el.php
Normal file
33
core/class/phpmailer/i18n/phpmailer.lang-el.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Greek PHPMailer language file: refer to English translation for definitive list
|
||||
* @package PHPMailer
|
||||
*/
|
||||
|
||||
$PHPMAILER_LANG['authenticate'] = 'Σφάλμα SMTP: Αδυναμία πιστοποίησης.';
|
||||
$PHPMAILER_LANG['buggy_php'] = 'Η έκδοση PHP που χρησιμοποιείτε παρουσιάζει σφάλμα που μπορεί να έχει ως αποτέλεσμα κατεστραμένα μηνύματα. Για να το διορθώσετε, αλλάξτε τον τρόπο αποστολής σε SMTP, απενεργοποιήστε την επιλογή mail.add_x_header στο αρχείο php.ini, αλλάξτε λειτουργικό σε MacOS ή Linux ή αναβαθμίστε την PHP σε έκδοση 7.0.17+ ή 7.1.3+.';
|
||||
$PHPMAILER_LANG['connect_host'] = 'Σφάλμα SMTP: Αδυναμία σύνδεσης με τον φιλοξενητή SMTP.';
|
||||
$PHPMAILER_LANG['data_not_accepted'] = 'Σφάλμα SMTP: Μη αποδεκτά δεδομένα.';
|
||||
$PHPMAILER_LANG['empty_message'] = 'Η ηλεκτρονική επιστολή δεν έχει περιεχόμενο.';
|
||||
$PHPMAILER_LANG['encoding'] = 'Άγνωστη μορφή κωδικοποίησης: ';
|
||||
$PHPMAILER_LANG['execute'] = 'Αδυναμία εκτέλεσης: ';
|
||||
$PHPMAILER_LANG['extension_missing'] = 'Απουσία επέκτασης: ';
|
||||
$PHPMAILER_LANG['file_access'] = 'Αδυναμία πρόσβασης στο αρχείο: ';
|
||||
$PHPMAILER_LANG['file_open'] = 'Σφάλμα Αρχείου: Αδυναμία ανοίγματος αρχείου: ';
|
||||
$PHPMAILER_LANG['from_failed'] = 'Η ακόλουθη διεύθυνση αποστολέα δεν είναι σωστή: ';
|
||||
$PHPMAILER_LANG['instantiate'] = 'Αδυναμία εκκίνησης συνάρτησης Mail.';
|
||||
$PHPMAILER_LANG['invalid_address'] = 'Μη έγκυρη διεύθυνση: ';
|
||||
$PHPMAILER_LANG['invalid_header'] = 'Μη έγκυρο όνομα κεφαλίδας ή τιμή';
|
||||
$PHPMAILER_LANG['invalid_hostentry'] = 'Μη έγκυρη εισαγωγή φιλοξενητή: ';
|
||||
$PHPMAILER_LANG['invalid_host'] = 'Μη έγκυρος φιλοξενητής: ';
|
||||
$PHPMAILER_LANG['mailer_not_supported'] = ' mailer δεν υποστηρίζεται.';
|
||||
$PHPMAILER_LANG['provide_address'] = 'Δώστε τουλάχιστον μια ηλεκτρονική διεύθυνση παραλήπτη.';
|
||||
$PHPMAILER_LANG['recipients_failed'] = 'Σφάλμα SMTP: Οι παρακάτω διευθύνσεις παραλήπτη δεν είναι έγκυρες: ';
|
||||
$PHPMAILER_LANG['signing'] = 'Σφάλμα υπογραφής: ';
|
||||
$PHPMAILER_LANG['smtp_code'] = 'Κώδικάς SMTP: ';
|
||||
$PHPMAILER_LANG['smtp_code_ex'] = 'Πρόσθετες πληροφορίες SMTP: ';
|
||||
$PHPMAILER_LANG['smtp_connect_failed'] = 'Αποτυχία σύνδεσης SMTP.';
|
||||
$PHPMAILER_LANG['smtp_detail'] = 'Λεπτομέρεια: ';
|
||||
$PHPMAILER_LANG['smtp_error'] = 'Σφάλμα με τον διακομιστή SMTP: ';
|
||||
$PHPMAILER_LANG['variable_set'] = 'Αδυναμία ορισμού ή επαναφοράς μεταβλητής: ';
|
31
core/class/phpmailer/i18n/phpmailer.lang-es.php
Normal file
31
core/class/phpmailer/i18n/phpmailer.lang-es.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Spanish PHPMailer language file: refer to English translation for definitive list
|
||||
* @package PHPMailer
|
||||
* @author Matt Sturdy <matt.sturdy@gmail.com>
|
||||
* @author Crystopher Glodzienski Cardoso <crystopher.glodzienski@gmail.com>
|
||||
*/
|
||||
|
||||
$PHPMAILER_LANG['authenticate'] = 'Error SMTP: Imposible autentificar.';
|
||||
$PHPMAILER_LANG['connect_host'] = 'Error SMTP: Imposible conectar al servidor SMTP.';
|
||||
$PHPMAILER_LANG['data_not_accepted'] = 'Error SMTP: Datos no aceptados.';
|
||||
$PHPMAILER_LANG['empty_message'] = 'El cuerpo del mensaje está vacío.';
|
||||
$PHPMAILER_LANG['encoding'] = 'Codificación desconocida: ';
|
||||
$PHPMAILER_LANG['execute'] = 'Imposible ejecutar: ';
|
||||
$PHPMAILER_LANG['file_access'] = 'Imposible acceder al archivo: ';
|
||||
$PHPMAILER_LANG['file_open'] = 'Error de Archivo: Imposible abrir el archivo: ';
|
||||
$PHPMAILER_LANG['from_failed'] = 'La(s) siguiente(s) direcciones de remitente fallaron: ';
|
||||
$PHPMAILER_LANG['instantiate'] = 'Imposible crear una instancia de la función Mail.';
|
||||
$PHPMAILER_LANG['invalid_address'] = 'Imposible enviar: dirección de email inválido: ';
|
||||
$PHPMAILER_LANG['mailer_not_supported'] = ' mailer no está soportado.';
|
||||
$PHPMAILER_LANG['provide_address'] = 'Debe proporcionar al menos una dirección de email de destino.';
|
||||
$PHPMAILER_LANG['recipients_failed'] = 'Error SMTP: Los siguientes destinos fallaron: ';
|
||||
$PHPMAILER_LANG['signing'] = 'Error al firmar: ';
|
||||
$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() falló.';
|
||||
$PHPMAILER_LANG['smtp_error'] = 'Error del servidor SMTP: ';
|
||||
$PHPMAILER_LANG['variable_set'] = 'No se pudo configurar la variable: ';
|
||||
$PHPMAILER_LANG['extension_missing'] = 'Extensión faltante: ';
|
||||
$PHPMAILER_LANG['smtp_code'] = 'Código del servidor SMTP: ';
|
||||
$PHPMAILER_LANG['smtp_code_ex'] = 'Información adicional del servidor SMTP: ';
|
||||
$PHPMAILER_LANG['invalid_header'] = 'Nombre o valor de encabezado no válido';
|
38
core/class/phpmailer/i18n/phpmailer.lang-fr.php
Normal file
38
core/class/phpmailer/i18n/phpmailer.lang-fr.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* French PHPMailer language file: refer to English translation for definitive list
|
||||
* @package PHPMailer
|
||||
* Some French punctuation requires a thin non-breaking space (U+202F) character before it,
|
||||
* for example before a colon or exclamation mark.
|
||||
* There is one of these characters between these quotes: " "
|
||||
* @see http://unicode.org/udhr/n/notes_fra.html
|
||||
*/
|
||||
|
||||
$PHPMAILER_LANG['authenticate'] = 'Erreur SMTP : échec de l’authentification.';
|
||||
$PHPMAILER_LANG['buggy_php'] = 'Votre version de PHP est affectée par un bug qui peut entraîner des messages corrompus. Pour résoudre ce problème, passez à l’envoi par SMTP, désactivez l’option mail.add_x_header dans le fichier php.ini, passez à MacOS ou Linux, ou passez PHP à la version 7.0.17+ ou 7.1.3+.';
|
||||
$PHPMAILER_LANG['connect_host'] = 'Erreur SMTP : impossible de se connecter au serveur SMTP.';
|
||||
$PHPMAILER_LANG['data_not_accepted'] = 'Erreur SMTP : données incorrectes.';
|
||||
$PHPMAILER_LANG['empty_message'] = 'Corps du message vide.';
|
||||
$PHPMAILER_LANG['encoding'] = 'Encodage inconnu : ';
|
||||
$PHPMAILER_LANG['execute'] = 'Impossible de lancer l’exécution : ';
|
||||
$PHPMAILER_LANG['extension_missing'] = 'Extension manquante : ';
|
||||
$PHPMAILER_LANG['file_access'] = 'Impossible d’accéder au fichier : ';
|
||||
$PHPMAILER_LANG['file_open'] = 'Ouverture du fichier impossible : ';
|
||||
$PHPMAILER_LANG['from_failed'] = 'L’adresse d’expéditeur suivante a échoué : ';
|
||||
$PHPMAILER_LANG['instantiate'] = 'Impossible d’instancier la fonction mail.';
|
||||
$PHPMAILER_LANG['invalid_address'] = 'Adresse courriel non valide : ';
|
||||
$PHPMAILER_LANG['invalid_header'] = 'Nom ou valeur de l’en-tête non valide';
|
||||
$PHPMAILER_LANG['invalid_hostentry'] = 'Entrée d’hôte non valide : ';
|
||||
$PHPMAILER_LANG['invalid_host'] = 'Hôte non valide : ';
|
||||
$PHPMAILER_LANG['mailer_not_supported'] = ' client de messagerie non supporté.';
|
||||
$PHPMAILER_LANG['provide_address'] = 'Vous devez fournir au moins une adresse de destinataire.';
|
||||
$PHPMAILER_LANG['recipients_failed'] = 'Erreur SMTP : les destinataires suivants ont échoué : ';
|
||||
$PHPMAILER_LANG['signing'] = 'Erreur de signature : ';
|
||||
$PHPMAILER_LANG['smtp_code'] = 'Code SMTP : ';
|
||||
$PHPMAILER_LANG['smtp_code_ex'] = 'Informations supplémentaires SMTP : ';
|
||||
$PHPMAILER_LANG['smtp_connect_failed'] = 'La fonction SMTP connect() a échouée.';
|
||||
$PHPMAILER_LANG['smtp_detail'] = 'Détails : ';
|
||||
$PHPMAILER_LANG['smtp_error'] = 'Erreur du serveur SMTP : ';
|
||||
$PHPMAILER_LANG['variable_set'] = 'Impossible d’initialiser ou de réinitialiser une variable : ';
|
||||
$PHPMAILER_LANG['extension_missing'] = 'Extension manquante : ';
|
28
core/class/phpmailer/i18n/phpmailer.lang-it.php
Normal file
28
core/class/phpmailer/i18n/phpmailer.lang-it.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Italian PHPMailer language file: refer to English translation for definitive list
|
||||
* @package PHPMailer
|
||||
* @author Ilias Bartolini <brain79@inwind.it>
|
||||
* @author Stefano Sabatini <sabas88@gmail.com>
|
||||
*/
|
||||
|
||||
$PHPMAILER_LANG['authenticate'] = 'SMTP Error: Impossibile autenticarsi.';
|
||||
$PHPMAILER_LANG['connect_host'] = 'SMTP Error: Impossibile connettersi all\'host SMTP.';
|
||||
$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Error: Dati non accettati dal server.';
|
||||
$PHPMAILER_LANG['empty_message'] = 'Il corpo del messaggio è vuoto';
|
||||
$PHPMAILER_LANG['encoding'] = 'Codifica dei caratteri sconosciuta: ';
|
||||
$PHPMAILER_LANG['execute'] = 'Impossibile eseguire l\'operazione: ';
|
||||
$PHPMAILER_LANG['file_access'] = 'Impossibile accedere al file: ';
|
||||
$PHPMAILER_LANG['file_open'] = 'File Error: Impossibile aprire il file: ';
|
||||
$PHPMAILER_LANG['from_failed'] = 'I seguenti indirizzi mittenti hanno generato errore: ';
|
||||
$PHPMAILER_LANG['instantiate'] = 'Impossibile istanziare la funzione mail';
|
||||
$PHPMAILER_LANG['invalid_address'] = 'Impossibile inviare, l\'indirizzo email non è valido: ';
|
||||
$PHPMAILER_LANG['provide_address'] = 'Deve essere fornito almeno un indirizzo ricevente';
|
||||
$PHPMAILER_LANG['mailer_not_supported'] = 'Mailer non supportato';
|
||||
$PHPMAILER_LANG['recipients_failed'] = 'SMTP Error: I seguenti indirizzi destinatari hanno generato un errore: ';
|
||||
$PHPMAILER_LANG['signing'] = 'Errore nella firma: ';
|
||||
$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() fallita.';
|
||||
$PHPMAILER_LANG['smtp_error'] = 'Errore del server SMTP: ';
|
||||
$PHPMAILER_LANG['variable_set'] = 'Impossibile impostare o resettare la variabile: ';
|
||||
$PHPMAILER_LANG['extension_missing'] = 'Estensione mancante: ';
|
27
core/class/phpmailer/i18n/phpmailer.lang-pt.php
Normal file
27
core/class/phpmailer/i18n/phpmailer.lang-pt.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Portuguese (European) PHPMailer language file: refer to English translation for definitive list
|
||||
* @package PHPMailer
|
||||
* @author Jonadabe <jonadabe@hotmail.com>
|
||||
*/
|
||||
|
||||
$PHPMAILER_LANG['authenticate'] = 'Erro do SMTP: Não foi possível realizar a autenticação.';
|
||||
$PHPMAILER_LANG['connect_host'] = 'Erro do SMTP: Não foi possível realizar ligação com o servidor SMTP.';
|
||||
$PHPMAILER_LANG['data_not_accepted'] = 'Erro do SMTP: Os dados foram rejeitados.';
|
||||
$PHPMAILER_LANG['empty_message'] = 'A mensagem no e-mail está vazia.';
|
||||
$PHPMAILER_LANG['encoding'] = 'Codificação desconhecida: ';
|
||||
$PHPMAILER_LANG['execute'] = 'Não foi possível executar: ';
|
||||
$PHPMAILER_LANG['file_access'] = 'Não foi possível aceder o ficheiro: ';
|
||||
$PHPMAILER_LANG['file_open'] = 'Abertura do ficheiro: Não foi possível abrir o ficheiro: ';
|
||||
$PHPMAILER_LANG['from_failed'] = 'Ocorreram falhas nos endereços dos seguintes remententes: ';
|
||||
$PHPMAILER_LANG['instantiate'] = 'Não foi possível iniciar uma instância da função mail.';
|
||||
$PHPMAILER_LANG['invalid_address'] = 'Não foi enviado nenhum e-mail para o endereço de e-mail inválido: ';
|
||||
$PHPMAILER_LANG['mailer_not_supported'] = ' mailer não é suportado.';
|
||||
$PHPMAILER_LANG['provide_address'] = 'Tem de fornecer pelo menos um endereço como destinatário do e-mail.';
|
||||
$PHPMAILER_LANG['recipients_failed'] = 'Erro do SMTP: O endereço do seguinte destinatário falhou: ';
|
||||
$PHPMAILER_LANG['signing'] = 'Erro ao assinar: ';
|
||||
$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() falhou.';
|
||||
$PHPMAILER_LANG['smtp_error'] = 'Erro de servidor SMTP: ';
|
||||
$PHPMAILER_LANG['variable_set'] = 'Não foi possível definir ou redefinir a variável: ';
|
||||
$PHPMAILER_LANG['extension_missing'] = 'Extensão em falta: ';
|
31
core/class/phpmailer/i18n/phpmailer.lang-tr.php
Normal file
31
core/class/phpmailer/i18n/phpmailer.lang-tr.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Turkish PHPMailer language file: refer to English translation for definitive list
|
||||
* @package PHPMailer
|
||||
* @author Elçin Özel
|
||||
* @author Can Yılmaz
|
||||
* @author Mehmet Benlioğlu
|
||||
* @author @yasinaydin
|
||||
* @author Ogün Karakuş
|
||||
*/
|
||||
|
||||
$PHPMAILER_LANG['authenticate'] = 'SMTP Hatası: Oturum açılamadı.';
|
||||
$PHPMAILER_LANG['connect_host'] = 'SMTP Hatası: SMTP sunucusuna bağlanılamadı.';
|
||||
$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Hatası: Veri kabul edilmedi.';
|
||||
$PHPMAILER_LANG['empty_message'] = 'Mesajın içeriği boş';
|
||||
$PHPMAILER_LANG['encoding'] = 'Bilinmeyen karakter kodlama: ';
|
||||
$PHPMAILER_LANG['execute'] = 'Çalıştırılamadı: ';
|
||||
$PHPMAILER_LANG['file_access'] = 'Dosyaya erişilemedi: ';
|
||||
$PHPMAILER_LANG['file_open'] = 'Dosya Hatası: Dosya açılamadı: ';
|
||||
$PHPMAILER_LANG['from_failed'] = 'Belirtilen adreslere gönderme başarısız: ';
|
||||
$PHPMAILER_LANG['instantiate'] = 'Örnek e-posta fonksiyonu oluşturulamadı.';
|
||||
$PHPMAILER_LANG['invalid_address'] = 'Geçersiz e-posta adresi: ';
|
||||
$PHPMAILER_LANG['mailer_not_supported'] = ' e-posta kütüphanesi desteklenmiyor.';
|
||||
$PHPMAILER_LANG['provide_address'] = 'En az bir alıcı e-posta adresi belirtmelisiniz.';
|
||||
$PHPMAILER_LANG['recipients_failed'] = 'SMTP Hatası: Belirtilen alıcılara ulaşılamadı: ';
|
||||
$PHPMAILER_LANG['signing'] = 'İmzalama hatası: ';
|
||||
$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP connect() fonksiyonu başarısız.';
|
||||
$PHPMAILER_LANG['smtp_error'] = 'SMTP sunucu hatası: ';
|
||||
$PHPMAILER_LANG['variable_set'] = 'Değişken ayarlanamadı ya da sıfırlanamadı: ';
|
||||
$PHPMAILER_LANG['extension_missing'] = 'Eklenti bulunamadı: ';
|
945
core/class/router.class.php
Normal file
945
core/class/router.class.php
Normal file
@ -0,0 +1,945 @@
|
||||
<?php
|
||||
|
||||
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(128));
|
||||
}
|
||||
|
||||
// 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(self::TEMP_DIR);
|
||||
foreach ($iterator as $fileInfos) {
|
||||
if (
|
||||
$fileInfos->isFile() &&
|
||||
$fileInfos->getBasename() !== '.htaccess' &&
|
||||
$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 des fichier de données
|
||||
helper::autoBackup(self::BACKUP_DIR, ['backup', 'tmp', 'file']);
|
||||
// Date du dernier backup
|
||||
$this->setData(['core', 'lastBackup', $lastBackup]);
|
||||
// Supprime les backups de plus de 30 jours
|
||||
$iterator = new DirectoryIterator(self::BACKUP_DIR);
|
||||
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(self::DATA_DIR . 'custom.css') === false) {
|
||||
file_put_contents(self::DATA_DIR . 'custom.css', file_get_contents('core/module/theme/resource/custom.css'));
|
||||
chmod(self::DATA_DIR . 'custom.css', 0755);
|
||||
}
|
||||
// Crée le fichier de personnalisation
|
||||
if (file_exists(self::DATA_DIR . 'theme.css') === false) {
|
||||
file_put_contents(self::DATA_DIR . 'theme.css', '');
|
||||
chmod(self::DATA_DIR . 'theme.css', 0755);
|
||||
}
|
||||
// Crée le fichier de personnalisation de l'administration
|
||||
if (file_exists(self::DATA_DIR . 'admin.css') === false) {
|
||||
file_put_contents(self::DATA_DIR . 'admin.css', '');
|
||||
chmod(self::DATA_DIR . 'admin.css', 0755);
|
||||
}
|
||||
|
||||
// Check la version rafraichissement du theme
|
||||
$cssVersion = preg_split('/\*+/', file_get_contents(self::DATA_DIR . '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
|
||||
* A partir du CDN
|
||||
* ou dans le dossier site/file/source/fonts
|
||||
* ou pas du tout si fonte webSafe
|
||||
*/
|
||||
|
||||
// Fonts disponibles
|
||||
$fontsAvailable['files'] = $this->getData(['font', 'files']);
|
||||
$fontsAvailable['imported'] = $this->getData(['font', 'imported']);
|
||||
$fontsAvailable['websafe'] = self::$fontsWebSafe;
|
||||
|
||||
// Fontes installées
|
||||
$fonts = [
|
||||
$this->getData(['theme', 'text', 'font']),
|
||||
$this->getData(['theme', 'title', 'font']),
|
||||
$this->getData(['theme', 'header', 'font']),
|
||||
$this->getData(['theme', 'menu', 'font']),
|
||||
$this->getData(['theme', 'footer', 'font'])
|
||||
];
|
||||
// Suppression des polices identiques
|
||||
$fonts = array_unique($fonts);
|
||||
|
||||
/**
|
||||
* Charge les fontes websafe
|
||||
*/
|
||||
$fontFile = '';
|
||||
foreach ($fonts as $fontId) {
|
||||
if (isset($fontsAvailable['websafe'][$fontId])) {
|
||||
$fonts[$fontId] = $fontsAvailable['websafe'][$fontId]['font-family'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Chargement des polices en ligne dans un fichier font.html inclus dans main.php
|
||||
*/
|
||||
$fontFile = '';
|
||||
$gf = false;
|
||||
foreach ($fonts as $fontId) {
|
||||
if (isset($fontsAvailable['imported'][$fontId])) {
|
||||
$fontFile .= '<link href="' . $fontsAvailable['imported'][$fontId]['resource'] . '" rel="stylesheet">';
|
||||
// Tableau pour la construction de la feuille de style
|
||||
$fonts[$fontId] = $fontsAvailable['imported'][$fontId]['font-family'];
|
||||
$gf = strpos($fontsAvailable['imported'][$fontId]['resource'], 'fonts.googleapis.com') === false ? $gf || false : $gf || true;
|
||||
}
|
||||
}
|
||||
// Ajoute le préconnect des fontes Googles.
|
||||
$fontFile = $gf ? '<link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>' . $fontFile
|
||||
: $fontFile;
|
||||
// Enregistre la personnalisation
|
||||
if (!is_dir(self::DATA_DIR . 'font')) {
|
||||
mkdir(self::DATA_DIR . 'font');
|
||||
}
|
||||
file_put_contents(self::DATA_DIR . 'font/font.html', $fontFile);
|
||||
|
||||
/**
|
||||
* Fontes installées localement
|
||||
*/
|
||||
foreach ($fonts as $fontId) {
|
||||
// Validité du tableau :
|
||||
if (isset($fontsAvailable['files'][$fontId])) {
|
||||
if (file_exists(self::DATA_DIR . 'font/' . $fontId)) {
|
||||
// Chargement de la police
|
||||
$css .= '@font-face {font-family:"' . $fontsAvailable['files'][$fontId]['font-family'] . '";';
|
||||
$css .= 'src: url("' . helper::baseUrl(false) . self::DATA_DIR . 'font/' . $fontsAvailable['files'][$fontId]['resource'] . '");}';
|
||||
// Tableau pour la construction de la feuille de style
|
||||
$fonts[$fontId] = $fontsAvailable['files'][$fontId]['font-family'];
|
||||
} else {
|
||||
// Le fichier de font n'est pas disponible, fonte par défaut
|
||||
$fonts[$fontId] = 'verdana';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fond du body
|
||||
$colors = helper::colorVariants($this->getData(['theme', 'body', 'backgroundColor']));
|
||||
// Body
|
||||
$css .= 'body{font-family:' . $fonts[$this->getData(['theme', 'text', 'font'])] . ';}';
|
||||
if ($themeBodyImage = $this->getData(['theme', 'body', 'image'])) {
|
||||
// Image dans html pour éviter les déformations.
|
||||
$css .= 'html {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']) . '}';
|
||||
// Couleur du body transparente
|
||||
$css .= 'body {background-color: rgba(0,0,0,0)}';
|
||||
} else {
|
||||
// Pas d'image couleur du body
|
||||
$css .= 'html {background-color:' . $colors['normal'] . ';}';
|
||||
}
|
||||
// Icône BacktoTop
|
||||
$css .= '#backToTop {background-color:' . $this->getData(['theme', 'body', 'toTopbackgroundColor']) . ';color:' . $this->getData(['theme', 'body', 'toTopColor']) . ';}';
|
||||
// Site
|
||||
$colors = helper::colorVariants($this->getData(['theme', 'text', 'linkColor']));
|
||||
$css .= 'a{color:' . $colors['normal'] . '}';
|
||||
// Couleurs de site dans TinyMCe
|
||||
$css .= 'div.mce-edit-area {font-family:' . $fonts[$this->getData(['theme', 'text', 'font'])] . ';}';
|
||||
// Site dans TinyMCE
|
||||
$css .= '.editorWysiwyg, .editorWysiwygComment {background-color:' . $this->getData(['theme', 'site', 'backgroundColor']) . ';}';
|
||||
$css .= 'span.mce-text{background-color: unset !important;}';
|
||||
$css .= 'body,.row > div{font-size:' . $this->getData(['theme', 'text', 'fontSize']) . '}';
|
||||
$css .= 'body{color:' . $this->getData(['theme', 'text', 'textColor']) . '}';
|
||||
$css .= 'select,input[type=password],input[type=email],input[type=text],input[type=date],input[type=time],input[type=week],input[type=month],input[type=datetime-local],.inputFile,select,textarea{color:' . $this->getData(['theme', 'text', 'textColor']) . ';background-color:' . $this->getData(['theme', 'site', 'backgroundColor']) . ';}';
|
||||
// spécifiques au module de blog
|
||||
$css .= '.blogDate {color:' . $this->getData(['theme', 'text', 'textColor']) . ';}.blogPicture img{border:1px solid ' . $this->getData(['theme', 'text', 'textColor']) . '; box-shadow: 1px 1px 5px ' . $this->getData(['theme', 'text', 'textColor']) . ';}';
|
||||
// Couleur fixée dans admin.css
|
||||
$css .= '.container {max-width:' . $this->getData(['theme', 'site', 'width']) . '}';
|
||||
$margin = $this->getData(['theme', 'site', 'margin']) ? '0' : '20px';
|
||||
// Marge supplémentaire lorsque le pied de page est fixe
|
||||
if (
|
||||
$this->getData(['theme', 'footer', 'fixed']) === true &&
|
||||
$this->getData(['theme', 'footer', 'position']) === 'body'
|
||||
) {
|
||||
|
||||
$marginBottomLarge = ((str_replace('px', '', $this->getData(['theme', 'footer', 'height'])) * 2) + 31) . 'px';
|
||||
$marginBottomSmall = ((str_replace('px', '', $this->getData(['theme', 'footer', 'height'])) * 2) + 93) . 'px';
|
||||
} else {
|
||||
$marginBottomSmall = $margin;
|
||||
$marginBottomLarge = $margin;
|
||||
}
|
||||
$css .= $this->getData(['theme', 'site', 'width']) === '100%'
|
||||
? '@media (min-width: 769px) {#site{margin:0 auto ' . $marginBottomLarge . ' 0 !important;}}@media (max-width: 768px) {#site{margin:0 auto ' . $marginBottomSmall . ' 0 !important;}}#site.light{margin:5% auto !important;} body{margin:0 auto !important;} #bar{margin:0 auto !important;} body > header{margin:0 auto !important;} body > nav {margin: 0 auto !important;} body > footer {margin:0 auto !important;}'
|
||||
: '@media (min-width: 769px) {#site{margin: ' . $margin . ' auto ' . $marginBottomLarge . ' auto !important;}}@media (max-width: 768px) {#site{margin: ' . $margin . ' auto ' . $marginBottomSmall . ' auto !important;}}#site.light{margin: 5% auto !important;} body{margin:0px 10px;} #bar{margin: 0 -10px;} body > header{margin: 0 -10px;} body > nav {margin: 0 -10px;} body > footer {margin: 0 -10px;} ';
|
||||
$css .= $this->getData(['theme', 'site', 'width']) === '750px'
|
||||
? '.button, button{font-size:0.8em;}'
|
||||
: '';
|
||||
$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=date]:hover,input[type=time]:hover,input[type=week]:hover,input[type=month]:hover,input[type=datetime-local]: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,h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{color:' . $colors['normal'] . ';font-family:' . $fonts[$this->getData(['theme', 'title', 'font'])] . ';font-weight:' . $this->getData(['theme', 'title', 'fontWeight']) . ';text-transform:' . $this->getData(['theme', 'title', 'textTransform']) . '}';
|
||||
$css .= 'h1 a:hover,h2 a:hover,h3 a:hover,h4 a:hover,h5 a:hover,h6 a:hover{color:' . $colors['darken'] . '}';
|
||||
// Les blocs
|
||||
$colors = helper::colorVariants($this->getData(['theme', 'block', 'backgroundColor']));
|
||||
$css .= '.block {border: 1px solid ' . $this->getdata(['theme', 'block', 'borderColor']) . ';}.block h4 {background-color:' . $colors['normal'] . ';color:' . $colors['text'] . ';}';
|
||||
|
||||
// Bannière
|
||||
|
||||
// Eléments communs
|
||||
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}';
|
||||
}
|
||||
}
|
||||
$colors = helper::colorVariants($this->getData(['theme', 'header', 'backgroundColor']));
|
||||
$css .= 'header{background-color:' . $colors['normal'] . ';}';
|
||||
|
||||
// Bannière de type papier peint
|
||||
if ($this->getData(['theme', 'header', 'feature']) === 'wallpaper') {
|
||||
$css .= 'header{background-size:' . $this->getData(['theme', 'header', 'imageContainer']) . '}';
|
||||
$css .= 'header{background-color:' . $colors['normal'];
|
||||
|
||||
// Valeur de hauteur traditionnelle
|
||||
$css .= ';height:' . $this->getData(['theme', 'header', 'height']) . ';line-height:' . $this->getData(['theme', 'header', 'height']);
|
||||
|
||||
$css .= ';text-align:' . $this->getData(['theme', 'header', 'textAlign']) . '}';
|
||||
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:' . $fonts[$this->getData(['theme', 'header', 'font'])] . ';font-weight:' . $this->getData(['theme', 'header', 'fontWeight']) . ';font-size:' . $this->getData(['theme', 'header', 'fontSize']) . ';text-transform:' . $this->getData(['theme', 'header', 'textTransform']) . '}';
|
||||
}
|
||||
|
||||
// Bannière au Contenu HTML
|
||||
if ($this->getData(['theme', 'header', 'feature']) === 'feature') {
|
||||
// Hauteur de la taille du contenu perso
|
||||
$css .= 'header {height:' . $this->getData(['theme', 'header', 'height']) . '; min-height:' . $this->getData(['theme', 'header', 'height']) . ';overflow: hidden;}';
|
||||
}
|
||||
|
||||
// Menu
|
||||
$colors = helper::colorVariants($this->getData(['theme', 'menu', 'backgroundColor']));
|
||||
$css .= 'nav,nav.navMain 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{color:' . $this->getData(['theme', 'menu', 'activeTextColor']) . ';}';
|
||||
if ($this->getData(['theme', 'menu', 'activeColorAuto']) === true) {
|
||||
$css .= 'nav a.active{background-color:' . $colors['veryDarken'] . '}';
|
||||
} else {
|
||||
$css .= 'nav a.active{background-color:' . $this->getData(['theme', 'menu', 'activeColor']) . '}';
|
||||
}
|
||||
$css .= 'nav #burgerText{color:' . $colors['text'] . '}';
|
||||
// Sous menu
|
||||
$colors = helper::colorVariants($this->getData(['theme', 'menu', 'backgroundColorSub']));
|
||||
$css .= 'nav .navSub a{background-color:' . $colors['normal'] . '}';
|
||||
$css .= 'nav .navMain a.active {border-radius:' . $this->getData(['theme', 'menu', 'radius']) . '}';
|
||||
$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', 'menu', 'position']) === 'site-second'
|
||||
) {
|
||||
$css .= 'nav{padding:10px 10px 0 10px;}';
|
||||
} else {
|
||||
$css .= 'nav{padding:0 10px}';
|
||||
}
|
||||
} else {
|
||||
$css .= 'nav{margin:0}';
|
||||
}
|
||||
if (
|
||||
$this->getData(['theme', 'menu', 'position']) === 'top'
|
||||
) {
|
||||
$css .= 'nav{padding:0 10px;}';
|
||||
}
|
||||
|
||||
$css .= '#toggle span,#menu a{padding:' . $this->getData(['theme', 'menu', 'height']) . ';font-family:' . $fonts[$this->getData(['theme', 'menu', 'font'])] . ';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']));
|
||||
if ($this->getData(['theme', 'footer', 'margin'])) {
|
||||
$css .= 'footer{padding:0 20px;}';
|
||||
} else {
|
||||
$css .= 'footer{padding:0}';
|
||||
}
|
||||
|
||||
$css .= 'footer span, #footerText > p {color:' . $this->getData(['theme', 'footer', 'textColor']) . ';font-family:' . $fonts[$this->getData(['theme', 'footer', 'font'])] . ';font-weight:' . $this->getData(['theme', 'footer', 'fontWeight']) . ';font-size:' . $this->getData(['theme', 'footer', 'fontSize']) . ';text-transform:' . $this->getData(['theme', 'footer', 'textTransform']) . '}';
|
||||
$css .= 'footer {background-color:' . $colors['normal'] . ';color:' . $this->getData(['theme', 'footer', 'textColor']) . '}';
|
||||
$css .= 'footer a{color:' . $this->getData(['theme', 'footer', 'textColor']) . '}';
|
||||
$css .= 'footer #footersite > div {margin:' . $this->getData(['theme', 'footer', 'height']) . ' 0}';
|
||||
|
||||
$css .= 'footer #footerbody > div {margin:' . $this->getData(['theme', 'footer', 'height']) . ' 0}';
|
||||
$css .= '@media (max-width: 768px) {footer #footerbody > div { padding: 2px }}';
|
||||
$css .= '#footerSocials{text-align:' . $this->getData(['theme', 'footer', 'socialsAlign']) . '}';
|
||||
$css .= '#footerText > p {text-align:' . $this->getData(['theme', 'footer', 'textAlign']) . '}';
|
||||
$css .= '#footerCopyright{text-align:' . $this->getData(['theme', 'footer', 'copyrightAlign']) . '}';
|
||||
|
||||
// Enregistre les fontes
|
||||
if (!is_dir(self::DATA_DIR . 'font')) {
|
||||
mkdir(self::DATA_DIR . 'font');
|
||||
}
|
||||
file_put_contents(self::DATA_DIR . 'font/font.html', $fontFile);
|
||||
|
||||
// Enregistre la personnalisation
|
||||
file_put_contents(self::DATA_DIR . 'theme.css', $css);
|
||||
|
||||
// Effacer le cache pour tenir compte de la couleur de fond TinyMCE
|
||||
header("Expires: Tue, 01 Jan 2000 00:00:00 GMT");
|
||||
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
|
||||
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
|
||||
header("Cache-Control: post-check=0, pre-check=0", false);
|
||||
header("Pragma: no-cache");
|
||||
}
|
||||
|
||||
// Check la version rafraichissement du theme admin
|
||||
$cssVersion = preg_split('/\*+/', file_get_contents(self::DATA_DIR . 'admin.css'));
|
||||
if (empty($cssVersion[1]) or $cssVersion[1] !== md5(json_encode($this->getData(['admin'])))) {
|
||||
|
||||
// Version
|
||||
$css = '/*' . md5(json_encode($this->getData(['admin']))) . '*/';
|
||||
|
||||
// Fonts disponibles
|
||||
$fontsAvailable['files'] = $this->getData(['font', 'files']);
|
||||
$fontsAvailable['imported'] = $this->getData(['font', 'imported']);
|
||||
$fontsAvailable['websafe'] = self::$fontsWebSafe;
|
||||
|
||||
/**
|
||||
* Import des polices de caractères
|
||||
* A partir du CDN ou dans le dossier site/file/source/fonts
|
||||
*/
|
||||
$fonts = [
|
||||
$this->getData(['admin', 'fontText']),
|
||||
$this->getData(['admin', 'fontTitle']),
|
||||
];
|
||||
// Suppression des polices identiques
|
||||
$fonts = array_unique($fonts);
|
||||
|
||||
/**
|
||||
* Charge les fontes websafe
|
||||
*/
|
||||
$fontFile = '';
|
||||
foreach ($fonts as $fontId) {
|
||||
if (isset($fontsAvailable['websafe'][$fontId])) {
|
||||
$fonts[$fontId] = $fontsAvailable['websafe'][$fontId]['font-family'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Chargement des polices en ligne dans un fichier font.html inclus dans main.php
|
||||
*/
|
||||
$fontFile = '';
|
||||
foreach ($fonts as $fontId) {
|
||||
if (isset($fontsAvailable['imported'][$fontId])) {
|
||||
$fontFile .= '<link href="' . $fontsAvailable['imported'][$fontId]['resource'] . '" rel="stylesheet">';
|
||||
// Tableau pour la construction de la feuille de style
|
||||
$fonts[$fontId] = $fontsAvailable['imported'][$fontId]['font-family'];
|
||||
}
|
||||
}
|
||||
// Enregistre la personnalisation
|
||||
file_put_contents(self::DATA_DIR . 'font/font.html', $fontFile);
|
||||
|
||||
/**
|
||||
* Fontes installées localement
|
||||
*/
|
||||
foreach ($fonts as $fontId) {
|
||||
// Validité du tableau :
|
||||
if (isset($fontsAvailable['files'][$fontId])) {
|
||||
if (file_exists(self::DATA_DIR . 'font/' . $fontId)) {
|
||||
// Chargement de la police
|
||||
$css .= '@font-face {font-family:"' . $fontsAvailable['files'][$fontId]['font-family'] . '";';
|
||||
$css .= 'src: url("' . helper::baseUrl(false) . self::DATA_DIR . 'font/' . $fontsAvailable['files'][$fontId]['resource'] . '");}';
|
||||
// Tableau pour la construction de la feuille de style
|
||||
$fonts[$fontId] = $fontsAvailable['files'][$fontId]['font-family'];
|
||||
} else {
|
||||
// Le fichier de font n'est pas disponible, fonte par défaut
|
||||
$fonts[$fontId] = 'verdana';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Thème Administration
|
||||
$colors = helper::colorVariants($this->getData(['admin', 'backgroundColor']));
|
||||
$css .= '#site{background-color:' . $colors['normal'] . ';}';
|
||||
$css .= 'p, div, label, select, input, table, span {font-family:' . $fonts[$this->getData(['admin', 'fontText'])] . '}';
|
||||
$css .= 'body,.row > div {font-size:' . $this->getData(['admin', 'fontSize']) . '}';
|
||||
$css .= 'body h1, h2, h3, h4 a, h5, h6 {font-family:' . $fonts[$this->getData(['admin', 'fontTitle'])] . ';color:' . $this->getData(['admin', 'colorTitle']) . ';}';
|
||||
|
||||
// TinyMCE
|
||||
$colors = helper::colorVariants($this->getData(['admin', 'colorText']));
|
||||
$css .= 'body:not(.editorWysiwyg), body:not(editorWysiwygComment),span .zwiico-help {color:' . $colors['normal'] . ';}';
|
||||
$css .= 'table thead tr, table thead tr .zwiico-help{ background-color:' . $colors['normal'] . '; color:' . $colors['text'] . ';}';
|
||||
$css .= 'table thead th { color:' . $colors['text'] . ';}';
|
||||
$colors = helper::colorVariants($this->getData(['admin', 'backgroundColorButton']));
|
||||
$css .= 'input[type=checkbox]:checked + label::before,.speechBubble{background-color:' . $colors['normal'] . ';color:' . $colors['text'] . ';}';
|
||||
$css .= '.speechBubble::before {border-color:' . $colors['normal'] . ' transparent transparent transparent;}';
|
||||
$css .= '.button {background-color:' . $colors['normal'] . ';color:' . $colors['text'] . ';}.button:hover {background-color:' . $colors['darken'] . ';color:' . $colors['text'] . ';}.button:active {background-color:' . $colors['veryDarken'] . ';color:' . $colors['text'] . ';}';
|
||||
$colors = helper::colorVariants($this->getData(['admin', 'backgroundColorButtonGrey']));
|
||||
$css .= '.button.buttonGrey {background-color: ' . $colors['normal'] . ';color: ' . $colors['text'] . ';}.button.buttonGrey:hover {background-color:' . $colors['darken'] . ';color:' . $colors['text'] . ';}.button.buttonGrey:active {background-color:' . $colors['veryDarken'] . ';color:' . $colors['text'] . ';}';
|
||||
$colors = helper::colorVariants($this->getData(['admin', 'backgroundColorButtonRed']));
|
||||
$css .= '.button.buttonRed {background-color: ' . $colors['normal'] . ';color: ' . $colors['text'] . ';}.button.buttonRed:hover {background-color:' . $colors['darken'] . ';color:' . $colors['text'] . ';}.button.buttonRed:active {background-color:' . $colors['veryDarken'] . ';color:' . $colors['text'] . ';}';
|
||||
$colors = helper::colorVariants($this->getData(['admin', 'backgroundColorButtonHelp']));
|
||||
$css .= '.button.buttonHelp {background-color: ' . $colors['normal'] . ';color: ' . $colors['text'] . ';}.button.buttonHelp:hover {background-color:' . $colors['darken'] . ';color:' . $colors['text'] . ';}.button.buttonHelp:active {background-color:' . $colors['veryDarken'] . ';color:' . $colors['text'] . ';}';
|
||||
$colors = helper::colorVariants($this->getData(['admin', 'backgroundColorButtonGreen']));
|
||||
$css .= '.button.buttonGreen, button[type=submit] {background-color: ' . $colors['normal'] . ';color: ' . $colors['text'] . ';}.button.buttonGreen:hover, button[type=submit]:hover {background-color: ' . $colors['darken'] . ';color: ' . $colors['text'] . ';}.button.buttonGreen:active, button[type=submit]:active {background-color: ' . $colors['darken'] . ';color: ' . $colors['text'] . ';}';
|
||||
$colors = helper::colorVariants($this->getData(['admin', 'backgroundBlockColor']));
|
||||
$css .= '.buttonTab, .block {border: 1px solid ' . $this->getData(['admin', 'borderBlockColor']) . ';}.buttonTab, .block h4 {background-color: ' . $colors['normal'] . ';color:' . $colors['text'] . ';}';
|
||||
$css .= 'table tr,input[type=email],input[type=date],input[type=time],input[type=month],input[type=week],input[type=datetime-local],input[type=text],input[type=password],select:not(#barSelectLanguage),select:not(#barSelectPage),textarea:not(.editorWysiwyg), textarea:not(.editorWysiwygComment),.inputFile{background-color: ' . $colors['normal'] . ';color:' . $colors['text'] . ';border: 1px solid ' . $this->getData(['admin', 'borderBlockColor']) . ';}';
|
||||
// Bordure du contour TinyMCE
|
||||
$css .= '.mce-tinymce{border: 1px solid ' . $this->getData(['admin', 'borderBlockColor']) . '!important;}';
|
||||
// Enregistre la personnalisation
|
||||
file_put_contents(self::DATA_DIR . 'admin.css', $css);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Auto-chargement des classes
|
||||
* @param string $className Nom de la classe à charger
|
||||
*/
|
||||
public static function autoload($className)
|
||||
{
|
||||
|
||||
$classPath = strtolower($className) . '/' . strtolower($className) . '.php';
|
||||
// Module du coeur
|
||||
if (is_readable('core/module/' . $classPath)) {
|
||||
require 'core/module/' . $classPath;
|
||||
}
|
||||
// Module
|
||||
elseif (is_readable(self::MODULE_DIR . $classPath)) {
|
||||
require self::MODULE_DIR . $classPath;
|
||||
}
|
||||
// Librairie
|
||||
elseif (is_readable('core/vendor/' . $classPath)) {
|
||||
require 'core/vendor/' . $classPath;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Routage des modules
|
||||
*/
|
||||
public function router()
|
||||
{
|
||||
|
||||
$layout = new layout($this);
|
||||
|
||||
// Installation
|
||||
if (
|
||||
$this->getData(['user']) === []
|
||||
and $this->getUrl(0) !== 'install'
|
||||
) {
|
||||
http_response_code(302);
|
||||
header('Location:' . helper::baseUrl() . 'install');
|
||||
exit();
|
||||
}
|
||||
|
||||
// Journalisation
|
||||
$this->saveLog();
|
||||
|
||||
// Force la déconnexion des membres bannis ou d'une seconde session
|
||||
if (
|
||||
$this->getUser('password') === $this->getInput('ZWII_USER_PASSWORD')
|
||||
and ($this->getUser('group') === self::GROUP_BANNED
|
||||
or ($_SESSION['csrf'] !== $this->getData(['user', $this->getUser('id'), 'accessCsrf'])
|
||||
and $this->getData(['config', 'connect', 'autoDisconnect']) === true)
|
||||
)
|
||||
) {
|
||||
$user = new user;
|
||||
$user->logout();
|
||||
}
|
||||
// Mode maintenance
|
||||
if (
|
||||
$this->getData(['config', 'maintenance'])
|
||||
and in_array($this->getUrl(0), ['maintenance', 'user']) === false
|
||||
and $this->getUrl(1) !== 'login'
|
||||
and ($this->getUser('password') !== $this->getInput('ZWII_USER_PASSWORD')
|
||||
or ($this->getUser('password') === $this->getInput('ZWII_USER_PASSWORD')
|
||||
and $this->getUser('group') < self::GROUP_ADMIN
|
||||
)
|
||||
)
|
||||
) {
|
||||
// Déconnexion
|
||||
$user = new user;
|
||||
$user->logout();
|
||||
// Redirection
|
||||
http_response_code(302);
|
||||
header('Location:' . helper::baseUrl() . 'maintenance');
|
||||
exit();
|
||||
}
|
||||
|
||||
// Pour éviter une 404 sur une langue étrangère, bascule dans la langue correcte.
|
||||
if (is_null($this->getData(['page', $this->getUrl(0)]))) {
|
||||
foreach (self::$languages as $key => $value) {
|
||||
if (
|
||||
is_dir(self::DATA_DIR . $key) &&
|
||||
file_exists(self::DATA_DIR . $key . '/page.json')
|
||||
) {
|
||||
$pagesId = json_decode(file_get_contents(self::DATA_DIR . $key . '/page.json'), true);
|
||||
if (
|
||||
is_array($pagesId['page']) &&
|
||||
array_key_exists($this->getUrl(0), $pagesId['page'])
|
||||
) {
|
||||
$_SESSION['ZWII_CONTENT'] = $key;
|
||||
header('Refresh:0; url=' . helper::baseUrl() . $this->getUrl(0));
|
||||
exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check l'accès à la page
|
||||
$access = null;
|
||||
if ($this->getData(['page', $this->getUrl(0)]) !== null) {
|
||||
if (
|
||||
$this->getData(['page', $this->getUrl(0), 'group']) === self::GROUP_VISITOR
|
||||
or ($this->getUser('password') === $this->getInput('ZWII_USER_PASSWORD')
|
||||
// and $this->getUser('group') >= $this->getData(['page', $this->getUrl(0), 'group'])
|
||||
// Modification qui tient compte du profil de la page
|
||||
and ($this->getUser('group') * 10 + $this->getUser('profil')) >= ($this->getData(['page', $this->getUrl(0), 'group']) * 10 + $this->getData(['page', $this->getUrl(0), 'profil']))
|
||||
)
|
||||
) {
|
||||
$access = true;
|
||||
} else {
|
||||
if ($this->getUrl(0) === $this->getData(['locale', 'homePageId'])) {
|
||||
$access = 'login';
|
||||
} else {
|
||||
$access = false;
|
||||
}
|
||||
}
|
||||
// Empêcher l'accès aux pages désactivées par URL directe
|
||||
if (
|
||||
($this->getData(['page', $this->getUrl(0), 'disable']) === true
|
||||
and $this->getUser('password') !== $this->getInput('ZWII_USER_PASSWORD')
|
||||
) or ($this->getData(['page', $this->getUrl(0), 'disable']) === true
|
||||
and $this->getUser('password') === $this->getInput('ZWII_USER_PASSWORD')
|
||||
and $this->getUser('group') < self::GROUP_EDITOR
|
||||
)
|
||||
) {
|
||||
$access = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Contrôle si la page demandée est en édition ou accès à la gestion du site
|
||||
* conditions de blocage :
|
||||
* - Les deux utilisateurs qui accèdent à la même page sont différents
|
||||
* - les URLS sont identiques
|
||||
* - Une partie de l'URL fait partie de la liste de filtrage (édition d'un module etc..)
|
||||
* - L'édition est ouverte depuis un temps dépassé, on considère que la page est restée ouverte et qu'elle ne sera pas validée
|
||||
*/
|
||||
$accessInfo['userName'] = '';
|
||||
$accessInfo['pageId'] = '';
|
||||
if ($this->getData(['user'])) {
|
||||
foreach ($this->getData(['user']) as $userId => $userIds) {
|
||||
if (!is_null($this->getData(['user', $userId, 'accessUrl']))) {
|
||||
$t = explode('/', $this->getData(['user', $userId, 'accessUrl']));
|
||||
}
|
||||
if (
|
||||
$this->getUser('id') &&
|
||||
$userId !== $this->getUser('id') &&
|
||||
$this->getData(['user', $userId, 'accessUrl']) === $this->getUrl() &&
|
||||
array_intersect($t, self::$concurrentAccess) &&
|
||||
//array_intersect($t, self::$accessExclude) !== false &&
|
||||
time() < $this->getData(['user', $userId, 'accessTimer']) + self::ACCESS_TIMER
|
||||
) {
|
||||
$access = false;
|
||||
$accessInfo['userName'] = $this->getData(['user', $userId, 'lastname']) . ' ' . $this->getData(['user', $userId, 'firstname']);
|
||||
$accessInfo['pageId'] = end($t);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Accès concurrent stocke la page visitée
|
||||
if (
|
||||
$this->getUser('password') === $this->getInput('ZWII_USER_PASSWORD')
|
||||
&& $this->getUser('id')
|
||||
) {
|
||||
$this->setData(['user', $this->getUser('id'), 'accessUrl', $this->getUrl()]);
|
||||
$this->setData(['user', $this->getUser('id'), 'accessTimer', time()]);
|
||||
}
|
||||
// Breadcrumb
|
||||
$title = $this->getData(['page', $this->getUrl(0), 'title']);
|
||||
if (
|
||||
!empty($this->getData(['page', $this->getUrl(0), 'parentPageId'])) &&
|
||||
$this->getData(['page', $this->getUrl(0), 'breadCrumb'])
|
||||
) {
|
||||
$title = '<a href="' . helper::baseUrl() .
|
||||
$this->getData(['page', $this->getUrl(0), 'parentPageId']) .
|
||||
'">' .
|
||||
ucfirst($this->getData(['page', $this->getData(['page', $this->getUrl(0), 'parentPageId']), 'title'])) .
|
||||
'</a> › ' .
|
||||
$this->getData(['page', $this->getUrl(0), 'title']);
|
||||
}
|
||||
|
||||
|
||||
// Importe le style de la page principale
|
||||
$inlineStyle[] = $this->getData(['page', $this->getUrl(0), 'css']) === null ? '' : $this->getData(['page', $this->getUrl(0), 'css']);
|
||||
// Importe le script de la page principale
|
||||
$inlineScript[] = $this->getData(['page', $this->getUrl(0), 'js']) === null ? '' : $this->getData(['page', $this->getUrl(0), 'js']);
|
||||
|
||||
// Importe le contenu, le CSS et le script des barres
|
||||
$contentRight = $this->getData(['page', $this->getUrl(0), 'barRight']) ? $this->getPage($this->getData(['page', $this->getUrl(0), 'barRight']), self::$i18nContent) : '';
|
||||
$inlineStyle[] = $this->getData(['page', $this->getData(['page', $this->getUrl(0), 'barRight']), 'css']) === null ? '' : $this->getData(['page', $this->getData(['page', $this->getUrl(0), 'barRight']), 'css']);
|
||||
$inlineScript[] = $this->getData(['page', $this->getData(['page', $this->getUrl(0), 'barRight']), 'js']) === null ? '' : $this->getData(['page', $this->getData(['page', $this->getUrl(0), 'barRight']), 'js']);
|
||||
$contentLeft = $this->getData(['page', $this->getUrl(0), 'barLeft']) ? $this->getPage($this->getData(['page', $this->getUrl(0), 'barLeft']), self::$i18nContent) : '';
|
||||
$inlineStyle[] = $this->getData(['page', $this->getData(['page', $this->getUrl(0), 'barLeft']), 'css']) === null ? '' : $this->getData(['page', $this->getData(['page', $this->getUrl(0), 'barLeft']), 'css']);
|
||||
$inlineScript[] = $this->getData(['page', $this->getData(['page', $this->getUrl(0), 'barLeft']), 'js']) === null ? '' : $this->getData(['page', $this->getData(['page', $this->getUrl(0), 'barLeft']), 'js']);
|
||||
|
||||
|
||||
// Importe la page simple sans module ou avec un module inexistant
|
||||
if (
|
||||
$this->getData(['page', $this->getUrl(0)]) !== null
|
||||
and ($this->getData(['page', $this->getUrl(0), 'moduleId']) === ''
|
||||
or !class_exists($this->getData(['page', $this->getUrl(0), 'moduleId']))
|
||||
)
|
||||
and $access
|
||||
) {
|
||||
|
||||
// Importe le CSS de la page principale
|
||||
|
||||
$this->addOutput([
|
||||
'title' => $title,
|
||||
'content' => $this->getPage($this->getUrl(0), self::$i18nContent),
|
||||
'metaDescription' => $this->getData(['page', $this->getUrl(0), 'metaDescription']),
|
||||
'metaTitle' => $this->getData(['page', $this->getUrl(0), 'metaTitle']),
|
||||
'typeMenu' => $this->getData(['page', $this->getUrl(0), 'typeMenu']),
|
||||
'iconUrl' => $this->getData(['page', $this->getUrl(0), 'iconUrl']),
|
||||
'disable' => $this->getData(['page', $this->getUrl(0), 'disable']),
|
||||
'contentRight' => $contentRight,
|
||||
'contentLeft' => $contentLeft,
|
||||
'inlineStyle' => $inlineStyle,
|
||||
'inlineScript' => $inlineScript,
|
||||
]);
|
||||
|
||||
}
|
||||
// Importe le module
|
||||
else {
|
||||
// Id du module, et valeurs en sortie de la page s'il s'agit d'un module de page
|
||||
|
||||
if ($access and $this->getData(['page', $this->getUrl(0), 'moduleId'])) {
|
||||
$moduleId = $this->getData(['page', $this->getUrl(0), 'moduleId']);
|
||||
|
||||
// Construit un meta absent
|
||||
$metaDescription = $this->getData(['page', $this->getUrl(0), 'moduleId']) === 'blog' && !empty($this->getUrl(1)) && in_array($this->getUrl(1), $this->getData(['module']))
|
||||
? strip_tags(substr($this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'content']), 0, 159))
|
||||
: $this->getData(['page', $this->getUrl(0), 'metaDescription']);
|
||||
|
||||
// Importe le CSS de la page principale
|
||||
$pageContent = $this->getPage($this->getUrl(0), self::$i18nContent);
|
||||
|
||||
$this->addOutput([
|
||||
'title' => $title,
|
||||
// Meta description = 160 premiers caractères de l'article
|
||||
'content' => $pageContent,
|
||||
'metaDescription' => $metaDescription,
|
||||
'metaTitle' => $this->getData(['page', $this->getUrl(0), 'metaTitle']),
|
||||
'typeMenu' => $this->getData(['page', $this->getUrl(0), 'typeMenu']),
|
||||
'iconUrl' => $this->getData(['page', $this->getUrl(0), 'iconUrl']),
|
||||
'disable' => $this->getData(['page', $this->getUrl(0), 'disable']),
|
||||
'contentRight' => $contentRight,
|
||||
'contentLeft' => $contentLeft,
|
||||
'inlineStyle' => $inlineStyle,
|
||||
'inlineScript' => $inlineScript,
|
||||
]);
|
||||
} else {
|
||||
$moduleId = $this->getUrl(0);
|
||||
$pageContent = '';
|
||||
}
|
||||
|
||||
// Check l'existence du module
|
||||
if (class_exists($moduleId)) {
|
||||
/** @var common $module */
|
||||
$module = new $moduleId;
|
||||
|
||||
// Check l'existence de l'action
|
||||
$action = '';
|
||||
$ignore = true;
|
||||
if (!is_null($this->getUrl(1))) {
|
||||
foreach (explode('-', $this->getUrl(1)) as $actionPart) {
|
||||
if ($ignore) {
|
||||
$action .= $actionPart;
|
||||
$ignore = false;
|
||||
} else {
|
||||
$action .= ucfirst($actionPart);
|
||||
}
|
||||
}
|
||||
}
|
||||
$action = array_key_exists($action, $module::$actions) ? $action : 'index';
|
||||
if (array_key_exists($action, $module::$actions)) {
|
||||
$module->$action();
|
||||
$output = $module->output;
|
||||
// Check le groupe de l'utilisateur
|
||||
if (
|
||||
($module::$actions[$action] === self::GROUP_VISITOR
|
||||
or ($this->getUser('password') === $this->getInput('ZWII_USER_PASSWORD')
|
||||
and $this->getUser('group') >= $module::$actions[$action]
|
||||
and $this->getUser('permission', $moduleId, $action)
|
||||
)
|
||||
)
|
||||
and $output['access'] === true
|
||||
) {
|
||||
// Enregistrement du contenu de la méthode POST lorsqu'une notice est présente
|
||||
if (common::$inputNotices) {
|
||||
foreach ($_POST as $postId => $postValue) {
|
||||
if (is_array($postValue)) {
|
||||
foreach ($postValue as $subPostId => $subPostValue) {
|
||||
self::$inputBefore[$postId . '_' . $subPostId] = $subPostValue;
|
||||
}
|
||||
} else {
|
||||
self::$inputBefore[$postId] = $postValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Sinon traitement des données de sortie qui requiert qu'aucune notice ne soit présente
|
||||
else {
|
||||
// Notification
|
||||
if ($output['notification']) {
|
||||
if ($output['state'] === true) {
|
||||
$notification = 'ZWII_NOTIFICATION_SUCCESS';
|
||||
} elseif ($output['state'] === false) {
|
||||
$notification = 'ZWII_NOTIFICATION_ERROR';
|
||||
} else {
|
||||
$notification = 'ZWII_NOTIFICATION_OTHER';
|
||||
}
|
||||
$_SESSION[$notification] = $output['notification'];
|
||||
}
|
||||
// Redirection
|
||||
if ($output['redirect']) {
|
||||
http_response_code(301);
|
||||
header('Location:' . $output['redirect']);
|
||||
exit();
|
||||
}
|
||||
}
|
||||
// Données en sortie applicables même lorsqu'une notice est présente
|
||||
// Affichage
|
||||
if ($output['display']) {
|
||||
$this->addOutput([
|
||||
'display' => $output['display']
|
||||
]);
|
||||
}
|
||||
// Contenu brut
|
||||
if ($output['content']) {
|
||||
$this->addOutput([
|
||||
'content' => $output['content']
|
||||
]);
|
||||
}
|
||||
// Contenu par vue
|
||||
elseif ($output['view']) {
|
||||
// Chemin en fonction d'un module du coeur ou d'un module
|
||||
$modulePath = in_array($moduleId, self::$coreModuleIds) ? 'core/' : '';
|
||||
// CSS
|
||||
$stylePath = $modulePath . self::MODULE_DIR . $moduleId . '/view/' . $output['view'] . '/' . $output['view'] . '.css';
|
||||
if (file_exists($stylePath)) {
|
||||
$this->addOutput([
|
||||
'style' => file_get_contents($stylePath)
|
||||
]);
|
||||
}
|
||||
if ($output['style']) {
|
||||
$this->addOutput([
|
||||
'style' => file_get_contents($output['style'])
|
||||
]);
|
||||
}
|
||||
|
||||
// JS
|
||||
$scriptPath = $modulePath . self::MODULE_DIR . $moduleId . '/view/' . $output['view'] . '/' . $output['view'] . '.js.php';
|
||||
if (file_exists($scriptPath)) {
|
||||
ob_start();
|
||||
include $scriptPath;
|
||||
$this->addOutput([
|
||||
'script' => ob_get_clean()
|
||||
]);
|
||||
}
|
||||
// Vue
|
||||
$viewPath = $modulePath . self::MODULE_DIR . $moduleId . '/view/' . $output['view'] . '/' . $output['view'] . '.php';
|
||||
if (file_exists($viewPath)) {
|
||||
ob_start();
|
||||
include $viewPath;
|
||||
$modpos = $this->getData(['page', $this->getUrl(0), 'modulePosition']);
|
||||
if ($modpos === 'top') {
|
||||
$this->addOutput([
|
||||
'content' => ob_get_clean() . ($output['showPageContent'] ? $pageContent : '')
|
||||
]);
|
||||
} else if ($modpos === 'free') {
|
||||
if (strstr($pageContent, '[MODULE]', true) === false) {
|
||||
$begin = strstr($pageContent, '[]', true);
|
||||
} else {
|
||||
$begin = strstr($pageContent, '[MODULE]', true);
|
||||
}
|
||||
if (strstr($pageContent, '[MODULE]') === false) {
|
||||
$end = strstr($pageContent, '[]');
|
||||
} else {
|
||||
$end = strstr($pageContent, '[MODULE]');
|
||||
}
|
||||
$cut = 8;
|
||||
$end = substr($end, -strlen($end) + $cut);
|
||||
$this->addOutput([
|
||||
'content' => ($output['showPageContent'] ? $begin : '') . ob_get_clean() . ($output['showPageContent'] ? $end : '')
|
||||
]);
|
||||
} else {
|
||||
$this->addOutput([
|
||||
'content' => ($output['showPageContent'] ? $pageContent : '') . ob_get_clean()
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Librairies
|
||||
if ($output['vendor'] !== $this->output['vendor']) {
|
||||
$this->addOutput([
|
||||
'vendor' => array_merge($this->output['vendor'], $output['vendor'])
|
||||
]);
|
||||
}
|
||||
|
||||
if ($output['title'] !== null) {
|
||||
$this->addOutput([
|
||||
'title' => $output['title']
|
||||
]);
|
||||
}
|
||||
// Affiche le bouton d'édition de la page dans la barre de membre
|
||||
if ($output['showBarEditButton']) {
|
||||
$this->addOutput([
|
||||
'showBarEditButton' => $output['showBarEditButton']
|
||||
]);
|
||||
}
|
||||
}
|
||||
// Erreur 403
|
||||
else {
|
||||
$access = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Erreurs
|
||||
if ($access === 'login') {
|
||||
http_response_code(302);
|
||||
header('Location:' . helper::baseUrl() . 'user/login/');
|
||||
exit();
|
||||
}
|
||||
if ($access === false) {
|
||||
http_response_code(403);
|
||||
if ($accessInfo['userName']) {
|
||||
$this->addOutput([
|
||||
'title' => 'Accès verrouillé',
|
||||
'content' => template::speech(sprintf(helper::translate('La page %s est ouverte par l\'utilisateur %s'), $accessInfo['pageId'], $accessInfo['userName']))
|
||||
|
||||
]);
|
||||
} else {
|
||||
if (
|
||||
$this->getData(['locale', 'page403']) !== 'none'
|
||||
and $this->getData(['page', $this->getData(['locale', 'page403'])])
|
||||
) {
|
||||
header('Location:' . helper::baseUrl() . $this->getData(['locale', 'page403']));
|
||||
} else {
|
||||
$this->addOutput([
|
||||
'title' => 'Accès interdit',
|
||||
'content' => template::speech(helper::translate('Vous n\'êtes pas autorisé à consulter cette page (erreur 403)'))
|
||||
]);
|
||||
}
|
||||
}
|
||||
} elseif ($this->output['content'] === '') {
|
||||
http_response_code(404);
|
||||
if (
|
||||
$this->getData(['locale', 'page404']) !== 'none'
|
||||
and $this->getData(['page', $this->getData(['locale', 'page404'])])
|
||||
) {
|
||||
header('Location:' . helper::baseUrl() . $this->getData(['locale', 'page404']));
|
||||
} else {
|
||||
$this->addOutput([
|
||||
'title' => 'Page indisponible',
|
||||
'content' => template::speech(helper::translate('La page demandée n\'existe pas ou est introuvable (erreur 404)'))
|
||||
]);
|
||||
}
|
||||
}
|
||||
// Mise en forme des métas
|
||||
if ($this->output['metaTitle'] === '') {
|
||||
if ($this->output['title']) {
|
||||
$this->addOutput([
|
||||
'metaTitle' => strip_tags($this->output['title']) . ' - ' . $this->getData(['locale', 'title'])
|
||||
]);
|
||||
} else {
|
||||
$this->addOutput([
|
||||
'metaTitle' => $this->getData(['locale', 'title'])
|
||||
]);
|
||||
}
|
||||
}
|
||||
if ($this->output['metaDescription'] === '') {
|
||||
$this->addOutput([
|
||||
'metaDescription' => $this->getData(['locale', 'metaDescription'])
|
||||
]);
|
||||
}
|
||||
switch ($this->output['display']) {
|
||||
// Layout brut
|
||||
case self::DISPLAY_RAW:
|
||||
echo $this->output['content'];
|
||||
break;
|
||||
// Layout vide
|
||||
case self::DISPLAY_LAYOUT_BLANK:
|
||||
require 'core/layout/blank.php';
|
||||
break;
|
||||
// Affichage en JSON
|
||||
case self::DISPLAY_JSON:
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($this->output['content']);
|
||||
break;
|
||||
// RSS feed
|
||||
case self::DISPLAY_RSS:
|
||||
header('Content-type: application/rss+xml; charset=UTF-8');
|
||||
echo $this->output['content'];
|
||||
break;
|
||||
// Layout allégé
|
||||
case self::DISPLAY_LAYOUT_LIGHT:
|
||||
ob_start();
|
||||
require 'core/layout/light.php';
|
||||
$content = ob_get_clean();
|
||||
// Convertit la chaîne en UTF-8 pour conserver les caractères accentués
|
||||
$content = mb_convert_encoding($content, 'UTF-8', 'UTF-8');
|
||||
// Supprime les espaces, les sauts de ligne, les tabulations et autres caractères inutiles
|
||||
$content = preg_replace('/[\t ]+/u', ' ', $content);
|
||||
echo $content;
|
||||
break;
|
||||
// Layout principal
|
||||
case self::DISPLAY_LAYOUT_MAIN:
|
||||
ob_start();
|
||||
require 'core/layout/main.php';
|
||||
$content = ob_get_clean();
|
||||
// Convertit la chaîne en UTF-8 pour conserver les caractères accentués
|
||||
$content = mb_convert_encoding($content, 'UTF-8', 'UTF-8');
|
||||
// Supprime les espaces, les sauts de ligne, les tabulations et autres caractères inutiles
|
||||
$content = preg_replace('/[\t ]+/u', ' ', $content);
|
||||
echo $content;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
36
core/class/sitemap/FileSystem.class.php
Normal file
36
core/class/sitemap/FileSystem.class.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Icamys\SitemapGenerator;
|
||||
|
||||
class FileSystem
|
||||
{
|
||||
public function file_get_contents($filepath)
|
||||
{
|
||||
return file_get_contents($filepath);
|
||||
}
|
||||
|
||||
public function file_put_contents($filepath, $content, $flags = 0)
|
||||
{
|
||||
return file_put_contents($filepath, $content, $flags);
|
||||
}
|
||||
|
||||
public function file_exists($filepath)
|
||||
{
|
||||
return file_exists($filepath);
|
||||
}
|
||||
|
||||
public function rename($oldname, $newname)
|
||||
{
|
||||
return rename($oldname, $newname);
|
||||
}
|
||||
|
||||
public function copy($source, $destination)
|
||||
{
|
||||
return copy($source, $destination);
|
||||
}
|
||||
|
||||
public function unlink($filepath)
|
||||
{
|
||||
return unlink($filepath);
|
||||
}
|
||||
}
|
36
core/class/sitemap/Runtime.class.php
Normal file
36
core/class/sitemap/Runtime.class.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Icamys\SitemapGenerator;
|
||||
|
||||
class Runtime
|
||||
{
|
||||
public function extension_loaded($extname)
|
||||
{
|
||||
return extension_loaded($extname);
|
||||
}
|
||||
|
||||
public function is_writable($filepath)
|
||||
{
|
||||
return is_writable($filepath);
|
||||
}
|
||||
|
||||
public function curl_init($url)
|
||||
{
|
||||
return curl_init($url);
|
||||
}
|
||||
|
||||
public function curl_setopt($handle, $option, $value)
|
||||
{
|
||||
return curl_setopt($handle, $option, $value);
|
||||
}
|
||||
|
||||
public function curl_exec($handle)
|
||||
{
|
||||
return curl_exec($handle);
|
||||
}
|
||||
|
||||
public function curl_getinfo($handle, $option = null)
|
||||
{
|
||||
return curl_getinfo($handle, $option);
|
||||
}
|
||||
}
|
705
core/class/sitemap/SitemapGenerator.class.php
Normal file
705
core/class/sitemap/SitemapGenerator.class.php
Normal file
@ -0,0 +1,705 @@
|
||||
<?php
|
||||
|
||||
namespace Icamys\SitemapGenerator;
|
||||
|
||||
use BadMethodCallException;
|
||||
use DateTime;
|
||||
use Icamys\SitemapGenerator\Extensions\GoogleVideoExtension;
|
||||
use InvalidArgumentException;
|
||||
use OutOfRangeException;
|
||||
use RuntimeException;
|
||||
use XMLWriter;
|
||||
|
||||
/**
|
||||
* Class SitemapGenerator
|
||||
* @package Icamys\SitemapGenerator
|
||||
*/
|
||||
class SitemapGenerator
|
||||
{
|
||||
/**
|
||||
* Max size of a sitemap according to spec.
|
||||
* @see https://www.sitemaps.org/protocol.html
|
||||
*/
|
||||
private const MAX_FILE_SIZE = 52428800;
|
||||
|
||||
/**
|
||||
* Max number of urls per sitemap according to spec.
|
||||
* @see https://www.sitemaps.org/protocol.html
|
||||
*/
|
||||
private const MAX_URLS_PER_SITEMAP = 50000;
|
||||
|
||||
/**
|
||||
* Max number of sitemaps per index file according to spec.
|
||||
* @see http://www.sitemaps.org/protocol.html
|
||||
*/
|
||||
private const MAX_SITEMAPS_PER_INDEX = 50000;
|
||||
|
||||
/**
|
||||
* Total max number of URLs.
|
||||
*/
|
||||
private const TOTAL_MAX_URLS = self::MAX_URLS_PER_SITEMAP * self::MAX_SITEMAPS_PER_INDEX;
|
||||
|
||||
/**
|
||||
* Max url length according to spec.
|
||||
* @see https://www.sitemaps.org/protocol.html#xmlTagDefinitions
|
||||
*/
|
||||
private const MAX_URL_LEN = 2048;
|
||||
|
||||
/**
|
||||
* Robots file name
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
private $robotsFileName = "robots.txt";
|
||||
/**
|
||||
* Name of sitemap file
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
private $sitemapFileName = "sitemap.xml";
|
||||
/**
|
||||
* Name of sitemap index file
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
private $sitemapIndexFileName = "sitemap-index.xml";
|
||||
/**
|
||||
* Quantity of URLs per single sitemap file.
|
||||
* If Your links are very long, sitemap file can be bigger than 10MB,
|
||||
* in this case use smaller value.
|
||||
* @var int
|
||||
* @access public
|
||||
*/
|
||||
private $maxUrlsPerSitemap = self::MAX_URLS_PER_SITEMAP;
|
||||
/**
|
||||
* If true, two sitemap files (.xml and .xml.gz) will be created and added to robots.txt.
|
||||
* If true, .gz file will be submitted to search engines.
|
||||
* If quantity of URLs will be bigger than 50.000, option will be ignored,
|
||||
* all sitemap files except sitemap index will be compressed.
|
||||
* @var bool
|
||||
* @access public
|
||||
*/
|
||||
private $isCompressionEnabled = false;
|
||||
/**
|
||||
* URL to Your site.
|
||||
* Script will use it to send sitemaps to search engines.
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
private $baseURL;
|
||||
/**
|
||||
* Base path. Relative to script location.
|
||||
* Use this if Your sitemap and robots files should be stored in other
|
||||
* directory then script.
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
private $basePath;
|
||||
/**
|
||||
* Version of this class
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
private $classVersion = "4.3.1";
|
||||
/**
|
||||
* Search engines URLs
|
||||
* @var array of strings
|
||||
* @access private
|
||||
*/
|
||||
private $searchEngines = [
|
||||
[
|
||||
"http://search.yahooapis.com/SiteExplorerService/V1/updateNotification?appid=USERID&url=",
|
||||
"http://search.yahooapis.com/SiteExplorerService/V1/ping?sitemap=",
|
||||
],
|
||||
"http://www.google.com/ping?sitemap=",
|
||||
"http://submissions.ask.com/ping?sitemap=",
|
||||
"http://www.bing.com/ping?sitemap=",
|
||||
"http://www.webmaster.yandex.ru/ping?sitemap=",
|
||||
];
|
||||
/**
|
||||
* Array with urls
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
private $urls;
|
||||
/**
|
||||
* Lines for robots.txt file that are written if file does not exist
|
||||
* @var array
|
||||
*/
|
||||
private $sampleRobotsLines = [
|
||||
"User-agent: *",
|
||||
"Allow: /",
|
||||
];
|
||||
/**
|
||||
* @var array list of valid changefreq values according to the spec
|
||||
*/
|
||||
private $validChangefreqValues = [
|
||||
'always',
|
||||
'hourly',
|
||||
'daily',
|
||||
'weekly',
|
||||
'monthly',
|
||||
'yearly',
|
||||
'never',
|
||||
];
|
||||
/**
|
||||
* @var float[] list of valid priority values according to the spec
|
||||
*/
|
||||
private $validPriorities = [
|
||||
0.0,
|
||||
0.1,
|
||||
0.2,
|
||||
0.3,
|
||||
0.4,
|
||||
0.5,
|
||||
0.6,
|
||||
0.7,
|
||||
0.8,
|
||||
0.9,
|
||||
1.0,
|
||||
];
|
||||
/**
|
||||
* @var FileSystem object used to communicate with file system
|
||||
*/
|
||||
private $fs;
|
||||
/**
|
||||
* @var Runtime object used to communicate with runtime
|
||||
*/
|
||||
private $runtime;
|
||||
|
||||
/**
|
||||
* @var XMLWriter Used for writing xml to files
|
||||
*/
|
||||
private $xmlWriter;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $flushedSitemapFilenameFormat;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $flushedSitemapSize = 0;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $flushedSitemapCounter = 0;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $flushedSitemaps = [];
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $isSitemapStarted = false;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $totalUrlCount = 0;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $urlsetClosingTagLen = 10; // strlen("</urlset>\n")
|
||||
private $sitemapUrlCount = 0;
|
||||
private $generatedFiles = [];
|
||||
|
||||
/**
|
||||
* @param string $baseURL You site URL
|
||||
* @param string $basePath Relative path where sitemap and robots should be stored.
|
||||
* @param FileSystem|null $fs
|
||||
* @param Runtime|null $runtime
|
||||
*/
|
||||
public function __construct(string $baseURL, string $basePath = "", FileSystem $fs = null, Runtime $runtime = null)
|
||||
{
|
||||
$this->urls = [];
|
||||
$this->baseURL = rtrim($baseURL, '/');
|
||||
|
||||
if ($fs === null) {
|
||||
$this->fs = new FileSystem();
|
||||
} else {
|
||||
$this->fs = $fs;
|
||||
}
|
||||
|
||||
if ($runtime === null) {
|
||||
$this->runtime = new Runtime();
|
||||
} else {
|
||||
$this->runtime = $runtime;
|
||||
}
|
||||
|
||||
if ($this->runtime->is_writable($basePath) === false) {
|
||||
throw new InvalidArgumentException(
|
||||
sprintf('the provided basePath (%s) should be a writable directory,', $basePath) .
|
||||
' please check its existence and permissions'
|
||||
);
|
||||
}
|
||||
if (strlen($basePath) > 0 && substr($basePath, -1) != DIRECTORY_SEPARATOR) {
|
||||
$basePath = $basePath . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
$this->basePath = $basePath;
|
||||
|
||||
$this->xmlWriter = $this->createXmlWriter();
|
||||
$this->flushedSitemapFilenameFormat = sprintf("sm-%%d-%d.xml", time());
|
||||
}
|
||||
|
||||
private function createXmlWriter(): XMLWriter
|
||||
{
|
||||
$w = new XMLWriter();
|
||||
$w->openMemory();
|
||||
$w->setIndent(true);
|
||||
return $w;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
* @return SitemapGenerator
|
||||
*/
|
||||
public function setSitemapFilename(string $filename = ''): SitemapGenerator
|
||||
{
|
||||
if (strlen($filename) === 0) {
|
||||
throw new InvalidArgumentException('sitemap filename should not be empty');
|
||||
}
|
||||
if (pathinfo($filename, PATHINFO_EXTENSION) !== 'xml') {
|
||||
throw new InvalidArgumentException('sitemap filename should have *.xml extension');
|
||||
}
|
||||
$this->sitemapFileName = $filename;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
* @return $this
|
||||
*/
|
||||
public function setSitemapIndexFilename(string $filename = ''): SitemapGenerator
|
||||
{
|
||||
if (strlen($filename) === 0) {
|
||||
throw new InvalidArgumentException('filename should not be empty');
|
||||
}
|
||||
$this->sitemapIndexFileName = $filename;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
* @return $this
|
||||
*/
|
||||
public function setRobotsFileName(string $filename): SitemapGenerator
|
||||
{
|
||||
if (strlen($filename) === 0) {
|
||||
throw new InvalidArgumentException('filename should not be empty');
|
||||
}
|
||||
$this->robotsFileName = $filename;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $value
|
||||
* @return $this
|
||||
*/
|
||||
public function setMaxUrlsPerSitemap(int $value): SitemapGenerator
|
||||
{
|
||||
if ($value < 1 || self::MAX_URLS_PER_SITEMAP < $value) {
|
||||
throw new OutOfRangeException(
|
||||
sprintf('value %d is out of range 1-%d', $value, self::MAX_URLS_PER_SITEMAP)
|
||||
);
|
||||
}
|
||||
$this->maxUrlsPerSitemap = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function enableCompression(): SitemapGenerator
|
||||
{
|
||||
$this->isCompressionEnabled = true;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function disableCompression(): SitemapGenerator
|
||||
{
|
||||
$this->isCompressionEnabled = false;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isCompressionEnabled(): bool
|
||||
{
|
||||
return $this->isCompressionEnabled;
|
||||
}
|
||||
|
||||
public function validate(
|
||||
string $path,
|
||||
DateTime $lastModified = null,
|
||||
string $changeFrequency = null,
|
||||
float $priority = null,
|
||||
array $alternates = null,
|
||||
array $extensions = [])
|
||||
{
|
||||
if (!(1 <= mb_strlen($path) && mb_strlen($path) <= self::MAX_URL_LEN)) {
|
||||
throw new InvalidArgumentException(
|
||||
sprintf("The urlPath argument length must be between 1 and %d.", self::MAX_URL_LEN)
|
||||
);
|
||||
}
|
||||
if ($changeFrequency !== null && !in_array($changeFrequency, $this->validChangefreqValues)) {
|
||||
throw new InvalidArgumentException(
|
||||
'The change frequency argument should be one of: %s' . implode(',', $this->validChangefreqValues)
|
||||
);
|
||||
}
|
||||
if ($priority !== null && !in_array($priority, $this->validPriorities)) {
|
||||
throw new InvalidArgumentException("Priority argument should be a float number in the range [0.0..1.0]");
|
||||
}
|
||||
if ($extensions !== null && isset($extensions['google_video'])) {
|
||||
GoogleVideoExtension::validate($this->baseURL . $path, $extensions['google_video']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add url components.
|
||||
* Instead of storing all urls in the memory, the generator will flush sets of added urls
|
||||
* to the temporary files created on your disk.
|
||||
* The file format is 'sm-{index}-{timestamp}.xml'
|
||||
* @param string $path
|
||||
* @param DateTime|null $lastModified
|
||||
* @param string|null $changeFrequency
|
||||
* @param float|null $priority
|
||||
* @param array|null $alternates
|
||||
* @param array $extensions
|
||||
* @return $this
|
||||
*/
|
||||
public function addURL(
|
||||
string $path,
|
||||
DateTime $lastModified = null,
|
||||
string $changeFrequency = null,
|
||||
float $priority = null,
|
||||
array $alternates = null,
|
||||
array $extensions = []
|
||||
): SitemapGenerator
|
||||
{
|
||||
$this->validate($path, $lastModified, $changeFrequency, $priority, $alternates, $extensions);
|
||||
|
||||
if ($this->totalUrlCount >= self::TOTAL_MAX_URLS) {
|
||||
throw new OutOfRangeException(
|
||||
sprintf("Max url limit reached (%d)", self::TOTAL_MAX_URLS)
|
||||
);
|
||||
}
|
||||
if ($this->isSitemapStarted === false) {
|
||||
$this->writeSitemapStart();
|
||||
}
|
||||
|
||||
$this->writeSitemapUrl($this->baseURL . $path, $lastModified, $changeFrequency, $priority, $alternates, $extensions);
|
||||
|
||||
if ($this->totalUrlCount % 1000 === 0 || $this->sitemapUrlCount >= $this->maxUrlsPerSitemap) {
|
||||
$this->flushWriter();
|
||||
}
|
||||
|
||||
if ($this->sitemapUrlCount === $this->maxUrlsPerSitemap) {
|
||||
$this->writeSitemapEnd();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function writeSitemapStart()
|
||||
{
|
||||
$this->xmlWriter->startDocument("1.0", "UTF-8");
|
||||
$this->xmlWriter->writeComment(sprintf('generator-class="%s"', get_class($this)));
|
||||
$this->xmlWriter->writeComment(sprintf('generator-version="%s"', $this->classVersion));
|
||||
$this->xmlWriter->writeComment(sprintf('generated-on="%s"', date('c')));
|
||||
$this->xmlWriter->startElement('urlset');
|
||||
$this->xmlWriter->writeAttribute('xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9');
|
||||
$this->xmlWriter->writeAttribute('xmlns:xhtml', 'http://www.w3.org/1999/xhtml');
|
||||
$this->xmlWriter->writeAttribute('xmlns:video', 'http://www.google.com/schemas/sitemap-video/1.1');
|
||||
$this->xmlWriter->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
|
||||
$this->xmlWriter->writeAttribute('xsi:schemaLocation', 'http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd');
|
||||
$this->isSitemapStarted = true;
|
||||
}
|
||||
|
||||
private function writeSitemapUrl($loc, $lastModified, $changeFrequency, $priority, $alternates, $extensions)
|
||||
{
|
||||
$this->xmlWriter->startElement('url');
|
||||
$this->xmlWriter->writeElement('loc', htmlspecialchars($loc, ENT_QUOTES));
|
||||
|
||||
if ($lastModified !== null) {
|
||||
$this->xmlWriter->writeElement('lastmod', $lastModified->format(DateTime::ATOM));
|
||||
}
|
||||
|
||||
if ($changeFrequency !== null) {
|
||||
$this->xmlWriter->writeElement('changefreq', $changeFrequency);
|
||||
}
|
||||
|
||||
if ($priority !== null) {
|
||||
$this->xmlWriter->writeElement('priority', number_format($priority, 1, ".", ""));
|
||||
}
|
||||
|
||||
if (is_array($alternates) && count($alternates) > 0) {
|
||||
foreach ($alternates as $alternate) {
|
||||
if (is_array($alternate) && isset($alternate['hreflang']) && isset($alternate['href'])) {
|
||||
$this->xmlWriter->startElement('xhtml:link');
|
||||
$this->xmlWriter->writeAttribute('rel', 'alternate');
|
||||
$this->xmlWriter->writeAttribute('hreflang', $alternate['hreflang']);
|
||||
$this->xmlWriter->writeAttribute('href', $alternate['href']);
|
||||
$this->xmlWriter->endElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($extensions as $extName => $extFields) {
|
||||
if ($extName === 'google_video') {
|
||||
GoogleVideoExtension::writeVideoTag($this->xmlWriter, $loc, $extFields);
|
||||
}
|
||||
}
|
||||
|
||||
$this->xmlWriter->endElement(); // url
|
||||
$this->sitemapUrlCount++;
|
||||
$this->totalUrlCount++;
|
||||
}
|
||||
|
||||
private function flushWriter()
|
||||
{
|
||||
$targetSitemapFilepath = $this->basePath . sprintf($this->flushedSitemapFilenameFormat, $this->flushedSitemapCounter);
|
||||
$flushedString = $this->xmlWriter->outputMemory(true);
|
||||
$flushedStringLen = mb_strlen($flushedString);
|
||||
|
||||
if ($flushedStringLen === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->flushedSitemapSize += $flushedStringLen;
|
||||
|
||||
if ($this->flushedSitemapSize > self::MAX_FILE_SIZE - $this->urlsetClosingTagLen) {
|
||||
$this->writeSitemapEnd();
|
||||
$this->writeSitemapStart();
|
||||
}
|
||||
$this->fs->file_put_contents($targetSitemapFilepath, $flushedString, FILE_APPEND);
|
||||
}
|
||||
|
||||
private function writeSitemapEnd()
|
||||
{
|
||||
$targetSitemapFilepath = $this->basePath . sprintf($this->flushedSitemapFilenameFormat, $this->flushedSitemapCounter);
|
||||
$this->xmlWriter->endElement(); // urlset
|
||||
$this->xmlWriter->endDocument();
|
||||
$this->fs->file_put_contents($targetSitemapFilepath, $this->xmlWriter->flush(true), FILE_APPEND);
|
||||
$this->isSitemapStarted = false;
|
||||
$this->flushedSitemaps[] = $targetSitemapFilepath;
|
||||
$this->flushedSitemapCounter++;
|
||||
$this->sitemapUrlCount = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush all stored urls from memory to the disk and close all necessary tags.
|
||||
*/
|
||||
public function flush()
|
||||
{
|
||||
$this->flushWriter();
|
||||
if ($this->isSitemapStarted) {
|
||||
$this->writeSitemapEnd();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move flushed files to their final location. Compress if necessary.
|
||||
*/
|
||||
public function finalize()
|
||||
{
|
||||
$this->generatedFiles = [];
|
||||
|
||||
if (count($this->flushedSitemaps) === 1) {
|
||||
$targetSitemapFilename = $this->sitemapFileName;
|
||||
if ($this->isCompressionEnabled) {
|
||||
$targetSitemapFilename .= '.gz';
|
||||
}
|
||||
|
||||
$targetSitemapFilepath = $this->basePath . $targetSitemapFilename;
|
||||
|
||||
if ($this->isCompressionEnabled) {
|
||||
$this->fs->copy($this->flushedSitemaps[0], 'compress.zlib://' . $targetSitemapFilepath);
|
||||
$this->fs->unlink($this->flushedSitemaps[0]);
|
||||
} else {
|
||||
$this->fs->rename($this->flushedSitemaps[0], $targetSitemapFilepath);
|
||||
}
|
||||
$this->generatedFiles['sitemaps_location'] = [$targetSitemapFilepath];
|
||||
$this->generatedFiles['sitemaps_index_url'] = $this->baseURL . '/' . $targetSitemapFilename;
|
||||
} else if (count($this->flushedSitemaps) > 1) {
|
||||
$ext = '.' . pathinfo($this->sitemapFileName, PATHINFO_EXTENSION);
|
||||
$targetExt = $ext;
|
||||
if ($this->isCompressionEnabled) {
|
||||
$targetExt .= '.gz';
|
||||
}
|
||||
|
||||
$sitemapsUrls = [];
|
||||
$targetSitemapFilepaths = [];
|
||||
foreach ($this->flushedSitemaps as $i => $flushedSitemap) {
|
||||
$targetSitemapFilename = str_replace($ext, ($i + 1) . $targetExt, $this->sitemapFileName);
|
||||
$targetSitemapFilepath = $this->basePath . $targetSitemapFilename;
|
||||
|
||||
if ($this->isCompressionEnabled) {
|
||||
$this->fs->copy($flushedSitemap, 'compress.zlib://' . $targetSitemapFilepath);
|
||||
$this->fs->unlink($flushedSitemap);
|
||||
} else {
|
||||
$this->fs->rename($flushedSitemap, $targetSitemapFilepath);
|
||||
}
|
||||
$sitemapsUrls[] = htmlspecialchars($this->baseURL . '/' . $targetSitemapFilename, ENT_QUOTES);
|
||||
$targetSitemapFilepaths[] = $targetSitemapFilepath;
|
||||
}
|
||||
|
||||
$targetSitemapIndexFilepath = $this->basePath . $this->sitemapIndexFileName;
|
||||
$this->createSitemapIndex($sitemapsUrls, $targetSitemapIndexFilepath);
|
||||
$this->generatedFiles['sitemaps_location'] = $targetSitemapFilepaths;
|
||||
$this->generatedFiles['sitemaps_index_location'] = $targetSitemapIndexFilepath;
|
||||
$this->generatedFiles['sitemaps_index_url'] = $this->baseURL . '/' . $this->sitemapIndexFileName;
|
||||
} else {
|
||||
throw new RuntimeException('failed to finalize, please add urls and flush first');
|
||||
}
|
||||
}
|
||||
|
||||
private function createSitemapIndex($sitemapsUrls, $sitemapIndexFileName)
|
||||
{
|
||||
$this->xmlWriter->flush(true);
|
||||
$this->writeSitemapIndexStart();
|
||||
foreach ($sitemapsUrls as $sitemapsUrl) {
|
||||
$this->writeSitemapIndexUrl($sitemapsUrl);
|
||||
}
|
||||
$this->writeSitemapIndexEnd();
|
||||
$this->fs->file_put_contents(
|
||||
$sitemapIndexFileName,
|
||||
$this->xmlWriter->flush(true),
|
||||
FILE_APPEND
|
||||
);
|
||||
}
|
||||
|
||||
private function writeSitemapIndexStart()
|
||||
{
|
||||
$this->xmlWriter->startDocument("1.0", "UTF-8");
|
||||
$this->xmlWriter->writeComment(sprintf('generator-class="%s"', get_class($this)));
|
||||
$this->xmlWriter->writeComment(sprintf('generator-version="%s"', $this->classVersion));
|
||||
$this->xmlWriter->writeComment(sprintf('generated-on="%s"', date('c')));
|
||||
$this->xmlWriter->startElement('sitemapindex');
|
||||
$this->xmlWriter->writeAttribute('xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9');
|
||||
$this->xmlWriter->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
|
||||
$this->xmlWriter->writeAttribute('xsi:schemaLocation', 'http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd');
|
||||
}
|
||||
|
||||
private function writeSitemapIndexUrl($url)
|
||||
{
|
||||
$this->xmlWriter->startElement('sitemap');
|
||||
$this->xmlWriter->writeElement('loc', htmlspecialchars($url, ENT_QUOTES));
|
||||
$this->xmlWriter->writeElement('lastmod', date('c'));
|
||||
$this->xmlWriter->endElement(); // sitemap
|
||||
}
|
||||
|
||||
private function writeSitemapIndexEnd()
|
||||
{
|
||||
$this->xmlWriter->endElement(); // sitemapindex
|
||||
$this->xmlWriter->endDocument();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array Array of previously generated files
|
||||
*/
|
||||
public function getGeneratedFiles(): array
|
||||
{
|
||||
return $this->generatedFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will inform search engines about newly created sitemaps.
|
||||
* Google, Ask, Bing and Yahoo will be noticed.
|
||||
* If You don't pass yahooAppId, Yahoo still will be informed,
|
||||
* but this method can be used once per day. If You will do this often,
|
||||
* message that limit was exceeded will be returned from Yahoo.
|
||||
* @param string $yahooAppId Your site Yahoo appid.
|
||||
* @return array of messages and http codes from each search engine
|
||||
* @access public
|
||||
* @throws BadMethodCallException
|
||||
*/
|
||||
public function submitSitemap($yahooAppId = null): array
|
||||
{
|
||||
if (count($this->generatedFiles) === 0) {
|
||||
throw new BadMethodCallException("To update robots.txt, call finalize() first.");
|
||||
}
|
||||
if (!$this->runtime->extension_loaded('curl')) {
|
||||
throw new BadMethodCallException("cURL extension is needed to do submission.");
|
||||
}
|
||||
$searchEngines = $this->searchEngines;
|
||||
$searchEngines[0] = isset($yahooAppId) ?
|
||||
str_replace("USERID", $yahooAppId, $searchEngines[0][0]) :
|
||||
$searchEngines[0][1];
|
||||
$result = [];
|
||||
for ($i = 0; $i < count($searchEngines); $i++) {
|
||||
$submitUrl = $searchEngines[$i] . htmlspecialchars($this->generatedFiles['sitemaps_index_url'], ENT_QUOTES);
|
||||
$submitSite = $this->runtime->curl_init($submitUrl);
|
||||
$this->runtime->curl_setopt($submitSite, CURLOPT_RETURNTRANSFER, true);
|
||||
$responseContent = $this->runtime->curl_exec($submitSite);
|
||||
$response = $this->runtime->curl_getinfo($submitSite);
|
||||
$submitSiteShort = array_reverse(explode(".", parse_url($searchEngines[$i], PHP_URL_HOST)));
|
||||
$result[] = [
|
||||
"site" => $submitSiteShort[1] . "." . $submitSiteShort[0],
|
||||
"fullsite" => $submitUrl,
|
||||
"http_code" => $response['http_code'],
|
||||
"message" => str_replace("\n", " ", strip_tags($responseContent)),
|
||||
];
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds sitemap url to robots.txt file located in basePath.
|
||||
* If robots.txt file exists,
|
||||
* the function will append sitemap url to file.
|
||||
* If robots.txt does not exist,
|
||||
* the function will create new robots.txt file with sample content and sitemap url.
|
||||
* @access public
|
||||
* @throws BadMethodCallException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function updateRobots(): SitemapGenerator
|
||||
{
|
||||
if (count($this->generatedFiles) === 0) {
|
||||
throw new BadMethodCallException("To update robots.txt, call finalize() first.");
|
||||
}
|
||||
|
||||
$robotsFilePath = $this->basePath . $this->robotsFileName;
|
||||
|
||||
$robotsFileContent = $this->createNewRobotsContentFromFile($robotsFilePath);
|
||||
|
||||
$this->fs->file_put_contents($robotsFilePath, $robotsFileContent);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $filepath
|
||||
* @return string
|
||||
*/
|
||||
private function createNewRobotsContentFromFile($filepath): string
|
||||
{
|
||||
if ($this->fs->file_exists($filepath)) {
|
||||
$robotsFileContent = "";
|
||||
$robotsFile = explode(PHP_EOL, $this->fs->file_get_contents($filepath));
|
||||
foreach ($robotsFile as $key => $value) {
|
||||
if (substr($value, 0, 8) == 'Sitemap:') {
|
||||
unset($robotsFile[$key]);
|
||||
} else {
|
||||
$robotsFileContent .= $value . PHP_EOL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$robotsFileContent = $this->getSampleRobotsContent();
|
||||
}
|
||||
|
||||
$robotsFileContent .= "Sitemap: {$this->generatedFiles['sitemaps_index_url']}";
|
||||
|
||||
return $robotsFileContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @access private
|
||||
*/
|
||||
private function getSampleRobotsContent(): string
|
||||
{
|
||||
return implode(PHP_EOL, $this->sampleRobotsLines) . PHP_EOL;
|
||||
}
|
||||
}
|
217
core/class/strftime/php-8.1-strftime.class.php
Normal file
217
core/class/strftime/php-8.1-strftime.class.php
Normal file
@ -0,0 +1,217 @@
|
||||
<?php
|
||||
namespace PHP81_BC;
|
||||
|
||||
use DateTime;
|
||||
use DateTimeZone;
|
||||
use DateTimeInterface;
|
||||
use Exception;
|
||||
use IntlDateFormatter;
|
||||
use IntlGregorianCalendar;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Locale-formatted PHP81_BC\PHP81_BC\strftime using IntlDateFormatter (PHP 8.1 compatible)
|
||||
* This provides a cross-platform alternative to PHP81_BC\PHP81_BC\strftime() for when it will be removed from PHP.
|
||||
* Note that output can be slightly different between libc sprintf and this function as it is using ICU.
|
||||
*
|
||||
* Usage:
|
||||
* use function \PHP81_BC\PHP81_BC\PHP81_BC\strftime;
|
||||
* echo PHP81_BC\PHP81_BC\strftime('%A %e %B %Y %X', new \DateTime('2021-09-28 00:00:00'), 'fr_FR');
|
||||
*
|
||||
* Original use:
|
||||
* \setlocale(LC_TIME, 'fr_FR.UTF-8');
|
||||
* echo \PHP81_BC\PHP81_BC\strftime('%A %e %B %Y %X', strtotime('2021-09-28 00:00:00'));
|
||||
*
|
||||
* @param string $format Date format
|
||||
* @param integer|string|DateTime $timestamp Timestamp
|
||||
* @return string
|
||||
* @author BohwaZ <https://bohwaz.net/>
|
||||
*/
|
||||
function strftime (string $format, $timestamp = null, ?string $locale = null) : string {
|
||||
if (!($timestamp instanceof DateTimeInterface)) {
|
||||
$timestamp = is_int($timestamp) ? '@' . $timestamp : (string) $timestamp;
|
||||
|
||||
try {
|
||||
$timestamp = new DateTime($timestamp);
|
||||
} catch (Exception $e) {
|
||||
throw new InvalidArgumentException('$timestamp argument is neither a valid UNIX timestamp, a valid date-time string or a DateTime object.', 0, $e);
|
||||
}
|
||||
}
|
||||
|
||||
$timestamp->setTimezone(new DateTimeZone(date_default_timezone_get()));
|
||||
|
||||
if (empty($locale)) {
|
||||
// get current locale
|
||||
$locale = setlocale(LC_TIME, '0');
|
||||
}
|
||||
// remove trailing part not supported by ext-intl locale
|
||||
$locale = preg_replace('/[^\w-].*$/', '', $locale);
|
||||
|
||||
$intl_formats = [
|
||||
'%a' => 'EEE', // An abbreviated textual representation of the day Sun through Sat
|
||||
'%A' => 'EEEE', // A full textual representation of the day Sunday through Saturday
|
||||
'%b' => 'MMM', // Abbreviated month name, based on the locale Jan through Dec
|
||||
'%B' => 'MMMM', // Full month name, based on the locale January through December
|
||||
'%h' => 'MMM', // Abbreviated month name, based on the locale (an alias of %b) Jan through Dec
|
||||
];
|
||||
|
||||
$intl_formatter = function (DateTimeInterface $timestamp, string $format) use ($intl_formats, $locale) {
|
||||
$tz = $timestamp->getTimezone();
|
||||
$date_type = IntlDateFormatter::FULL;
|
||||
$time_type = IntlDateFormatter::FULL;
|
||||
$pattern = '';
|
||||
|
||||
switch ($format) {
|
||||
// %c = Preferred date and time stamp based on locale
|
||||
// Example: Tue Feb 5 00:45:10 2009 for February 5, 2009 at 12:45:10 AM
|
||||
case '%c':
|
||||
$date_type = IntlDateFormatter::LONG;
|
||||
$time_type = IntlDateFormatter::SHORT;
|
||||
break;
|
||||
|
||||
// %x = Preferred date representation based on locale, without the time
|
||||
// Example: 02/05/09 for February 5, 2009
|
||||
case '%x':
|
||||
$date_type = IntlDateFormatter::SHORT;
|
||||
$time_type = IntlDateFormatter::NONE;
|
||||
break;
|
||||
|
||||
// Localized time format
|
||||
case '%X':
|
||||
$date_type = IntlDateFormatter::NONE;
|
||||
$time_type = IntlDateFormatter::MEDIUM;
|
||||
break;
|
||||
|
||||
default:
|
||||
$pattern = $intl_formats[$format];
|
||||
}
|
||||
|
||||
// In October 1582, the Gregorian calendar replaced the Julian in much of Europe, and
|
||||
// the 4th October was followed by the 15th October.
|
||||
// ICU (including IntlDateFormattter) interprets and formats dates based on this cutover.
|
||||
// Posix (including PHP81_BC\PHP81_BC\strftime) and timelib (including DateTimeImmutable) instead use
|
||||
// a "proleptic Gregorian calendar" - they pretend the Gregorian calendar has existed forever.
|
||||
// This leads to the same instants in time, as expressed in Unix time, having different representations
|
||||
// in formatted strings.
|
||||
// To adjust for this, a custom calendar can be supplied with a cutover date arbitrarily far in the past.
|
||||
$calendar = IntlGregorianCalendar::createInstance();
|
||||
$calendar->setGregorianChange(PHP_INT_MIN);
|
||||
|
||||
return (new IntlDateFormatter($locale, $date_type, $time_type, $tz, $calendar, $pattern))->format($timestamp);
|
||||
};
|
||||
|
||||
// Same order as https://www.php.net/manual/en/function.PHP81_BC\PHP81_BC\strftime.php
|
||||
$translation_table = [
|
||||
// Day
|
||||
'%a' => $intl_formatter,
|
||||
'%A' => $intl_formatter,
|
||||
'%d' => 'd',
|
||||
'%e' => function ($timestamp) {
|
||||
return sprintf('% 2u', $timestamp->format('j'));
|
||||
},
|
||||
'%j' => function ($timestamp) {
|
||||
// Day number in year, 001 to 366
|
||||
return sprintf('%03d', $timestamp->format('z')+1);
|
||||
},
|
||||
'%u' => 'N',
|
||||
'%w' => 'w',
|
||||
|
||||
// Week
|
||||
'%U' => function ($timestamp) {
|
||||
// Number of weeks between date and first Sunday of year
|
||||
$day = new DateTime(sprintf('%d-01 Sunday', $timestamp->format('Y')));
|
||||
return sprintf('%02u', 1 + ($timestamp->format('z') - $day->format('z')) / 7);
|
||||
},
|
||||
'%V' => 'W',
|
||||
'%W' => function ($timestamp) {
|
||||
// Number of weeks between date and first Monday of year
|
||||
$day = new DateTime(sprintf('%d-01 Monday', $timestamp->format('Y')));
|
||||
return sprintf('%02u', 1 + ($timestamp->format('z') - $day->format('z')) / 7);
|
||||
},
|
||||
|
||||
// Month
|
||||
'%b' => $intl_formatter,
|
||||
'%B' => $intl_formatter,
|
||||
'%h' => $intl_formatter,
|
||||
'%m' => 'm',
|
||||
|
||||
// Year
|
||||
'%C' => function ($timestamp) {
|
||||
// Century (-1): 19 for 20th century
|
||||
return floor($timestamp->format('Y') / 100);
|
||||
},
|
||||
'%g' => function ($timestamp) {
|
||||
return substr($timestamp->format('o'), -2);
|
||||
},
|
||||
'%G' => 'o',
|
||||
'%y' => 'y',
|
||||
'%Y' => 'Y',
|
||||
|
||||
// Time
|
||||
'%H' => 'H',
|
||||
'%k' => function ($timestamp) {
|
||||
return sprintf('% 2u', $timestamp->format('G'));
|
||||
},
|
||||
'%I' => 'h',
|
||||
'%l' => function ($timestamp) {
|
||||
return sprintf('% 2u', $timestamp->format('g'));
|
||||
},
|
||||
'%M' => 'i',
|
||||
'%p' => 'A', // AM PM (this is reversed on purpose!)
|
||||
'%P' => 'a', // am pm
|
||||
'%r' => 'h:i:s A', // %I:%M:%S %p
|
||||
'%R' => 'H:i', // %H:%M
|
||||
'%S' => 's',
|
||||
'%T' => 'H:i:s', // %H:%M:%S
|
||||
'%X' => $intl_formatter, // Preferred time representation based on locale, without the date
|
||||
|
||||
// Timezone
|
||||
'%z' => 'O',
|
||||
'%Z' => 'T',
|
||||
|
||||
// Time and Date Stamps
|
||||
'%c' => $intl_formatter,
|
||||
'%D' => 'm/d/Y',
|
||||
'%F' => 'Y-m-d',
|
||||
'%s' => 'U',
|
||||
'%x' => $intl_formatter,
|
||||
];
|
||||
|
||||
$out = preg_replace_callback('/(?<!%)%([_#-]?)([a-zA-Z])/', function ($match) use ($translation_table, $timestamp) {
|
||||
$prefix = $match[1];
|
||||
$char = $match[2];
|
||||
$pattern = '%'.$char;
|
||||
if ($pattern == '%n') {
|
||||
return "\n";
|
||||
} elseif ($pattern == '%t') {
|
||||
return "\t";
|
||||
}
|
||||
|
||||
if (!isset($translation_table[$pattern])) {
|
||||
throw new InvalidArgumentException(sprintf('Format "%s" is unknown in time format', $pattern));
|
||||
}
|
||||
|
||||
$replace = $translation_table[$pattern];
|
||||
|
||||
if (is_string($replace)) {
|
||||
$result = $timestamp->format($replace);
|
||||
} else {
|
||||
$result = $replace($timestamp, $pattern);
|
||||
}
|
||||
|
||||
switch ($prefix) {
|
||||
case '_':
|
||||
// replace leading zeros with spaces but keep last char if also zero
|
||||
return preg_replace('/\G0(?=.)/', ' ', $result);
|
||||
case '#':
|
||||
case '-':
|
||||
// remove leading zeros but keep last char if also zero
|
||||
return preg_replace('/^0+(?=.)/', '', $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}, $format);
|
||||
|
||||
$out = str_replace('%%', '%', $out);
|
||||
return $out;
|
||||
}
|
966
core/class/template.class.php
Normal file
966
core/class/template.class.php
Normal file
@ -0,0 +1,966 @@
|
||||
<?php
|
||||
|
||||
class template
|
||||
{
|
||||
|
||||
/**
|
||||
* Crée un bouton
|
||||
* @param string $nameId Nom et id du champ
|
||||
* @param array $attributes Attributs ($key => $value)
|
||||
* @return string
|
||||
*/
|
||||
public static function button($nameId, array $attributes = [])
|
||||
{
|
||||
// Attributs par défaut
|
||||
$attributes = array_merge([
|
||||
'class' => '',
|
||||
'disabled' => false,
|
||||
'href' => 'javascript:void(0);',
|
||||
'ico' => '',
|
||||
'id' => $nameId,
|
||||
'name' => $nameId,
|
||||
'target' => '',
|
||||
'uniqueSubmission' => false,
|
||||
'value' => 'Bouton',
|
||||
'help' => ''
|
||||
], $attributes);
|
||||
// Traduction de l'aide et de l'étiquette
|
||||
$attributes['value'] = helper::translate($attributes['value']);
|
||||
$attributes['help'] = helper::translate($attributes['help']);
|
||||
// Retourne le html
|
||||
return sprintf(
|
||||
'<a %s class="button %s %s %s" %s>%s</a>',
|
||||
helper::sprintAttributes($attributes, ['class', 'disabled', 'ico', 'value']),
|
||||
$attributes['disabled'] ? 'disabled' : '',
|
||||
$attributes['class'],
|
||||
$attributes['uniqueSubmission'] ? 'uniqueSubmission' : '',
|
||||
$attributes['help'] ? ' title="' . $attributes['help'] . '" ' : '',
|
||||
($attributes['ico'] ? template::ico($attributes['ico'], ['margin' => 'right']) : '') . $attributes['value']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée un champ captcha
|
||||
* @param string $nameId Nom et id du champ
|
||||
* @param array $attributes Attributs ($key => $value)
|
||||
* @return string
|
||||
*/
|
||||
public static function captcha($nameId, array $attributes = [])
|
||||
{
|
||||
// Attributs par défaut
|
||||
$attributes = array_merge([
|
||||
'class' => '',
|
||||
'classWrapper' => '',
|
||||
'help' => '',
|
||||
'id' => $nameId,
|
||||
'name' => $nameId,
|
||||
'value' => '',
|
||||
'limit' => false, // captcha simple
|
||||
'type' => 'alpha' // num(érique) ou alpha(bétique)
|
||||
], $attributes);
|
||||
// Traduction de l'aide et de l'étiquette
|
||||
// $attributes['value'] = helper::translate($attributes['value']);
|
||||
$attributes['help'] = helper::translate($attributes['help']);
|
||||
// Captcha quatre opérations
|
||||
// Limite addition et soustraction selon le type de captcha
|
||||
$numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20];
|
||||
$letters = ['u', 't', 's', 'r', 'q', 'p', 'o', 'n', 'm', 'l', 'k', 'j', 'i', 'h', 'g', 'f', 'e', 'd', 'c', 'b', 'a'];
|
||||
$limit = $attributes['limit'] ? count($letters) - 1 : 10;
|
||||
|
||||
// Tirage de l'opération
|
||||
mt_srand();
|
||||
// Captcha simple limité à l'addition
|
||||
$operator = $attributes['limit'] ? mt_rand(1, 4) : 1;
|
||||
|
||||
// Limite si multiplication ou division
|
||||
if ($operator > 2) {
|
||||
$limit = 10;
|
||||
}
|
||||
|
||||
// Tirage des nombres
|
||||
mt_srand();
|
||||
$firstNumber = mt_rand(1, $limit);
|
||||
mt_srand();
|
||||
$secondNumber = mt_rand(1, $limit);
|
||||
|
||||
// Permutation si addition ou soustraction
|
||||
if (($operator < 3) and ($firstNumber < $secondNumber)) {
|
||||
$temp = $firstNumber;
|
||||
$firstNumber = $secondNumber;
|
||||
$secondNumber = $temp;
|
||||
}
|
||||
|
||||
// Icône de l'opérateur et calcul du résultat
|
||||
switch ($operator) {
|
||||
case 1:
|
||||
$operator = template::ico('plus');
|
||||
$result = $firstNumber + $secondNumber;
|
||||
break;
|
||||
case 2:
|
||||
$operator = template::ico('minus');
|
||||
$result = $firstNumber - $secondNumber;
|
||||
break;
|
||||
case 3:
|
||||
$operator = template::ico('cancel');
|
||||
$result = $firstNumber * $secondNumber;
|
||||
break;
|
||||
case 4:
|
||||
$operator = template::ico('divide');
|
||||
$limit2 = [10, 10, 6, 5, 4, 3, 2, 2, 2, 2];
|
||||
for ($i = 1; $i <= $firstNumber; $i++) {
|
||||
$limit = $limit2[$i - 1];
|
||||
}
|
||||
mt_srand();
|
||||
$secondNumber = mt_rand(1, $limit);
|
||||
$firstNumber = $firstNumber * $secondNumber;
|
||||
$result = $firstNumber / $secondNumber;
|
||||
break;
|
||||
}
|
||||
|
||||
// Hashage du résultat
|
||||
$result = password_hash($result, PASSWORD_BCRYPT);
|
||||
|
||||
// Codage des valeurs de l'opération
|
||||
$firstLetter = uniqid();
|
||||
$secondLetter = uniqid();
|
||||
|
||||
// Masquage image source pour éviter un décodage
|
||||
copy('core/vendor/zwiico/png/' . $attributes['type'] . '/' . $letters[$firstNumber] . '.png', 'site/tmp/' . $firstLetter . '.png');
|
||||
copy('core/vendor/zwiico/png/' . $attributes['type'] . '/' . $letters[$secondNumber] . '.png', 'site/tmp/' . $secondLetter . '.png');
|
||||
|
||||
|
||||
// Début du wrapper
|
||||
$html = '<div id="' . $attributes['id'] . 'Wrapper" class="captcha inputWrapper ' . $attributes['classWrapper'] . '">';
|
||||
// Label
|
||||
$html .= self::label(
|
||||
$attributes['id'],
|
||||
'<img class="captcha' . ucFirst($attributes['type']) . '" src="' . helper::baseUrl(false) . 'site/tmp/' . $firstLetter . '.png" /> <strong>' . $operator . '</strong> <img class="captcha' . ucFirst($attributes['type']) . '" src="' . helper::baseUrl(false) . 'site/tmp/' . $secondLetter . '.png" />' . template::ico('eq'),
|
||||
[
|
||||
'help' => $attributes['help']
|
||||
]
|
||||
);
|
||||
|
||||
// Notice
|
||||
$notice = '';
|
||||
if (array_key_exists($attributes['id'], common::$inputNotices)) {
|
||||
$notice = common::$inputNotices[$attributes['id']];
|
||||
$attributes['class'] .= ' notice';
|
||||
}
|
||||
$html .= self::notice($attributes['id'], $notice);
|
||||
|
||||
// captcha
|
||||
$html .= sprintf(
|
||||
'<input type="text" %s>',
|
||||
helper::sprintAttributes($attributes)
|
||||
);
|
||||
|
||||
// Champ résultat codé
|
||||
$html .= self::hidden($attributes['id'] . 'Result', [
|
||||
'value' => $result,
|
||||
'before' => false
|
||||
]);
|
||||
|
||||
// Fin du wrapper
|
||||
$html .= '</div>';
|
||||
|
||||
// Retourne le html
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée une case à cocher à sélection multiple
|
||||
* @param string $nameId Nom et id du champ
|
||||
* @param string $value Valeur de la case à cocher
|
||||
* @param string $label Label de la case à cocher
|
||||
* @param array $attributes Attributs ($key => $value)
|
||||
* @return string
|
||||
*/
|
||||
public static function checkbox($nameId, $value, $label, array $attributes = [])
|
||||
{
|
||||
// Attributs par défaut
|
||||
$attributes = array_merge([
|
||||
'before' => true,
|
||||
'checked' => '',
|
||||
'class' => '',
|
||||
'classWrapper' => '',
|
||||
'disabled' => false,
|
||||
'help' => '',
|
||||
'id' => $nameId,
|
||||
'name' => $nameId
|
||||
], $attributes);
|
||||
// Traduction de l'aide et de l'étiquette
|
||||
$label = helper::translate($label);
|
||||
$attributes['help'] = helper::translate($attributes['help']);
|
||||
// Sauvegarde des données en cas d'erreur
|
||||
if ($attributes['before'] and array_key_exists($attributes['id'], common::$inputBefore)) {
|
||||
$attributes['checked'] = (bool) common::$inputBefore[$attributes['id']];
|
||||
}
|
||||
// Début du wrapper
|
||||
$html = '<div id="' . $attributes['id'] . 'Wrapper" class="inputWrapper ' . $attributes['classWrapper'] . '">';
|
||||
// Notice
|
||||
$notice = '';
|
||||
if (array_key_exists($attributes['id'], common::$inputNotices)) {
|
||||
$notice = common::$inputNotices[$attributes['id']];
|
||||
$attributes['class'] .= ' notice';
|
||||
}
|
||||
$html .= self::notice($attributes['id'], $notice);
|
||||
// Case à cocher
|
||||
$html .= sprintf(
|
||||
'<input type="checkbox" value="%s" %s>',
|
||||
$value,
|
||||
helper::sprintAttributes($attributes)
|
||||
);
|
||||
// Label
|
||||
$html .= self::label($attributes['id'], '<span>' . $label . '</span>', [
|
||||
'help' => $attributes['help']
|
||||
]);
|
||||
// Fin du wrapper
|
||||
$html .= '</div>';
|
||||
// Retourne le html
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée un champ date
|
||||
* @param string $nameId Nom et id du champ
|
||||
* @param array $attributes Attributs ($key => $value)
|
||||
* @param string type date time datetime-local month week
|
||||
* @return string
|
||||
*/
|
||||
public static function date($nameId, array $attributes = [])
|
||||
{
|
||||
// Attributs par défaut
|
||||
$attributes = array_merge([
|
||||
'autocomplete' => 'on',
|
||||
'before' => true,
|
||||
'class' => '',
|
||||
'classWrapper' => '',
|
||||
'noDirty' => false,
|
||||
'disabled' => false,
|
||||
'help' => '',
|
||||
'id' => $nameId,
|
||||
'label' => '',
|
||||
'name' => $nameId,
|
||||
'placeholder' => '',
|
||||
'readonly' => false,
|
||||
'value' => '',
|
||||
'type'=> 'date',
|
||||
], $attributes);
|
||||
// Traduction de l'aide et de l'étiquette
|
||||
$attributes['label'] = helper::translate($attributes['label']);
|
||||
$attributes['help'] = helper::translate($attributes['help']);
|
||||
//$attributes['placeholder'] = helper::translate($attributes['placeholder']);
|
||||
// Sauvegarde des données en cas d'erreur
|
||||
if ($attributes['before'] and array_key_exists($attributes['id'], common::$inputBefore)) {
|
||||
$attributes['value'] = common::$inputBefore[$attributes['id']];
|
||||
} else {
|
||||
$attributes['value'] = ($attributes['value'] ? helper::filter($attributes['value'], helper::FILTER_TIMESTAMP) : '');
|
||||
}
|
||||
// Début du wrapper
|
||||
$html = '<div id="' . $attributes['id'] . 'Wrapper" class="inputWrapper ' . $attributes['classWrapper'] . '">';
|
||||
// Label
|
||||
if ($attributes['label']) {
|
||||
$html .= self::label($attributes['id'], $attributes['label'], [
|
||||
'help' => $attributes['help']
|
||||
]);
|
||||
}
|
||||
// Notice
|
||||
$notice = '';
|
||||
if (array_key_exists($attributes['id'], common::$inputNotices)) {
|
||||
$notice = common::$inputNotices[$attributes['id']];
|
||||
$attributes['class'] .= ' notice';
|
||||
}
|
||||
$html .= self::notice($attributes['id'], $notice);
|
||||
// Date visible
|
||||
$html .= '<div class="inputDateManagerWrapper">';
|
||||
$html .= sprintf(
|
||||
'<input type="' . $attributes['type'] . '" class="datepicker %s" value="%s" %s>',
|
||||
$attributes['class'],
|
||||
$attributes['value'],
|
||||
helper::sprintAttributes($attributes, ['class', 'value'])
|
||||
);
|
||||
$html .= '</div>';
|
||||
// Fin du wrapper
|
||||
$html .= '</div>';
|
||||
// Retourne le html
|
||||
return $html;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Crée un champ d'upload de fichier
|
||||
* @param string $nameId Nom et id du champ
|
||||
* @param array $attributes Attributs ($key => $value)
|
||||
* @return string
|
||||
*/
|
||||
public static function file($nameId, array $attributes = [])
|
||||
{
|
||||
// Attributs par défaut
|
||||
$attributes = array_merge([
|
||||
'before' => true,
|
||||
'class' => '',
|
||||
'classWrapper' => '',
|
||||
'noDirty' => false,
|
||||
'disabled' => false,
|
||||
'extensions' => '',
|
||||
'help' => '',
|
||||
'id' => $nameId,
|
||||
'label' => '',
|
||||
'maxlength' => '500',
|
||||
'name' => $nameId,
|
||||
'type' => 2,
|
||||
'value' => '',
|
||||
'language' => 'fr_FR'
|
||||
], $attributes);
|
||||
// Traduction de l'aide et de l'étiquette
|
||||
$attributes['value'] = helper::translate($attributes['value']);
|
||||
$attributes['help'] = helper::translate($attributes['help']);
|
||||
// Sauvegarde des données en cas d'erreur
|
||||
if ($attributes['before'] and array_key_exists($attributes['id'], common::$inputBefore)) {
|
||||
$attributes['value'] = common::$inputBefore[$attributes['id']];
|
||||
}
|
||||
// Début du wrapper
|
||||
$html = '<div id="' . $attributes['id'] . 'Wrapper" class="inputWrapper ' . $attributes['classWrapper'] . '">';
|
||||
// Notice
|
||||
$notice = '';
|
||||
if (array_key_exists($attributes['id'], common::$inputNotices)) {
|
||||
$notice = common::$inputNotices[$attributes['id']];
|
||||
$attributes['class'] .= ' notice';
|
||||
}
|
||||
$html .= self::notice($attributes['id'], $notice);
|
||||
// Label
|
||||
if ($attributes['label']) {
|
||||
$html .= self::label($attributes['id'], $attributes['label'], [
|
||||
'help' => $attributes['help']
|
||||
]);
|
||||
}
|
||||
// Champ caché contenant l'url de la page
|
||||
$html .= self::hidden($attributes['id'], [
|
||||
'class' => 'inputFileHidden',
|
||||
'disabled' => $attributes['disabled'],
|
||||
'maxlength' => $attributes['maxlength'],
|
||||
'value' => $attributes['value']
|
||||
]);
|
||||
// Champ d'upload
|
||||
$html .= '<div class="inputFileManagerWrapper">';
|
||||
$html .= sprintf(
|
||||
'<a
|
||||
href="' .
|
||||
helper::baseUrl(false) . 'core/vendor/filemanager/dialog.php' .
|
||||
'?relative_url=1' .
|
||||
'&lang=' . $attributes['language'] .
|
||||
'&field_id=' . $attributes['id'] .
|
||||
'&type=' . $attributes['type'] .
|
||||
'&akey=' . md5_file(core::DATA_DIR . 'core.json') .
|
||||
($attributes['extensions'] ? '&extensions=' . $attributes['extensions'] : '')
|
||||
. '"
|
||||
class="inputFile %s %s"
|
||||
%s
|
||||
data-lity
|
||||
>
|
||||
' . self::ico('upload', ['margin' => 'right']) . '
|
||||
<span class="inputFileLabel"></span>
|
||||
</a>',
|
||||
$attributes['class'],
|
||||
$attributes['disabled'] ? 'disabled' : '',
|
||||
helper::sprintAttributes($attributes, ['class', 'extensions', 'type', 'maxlength'])
|
||||
|
||||
);
|
||||
$html .= self::button($attributes['id'] . 'Delete', [
|
||||
'class' => 'inputFileDelete',
|
||||
'value' => self::ico('cancel')
|
||||
]);
|
||||
$html .= '</div>';
|
||||
// Fin du wrapper
|
||||
$html .= '</div>';
|
||||
// Retourne le html
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ferme un formulaire
|
||||
* @return string
|
||||
*/
|
||||
public static function formClose()
|
||||
{
|
||||
return '</form>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Ouvre un formulaire protégé par CSRF
|
||||
* @param string $id Id du formulaire
|
||||
* @return string
|
||||
*/
|
||||
public static function formOpen($id)
|
||||
{
|
||||
// Ouverture formulaire
|
||||
$html = '<form id="' . $id . '" method="post">';
|
||||
// Stock le token CSRF
|
||||
$html .= self::hidden('csrf', [
|
||||
'value' => htmlentities($_SESSION['csrf'], ENT_QUOTES | ENT_HTML5, 'UTF-8')
|
||||
]);
|
||||
// Retourne le html
|
||||
return $html;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Crée une aide qui s'affiche au survole
|
||||
* @param string $text Texte de l'aide
|
||||
* @return string
|
||||
*/
|
||||
public static function help($text)
|
||||
{
|
||||
return '<span class="helpButton" data-tippy-content="' . $text . '">' . self::ico('help') . '<!----></span>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée un champ caché
|
||||
* @param string $nameId Nom et id du champ
|
||||
* @param array $attributes Attributs ($key => $value)
|
||||
* @return string
|
||||
*/
|
||||
public static function hidden($nameId, array $attributes = [])
|
||||
{
|
||||
// Attributs par défaut
|
||||
$attributes = array_merge([
|
||||
'before' => true,
|
||||
'class' => '',
|
||||
'noDirty' => false,
|
||||
'id' => $nameId,
|
||||
//'maxlength' => '500',
|
||||
'name' => $nameId,
|
||||
'value' => ''
|
||||
], $attributes);
|
||||
// Sauvegarde des données en cas d'erreur
|
||||
if ($attributes['before'] and array_key_exists($attributes['id'], common::$inputBefore)) {
|
||||
$attributes['value'] = common::$inputBefore[$attributes['id']];
|
||||
}
|
||||
// Texte
|
||||
$html = sprintf('<input type="hidden" %s>', helper::sprintAttributes($attributes, ['before']));
|
||||
// Retourne le html
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée un icône
|
||||
* @Array :
|
||||
* @param string $ico Classe de l'icône
|
||||
* @param string $margin Ajoute un margin autour de l'icône (choix : left, right, all)
|
||||
* @param bool $animate Ajoute une animation à l'icône
|
||||
* @param string $fontSize Taille de la police
|
||||
* @param string $href lien vers une url
|
||||
* @param string $help popup d'aide
|
||||
* @param string $id de l'élement
|
||||
* @return string
|
||||
*/
|
||||
// public static function ico($ico, $margin = '', $animate = false, $fontSize = '1em') {
|
||||
public static function ico($ico, array $attributes = [])
|
||||
{
|
||||
// Attributs par défaut
|
||||
$attributes = array_merge([
|
||||
'margin' => '',
|
||||
'animate' => false,
|
||||
'fontSize' => '1em',
|
||||
'href' => '',
|
||||
'attr' => '',
|
||||
'help' => '',
|
||||
'id' => '',
|
||||
], $attributes);
|
||||
// Traduction de l'aide
|
||||
$attributes['help'] = helper::translate($attributes['help']);
|
||||
// Contenu de l'icône
|
||||
$alt = $attributes['help'] ? $attributes['help'] : $ico;
|
||||
$item = $attributes['href'] ? '<a id="' . $attributes['id'] . '" data-tippy-content="' . $attributes['help'] . '" alt="' . $alt . '" href="' . $attributes['href'] . '" ' . $attributes['attr'] . ' >' : '';
|
||||
$item .= '<span class="zwiico-' . $ico . ($attributes['margin'] ? ' zwiico-margin-' . $attributes['margin'] : '') . ($attributes['animate'] ? ' animate-spin' : '') . '" style="font-size:' . $attributes['fontSize'] . '"><!----></span>';
|
||||
$item .= ($attributes['href']) ? '</a>' : '';
|
||||
return $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée un drapeau du site courante
|
||||
* @param string $langId Id de la langue à affiche ou selected pour la langue courante
|
||||
* @param string size en pixels ou en rem
|
||||
* @return string
|
||||
*/
|
||||
public static function flag($langId, $size = 'auto')
|
||||
{
|
||||
$lang = 'fr_FR';
|
||||
switch ($langId) {
|
||||
case '':
|
||||
break;
|
||||
case array_key_exists($langId, core::$languages):
|
||||
$lang = $langId;
|
||||
break;
|
||||
case 'selected':
|
||||
if (isset($_SESSION['ZWII_CONTENT'])) {
|
||||
$lang = $_SESSION['ZWII_CONTENT'];
|
||||
} else {
|
||||
$lang = 'fr_FR';
|
||||
}
|
||||
}
|
||||
return '<img class="flag" src="' . helper::baseUrl(false) . 'core/vendor/i18n/png/' . $lang . '.png"
|
||||
width="' . $size . '"
|
||||
height="' . $size . '"
|
||||
title="' . $lang . '"
|
||||
alt="(' . $lang . ')"/>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée un label
|
||||
* @param string $for For du label
|
||||
* @param array $attributes Attributs ($key => $value)
|
||||
* @param string $text Texte du label
|
||||
* @return string
|
||||
*/
|
||||
public static function label($for, $text, array $attributes = [])
|
||||
{
|
||||
// Attributs par défaut
|
||||
$attributes = array_merge([
|
||||
'class' => '',
|
||||
'for' => $for,
|
||||
'help' => ''
|
||||
], $attributes);
|
||||
// Traduction de l'aide et de l'étiquette
|
||||
$text = helper::translate($text);
|
||||
$attributes['help'] = helper::translate($attributes['help']);
|
||||
|
||||
if (
|
||||
get_called_class() !== 'template'
|
||||
) {
|
||||
$attributes['help'] = helper::translate($attributes['help']);
|
||||
}
|
||||
if ($attributes['help'] !== '') {
|
||||
$text = $text . self::help($attributes['help']);
|
||||
}
|
||||
// Retourne le html
|
||||
return sprintf(
|
||||
'<label %s>%s</label>',
|
||||
helper::sprintAttributes($attributes),
|
||||
$text
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée un champ mail
|
||||
* @param string $nameId Nom et id du champ
|
||||
* @param array $attributes Attributs ($key => $value)
|
||||
* @return string
|
||||
*/
|
||||
public static function mail($nameId, array $attributes = [])
|
||||
{
|
||||
// Attributs par défaut
|
||||
$attributes = array_merge([
|
||||
'autocomplete' => 'on',
|
||||
'before' => true,
|
||||
'class' => '',
|
||||
'classWrapper' => '',
|
||||
'noDirty' => false,
|
||||
'disabled' => false,
|
||||
'help' => '',
|
||||
'id' => $nameId,
|
||||
'label' => '',
|
||||
//'maxlength' => '500',
|
||||
'name' => $nameId,
|
||||
'placeholder' => '',
|
||||
'readonly' => false,
|
||||
'value' => ''
|
||||
], $attributes);
|
||||
// Traduction de l'aide et de l'étiquette
|
||||
$attributes['label'] = helper::translate($attributes['label']);
|
||||
$attributes['help'] = helper::translate($attributes['help']);
|
||||
//$attributes['placeholder'] = helper::translate($attributes['placeholder']);
|
||||
// Sauvegarde des données en cas d'erreur
|
||||
if ($attributes['before'] and array_key_exists($attributes['id'], common::$inputBefore)) {
|
||||
$attributes['value'] = common::$inputBefore[$attributes['id']];
|
||||
}
|
||||
// Début du wrapper
|
||||
$html = '<div id="' . $attributes['id'] . 'Wrapper" class="inputWrapper ' . $attributes['classWrapper'] . '">';
|
||||
// Label
|
||||
if ($attributes['label']) {
|
||||
$html .= self::label($attributes['id'], $attributes['label'], [
|
||||
'help' => $attributes['help']
|
||||
]);
|
||||
}
|
||||
// Notice
|
||||
$notice = '';
|
||||
if (array_key_exists($attributes['id'], common::$inputNotices)) {
|
||||
$notice = common::$inputNotices[$attributes['id']];
|
||||
$attributes['class'] .= ' notice';
|
||||
}
|
||||
$html .= self::notice($attributes['id'], $notice);
|
||||
// Texte
|
||||
$html .= sprintf(
|
||||
'<input type="email" %s>',
|
||||
helper::sprintAttributes($attributes)
|
||||
);
|
||||
// Fin du wrapper
|
||||
$html .= '</div>';
|
||||
// Retourne le html
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée une notice
|
||||
* @param string $id Id du champ
|
||||
* @param string $notice Notice
|
||||
* @return string
|
||||
*/
|
||||
public static function notice($id, $notice)
|
||||
{
|
||||
return ' <span id="' . $id . 'Notice" class="notice ' . ($notice ? '' : 'displayNone') . '">' . $notice . '</span>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée un champ mot de passe
|
||||
* @param string $nameId Nom et id du champ
|
||||
* @param array $attributes Attributs ($key => $value)
|
||||
* @return string
|
||||
*/
|
||||
public static function password($nameId, array $attributes = [])
|
||||
{
|
||||
// Attributs par défaut
|
||||
$attributes = array_merge([
|
||||
'autocomplete' => 'on',
|
||||
'class' => '',
|
||||
'classWrapper' => '',
|
||||
'noDirty' => false,
|
||||
'disabled' => false,
|
||||
'help' => '',
|
||||
'id' => $nameId,
|
||||
'label' => '',
|
||||
//'maxlength' => '500',
|
||||
'name' => $nameId,
|
||||
'placeholder' => '',
|
||||
'readonly' => false
|
||||
], $attributes);
|
||||
// Traduction de l'aide et de l'étiquette
|
||||
$attributes['label'] = helper::translate($attributes['label']);
|
||||
//$attributes['placeholder'] = helper::translate($attributes['placeholder']);
|
||||
$attributes['help'] = helper::translate($attributes['help']);
|
||||
// Début du wrapper
|
||||
$html = '<div id="' . $attributes['id'] . 'Wrapper" class="inputWrapper ' . $attributes['classWrapper'] . '">';
|
||||
// Label
|
||||
if ($attributes['label']) {
|
||||
$html .= self::label($attributes['id'], $attributes['label'], [
|
||||
'help' => $attributes['help']
|
||||
]);
|
||||
}
|
||||
// Notice
|
||||
$notice = '';
|
||||
if (array_key_exists($attributes['id'], common::$inputNotices)) {
|
||||
$notice = common::$inputNotices[$attributes['id']];
|
||||
$attributes['class'] .= ' notice';
|
||||
}
|
||||
$html .= self::notice($attributes['id'], $notice);
|
||||
// Mot de passe
|
||||
$html .= sprintf(
|
||||
'<input type="password" %s>',
|
||||
helper::sprintAttributes($attributes)
|
||||
);
|
||||
// Fin du wrapper
|
||||
$html .= '</div>';
|
||||
// Retourne le html
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée un champ sélection
|
||||
* @param string $nameId Nom et id du champ
|
||||
* @param array $options Liste des options du champ de sélection ($value => $text)
|
||||
* @param array $attributes Attributs ($key => $value)
|
||||
* @return string
|
||||
*/
|
||||
public static function select($nameId, array $options, array $attributes = [])
|
||||
{
|
||||
// Attributs par défaut
|
||||
$attributes = array_merge([
|
||||
'before' => true,
|
||||
'class' => '',
|
||||
'classWrapper' => '',
|
||||
'noDirty' => false,
|
||||
'disabled' => false,
|
||||
'help' => '',
|
||||
'id' => $nameId,
|
||||
'label' => '',
|
||||
'name' => $nameId,
|
||||
'selected' => '',
|
||||
'font' => []
|
||||
], $attributes);
|
||||
// Traduction de l'aide et de l'étiquette
|
||||
$attributes['label'] = helper::translate($attributes['label']);
|
||||
$attributes['help'] = helper::translate($attributes['help']);
|
||||
// Stocker les fontes et remettre à zéro le tableau des fontes transmis pour éviter une erreur de sprintAttributes
|
||||
if (empty($attributes['font']) === false) {
|
||||
$fonts = $attributes['font'];
|
||||
$attributes['font'] = [];
|
||||
}
|
||||
// Sauvegarde des données en cas d'erreur
|
||||
if ($attributes['before'] and array_key_exists($attributes['id'], common::$inputBefore)) {
|
||||
$attributes['selected'] = common::$inputBefore[$attributes['id']];
|
||||
}
|
||||
// Début du wrapper
|
||||
$html = '<div id="' . $attributes['id'] . 'Wrapper" class="inputWrapper ' . $attributes['classWrapper'] . '">';
|
||||
// Label
|
||||
if ($attributes['label']) {
|
||||
$html .= self::label($attributes['id'], $attributes['label'], [
|
||||
'help' => $attributes['help']
|
||||
]);
|
||||
}
|
||||
// Notice
|
||||
$notice = '';
|
||||
if (array_key_exists($attributes['id'], common::$inputNotices)) {
|
||||
$notice = common::$inputNotices[$attributes['id']];
|
||||
$attributes['class'] .= ' notice';
|
||||
}
|
||||
$html .= self::notice($attributes['id'], $notice);
|
||||
// Début sélection
|
||||
$html .= sprintf(
|
||||
'<select %s>',
|
||||
helper::sprintAttributes($attributes)
|
||||
);
|
||||
foreach ($options as $value => $text) {
|
||||
// Select des liste de fontes
|
||||
$html .= isset($fonts) ? sprintf(
|
||||
'<option value="%s"%s style="font-family: %s;">%s</option>',
|
||||
$value,
|
||||
$attributes['selected'] == $value ? ' selected' : '', // Double == pour ignorer le type de variable car $_POST change les types en string
|
||||
$fonts[$value],
|
||||
$text
|
||||
// Select standard
|
||||
) : sprintf(
|
||||
'<option value="%s"%s>%s</option>',
|
||||
$value,
|
||||
$attributes['selected'] == $value ? ' selected' : '', // Double == pour ignorer le type de variable car $_POST change les types en string
|
||||
helper::translate($text)
|
||||
);
|
||||
}
|
||||
// Fin sélection
|
||||
$html .= '</select>';
|
||||
// Fin du wrapper
|
||||
$html .= '</div>';
|
||||
// Retourne le html
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée une bulle de dialogue
|
||||
* @param string $text Texte de la bulle
|
||||
* @return string
|
||||
*/
|
||||
public static function speech($text)
|
||||
{
|
||||
return '<div class="speech"><div class="speechBubble">' . helper::translate($text) . '</div>' . template::ico('mimi speechMimi', ['fontSize' => '7em']) . '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée un bouton validation
|
||||
* @param string $nameId Nom & id du bouton validation
|
||||
* @param array $attributes Attributs ($key => $value)
|
||||
* @return string
|
||||
*/
|
||||
public static function submit($nameId, array $attributes = [])
|
||||
{
|
||||
// Attributs par défaut
|
||||
$attributes = array_merge([
|
||||
'class' => '',
|
||||
'disabled' => false,
|
||||
'ico' => 'check',
|
||||
'id' => $nameId,
|
||||
'name' => $nameId,
|
||||
'uniqueSubmission' => false, //true avant 9.1.08
|
||||
'value' => 'Enregistrer'
|
||||
], $attributes);
|
||||
// Traduction de l'aide et de l'étiquette
|
||||
$attributes['value'] = helper::translate($attributes['value']);
|
||||
// Retourne le html
|
||||
return sprintf(
|
||||
'<button type="submit" class="%s%s" %s>%s</button>',
|
||||
$attributes['class'],
|
||||
$attributes['uniqueSubmission'] ? 'uniqueSubmission' : '',
|
||||
helper::sprintAttributes($attributes, ['class', 'ico', 'value']),
|
||||
($attributes['ico'] ? template::ico($attributes['ico'], ['margin' => 'right']) : '') . $attributes['value']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée un tableau
|
||||
* @param array $cols Cols des colonnes (format: [col colonne1, col colonne2, etc])
|
||||
* @param array $body Contenu (format: [[contenu1, contenu2, etc], [contenu1, contenu2, etc]])
|
||||
* @param array $head Entêtes (format : [[titre colonne1, titre colonne2, etc])
|
||||
* @param array $rowsId Id pour la numérotation des rows (format : [id colonne1, id colonne2, etc])
|
||||
* @param array $attributes Attributs ($key => $value)
|
||||
* @return string
|
||||
*/
|
||||
public static function table(array $cols = [], array $body = [], array $head = [], array $attributes = [], array $rowsId = [])
|
||||
{
|
||||
// Attributs par défaut
|
||||
$attributes = array_merge([
|
||||
'class' => '',
|
||||
'classWrapper' => '',
|
||||
'id' => ''
|
||||
], $attributes);
|
||||
// Traduction de l'aide et de l'étiquette
|
||||
foreach ($head as $value) {
|
||||
$head[array_search($value, $head)] = helper::translate($value);
|
||||
}
|
||||
// Début du wrapper
|
||||
$html = '<div id="' . $attributes['id'] . 'Wrapper" class="tableWrapper ' . $attributes['classWrapper'] . '">';
|
||||
// Début tableau
|
||||
$html .= '<table id="' . $attributes['id'] . '" class="table ' . $attributes['class'] . '">';
|
||||
// Entêtes
|
||||
if ($head) {
|
||||
// Début des entêtes
|
||||
$html .= '<thead>';
|
||||
$html .= '<tr class="nodrag">';
|
||||
$i = 0;
|
||||
foreach ($head as $th) {
|
||||
$html .= '<th class="col' . $cols[$i++] . '">' . $th . '</th>';
|
||||
}
|
||||
// Fin des entêtes
|
||||
$html .= '</tr>';
|
||||
$html .= '</thead>';
|
||||
}
|
||||
// Pas de tableau d'Id transmis, générer une numérotation
|
||||
if (empty($rowsId)) {
|
||||
$rowsId = range(0, count($body));
|
||||
}
|
||||
// Début contenu
|
||||
$j = 0;
|
||||
foreach ($body as $tr) {
|
||||
// Id de ligne pour les tableaux drag and drop
|
||||
$html .= '<tr id="' . $rowsId[$j++] . '">';
|
||||
$i = 0;
|
||||
foreach ($tr as $td) {
|
||||
$html .= '<td class="col' . $cols[$i++] . '">' . $td . '</td>';
|
||||
}
|
||||
$html .= '</tr>';
|
||||
}
|
||||
// Fin contenu
|
||||
$html .= '</tbody>';
|
||||
// Fin tableau
|
||||
$html .= '</table>';
|
||||
// Fin container
|
||||
$html .= '</div>';
|
||||
// Retourne le html
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée un champ texte court
|
||||
* @param string $nameId Nom et id du champ
|
||||
* @param array $attributes Attributs ($key => $value)
|
||||
* @return string
|
||||
*/
|
||||
public static function text($nameId, array $attributes = [])
|
||||
{
|
||||
// Attributs par défaut
|
||||
$attributes = array_merge([
|
||||
'autocomplete' => 'on',
|
||||
'before' => true,
|
||||
'class' => '',
|
||||
'classWrapper' => '',
|
||||
'noDirty' => false,
|
||||
'disabled' => false,
|
||||
'help' => '',
|
||||
'id' => $nameId,
|
||||
'label' => '',
|
||||
//'maxlength' => '500',
|
||||
'name' => $nameId,
|
||||
'placeholder' => '',
|
||||
'readonly' => false,
|
||||
'value' => '',
|
||||
'type' => 'text'
|
||||
], $attributes);
|
||||
// Traduction de l'aide et de l'étiquette
|
||||
$attributes['label'] = helper::translate($attributes['label']);
|
||||
$attributes['help'] = helper::translate($attributes['help']);
|
||||
//$attributes['placeholder'] = helper::translate($attributes['placeholder']);
|
||||
// Sauvegarde des données en cas d'erreur
|
||||
if ($attributes['before'] and array_key_exists($attributes['id'], common::$inputBefore)) {
|
||||
$attributes['value'] = common::$inputBefore[$attributes['id']];
|
||||
}
|
||||
// Début du wrapper
|
||||
$html = '<div id="' . $attributes['id'] . 'Wrapper" class="inputWrapper ' . $attributes['classWrapper'] . '">';
|
||||
// Label
|
||||
if ($attributes['label']) {
|
||||
$html .= self::label($attributes['id'], $attributes['label'], [
|
||||
'help' => $attributes['help']
|
||||
]);
|
||||
}
|
||||
// Notice
|
||||
$notice = '';
|
||||
if (array_key_exists($attributes['id'], common::$inputNotices)) {
|
||||
$notice = common::$inputNotices[$attributes['id']];
|
||||
$attributes['class'] .= ' notice';
|
||||
}
|
||||
$html .= self::notice($attributes['id'], $notice);
|
||||
// Texte
|
||||
$html .= sprintf(
|
||||
'<input type="' . $attributes['type']. '" %s>',
|
||||
helper::sprintAttributes($attributes)
|
||||
);
|
||||
// Fin du wrapper
|
||||
$html .= '</div>';
|
||||
// Retourne le html
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée un champ texte long
|
||||
* @param string $nameId Nom et id du champ
|
||||
* @param array $attributes Attributs ($key => $value)
|
||||
* @return string
|
||||
*/
|
||||
public static function textarea($nameId, array $attributes = [])
|
||||
{
|
||||
// Attributs par défaut
|
||||
$attributes = array_merge([
|
||||
'before' => true,
|
||||
'class' => '', // editorWysiwyg et editor possible pour utiliser un éditeur (il faut également instancier les librairies)
|
||||
'classWrapper' => '',
|
||||
'disabled' => false,
|
||||
'noDirty' => false,
|
||||
'help' => '',
|
||||
'id' => $nameId,
|
||||
'label' => '',
|
||||
//'maxlength' => '500',
|
||||
'name' => $nameId,
|
||||
'readonly' => false,
|
||||
'value' => ''
|
||||
], $attributes);
|
||||
// Traduction de l'aide et de l'étiquette
|
||||
$attributes['label'] = helper::translate($attributes['label']);
|
||||
$attributes['help'] = helper::translate($attributes['help']);
|
||||
// Sauvegarde des données en cas d'erreur
|
||||
if ($attributes['before'] and array_key_exists($attributes['id'], common::$inputBefore)) {
|
||||
$attributes['value'] = common::$inputBefore[$attributes['id']];
|
||||
}
|
||||
// Début du wrapper
|
||||
$html = '<div id="' . $attributes['id'] . 'Wrapper" class="inputWrapper ' . $attributes['classWrapper'] . '">';
|
||||
// Label
|
||||
if ($attributes['label']) {
|
||||
$html .= self::label($attributes['id'], $attributes['label'], [
|
||||
'help' => $attributes['help']
|
||||
]);
|
||||
}
|
||||
// Notice
|
||||
$notice = '';
|
||||
if (array_key_exists($attributes['id'], common::$inputNotices)) {
|
||||
$notice = common::$inputNotices[$attributes['id']];
|
||||
$attributes['class'] .= ' notice';
|
||||
}
|
||||
$html .= self::notice($attributes['id'], $notice);
|
||||
// Texte long
|
||||
$html .= sprintf(
|
||||
'<textarea %s>%s</textarea>',
|
||||
helper::sprintAttributes($attributes, ['value']),
|
||||
$attributes['value']
|
||||
);
|
||||
// Fin du wrapper
|
||||
$html .= '</div>';
|
||||
// Retourne le html
|
||||
return $html;
|
||||
}
|
||||
}
|
552
core/core.js.php
Normal file
552
core/core.js.php
Normal file
@ -0,0 +1,552 @@
|
||||
/**
|
||||
* 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
|
||||
* @author Frédéric Tempez <frederic.tempez@outlook.com>
|
||||
* @copyright Copyright (C) 2018-2023, Frédéric Tempez
|
||||
* @license CC Attribution-NonCommercial-NoDerivatives 4.0 International
|
||||
* @link http://zwiicms.fr/
|
||||
*/
|
||||
|
||||
var core = {};
|
||||
|
||||
/**
|
||||
* Crée un message d'alerte
|
||||
*/
|
||||
core.alert = function (text) {
|
||||
var lightbox = lity(function ($) {
|
||||
return $("<div>")
|
||||
.addClass("lightbox")
|
||||
.append(
|
||||
$("<span>").text(text),
|
||||
$("<div>")
|
||||
.addClass("lightboxButtons")
|
||||
.append(
|
||||
$("<a>")
|
||||
.addClass("button")
|
||||
.text("Ok")
|
||||
.on("click", function () {
|
||||
lightbox.close();
|
||||
})
|
||||
)
|
||||
)
|
||||
}(jQuery));
|
||||
// Validation de la lightbox avec le bouton entrée
|
||||
$(document).on("keyup", function (event) {
|
||||
if (event.keyCode === 13) {
|
||||
lightbox.close();
|
||||
}
|
||||
});
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Génère des variations d'une couleur
|
||||
*/
|
||||
core.colorVariants = function (rgba) {
|
||||
rgba = rgba.match(/\(+(.*)\)/);
|
||||
rgba = rgba[1].split(", ");
|
||||
return {
|
||||
"normal": "rgba(" + rgba[0] + "," + rgba[1] + "," + rgba[2] + "," + rgba[3] + ")",
|
||||
"darken": "rgba(" + Math.max(0, rgba[0] - 15) + "," + Math.max(0, rgba[1] - 15) + "," + Math.max(0, rgba[2] - 15) + "," + rgba[3] + ")",
|
||||
"veryDarken": "rgba(" + Math.max(0, rgba[0] - 20) + "," + Math.max(0, rgba[1] - 20) + "," + Math.max(0, rgba[2] - 20) + "," + rgba[3] + ")",
|
||||
"text": core.relativeLuminanceW3C(rgba) > .22 ? "#222" : "#DDD"
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Crée un message de confirmation
|
||||
*/
|
||||
core.confirm = function (text, yesCallback, noCallback) {
|
||||
var lightbox = lity(function ($) {
|
||||
return $("<div>")
|
||||
.addClass("lightbox")
|
||||
.append(
|
||||
$("<span>").text(text),
|
||||
$("<div>")
|
||||
.addClass("lightboxButtons")
|
||||
.append(
|
||||
$("<a>")
|
||||
.addClass("button grey")
|
||||
.text("<?php echo helper::translate('Non');?>")
|
||||
.on("click", function () {
|
||||
lightbox.options('button', true);
|
||||
lightbox.close();
|
||||
if (typeof noCallback !== "undefined") {
|
||||
noCallback();
|
||||
}
|
||||
}),
|
||||
$("<a>")
|
||||
.addClass("button")
|
||||
.text("<?php echo helper::translate('Oui');?>")
|
||||
.on("click", function () {
|
||||
lightbox.options('button', true);
|
||||
lightbox.close();
|
||||
if (typeof yesCallback !== "undefined") {
|
||||
yesCallback();
|
||||
}
|
||||
})
|
||||
)
|
||||
)
|
||||
}(jQuery));
|
||||
// Callback lors d'un clic sur le fond et sur la croix de fermeture
|
||||
lightbox.options('button', false);
|
||||
$(document).on('lity:close', function (event, instance) {
|
||||
if (
|
||||
instance.options('button') === false &&
|
||||
typeof noCallback !== "undefined"
|
||||
) {
|
||||
noCallback();
|
||||
}
|
||||
});
|
||||
// Validation de la lightbox avec le bouton entrée
|
||||
$(document).on("keyup", function (event) {
|
||||
if (event.keyCode === 13) {
|
||||
lightbox.close();
|
||||
if (typeof yesCallback !== "undefined") {
|
||||
yesCallback();
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Scripts à exécuter en dernier
|
||||
*/
|
||||
core.end = function () {
|
||||
/**
|
||||
* Modifications non enregistrées du formulaire
|
||||
*/
|
||||
var formDOM = $("form");
|
||||
// Ignore :
|
||||
// - TinyMCE car il gère lui même le message
|
||||
// - Les champs avec data-no-dirty
|
||||
var inputsDOM = formDOM.find("input:not([data-no-dirty]), select:not([data-no-dirty]), textarea:not(.editorWysiwyg):not([data-no-dirty])");
|
||||
var inputSerialize = inputsDOM.serialize();
|
||||
$(window).on("beforeunload", function () {
|
||||
if (inputsDOM.serialize() !== inputSerialize) {
|
||||
message = "<?php echo helper::translate('Les modifications que vous avez apportées ne seront peut-être pas enregistrées.');?>";
|
||||
return message;
|
||||
}
|
||||
});
|
||||
formDOM.submit(function () {
|
||||
$(window).off("beforeunload");
|
||||
});
|
||||
};
|
||||
$(function () {
|
||||
core.end();
|
||||
});
|
||||
|
||||
/**
|
||||
* Ajoute une notice
|
||||
*/
|
||||
core.noticeAdd = function (id, notice) {
|
||||
$("#" + id + "Notice").text(notice).removeClass("displayNone");
|
||||
$("#" + id).addClass("notice");
|
||||
};
|
||||
|
||||
/**
|
||||
* Supprime une notice
|
||||
*/
|
||||
core.noticeRemove = function (id) {
|
||||
$("#" + id + "Notice").text("").addClass("displayNone");
|
||||
$("#" + id).removeClass("notice");
|
||||
};
|
||||
|
||||
/**
|
||||
* Scripts à exécuter en premier
|
||||
*/
|
||||
core.start = function () {
|
||||
/**
|
||||
* Remonter en haut au clic sur le bouton
|
||||
*/
|
||||
var backToTopDOM = $("#backToTop");
|
||||
backToTopDOM.on("click", function () {
|
||||
$("body, html").animate({
|
||||
scrollTop: 0
|
||||
}, "400");
|
||||
});
|
||||
/**
|
||||
* Affiche / Cache le bouton pour remonter en haut
|
||||
*/
|
||||
$(window).on("scroll", function () {
|
||||
if ($(this).scrollTop() > 200) {
|
||||
backToTopDOM.fadeIn();
|
||||
} else {
|
||||
backToTopDOM.fadeOut();
|
||||
}
|
||||
});
|
||||
/**
|
||||
* Cache les notifications
|
||||
*/
|
||||
var notificationTimer;
|
||||
$("#notification")
|
||||
.on("mouseenter", function () {
|
||||
clearTimeout(notificationTimer);
|
||||
$("#notificationProgress")
|
||||
.stop()
|
||||
.width("100%");
|
||||
})
|
||||
.on("mouseleave", function () {
|
||||
// Disparition de la notification
|
||||
notificationTimer = setTimeout(function () {
|
||||
$("#notification").fadeOut();
|
||||
}, 3000);
|
||||
// Barre de progression
|
||||
$("#notificationProgress").animate({
|
||||
"width": "0%"
|
||||
}, 3000, "linear");
|
||||
})
|
||||
.trigger("mouseleave");
|
||||
$("#notificationClose").on("click", function () {
|
||||
clearTimeout(notificationTimer);
|
||||
$("#notification").fadeOut();
|
||||
$("#notificationProgress").stop();
|
||||
});
|
||||
|
||||
/**
|
||||
* Traitement du formulaire cookies
|
||||
*/
|
||||
$("#cookieForm").submit(function (event) {
|
||||
|
||||
// Variables des cookies
|
||||
var getUrl = window.location;
|
||||
var domain = "domain=" + getUrl.hostname + ";";
|
||||
var e = new Date();
|
||||
e.setFullYear(e.getFullYear() + 1);
|
||||
var expires = "expires=" + e.toUTCString();
|
||||
|
||||
// Stocke le cookie d'acceptation
|
||||
document.cookie = "ZWII_COOKIE_CONSENT=true;samesite=strict;" + domain + expires;
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Fermeture de la popup des cookies
|
||||
*/
|
||||
$("#cookieConsent .cookieClose").on("click", function () {
|
||||
$('#cookieConsent').addClass("displayNone");
|
||||
});
|
||||
|
||||
/**
|
||||
* Commande de gestion des cookies dans le footer
|
||||
*/
|
||||
|
||||
$("#footerLinkCookie").on("click", function () {
|
||||
$("#cookieConsent").removeClass("displayNone");
|
||||
});
|
||||
|
||||
/**
|
||||
* Affiche / Cache le menu en mode responsive
|
||||
*/
|
||||
var menuDOM = $("#menu");
|
||||
$("#toggle").on("click", function () {
|
||||
menuDOM.slideToggle();
|
||||
});
|
||||
$(window).on("resize", function () {
|
||||
if ($(window).width() > 768) {
|
||||
menuDOM.css("display", "");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Choix de page dans la barre de membre
|
||||
*/
|
||||
$("#barSelectPage").on("change", function () {
|
||||
var pageUrl = $(this).val();
|
||||
if (pageUrl) {
|
||||
$(location).attr("href", pageUrl);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Champs d'upload de fichiers
|
||||
*/
|
||||
// Mise à jour de l'affichage des champs d'upload
|
||||
$(".inputFileHidden").on("change", function () {
|
||||
var inputFileHiddenDOM = $(this);
|
||||
var fileName = inputFileHiddenDOM.val();
|
||||
if (fileName === "") {
|
||||
//fileName = "Sélectionner un fichier";
|
||||
fileName = "<?php echo helper::translate('Sélectionner un fichier');?>";
|
||||
$(inputFileHiddenDOM).addClass("disabled");
|
||||
} else {
|
||||
$(inputFileHiddenDOM).removeClass("disabled");
|
||||
}
|
||||
inputFileHiddenDOM.parent().find(".inputFileLabel").text(fileName);
|
||||
}).trigger("change");
|
||||
// Suppression du fichier contenu dans le champ
|
||||
$(".inputFileDelete").on("click", function () {
|
||||
$(this).parents(".inputWrapper").find(".inputFileHidden").val("").trigger("change");
|
||||
});
|
||||
// Suppression de la date contenu dans le champ
|
||||
$(".inputDateDelete").on("click", function () {
|
||||
$(this).parents(".inputWrapper").find(".datepicker").val("").trigger("change");
|
||||
});
|
||||
// Confirmation de mise à jour
|
||||
$("#barUpdate").on("click", function () {
|
||||
message = "<?php echo helper::translate('Mettre à jour') . ' ?';?>";
|
||||
return core.confirm(message, function () {
|
||||
$(location).attr("href", $("#barUpdate").attr("href"));
|
||||
});
|
||||
});
|
||||
// Confirmation de déconnexion
|
||||
$("#barLogout").on("click", function () {
|
||||
message = "<?php echo helper::translate('Se déconnecter') . '?';?>";
|
||||
return core.confirm(message, function () {
|
||||
$(location).attr("href", $("#barLogout").attr("href"));
|
||||
});
|
||||
});
|
||||
/**
|
||||
* Bloque la multi-soumission des boutons
|
||||
*/
|
||||
$("form").on("submit", function () {
|
||||
$(this).find(".uniqueSubmission")
|
||||
.addClass("disabled")
|
||||
.prop("disabled", true)
|
||||
.empty()
|
||||
.append(
|
||||
$("<span>").addClass("zwiico-spin animate-spin")
|
||||
)
|
||||
});
|
||||
/**
|
||||
* Check adresse email
|
||||
*/
|
||||
$("[type=email]").on("change", function () {
|
||||
var _this = $(this);
|
||||
var pattern = /^([a-z\d!#$%&'*+\-\/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+(\.[a-z\d!#$%&'*+\-\/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)*|"((([ \t]*\r\n)?[ \t]+)?([\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5d-\x7e\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|\\[\x01-\x09\x0b\x0c\x0d-\x7f\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))*(([ \t]*\r\n)?[ \t]+)?")@(([a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.)+([a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.?$/i;
|
||||
if (pattern.test(_this.val())) {
|
||||
core.noticeRemove(_this.attr("id"));
|
||||
} else {
|
||||
message = "<?php echo helper::translate('Format incorrect');?>";
|
||||
core.noticeAdd(_this.attr("id"), message);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Iframes et vidéos responsives
|
||||
*/
|
||||
var elementDOM = $("iframe, video, embed, object");
|
||||
// Calcul du ratio et suppression de la hauteur / largeur des iframes
|
||||
elementDOM.each(function () {
|
||||
var _this = $(this);
|
||||
_this
|
||||
.data("ratio", _this.height() / _this.width())
|
||||
.data("maxwidth", _this.width())
|
||||
.removeAttr("width height");
|
||||
});
|
||||
// Prend la largeur du parent et détermine la hauteur à l'aide du ratio lors du resize de la fenêtre
|
||||
$(window).on("resize", function () {
|
||||
elementDOM.each(function () {
|
||||
var _this = $(this);
|
||||
var width = _this.parent().first().width();
|
||||
if (width > _this.data("maxwidth")) {
|
||||
width = _this.data("maxwidth");
|
||||
}
|
||||
_this
|
||||
.width(width)
|
||||
.height(width * _this.data("ratio"));
|
||||
});
|
||||
}).trigger("resize");
|
||||
|
||||
/*
|
||||
* Header responsive
|
||||
*/
|
||||
$(window).on("resize", function () {
|
||||
var responsive = "<?php echo $this->getdata(['theme','header','imageContainer']);?>";
|
||||
if (responsive === "cover" || responsive === "contain") {
|
||||
var widthpx = "<?php echo $this->getdata(['theme','site','width']);?>";
|
||||
var width = widthpx.substr(0, widthpx.length - 2);
|
||||
var heightpx = "<?php echo $this->getdata(['theme','header','height']);?>";
|
||||
var height = heightpx.substr(0, heightpx.length - 2);
|
||||
var ratio = width / height;
|
||||
if (($(window).width() / ratio) <= height) {
|
||||
$("header").height($(window).width() / ratio);
|
||||
}
|
||||
}
|
||||
}).trigger("resize");
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
core.start();
|
||||
|
||||
/**
|
||||
* Confirmation de suppression
|
||||
*/
|
||||
$("#pageDelete").on("click", function () {
|
||||
var _this = $(this);
|
||||
message = "<?php echo helper::translate('Confirmez-vous la suppression de cette page ?');?>";
|
||||
return core.confirm(message, function () {
|
||||
$(location).attr("href", _this.attr("href"));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Calcul de la luminance relative d'une couleur
|
||||
*/
|
||||
core.relativeLuminanceW3C = function (rgba) {
|
||||
// Conversion en sRGB
|
||||
var RsRGB = rgba[0] / 255;
|
||||
var GsRGB = rgba[1] / 255;
|
||||
var BsRGB = rgba[2] / 255;
|
||||
// Ajout de la transparence
|
||||
var RsRGBA = rgba[3] * RsRGB + (1 - rgba[3]);
|
||||
var GsRGBA = rgba[3] * GsRGB + (1 - rgba[3]);
|
||||
var BsRGBA = rgba[3] * BsRGB + (1 - rgba[3]);
|
||||
// Calcul de la luminance
|
||||
var R = (RsRGBA <= .03928) ? RsRGBA / 12.92 : Math.pow((RsRGBA + .055) / 1.055, 2.4);
|
||||
var G = (GsRGBA <= .03928) ? GsRGBA / 12.92 : Math.pow((GsRGBA + .055) / 1.055, 2.4);
|
||||
var B = (BsRGBA <= .03928) ? BsRGBA / 12.92 : Math.pow((BsRGBA + .055) / 1.055, 2.4);
|
||||
return .2126 * R + .7152 * G + .0722 * B;
|
||||
};
|
||||
|
||||
// Fonctions
|
||||
function setCookie(name, value, days) {
|
||||
var expires = "";
|
||||
if (days) {
|
||||
var date = new Date();
|
||||
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
||||
expires = "; expires=" + date.toUTCString();
|
||||
}
|
||||
document.cookie = name + "=" + (value || "") + expires + "; path=/; samesite=lax";
|
||||
}
|
||||
|
||||
function getCookie(name) {
|
||||
var nameEQ = name + "=";
|
||||
var ca = document.cookie.split(';');
|
||||
for (var i = 0; i < ca.length; i++) {
|
||||
var c = ca[i];
|
||||
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
|
||||
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Define function to capitalize the first letter of a string
|
||||
function capitalizeFirstLetter(string) {
|
||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||
}
|
||||
|
||||
|
||||
$(document).ready(function () {
|
||||
/**
|
||||
* Affiche le sous-menu quand il est sticky
|
||||
*/
|
||||
$("nav").mouseenter(function () {
|
||||
$("#navfixedlogout .navSub").css({
|
||||
'pointer-events': 'auto'
|
||||
});
|
||||
$("#navfixedconnected .navSub").css({
|
||||
'pointer-events': 'auto'
|
||||
});
|
||||
});
|
||||
$("nav").mouseleave(function () {
|
||||
$("#navfixedlogout .navSub").css({
|
||||
'pointer-events': 'none'
|
||||
});
|
||||
$("#navfixedconnected .navSub").css({
|
||||
'pointer-events': 'none'
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Chargement paresseux des images et des iframes
|
||||
*/
|
||||
$("img,picture,iframe").attr("loading", "lazy");
|
||||
|
||||
/**
|
||||
* Effet accordéon
|
||||
*/
|
||||
$('.accordion').each(function (e) {
|
||||
// on stocke l'accordéon dans une variable locale
|
||||
var accordion = $(this);
|
||||
// on récupère la valeur data-speed si elle existe
|
||||
var toggleSpeed = accordion.attr('data-speed') || 100;
|
||||
|
||||
// fonction pour afficher un élément
|
||||
function open(item, speed) {
|
||||
// on récupère tous les éléments, on enlève l'élément actif de ce résultat, et on les cache
|
||||
accordion.find('.accordion-item').not(item).removeClass('active')
|
||||
.find('.accordion-content').slideUp(speed);
|
||||
// on affiche l'élément actif
|
||||
item.addClass('active')
|
||||
.find('.accordion-content').slideDown(speed);
|
||||
}
|
||||
|
||||
function close(item, speed) {
|
||||
accordion.find('.accordion-item').removeClass('active')
|
||||
.find('.accordion-content').slideUp(speed);
|
||||
}
|
||||
|
||||
// on initialise l'accordéon, sans animation
|
||||
open(accordion.find('.active:first'), 0);
|
||||
|
||||
// au clic sur un titre...
|
||||
accordion.on('click', '.accordion-title', function (ev) {
|
||||
ev.preventDefault();
|
||||
// Masquer l'élément déjà actif
|
||||
if ($(this).closest('.accordion-item').hasClass('active')) {
|
||||
close($(this).closest('.accordion-item'), toggleSpeed);
|
||||
} else {
|
||||
// ...on lance l'affichage de l'élément, avec animation
|
||||
open($(this).closest('.accordion-item'), toggleSpeed);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Icône du Menu Burger
|
||||
*/
|
||||
$("#toggle").click(function () {
|
||||
var changeIcon = $('#toggle').children("span");
|
||||
if ($(changeIcon).hasClass('zwiico-menu')) {
|
||||
$(changeIcon).removeClass('zwiico-menu').addClass('zwiico-cancel');
|
||||
} else {
|
||||
$(changeIcon).addClass('zwiico-menu');
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Remove ID Facebook from URL
|
||||
*/
|
||||
if (/^\?fbclid=/.test(location.search)) {
|
||||
location.replace(location.href.replace(/\?fbclid.+/, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sélection d'une langue du site
|
||||
*/
|
||||
$("select#barSelectLanguage").on("change", function () {
|
||||
// La langue courante ne déclenche pas de chargement
|
||||
var langSelected = $(this).val();
|
||||
var langSelected = langSelected.split("/");
|
||||
// Lit le cookie de langue
|
||||
var langSession = "<?php echo isset($_SESSION['ZWII_CONTENT']) ? $_SESSION['ZWII_CONTENT'] : '';?>";
|
||||
// Découpe l'URL pour exclure le changement de page avec le thème
|
||||
var url = window.location;
|
||||
var currentUrl = url.href.split("/");
|
||||
// Change si différent, corrige le problème avec le thème et le rechargement de la langue.
|
||||
if ((currentUrl !== "?theme" ||
|
||||
currentUrl !== "theme") &&
|
||||
langSelected[6] !== langSession
|
||||
) {
|
||||
//$(location).attr("href", langUrl);
|
||||
var select = document.getElementById("barSelectLanguage");
|
||||
var selectedOption = select.options[select.selectedIndex];
|
||||
if (selectedOption.value !== "") {
|
||||
window.location = selectedOption.value; }
|
||||
}
|
||||
});
|
||||
|
||||
});
|
1396
core/core.php
Normal file
1396
core/core.php
Normal file
File diff suppressed because it is too large
Load Diff
56
core/include/checkup.php
Normal file
56
core/include/checkup.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Vérification de la version de PHP
|
||||
*/
|
||||
|
||||
if(version_compare(PHP_VERSION, '7.2.0', '<') ) {
|
||||
exit('PHP 7.2+ mini requis - PHP 7.2+ mini required');
|
||||
|
||||
}
|
||||
|
||||
if ( version_compare(PHP_VERSION, '8.3.999', '>') ) {
|
||||
exit('PHP 8.3 pas encore supporté, installez PHP 7.n ou PHP 8.1.n - PHP 8.3 not yet supported, install PHP 7.n or PHP 8.1.n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check les modules installés
|
||||
*/
|
||||
|
||||
$e = [
|
||||
'gd',
|
||||
'json',
|
||||
'date',
|
||||
'mbstring',
|
||||
'zip',
|
||||
'intl',
|
||||
'exif',
|
||||
'Phar',
|
||||
'fileinfo',
|
||||
'session'
|
||||
];
|
||||
$m = get_loaded_extensions();
|
||||
$b = false;
|
||||
foreach ($e as $k => $v) {
|
||||
if (array_search($v,$m) === false) {
|
||||
$b = true;
|
||||
echo '<pre><p>Module ' . $v . ' manquant - Module ' . $v . ' missing.</p></pre>';
|
||||
}
|
||||
}
|
||||
if ($b)
|
||||
exit('<pre><p>ZwiiCMS ne peut pas démarrer ; activez les extensions requises - ZwiiCMS cannot start, enabled missing extensions.</p></pre>');
|
||||
/**
|
||||
* Contrôle les htacess
|
||||
*/
|
||||
|
||||
$d = [
|
||||
'',
|
||||
'site/data/',
|
||||
'site/backup/',
|
||||
'site/tmp/',
|
||||
// 'site/i18n/', pas contrôler pour éviter les pbs de mise à jour
|
||||
];
|
||||
foreach ($d as $key) {
|
||||
if (file_exists($key . '.htaccess') === false)
|
||||
exit('<pre>ZwiiCMS ne peut pas démarrer, le fichier ' .$key . '.htaccess est manquant.<br />ZwiiCMS cannot start, file ' . $key . '.htaccess is missing.</pre>' );
|
||||
}
|
5
core/include/update.inc.php
Normal file
5
core/include/update.inc.php
Normal file
@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Mises à jour suivant les versions de Zwii
|
||||
*/
|
20
core/layout/blank.css
Normal file
20
core/layout/blank.css
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* 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
|
||||
* @author Frédéric Tempez <frederic.tempez@outlook.com>
|
||||
* @copyright Copyright (C) 2018-2023, Frédéric Tempez
|
||||
* @license CC Attribution-NonCommercial-NoDerivatives 4.0 International
|
||||
* @link http://zwiicms.fr/
|
||||
*/
|
||||
|
||||
/**
|
||||
* Éléments génériques
|
||||
*/
|
||||
|
||||
body {
|
||||
background : #FFF !important;
|
||||
}
|
24
core/layout/blank.php
Normal file
24
core/layout/blank.php
Normal file
@ -0,0 +1,24 @@
|
||||
<!DOCTYPE html>
|
||||
<html prefix="og: http://ogp.me/ns#" lang="<?php echo substr(self::$i18nContent, 0, 2); ?>">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<?php $layout->showMetaTitle(); ?>
|
||||
<?php $layout->showMetaDescription(); ?>
|
||||
<?php $layout->showMetaType(); ?>
|
||||
<?php $layout->showMetaImage(); ?>
|
||||
<?php $layout->showFavicon(); ?>
|
||||
<?php $layout->showVendor(); ?>
|
||||
<?php $layout->showStyle(); ?>
|
||||
<?php $layout->showFonts(); ?>
|
||||
<link rel="stylesheet" href="<?php echo helper::baseUrl(false); ?>core/layout/common.css">
|
||||
<link rel="stylesheet" href="<?php echo helper::baseUrl(false); ?>core/layout/blank.css">
|
||||
<link rel="stylesheet" href="<?php echo helper::baseUrl(false) . self::DATA_DIR; ?>theme.css?<?php echo md5_file(self::DATA_DIR.'theme.css'); ?>">
|
||||
<link rel="stylesheet" href="<?php echo helper::baseUrl(false) . self::DATA_DIR; ?>custom.css?<?php echo md5_file(self::DATA_DIR.'custom.css'); ?>">
|
||||
</head>
|
||||
<body>
|
||||
<?php $layout->showContent(); ?>
|
||||
<?php $layout->showScript(); ?>
|
||||
</body>
|
||||
</html>
|
1821
core/layout/common.css
Normal file
1821
core/layout/common.css
Normal file
File diff suppressed because it is too large
Load Diff
33
core/layout/light.css
Normal file
33
core/layout/light.css
Normal file
@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 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
|
||||
* @author Frédéric Tempez <frederic.tempez@outlook.com>
|
||||
* @copyright Copyright (C) 2018-2023, Frédéric Tempez
|
||||
* @license CC Attribution-NonCommercial-NoDerivatives 4.0 International
|
||||
* @link http://zwiicms.fr/
|
||||
*/
|
||||
|
||||
/**
|
||||
* Éléments spécifiques
|
||||
*/
|
||||
|
||||
/* Site */
|
||||
#site {
|
||||
max-width: 600px !important;
|
||||
border-radius: 5px !important;
|
||||
}
|
||||
|
||||
#site > section:not(.message),
|
||||
input[type='password'], input[type='text']
|
||||
{
|
||||
background-color: rgba(255, 255, 255, 1) !important;
|
||||
color: rgba(33, 34, 35, 1) !important;
|
||||
}
|
||||
|
||||
section {
|
||||
min-height: 0px;
|
||||
}
|
27
core/layout/light.php
Normal file
27
core/layout/light.php
Normal file
@ -0,0 +1,27 @@
|
||||
<!DOCTYPE html>
|
||||
<html prefix="og: http://ogp.me/ns#" lang="<?php echo substr(self::$i18nContent, 0, 2); ?>">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<?php $layout->showMetaTitle(); ?>
|
||||
<?php $layout->showMetaDescription(); ?>
|
||||
<?php $layout->showMetaType(); ?>
|
||||
<?php $layout->showMetaImage(); ?>
|
||||
<?php $layout->showFavicon(); ?>
|
||||
<?php $layout->showVendor(); ?>
|
||||
<?php $layout->showStyle(); ?>
|
||||
<?php $layout->showFonts(); ?>
|
||||
<link rel="stylesheet" href="<?php echo helper::baseUrl(false); ?>core/layout/common.css">
|
||||
<link rel="stylesheet" href="<?php echo helper::baseUrl(false); ?>core/layout/light.css">
|
||||
<link rel="stylesheet" href="<?php echo helper::baseUrl(false) . self::DATA_DIR; ?>theme.css?<?php echo md5_file(self::DATA_DIR.'theme.css'); ?>">
|
||||
<link rel="stylesheet" href="<?php echo helper::baseUrl(false) . self::DATA_DIR; ?>custom.css?<?php echo md5_file(self::DATA_DIR.'custom.css'); ?>">
|
||||
</head>
|
||||
<body>
|
||||
<?php $layout->showNotification(); ?>
|
||||
<div id="site" class="container light">
|
||||
<section><?php $layout->showContent(); ?></section>
|
||||
</div>
|
||||
<?php $layout->showScript(); ?>
|
||||
</body>
|
||||
</html>
|
139
core/layout/mail.php
Normal file
139
core/layout/mail.php
Normal file
@ -0,0 +1,139 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="<?php echo substr(self::$i18nContent, 0, 2);?>">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="x-apple-disable-message-reformatting">
|
||||
<title><?php echo $subject; ?></title>
|
||||
<!--[if mso]>
|
||||
<style>
|
||||
* {
|
||||
font-family: sans-serif !important;
|
||||
}
|
||||
</style>
|
||||
<![endif]-->
|
||||
<!--[if !mso]>
|
||||
<link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
|
||||
<![endif]-->
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
margin: 0 auto !important;
|
||||
padding: 0 !important;
|
||||
height: 100% !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
* {
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
div[style*="margin: 16px 0"] {
|
||||
margin:0 !important;
|
||||
}
|
||||
table,
|
||||
td {
|
||||
mso-table-lspace: 0pt !important;
|
||||
mso-table-rspace: 0pt !important;
|
||||
}
|
||||
table {
|
||||
border-spacing: 0 !important;
|
||||
border-collapse: collapse !important;
|
||||
table-layout: fixed !important;
|
||||
margin: 0 auto !important;
|
||||
}
|
||||
table table table {
|
||||
table-layout: auto;
|
||||
}
|
||||
*[x-apple-data-detectors] {
|
||||
color: inherit !important;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
.x-gmail-data-detectors,
|
||||
.x-gmail-data-detectors *,
|
||||
.aBn {
|
||||
border-bottom: 0 !important;
|
||||
cursor: default !important;
|
||||
}
|
||||
.a6S {
|
||||
display: none !important;
|
||||
opacity: 0.01 !important;
|
||||
}
|
||||
@media only screen and (min-device-width: 375px) and (max-device-width: 413px) {
|
||||
.email-container {
|
||||
min-width: 375px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body width="100%" bgcolor="#EBEEF2" style="margin: 0; padding: 10px; mso-line-height-rule: exactly;">
|
||||
<center style="width: 100%; background: #EBEEF2; text-align: left;">
|
||||
<div style="display:none;font-size:1px;line-height:1px;max-height:0px;max-width:0px;opacity:0;overflow:hidden;mso-hide:all;font-family: sans-serif;">
|
||||
<?php echo $subject; ?>
|
||||
</div>
|
||||
<div style="max-width: 500px; margin: auto; margin-top: 30px; border: #aaa 1px solid;" class="email-container">
|
||||
<!--[if mso]>
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="500" align="center">
|
||||
<tr>
|
||||
<td>
|
||||
<![endif]-->
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" align="center" width="100%" style="max-width: 500px;">
|
||||
<tr>
|
||||
<td bgcolor="#ffffff">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="border-bottom: 1px solid #EBEEF2; padding: 20px; font-family: 'Open Sans', sans-serif; font-size: 19px; line-height: 24px; text-align: center; color: #212223;">
|
||||
<?php echo $this->getData(['locale', 'title']); ?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" align="center" width="100%" style="max-width: 500px;">
|
||||
<tr>
|
||||
<td bgcolor="#ffffff">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="padding: 30px; font-family: 'Open Sans', sans-serif; font-size: 14px; line-height: 19px; color: #212223;">
|
||||
<?php echo nl2br($content); ?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" align="center" width="100%" style="max-width: 500px;">
|
||||
<tr>
|
||||
<td bgcolor="#ffffff">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="border-top: 1px solid #EBEEF2; padding: 20px; text-align: center; font-family: 'Open Sans', sans-serif; font-size: 12px; line-height: 17px; color: #212223;">
|
||||
<a href="<?php echo helper::baseUrl(false); ?>" target="_blank">
|
||||
<?php
|
||||
if($this->getData(['module', $this->getUrl(0), 'config', 'signature' ]) === 'logo' && is_file( 'site/file/source/'. $this->getData(['module', $this->getUrl(0), 'config', 'logoUrl' ]))){
|
||||
$imageFile = helper::baseUrl(false).'site/file/source/'. $this->getData(['module', $this->getUrl(0), 'config', 'logoUrl' ]) ;
|
||||
$imageBase64 = base64_encode(file_get_contents($imageFile));
|
||||
?><img src=" data:image/<?php echo pathinfo($imageFile, PATHINFO_EXTENSION); ?>;base64,<?php echo $imageBase64; ?>" border="0" width="<?php echo $this->getData(['module', $this->getUrl(0), 'config', 'logoWidth']) ?>%" >
|
||||
<?php
|
||||
}
|
||||
else{
|
||||
echo $this->getData(['locale', 'title']);
|
||||
} ?>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<!--[if mso]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</div>
|
||||
</center>
|
||||
</body>
|
||||
</html>
|
192
core/layout/main.php
Normal file
192
core/layout/main.php
Normal file
@ -0,0 +1,192 @@
|
||||
<!DOCTYPE html>
|
||||
<html prefix="og: http://ogp.me/ns#" lang="<?php echo substr(self::$i18nContent, 0, 2); ?>">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<meta meta="description=" content="ZwiiCMS le CMS multilingue sans base de données">
|
||||
<meta name="generator" content="ZiiCMS https://forge.chapril.org/ZwiiCMS-Team/ZwiiCMS">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<?php $layout->showMetaTitle(); ?>
|
||||
<?php $layout->showMetaDescription(); ?>
|
||||
<?php $layout->showMetaType(); ?>
|
||||
<?php $layout->showMetaImage(); ?>
|
||||
<?php $layout->showFavicon(); ?>
|
||||
<?php $layout->showVendor(); ?>
|
||||
<?php $layout->showFonts(); ?>
|
||||
<link rel="stylesheet" href="<?php echo helper::baseUrl(false); ?>core/layout/common.css?<?php echo md5_file('core/layout/common.css'); ?>">
|
||||
<link rel="stylesheet" href="<?php echo helper::baseUrl(false) . self::DATA_DIR; ?>theme.css?<?php echo md5_file(self::DATA_DIR . 'theme.css'); ?>">
|
||||
<link rel="stylesheet" href="<?php echo helper::baseUrl(false) . self::DATA_DIR; ?>custom.css?<?php echo md5_file(self::DATA_DIR . 'custom.css'); ?>">
|
||||
<!-- Détection RSS -->
|
||||
<?php if (($this->getData(['page', $this->getUrl(0), 'moduleId']) === 'blog'
|
||||
or $this->getData(['page', $this->getUrl(0), 'moduleId']) === 'news')
|
||||
and $this->getData(['module', $this->getUrl(0), 'config', 'feeds']) === TRUE
|
||||
) : ?>
|
||||
<link rel="alternate" type="application/rss+xml" href="'<?php echo helper::baseUrl() . $this->getUrl(0) . '/rss'; ?>" title="fLUX rss">
|
||||
<?php endif; ?>
|
||||
<?php $layout->showStyle(); ?>
|
||||
<?php $layout->showInlineStyle(); ?>
|
||||
<!-- Script perso dans le header -->
|
||||
<?php if (file_exists(self::DATA_DIR . 'head.inc.html')) {
|
||||
include(self::DATA_DIR . 'head.inc.html');
|
||||
} ?>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Barre d'administration -->
|
||||
<?php if ($this->getUser('group') > self::GROUP_MEMBER) : ?>
|
||||
<?php $layout->showBar(); ?>
|
||||
<?php endif; ?>
|
||||
<!-- Notifications -->
|
||||
<?php $layout->showNotification(); ?>
|
||||
<!-- Menu dans le fond du site avant la bannière -->
|
||||
<?php if ($this->getData(['theme', 'menu', 'position']) === 'body-first' || $this->getData(['theme', 'menu', 'position']) === 'top') : ?>
|
||||
<!-- Détermine si le menu est fixe en haut de page lorsque l'utilisateur n'est pas connecté -->
|
||||
<?php
|
||||
if (
|
||||
$this->getData(['theme', 'menu', 'position']) === 'top'
|
||||
and $this->getData(['theme', 'menu', 'fixed']) === true
|
||||
and $this->getUser('password') === $this->getInput('ZWII_USER_PASSWORD')
|
||||
and $this->getUser('group') > self::GROUP_MEMBER
|
||||
) {
|
||||
echo '<nav id="navfixedconnected" >';
|
||||
} else {
|
||||
echo '<nav id="navfixedlogout" >';
|
||||
}
|
||||
?>
|
||||
<!-- Menu Burger -->
|
||||
<div id="toggle">
|
||||
<?php echo $this->getData(['theme', 'menu', 'burgerContent']) === 'title' ? '<div id="burgerText">' . $this->getData(['locale', 'title']) . '</div>' : ''; ?>
|
||||
<?php echo $this->getData(['theme', 'menu', 'burgerContent']) === 'logo' ? '<div id="burgerLogo"><img src="' . helper::baseUrl(false) . self::FILE_DIR . 'source/' . $this->getData(['theme', 'menu', 'burgerLogo']) . '"></div>' : ''; ?>
|
||||
<?php echo template::ico('menu', ['fontSize' => '2em']); ?></div>
|
||||
<!-- fin du menu burger -->
|
||||
<?php
|
||||
$menuClass = $this->getData(['theme', 'menu', 'position']) === 'top' ? 'class="container-large"' : 'class="container"';
|
||||
$menuClass = $this->getData(['theme', 'menu', 'wide']) === 'none' ? 'class="container-large"' : 'class="container"';
|
||||
?>
|
||||
<div id="menu" <?php echo $menuClass; ?>>
|
||||
<?php $layout->showMenu(); ?>
|
||||
</div> <!--fin menu -->
|
||||
</nav>
|
||||
<?php endif; ?>
|
||||
<!-- Bannière dans le fond du site -->
|
||||
<?php if ($this->getData(['theme', 'header', 'position']) === 'body') : ?>
|
||||
<?php echo ($this->getData(['theme', 'header', 'linkHomePage']) && $this->getData(['theme', 'header', 'feature']) === 'wallpaper') ? '<a href="' . helper::baseUrl(false) . '">' : ''; ?>
|
||||
<?php
|
||||
$headerClass = $this->getData(['theme', 'header', 'position']) === 'hide' ? 'displayNone' : '';
|
||||
$headerClass .= $this->getData(['theme', 'header', 'tinyHidden']) ? ' bannerDisplay ' : '';
|
||||
$headerClass .= $this->getData(['theme', 'header', 'wide']) === 'none' ? '' : 'container';
|
||||
?>
|
||||
<header <?php echo empty($headerClass) ? '' : 'class="' . $headerClass . '"'; ?>>
|
||||
<?php if ($this->getData(['theme', 'header', 'feature']) === 'wallpaper') : ?>
|
||||
<?php if (
|
||||
$this->getData(['theme', 'header', 'textHide']) === false
|
||||
// Affiche toujours le titre de la bannière pour l'édition du thème
|
||||
or ($this->getUrl(0) === 'theme' and $this->getUrl(1) === 'header')
|
||||
) : ?>
|
||||
<span id="themeHeaderTitle"><?php echo $this->getData(['locale', 'title']); ?></span>
|
||||
<?php else : ?>
|
||||
<span id="themeHeaderTitle"> </span>
|
||||
<?php endif; ?>
|
||||
<?php else : ?>
|
||||
<div id="featureContent">
|
||||
<?php echo $this->getData(['theme', 'header', 'featureContent']); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</header>
|
||||
<?php echo ($this->getData(['theme', 'header', 'linkHomePage']) && $this->getData(['theme', 'header', 'feature']) === 'wallpaper') ? '</a>' : ''; ?>
|
||||
<?php endif; ?>
|
||||
<!-- Menu dans le fond du site après la bannière -->
|
||||
<?php if ($this->getData(['theme', 'menu', 'position']) === 'body-second') : ?>
|
||||
<nav>
|
||||
<!-- Menu burger -->
|
||||
<div id="toggle">
|
||||
<?php echo $this->getData(['theme', 'menu', 'burgerContent']) === 'title' ? '<div id="burgerText">' . $this->getData(['locale', 'title']) . '</div>' : ''; ?>
|
||||
<?php echo $this->getData(['theme', 'menu', 'burgerContent']) === 'logo' ? '<div id="burgerLogo"><img src="' . helper::baseUrl(false) . self::FILE_DIR . 'source/' . $this->getData(['theme', 'menu', 'burgerLogo']) . '"></div>' : ''; ?>
|
||||
<?php echo template::ico('menu', ['fontSize' => '2em']); ?></div>
|
||||
<!-- fin du menu burger -->
|
||||
<?php
|
||||
$menuClass = $this->getData(['theme', 'menu', 'wide']) === 'none' ? 'class="container-large"' : 'class="container"';
|
||||
?>
|
||||
<div id="menu" <?php echo $menuClass; ?>>
|
||||
<?php $layout->showMenu(); ?></div>
|
||||
</nav>
|
||||
<?php endif; ?>
|
||||
<!-- Site -->
|
||||
<div id="site" class="container">
|
||||
<?php if ($this->getData(['theme', 'menu', 'position']) === 'site-first') : ?>
|
||||
<!-- Menu dans le site avant la bannière -->
|
||||
<nav>
|
||||
<div id="toggle">
|
||||
<?php echo $this->getData(['theme', 'menu', 'burgerContent']) === 'title' ? '<div id="burgerText">' . $this->getData(['locale', 'title']) . '</div>' : ''; ?>
|
||||
<?php echo $this->getData(['theme', 'menu', 'burgerContent']) === 'logo' ? '<div id="burgerLogo"><img src="' . helper::baseUrl(false) . self::FILE_DIR . 'source/' . $this->getData(['theme', 'menu', 'burgerLogo']) . '"></div>' : ''; ?>
|
||||
<?php echo template::ico('menu', ['fontSize' => '2em']); ?></div>
|
||||
<div id="menu" class="container"><?php $layout->showMenu(); ?></div>
|
||||
</nav>
|
||||
<?php endif; ?>
|
||||
<?php if (
|
||||
$this->getData(['theme', 'header', 'position']) === 'site'
|
||||
// Affiche toujours la bannière pour l'édition du thème
|
||||
or ($this->getData(['theme', 'header', 'position']) === 'hide'
|
||||
and $this->getUrl(0) === 'theme'
|
||||
)
|
||||
) : ?>
|
||||
<!-- Bannière dans le site -->
|
||||
<?php echo ($this->getData(['theme', 'header', 'linkHomePage']) && $this->getData(['theme', 'header', 'feature']) === 'wallpaper') ? '<a href="' . helper::baseUrl(false) . '">' : ''; ?>
|
||||
<?php
|
||||
$headerClass = $this->getData(['theme', 'header', 'position']) === 'hide' ? 'displayNone' : '';
|
||||
$headerClass .= $this->getData(['theme', 'header', 'tinyHidden']) ? ' bannerDisplay ' : '';
|
||||
?>
|
||||
<header <?php echo empty($headerClass) ? '' : 'class="' . $headerClass . '"'; ?>>
|
||||
<?php if ($this->getData(['theme', 'header', 'feature']) === 'wallpaper') : ?>
|
||||
<?php if (
|
||||
$this->getData(['theme', 'header', 'textHide']) === false
|
||||
// Affiche toujours le titre de la bannière pour l'édition du thème
|
||||
or ($this->getUrl(0) === 'theme' and $this->getUrl(1) === 'header')
|
||||
) : ?>
|
||||
<span id="themeHeaderTitle"><?php echo $this->getData(['locale', 'title']); ?></span>
|
||||
<?php else : ?>
|
||||
<span id="themeHeaderTitle"> </span>
|
||||
<?php endif; ?>
|
||||
<?php else : ?>
|
||||
<div id="featureContent">
|
||||
<?php echo $this->getData(['theme', 'header', 'featureContent']); ?>
|
||||
</diV>
|
||||
<?php endif; ?>
|
||||
</header>
|
||||
<?php echo ($this->getData(['theme', 'header', 'linkHomePage']) && $this->getData(['theme', 'header', 'feature']) === 'wallpaper') ? '</a>' : ''; ?>
|
||||
<?php endif; ?>
|
||||
<?php if (
|
||||
$this->getData(['theme', 'menu', 'position']) === 'site-second' ||
|
||||
$this->getData(['theme', 'menu', 'position']) === 'site'
|
||||
// Affiche toujours le menu pour l'édition du thème
|
||||
or ($this->getData(['theme', 'menu', 'position']) === 'hide'
|
||||
and $this->getUrl(0) === 'theme'
|
||||
)
|
||||
) : ?>
|
||||
<!-- Menu dans le site après la bannière -->
|
||||
<nav <?php if ($this->getData(['theme', 'menu', 'position']) === 'hide') : ?>class="displayNone" <?php endif; ?>>
|
||||
<div id="toggle">
|
||||
<?php echo $this->getData(['theme', 'menu', 'burgerContent']) === 'title' ? '<div id="burgerText">' . $this->getData(['locale', 'title']) . '</div>' : ''; ?>
|
||||
<?php echo $this->getData(['theme', 'menu', 'burgerContent']) === 'logo' ? '<div id="burgerLogo"><img src="' . helper::baseUrl(false) . self::FILE_DIR . 'source/' . $this->getData(['theme', 'menu', 'burgerLogo']) . '"></div>' : ''; ?>
|
||||
<?php echo template::ico('menu', ['fontSize' => '2em']); ?></div>
|
||||
<div id="menu" class="container"><?php $layout->showMenu(); ?></div>
|
||||
</nav>
|
||||
<?php endif; ?>
|
||||
<!-- Corps de page -->
|
||||
<?php $layout->showMain(); ?>
|
||||
<!-- footer -->
|
||||
<?php $layout->showFooter(); ?>
|
||||
<!-- Fin du site -->
|
||||
<?php echo $this->getData(['theme', 'footer', 'position']) === 'site' ? '</div>' : ''; ?>
|
||||
<!-- Lien remonter en haut -->
|
||||
<div id="backToTop"><?php echo template::ico('up'); ?></div>
|
||||
<!-- Affichage du consentement aux cookies-->
|
||||
<?php $layout->showCookies(); ?>
|
||||
<!-- Les scripts -->
|
||||
<?php $layout->showScript(); ?>
|
||||
<!-- Script perso dans body -->
|
||||
<?php if (file_exists(self::DATA_DIR . 'body.inc.html')) {
|
||||
include(self::DATA_DIR . 'body.inc.html');
|
||||
}?>
|
||||
</body>
|
||||
|
||||
</html>
|
949
core/module/config/config.php
Normal file
949
core/module/config/config.php
Normal file
@ -0,0 +1,949 @@
|
||||
<?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
|
||||
* @author Frédéric Tempez <frederic.tempez@outlook.com>
|
||||
* @copyright Copyright (C) 2018-2023, Frédéric Tempez
|
||||
* @license CC Attribution-NonCommercial-NoDerivatives 4.0 International
|
||||
* @link http://zwiicms.fr/
|
||||
*/
|
||||
|
||||
class config extends common
|
||||
{
|
||||
|
||||
public static $actions = [
|
||||
'backup' => self::GROUP_ADMIN,
|
||||
'copyBackups' => self::GROUP_ADMIN,
|
||||
'delBackups' => self::GROUP_ADMIN,
|
||||
'configMetaImage' => self::GROUP_ADMIN,
|
||||
'siteMap' => self::GROUP_ADMIN,
|
||||
'index' => self::GROUP_ADMIN,
|
||||
'restore' => self::GROUP_ADMIN,
|
||||
'updateBaseUrl' => self::GROUP_ADMIN,
|
||||
'script' => self::GROUP_ADMIN,
|
||||
'logReset' => self::GROUP_ADMIN,
|
||||
'logDownload' => self::GROUP_ADMIN,
|
||||
'blacklistReset' => self::GROUP_ADMIN,
|
||||
'blacklistDownload' => self::GROUP_ADMIN
|
||||
];
|
||||
|
||||
public static $timezones = [
|
||||
'Pacific/Midway' => '(GMT-11:00) Midway Island',
|
||||
'US/Samoa' => '(GMT-11:00) Samoa',
|
||||
'US/Hawaii' => '(GMT-10:00) Hawaii',
|
||||
'US/Alaska' => '(GMT-09:00) Alaska',
|
||||
'US/Pacific' => '(GMT-08:00) Pacific Time (US & Canada)',
|
||||
'America/Tijuana' => '(GMT-08:00) Tijuana',
|
||||
'US/Arizona' => '(GMT-07:00) Arizona',
|
||||
'US/Mountain' => '(GMT-07:00) Mountain Time (US & Canada)',
|
||||
'America/Chihuahua' => '(GMT-07:00) Chihuahua',
|
||||
'America/Mazatlan' => '(GMT-07:00) Mazatlan',
|
||||
'America/Mexico_City' => '(GMT-06:00) Mexico City',
|
||||
'America/Monterrey' => '(GMT-06:00) Monterrey',
|
||||
'Canada/Saskatchewan' => '(GMT-06:00) Saskatchewan',
|
||||
'US/Central' => '(GMT-06:00) Central Time (US & Canada)',
|
||||
'US/Eastern' => '(GMT-05:00) Eastern Time (US & Canada)',
|
||||
'US/East-Indiana' => '(GMT-05:00) Indiana (East)',
|
||||
'America/Bogota' => '(GMT-05:00) Bogota',
|
||||
'America/Lima' => '(GMT-05:00) Lima',
|
||||
'America/Caracas' => '(GMT-04:30) Caracas',
|
||||
'Canada/Atlantic' => '(GMT-04:00) Atlantic Time (Canada)',
|
||||
'America/La_Paz' => '(GMT-04:00) La Paz',
|
||||
'America/Santiago' => '(GMT-04:00) Santiago',
|
||||
'Canada/Newfoundland' => '(GMT-03:30) Newfoundland',
|
||||
'America/Buenos_Aires' => '(GMT-03:00) Buenos Aires',
|
||||
'Greenland' => '(GMT-03:00) Greenland',
|
||||
'Atlantic/Stanley' => '(GMT-02:00) Stanley',
|
||||
'Atlantic/Azores' => '(GMT-01:00) Azores',
|
||||
'Atlantic/Cape_Verde' => '(GMT-01:00) Cape Verde Is.',
|
||||
'Africa/Casablanca' => '(GMT) Casablanca',
|
||||
'Europe/Dublin' => '(GMT) Dublin',
|
||||
'Europe/Lisbon' => '(GMT) Lisbon',
|
||||
'Europe/London' => '(GMT) London',
|
||||
'Africa/Monrovia' => '(GMT) Monrovia',
|
||||
'Europe/Amsterdam' => '(GMT+01:00) Amsterdam',
|
||||
'Europe/Belgrade' => '(GMT+01:00) Belgrade',
|
||||
'Europe/Berlin' => '(GMT+01:00) Berlin',
|
||||
'Europe/Bratislava' => '(GMT+01:00) Bratislava',
|
||||
'Europe/Brussels' => '(GMT+01:00) Brussels',
|
||||
'Europe/Budapest' => '(GMT+01:00) Budapest',
|
||||
'Europe/Copenhagen' => '(GMT+01:00) Copenhagen',
|
||||
'Europe/Ljubljana' => '(GMT+01:00) Ljubljana',
|
||||
'Europe/Madrid' => '(GMT+01:00) Madrid',
|
||||
'Europe/Paris' => '(GMT+01:00) Paris',
|
||||
'Europe/Prague' => '(GMT+01:00) Prague',
|
||||
'Europe/Rome' => '(GMT+01:00) Rome',
|
||||
'Europe/Sarajevo' => '(GMT+01:00) Sarajevo',
|
||||
'Europe/Skopje' => '(GMT+01:00) Skopje',
|
||||
'Europe/Stockholm' => '(GMT+01:00) Stockholm',
|
||||
'Europe/Vienna' => '(GMT+01:00) Vienna',
|
||||
'Europe/Warsaw' => '(GMT+01:00) Warsaw',
|
||||
'Europe/Zagreb' => '(GMT+01:00) Zagreb',
|
||||
'Europe/Athens' => '(GMT+02:00) Athens',
|
||||
'Europe/Bucharest' => '(GMT+02:00) Bucharest',
|
||||
'Africa/Cairo' => '(GMT+02:00) Cairo',
|
||||
'Africa/Harare' => '(GMT+02:00) Harare',
|
||||
'Europe/Helsinki' => '(GMT+02:00) Helsinki',
|
||||
'Europe/Istanbul' => '(GMT+02:00) Istanbul',
|
||||
'Asia/Jerusalem' => '(GMT+02:00) Jerusalem',
|
||||
'Europe/Kiev' => '(GMT+02:00) Kyiv',
|
||||
'Europe/Minsk' => '(GMT+02:00) Minsk',
|
||||
'Europe/Riga' => '(GMT+02:00) Riga',
|
||||
'Europe/Sofia' => '(GMT+02:00) Sofia',
|
||||
'Europe/Tallinn' => '(GMT+02:00) Tallinn',
|
||||
'Europe/Vilnius' => '(GMT+02:00) Vilnius',
|
||||
'Asia/Baghdad' => '(GMT+03:00) Baghdad',
|
||||
'Asia/Kuwait' => '(GMT+03:00) Kuwait',
|
||||
'Europe/Moscow' => '(GMT+03:00) Moscow',
|
||||
'Africa/Nairobi' => '(GMT+03:00) Nairobi',
|
||||
'Asia/Riyadh' => '(GMT+03:00) Riyadh',
|
||||
'Europe/Volgograd' => '(GMT+03:00) Volgograd',
|
||||
'Asia/Tehran' => '(GMT+03:30) Tehran',
|
||||
'Asia/Baku' => '(GMT+04:00) Baku',
|
||||
'Asia/Muscat' => '(GMT+04:00) Muscat',
|
||||
'Asia/Tbilisi' => '(GMT+04:00) Tbilisi',
|
||||
'Asia/Yerevan' => '(GMT+04:00) Yerevan',
|
||||
'Asia/Kabul' => '(GMT+04:30) Kabul',
|
||||
'Asia/Yekaterinburg' => '(GMT+05:00) Ekaterinburg',
|
||||
'Asia/Karachi' => '(GMT+05:00) Karachi',
|
||||
'Asia/Tashkent' => '(GMT+05:00) Tashkent',
|
||||
'Asia/Kolkata' => '(GMT+05:30) Kolkata',
|
||||
'Asia/Kathmandu' => '(GMT+05:45) Kathmandu',
|
||||
'Asia/Almaty' => '(GMT+06:00) Almaty',
|
||||
'Asia/Dhaka' => '(GMT+06:00) Dhaka',
|
||||
'Asia/Novosibirsk' => '(GMT+06:00) Novosibirsk',
|
||||
'Asia/Bangkok' => '(GMT+07:00) Bangkok',
|
||||
'Asia/Jakarta' => '(GMT+07:00) Jakarta',
|
||||
'Asia/Krasnoyarsk' => '(GMT+07:00) Krasnoyarsk',
|
||||
'Asia/Chongqing' => '(GMT+08:00) Chongqing',
|
||||
'Asia/Hong_Kong' => '(GMT+08:00) Hong Kong',
|
||||
'Asia/Irkutsk' => '(GMT+08:00) Irkutsk',
|
||||
'Asia/Kuala_Lumpur' => '(GMT+08:00) Kuala Lumpur',
|
||||
'Australia/Perth' => '(GMT+08:00) Perth',
|
||||
'Asia/Singapore' => '(GMT+08:00) Singapore',
|
||||
'Asia/Taipei' => '(GMT+08:00) Taipei',
|
||||
'Asia/Ulaanbaatar' => '(GMT+08:00) Ulaan Bataar',
|
||||
'Asia/Urumqi' => '(GMT+08:00) Urumqi',
|
||||
'Asia/Seoul' => '(GMT+09:00) Seoul',
|
||||
'Asia/Tokyo' => '(GMT+09:00) Tokyo',
|
||||
'Asia/Yakutsk' => '(GMT+09:00) Yakutsk',
|
||||
'Australia/Adelaide' => '(GMT+09:30) Adelaide',
|
||||
'Australia/Darwin' => '(GMT+09:30) Darwin',
|
||||
'Australia/Brisbane' => '(GMT+10:00) Brisbane',
|
||||
'Australia/Canberra' => '(GMT+10:00) Canberra',
|
||||
'Pacific/Guam' => '(GMT+10:00) Guam',
|
||||
'Australia/Hobart' => '(GMT+10:00) Hobart',
|
||||
'Australia/Melbourne' => '(GMT+10:00) Melbourne',
|
||||
'Pacific/Port_Moresby' => '(GMT+10:00) Port Moresby',
|
||||
'Australia/Sydney' => '(GMT+10:00) Sydney',
|
||||
'Asia/Vladivostok' => '(GMT+10:00) Vladivostok',
|
||||
'Asia/Magadan' => '(GMT+11:00) Magadan',
|
||||
'Pacific/Auckland' => '(GMT+12:00) Auckland',
|
||||
'Pacific/Fiji' => '(GMT+12:00) Fiji',
|
||||
'Asia/Kamchatka' => '(GMT+12:00) Kamchatka'
|
||||
];
|
||||
// Type de proxy
|
||||
public static $proxyType = [
|
||||
'tcp://' => 'TCP',
|
||||
'http://' => 'HTTP'
|
||||
];
|
||||
// Authentification SMTP
|
||||
public static $SMTPauth = [
|
||||
true => 'Oui',
|
||||
false => 'Non'
|
||||
];
|
||||
// Encryptation SMTP
|
||||
public static $SMTPEnc = [
|
||||
'' => 'Aucune',
|
||||
'tls' => 'START TLS',
|
||||
'ssl' => 'SSL/TLS'
|
||||
];
|
||||
// Sécurité de la connexion - tentative max avant blocage
|
||||
public static $connectAttempt = [
|
||||
999 => 'Sécurité désactivée',
|
||||
3 => '3 tentatives',
|
||||
5 => '5 tentatives',
|
||||
10 => '10 tentatives'
|
||||
];
|
||||
// Sécurité de la connexion - durée du blocage
|
||||
public static $connectTimeout = [
|
||||
0 => 'Sécurité désactivée',
|
||||
300 => '5 minutes',
|
||||
600 => '10 minutes',
|
||||
900 => '15 minutes'
|
||||
];
|
||||
// Anonymisation des IP du journal
|
||||
public static $anonIP = [
|
||||
4 => 'Non tronquée',
|
||||
3 => 'Niveau 1 (192.168.12.x)',
|
||||
2 => 'Niveau 2 (192.168.x.x)',
|
||||
1 => 'Niveau 3 (192.x.x.x)',
|
||||
];
|
||||
public static $captchaTypes = [
|
||||
'num' => 'Chiffres',
|
||||
'alpha' => 'Lettres'
|
||||
];
|
||||
public static $updateDelay = [
|
||||
86400 => '1',
|
||||
172800 => '2',
|
||||
345600 => '4',
|
||||
604800 => '7',
|
||||
1209600 => '14',
|
||||
];
|
||||
|
||||
// Langue traduite courante
|
||||
public static $i18nSite = 'fr_FR';
|
||||
|
||||
// Variable pour construire la liste des pages du site
|
||||
public static $onlineVersion = '';
|
||||
public static $updateButtonText = 'Réinstaller';
|
||||
|
||||
public static $imageOpenGraph = [];
|
||||
public static $pagesList = [];
|
||||
public static $orphansList = [];
|
||||
|
||||
/**
|
||||
* Génére les fichiers pour les crawlers
|
||||
* Sitemap compressé et non compressé
|
||||
* Robots.txt
|
||||
*/
|
||||
public function siteMap()
|
||||
{
|
||||
// La page n'existe pas
|
||||
if (
|
||||
$this->getUser('permission', __CLASS__, __FUNCTION__) !== true
|
||||
) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'access' => false
|
||||
]);
|
||||
} else {
|
||||
// Mettre à jour le site map
|
||||
$successSitemap = $this->updateSitemap();
|
||||
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'redirect' => helper::baseUrl() . 'config',
|
||||
'notification' => $successSitemap ? helper::translate('La carte du site a été mise à jour') : helper::translate('Echec de l\'écriture, vérifiez les permissions'),
|
||||
'state' => $successSitemap
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sauvegarde des données
|
||||
*/
|
||||
public function backup()
|
||||
{
|
||||
// Soumission du formulaire
|
||||
if (
|
||||
$this->getUser('permission', __CLASS__, __FUNCTION__) === true &&
|
||||
$this->isPost()
|
||||
) {
|
||||
// Creation du ZIP
|
||||
$filter = $this->getInput('configBackupOption', helper::FILTER_BOOLEAN) === true ? ['backup', 'tmp'] : ['backup', 'tmp', 'file'];
|
||||
$fileName = helper::autoBackup(self::TEMP_DIR, $filter);
|
||||
// Créer le répertoire manquant
|
||||
if (!is_dir(self::FILE_DIR . 'source/backup')) {
|
||||
mkdir(self::FILE_DIR . 'source/backup', 0755);
|
||||
}
|
||||
// Copie dans les fichiers
|
||||
$success = copy(self::TEMP_DIR . $fileName, self::FILE_DIR . 'source/backup/' . $fileName);
|
||||
// Détruire le temporaire
|
||||
unlink(self::TEMP_DIR . $fileName);
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'display' => self::DISPLAY_JSON,
|
||||
'content' => json_encode($success)
|
||||
]);
|
||||
} else {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'title' => helper::translate('Sauvegarder'),
|
||||
'view' => 'backup'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Réalise une copie d'écran du site
|
||||
*/
|
||||
public function configMetaImage()
|
||||
{
|
||||
// fonction désactivée pour un site local
|
||||
if (strpos(helper::baseUrl(false), 'localhost') > 0 or strpos(helper::baseUrl(false), '127.0.0.1') > 0) {
|
||||
$site = 'https://zwiicms.fr/';
|
||||
} else {
|
||||
$site = helper::baseUrl(false);
|
||||
}
|
||||
|
||||
// Clé de l'API
|
||||
$token = $this->getData(['config', 'seo', 'keyApi']);
|
||||
|
||||
// Succès de l'opération par défaut
|
||||
$success = false;
|
||||
$data = false;
|
||||
|
||||
// lire l'API si le token est fourni
|
||||
if (!empty($token)) {
|
||||
// Tente de connecter 5 fois l'API
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$data = helper::getUrlContents('https://shot.screenshotapi.net/screenshot?token=' . $token . '&url=' . $site . '&width=1200&height=627&output=json&file_type=jpeg&no_cookie_banners=true&wait_for_event=load');
|
||||
if ($data !== false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Traitement des données reçues valides.
|
||||
if (!empty($token) && $data !== false) {
|
||||
$data = json_decode($data, true);
|
||||
$img = $data['screenshot'];
|
||||
// Effacer l'image et la miniature png
|
||||
if (file_exists(self::FILE_DIR . 'thumb/screenshot.jpg')) {
|
||||
unlink(self::FILE_DIR . 'thumb/screenshot.jpg');
|
||||
}
|
||||
if (file_exists(self::FILE_DIR . 'source/screenshot.jpg')) {
|
||||
unlink(self::FILE_DIR . 'source/screenshot.jpg');
|
||||
}
|
||||
$success = copy($img, self::FILE_DIR . 'source/screenshot.jpg');
|
||||
}
|
||||
|
||||
$notification = empty($token)
|
||||
? 'La clé de l\'API ne peut pas être vide'
|
||||
: ($success === false ? 'Service en ligne inaccessible' : 'Capture d\'écran générée avec succès');
|
||||
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'redirect' => helper::baseUrl() . 'config',
|
||||
'notification' => helper::translate($notification),
|
||||
'state' => ($success === false or empty($token)) ? false : true
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Procédure d'importation
|
||||
*/
|
||||
public function restore()
|
||||
{
|
||||
// Soumission du formulaire
|
||||
if (
|
||||
$this->getUser('permission', __CLASS__, __FUNCTION__) === true &&
|
||||
$this->isPost()
|
||||
) {
|
||||
|
||||
$success = false;
|
||||
|
||||
if ($this->getInput('configRestoreImportFile', null, true)) {
|
||||
|
||||
$fileZip = $this->getInput('configRestoreImportFile');
|
||||
$file_parts = pathinfo($fileZip);
|
||||
// Validité du nom du fichier sélectionné
|
||||
if ($file_parts['extension'] !== 'zip') {
|
||||
// Valeurs en sortie erreur
|
||||
$this->addOutput([
|
||||
'title' => helper::translate('Restaurer'),
|
||||
'view' => 'restore',
|
||||
'notification' => helper::translate('Archive invalide'),
|
||||
'state' => false
|
||||
]);
|
||||
}
|
||||
// Ouverture de l'archive
|
||||
$zip = new ZipArchive();
|
||||
if ($zip->open(self::FILE_DIR . 'source/' . $fileZip) === FALSE) {
|
||||
// Valeurs en sortie erreur
|
||||
$this->addOutput([
|
||||
'title' => helper::translate('Restaurer'),
|
||||
'view' => 'restore',
|
||||
'notification' => helper::translate('Archive invalide'),
|
||||
'state' => false
|
||||
]);
|
||||
}
|
||||
|
||||
// Extraction de l'archive dans un dossier temporaire
|
||||
$tmpDir = uniqid(8);
|
||||
$success = $zip->extractTo(self::TEMP_DIR . $tmpDir);
|
||||
// Version de l'archive
|
||||
$data = json_decode(file_get_contents(self::TEMP_DIR . $tmpDir . '/data/core.json'), true);
|
||||
$dataVersion = $data['core']['dataVersion'];
|
||||
// Version non prises en charge <9 ou erreur d'extraction
|
||||
if (intval(substr($dataVersion, 0, 1)) <= 9 or !$success) {
|
||||
// Valeurs en sortie erreur
|
||||
$this->addOutput([
|
||||
'title' => helper::translate('Restaurer'),
|
||||
'view' => 'restore',
|
||||
'notification' => helper::translate('Archive invalide'),
|
||||
'state' => false
|
||||
]);
|
||||
}
|
||||
|
||||
// Fermer le zip
|
||||
$zip->close();
|
||||
|
||||
// Option active, préservation des utilisateurs
|
||||
if ($this->getInput('configRestoreImportUser', helper::FILTER_BOOLEAN) === true) {
|
||||
$users = $this->getData(['user']);
|
||||
}
|
||||
|
||||
// Copie dans le dossier /site/data
|
||||
$success = $this->copyDir(self::TEMP_DIR . $tmpDir, 'site/');
|
||||
$this->deleteDir(self::TEMP_DIR . $tmpDir);
|
||||
|
||||
// Restaurer les users originaux d'une v10 si option cochée
|
||||
if (
|
||||
$this->getInput('configRestoreImportUser', helper::FILTER_BOOLEAN) === true
|
||||
) {
|
||||
$this->setData(['user', $users]);
|
||||
}
|
||||
}
|
||||
|
||||
// Message de notification
|
||||
$notification = $success === true ? 'Restauration effectuée avec succès' : 'Erreur inconnue';
|
||||
$redirect = $this->getInput('configRestoreImportUser', helper::FILTER_BOOLEAN) === true ? helper::baseUrl() . 'config/restore' : helper::baseUrl() . 'user/login/';
|
||||
// Valeurs en sortie erreur
|
||||
$this->addOutput([
|
||||
'redirect' => $redirect,
|
||||
'notification' => helper::translate($notification),
|
||||
'state' => $success
|
||||
]);
|
||||
}
|
||||
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'title' => helper::translate('Restaurer'),
|
||||
'view' => 'restore'
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Configuration
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
// Soumission du formulaire
|
||||
if (
|
||||
$this->getUser('permission', __CLASS__, __FUNCTION__) === true &&
|
||||
$this->isPost()
|
||||
) {
|
||||
|
||||
// Basculement en mise à jour auto, remise à 0 du compteur
|
||||
if (
|
||||
$this->getData(['config', 'autoUpdate']) === false &&
|
||||
$this->getInput('configAutoUpdate', helper::FILTER_BOOLEAN) === true
|
||||
) {
|
||||
$this->setData(['core', 'lastAutoUpdate', 0]);
|
||||
}
|
||||
|
||||
// Sauvegarder la configuration
|
||||
$this->setData([
|
||||
'config',
|
||||
[
|
||||
'favicon' => $this->getInput('configFavicon'),
|
||||
'faviconDark' => $this->getInput('configFaviconDark'),
|
||||
'timezone' => $this->getInput('configTimezone', helper::FILTER_STRING_SHORT, true),
|
||||
'autoUpdate' => $this->getInput('configAutoUpdate', helper::FILTER_BOOLEAN),
|
||||
'autoUpdateHtaccess' => $this->getInput('configAutoUpdateHtaccess', helper::FILTER_BOOLEAN),
|
||||
'autoBackup' => $this->getInput('configAutoBackup', helper::FILTER_BOOLEAN),
|
||||
'maintenance' => $this->getInput('configMaintenance', helper::FILTER_BOOLEAN),
|
||||
'cookieConsent' => $this->getInput('configCookieConsent', helper::FILTER_BOOLEAN),
|
||||
'proxyType' => $this->getInput('configProxyType'),
|
||||
'proxyUrl' => $this->getInput('configProxyUrl'),
|
||||
'proxyPort' => $this->getInput('configProxyPort', helper::FILTER_INT),
|
||||
'autoUpdateDelay' => $this->getInput('configAutoUpdateDelay', helper::FILTER_INT),
|
||||
'homePageId' => $this->getInput('configLocaleHomePageId', helper::FILTER_ID, true),
|
||||
'page404' => $this->getInput('configLocalePage404'),
|
||||
'page403' => $this->getInput('configLocalePage403'),
|
||||
'page302' => $this->getInput('configLocalePage302'),
|
||||
'legalPageId' => $this->getInput('configLocaleLegalPageId'),
|
||||
'searchPageId' => $this->getInput('configLocaleSearchPageId'),
|
||||
'poweredPageLabel' => empty($this->getInput('configLocalePoweredPageLabel', helper::FILTER_STRING_SHORT)) ? 'Motorisé par' : $this->getInput('configLocalePoweredPageLabel', helper::FILTER_STRING_SHORT),
|
||||
'searchPageLabel' => empty($this->getInput('configLocaleSearchPageLabel', helper::FILTER_STRING_SHORT)) ? 'Rechercher' : $this->getInput('configLocaleSearchPageLabel', helper::FILTER_STRING_SHORT),
|
||||
'legalPageLabel' => empty($this->getInput('configLocaleLegalPageLabel', helper::FILTER_STRING_SHORT)) ? 'Mentions légales' : $this->getInput('configLocaleLegalPageLabel', helper::FILTER_STRING_SHORT),
|
||||
'sitemapPageLabel' => empty($this->getInput('configLocaleSitemapPageLabel', helper::FILTER_STRING_SHORT)) ? 'Plan du site' : $this->getInput('configLocaleSitemapPageLabel', helper::FILTER_STRING_SHORT),
|
||||
'metaDescription' => $this->getInput('configLocaleMetaDescription', helper::FILTER_STRING_LONG, true),
|
||||
'title' => $this->getInput('configLocaleTitle', helper::FILTER_STRING_SHORT, true),
|
||||
'cookies' => [
|
||||
// Les champs sont obligatoires si l'option consentement des cookies est active
|
||||
'mainLabel' => $this->getInput('configLocaleCookiesZwiiText', helper::FILTER_STRING_LONG, $this->getInput('configCookieConsent', helper::FILTER_BOOLEAN)),
|
||||
'titleLabel' => $this->getInput('configLocaleCookiesTitleText', helper::FILTER_STRING_SHORT, $this->getInput('configCookieConsent', helper::FILTER_BOOLEAN)),
|
||||
'linkLegalLabel' => $this->getInput('configLocaleCookiesLinkMlText', helper::FILTER_STRING_SHORT, $this->getInput('configCookieConsent', helper::FILTER_BOOLEAN)),
|
||||
'cookiesFooterText' => $this->getInput('configLocaleCookiesFooterText', helper::FILTER_STRING_SHORT, $this->getInput('configCookieConsent', helper::FILTER_BOOLEAN)),
|
||||
'buttonValidLabel' => $this->getInput('configLocaleCookiesButtonText', helper::FILTER_STRING_SHORT, $this->getInput('configCookieConsent', helper::FILTER_BOOLEAN)),
|
||||
],
|
||||
'social' => [
|
||||
'facebookId' => $this->getInput('socialFacebookId'),
|
||||
'linkedinId' => $this->getInput('socialLinkedinId'),
|
||||
'instagramId' => $this->getInput('socialInstagramId'),
|
||||
'pinterestId' => $this->getInput('socialPinterestId'),
|
||||
'twitterId' => $this->getInput('socialTwitterId'),
|
||||
'youtubeId' => $this->getInput('socialYoutubeId'),
|
||||
'youtubeUserId' => $this->getInput('socialYoutubeUserId'),
|
||||
'githubId' => $this->getInput('socialGithubId'),
|
||||
'redditId' => $this->getInput('socialRedditId'),
|
||||
'twitchId' => $this->getInput('socialTwitchId'),
|
||||
'vimeoId' => $this->getInput('socialVimeoId'),
|
||||
'steamId' => $this->getInput('socialSteamId'),
|
||||
],
|
||||
'smtp' => [
|
||||
'enable' => $this->getInput('smtpEnable', helper::FILTER_BOOLEAN),
|
||||
'host' => $this->getInput('smtpHost', helper::FILTER_STRING_SHORT),
|
||||
'port' => $this->getInput('smtpPort', helper::FILTER_INT),
|
||||
'auth' => $this->getInput('smtpAuth', helper::FILTER_BOOLEAN),
|
||||
'secure' => $this->getInput('smtpSecure', helper::FILTER_STRING_SHORT),
|
||||
'username' => $this->getInput('smtpUsername', helper::FILTER_STRING_SHORT),
|
||||
'password' => helper::encrypt($this->getInput('smtpPassword', helper::FILTER_STRING_SHORT), $this->getInput('smtpHost', helper::FILTER_STRING_SHORT)),
|
||||
'from' => $this->getInput('smtpFrom', helper::FILTER_MAIL, true),
|
||||
],
|
||||
'seo' => [
|
||||
'robots' => $this->getInput('seoRobots', helper::FILTER_BOOLEAN),
|
||||
'openGraphImage' => $this->getInput('seoOpenGraphImage', helper::FILTER_STRING_SHORT),
|
||||
],
|
||||
'connect' => [
|
||||
'attempt' => $this->getInput('connectAttempt', helper::FILTER_INT),
|
||||
'timeout' => $this->getInput('connectTimeout', helper::FILTER_INT),
|
||||
'log' => $this->getInput('connectLog', helper::FILTER_BOOLEAN),
|
||||
'anonymousIp' => $this->getInput('connectAnonymousIp', helper::FILTER_INT),
|
||||
'captcha' => $this->getInput('connectCaptcha', helper::FILTER_BOOLEAN),
|
||||
'captchaStrong' => $this->getInput('connectCaptchaStrong', helper::FILTER_BOOLEAN),
|
||||
'autoDisconnect' => $this->getInput('connectAutoDisconnect', helper::FILTER_BOOLEAN),
|
||||
'captchaType' => $this->getInput('connectCaptchaType'),
|
||||
'showPassword' => $this->getInput('connectShowPassword', helper::FILTER_BOOLEAN),
|
||||
'redirectLogin' => $this->getInput('connectRedirectLogin', helper::FILTER_BOOLEAN)
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
// Efface les fichiers de backup lorsque l'option est désactivée
|
||||
if ($this->getInput('configFileBackup', helper::FILTER_BOOLEAN) === false) {
|
||||
$path = realpath('site/data');
|
||||
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)) as $filename) {
|
||||
if (strpos($filename, 'backup.json')) {
|
||||
unlink($filename);
|
||||
}
|
||||
}
|
||||
if (file_exists('site/data/.backup'))
|
||||
unlink('site/data/.backup');
|
||||
} else {
|
||||
touch('site/data/.backup');
|
||||
}
|
||||
// Notice
|
||||
if (self::$inputNotices === []) {
|
||||
// Active la réécriture d'URL
|
||||
$rewrite = $this->getInput('configRewrite', helper::FILTER_BOOLEAN);
|
||||
if (
|
||||
$rewrite
|
||||
and helper::checkRewrite() === false
|
||||
) {
|
||||
// Ajout des lignes dans le .htaccess
|
||||
$fileContent = file_get_contents('.htaccess');
|
||||
$rewriteData = PHP_EOL .
|
||||
'# URL rewriting' . PHP_EOL .
|
||||
'<IfModule mod_rewrite.c>' . PHP_EOL .
|
||||
"\tRewriteEngine on" . PHP_EOL .
|
||||
"\tRewriteBase " . helper::baseUrl(false, false) . PHP_EOL .
|
||||
"\tRewriteCond %{REQUEST_FILENAME} !-f" . PHP_EOL .
|
||||
"\tRewriteCond %{REQUEST_FILENAME} !-d" . PHP_EOL .
|
||||
"\tRewriteRule ^(.*)$ index.php?$1 [L]" . PHP_EOL .
|
||||
'</IfModule>' . PHP_EOL .
|
||||
'# URL rewriting' . PHP_EOL;
|
||||
$fileContent = str_replace('# URL rewriting', $rewriteData, $fileContent);
|
||||
file_put_contents(
|
||||
'.htaccess',
|
||||
$fileContent
|
||||
);
|
||||
// Change le statut de la réécriture d'URL (pour le helper::baseUrl() de la redirection)
|
||||
helper::$rewriteStatus = true;
|
||||
}
|
||||
// Désactive la réécriture d'URL
|
||||
elseif (
|
||||
$rewrite === false
|
||||
and helper::checkRewrite()
|
||||
) {
|
||||
// Suppression des lignes dans le .htaccess
|
||||
$fileContent = file_get_contents('.htaccess');
|
||||
$fileContent = explode('# URL rewriting', $fileContent);
|
||||
$fileContent = $fileContent[0] . '# URL rewriting' . $fileContent[2];
|
||||
file_put_contents(
|
||||
'.htaccess',
|
||||
$fileContent
|
||||
);
|
||||
// Change le statut de la réécriture d'URL (pour le helper::baseUrl() de la redirection)
|
||||
helper::$rewriteStatus = false;
|
||||
}
|
||||
}
|
||||
// Générer robots.txt et sitemap
|
||||
$this->siteMap();
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'title' => helper::translate('Configuration'),
|
||||
'view' => 'index',
|
||||
'notification' => helper::translate('Modifications enregistrées'),
|
||||
'state' => true
|
||||
]);
|
||||
}
|
||||
|
||||
// Activation du bouton de mise à jour
|
||||
if (
|
||||
helper::checkNewVersion(common::ZWII_UPDATE_CHANNEL)
|
||||
&& $this->getData(['core', 'updateAvailable']) === false
|
||||
&& $this->getData(['config', 'autoUpdate'])
|
||||
) {
|
||||
$this->setData(['core', 'updateAvailable', true]);
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'redirect' => helper::baseUrl() . 'config',
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
// Variable de version
|
||||
if (helper::checkNewVersion(common::ZWII_UPDATE_CHANNEL)) {
|
||||
self::$updateButtonText = helper::translate('Mettre à jour');
|
||||
}
|
||||
|
||||
|
||||
// Sélecteur de délais, compléter avec la traduction en jours
|
||||
foreach (self::$updateDelay as $key => $value) {
|
||||
self::$updateDelay[$key] = $key === 86400 ? $value . ' ' . helper::translate('jour') : $value . ' ' . helper::translate('jours');
|
||||
}
|
||||
|
||||
// Paramètres de l'image OpenGraph
|
||||
$imagePath = self::FILE_DIR . 'source/' . $this->getData(['config', 'seo', 'openGraphImage']);
|
||||
|
||||
// Par défaut
|
||||
self::$imageOpenGraph['type'] = '';
|
||||
self::$imageOpenGraph['size'] = '';
|
||||
self::$imageOpenGraph['wide'] = '';
|
||||
self::$imageOpenGraph['height'] = '';
|
||||
self::$imageOpenGraph['ratio'] = 0;
|
||||
if (
|
||||
$this->getData(['config', 'seo', 'openGraphImage'])
|
||||
&& file_exists($imagePath)
|
||||
) {
|
||||
// Infos sur l'image Open Graph
|
||||
$typeMime = exif_imagetype($imagePath);
|
||||
switch ($typeMime) {
|
||||
case IMAGETYPE_JPEG:
|
||||
$typeMime = 'jpeg';
|
||||
break;
|
||||
case IMAGETYPE_PNG:
|
||||
$typeMime = 'png';
|
||||
break;
|
||||
default:
|
||||
$typeMime = image_type_to_mime_type($typeMime);
|
||||
}
|
||||
self::$imageOpenGraph['type'] = $typeMime;
|
||||
$imageSize = getimagesize($imagePath);
|
||||
self::$imageOpenGraph['wide'] = $imageSize[0];
|
||||
self::$imageOpenGraph['height'] = $imageSize[1];
|
||||
self::$imageOpenGraph['ratio'] = self::$imageOpenGraph['wide'] / self::$imageOpenGraph['height'];
|
||||
|
||||
self::$imageOpenGraph['size'] = filesize($imagePath);
|
||||
$tailleEnOctets = filesize($imagePath);
|
||||
|
||||
if ($tailleEnOctets >= 1024 * 1024) {
|
||||
// Si la taille est supérieure ou égale à 1 Mo, afficher en mégaoctets
|
||||
self::$imageOpenGraph['size'] = round($tailleEnOctets / (1024 * 1024), 2) . ' Mo';
|
||||
} else {
|
||||
// Sinon, afficher en kilooctets
|
||||
self::$imageOpenGraph['size'] = round($tailleEnOctets / 1024, 2) . ' Ko';
|
||||
}
|
||||
}
|
||||
|
||||
// Générer la liste des pages disponibles
|
||||
self::$pagesList = $this->getData(['page']);
|
||||
foreach (self::$pagesList as $page => $pageId) {
|
||||
if (
|
||||
$this->getData(['page', $page, 'block']) === 'bar' ||
|
||||
$this->getData(['page', $page, 'disable']) === true
|
||||
) {
|
||||
unset(self::$pagesList[$page]);
|
||||
}
|
||||
}
|
||||
|
||||
self::$orphansList = $this->getData(['page']);
|
||||
foreach (self::$orphansList as $page => $pageId) {
|
||||
if (
|
||||
$this->getData(['page', $page, 'block']) === 'bar' ||
|
||||
$this->getData(['page', $page, 'disable']) === true ||
|
||||
$this->getdata(['page', $page, 'position']) !== 0
|
||||
) {
|
||||
unset(self::$orphansList[$page]);
|
||||
}
|
||||
}
|
||||
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'title' => helper::translate('Configuration'),
|
||||
'view' => 'index'
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
public function script()
|
||||
{
|
||||
// Soumission du formulaire
|
||||
if (
|
||||
$this->getUser('permission', __CLASS__, __FUNCTION__) === true &&
|
||||
$this->isPost()
|
||||
) {
|
||||
// Ecrire les fichiers de script
|
||||
if ($this->geturl(2) === 'head') {
|
||||
file_put_contents(self::DATA_DIR . 'head.inc.html', $this->getInput('configScriptHead', null));
|
||||
}
|
||||
if ($this->geturl(2) === 'body') {
|
||||
file_put_contents(self::DATA_DIR . 'body.inc.html', $this->getInput('configScriptBody', null));
|
||||
}
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'title' => helper::translate('Éditeur de script dans ' . ucfirst($this->geturl(2))),
|
||||
'vendor' => [
|
||||
'codemirror'
|
||||
],
|
||||
'view' => 'script',
|
||||
'state' => true
|
||||
]);
|
||||
}
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'title' => sprintf(helper::translate('Éditeur de script %s'), ucfirst($this->geturl(2))),
|
||||
'vendor' => [
|
||||
'codemirror'
|
||||
],
|
||||
'view' => 'script'
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Vider le fichier de log
|
||||
*/
|
||||
|
||||
public function logReset()
|
||||
{
|
||||
// Action interdite
|
||||
if (
|
||||
$this->getUser('permission', __CLASS__, __FUNCTION__) !== true
|
||||
) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'access' => false
|
||||
]);
|
||||
} else {
|
||||
if (file_exists(self::DATA_DIR . 'journal.log')) {
|
||||
unlink(self::DATA_DIR . 'journal.log');
|
||||
// Créer les en-têtes des journaux
|
||||
$d = 'Date;Heure;IP;Id;Action' . PHP_EOL;
|
||||
file_put_contents(self::DATA_DIR . 'journal.log', $d);
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'title' => helper::translate('Configuration'),
|
||||
'view' => 'index',
|
||||
'notification' => helper::translate('Journal réinitialisé avec succès'),
|
||||
'state' => true
|
||||
]);
|
||||
} else {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'title' => helper::translate('Configuration'),
|
||||
'view' => 'index',
|
||||
'notification' => helper::translate('Aucun journal à effacer'),
|
||||
'state' => false
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Télécharger le fichier de log
|
||||
*/
|
||||
public function logDownload()
|
||||
{
|
||||
// Action interdite
|
||||
if (
|
||||
$this->getUser('permission', __CLASS__, __FUNCTION__) !== true
|
||||
) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'access' => false
|
||||
]);
|
||||
} else {
|
||||
$fileName = self::DATA_DIR . 'journal.log';
|
||||
if (file_exists($fileName)) {
|
||||
ob_start();
|
||||
header('Content-Description: File Transfer');
|
||||
header('Content-Type: application/octet-stream');
|
||||
header('Content-Disposition: attachment; filename="' . $fileName . '"');
|
||||
header('Content-Length: ' . filesize($fileName));
|
||||
ob_clean();
|
||||
ob_end_flush();
|
||||
readfile($fileName);
|
||||
exit();
|
||||
} else {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'title' => helper::translate('Configuration'),
|
||||
'view' => 'index',
|
||||
'notification' => helper::translate('Aucun fichier journal à télécharger'),
|
||||
'state' => false
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tableau des IP blacklistés
|
||||
*/
|
||||
public function blacklistDownload()
|
||||
{
|
||||
// Action interdite
|
||||
if (
|
||||
$this->getUser('permission', __CLASS__, __FUNCTION__) !== true
|
||||
) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'access' => false
|
||||
]);
|
||||
} else {
|
||||
ob_start();
|
||||
$fileName = self::TEMP_DIR . 'blacklist.log';
|
||||
$d = 'Date dernière tentative;Heure dernière tentative;Id;Adresse IP;Nombre d\'échecs' . PHP_EOL;
|
||||
file_put_contents($fileName, $d);
|
||||
if (file_exists($fileName)) {
|
||||
$d = $this->getData(['blacklist']);
|
||||
$data = '';
|
||||
foreach ($d as $key => $item) {
|
||||
$data .= helper::dateUTF8('%Y %m %d', $item['lastFail']) . ' - ' . helper::dateUTF8('%H:%M', time());
|
||||
$data .= $key . ';' . $item['ip'] . ';' . $item['connectFail'] . PHP_EOL;
|
||||
}
|
||||
file_put_contents($fileName, $data, FILE_APPEND);
|
||||
header('Content-Description: File Transfer');
|
||||
header('Content-Type: application/octet-stream');
|
||||
header('Content-Transfer-Encoding: binary');
|
||||
header('Content-Disposition: attachment; filename="' . $fileName . '"');
|
||||
header('Content-Length: ' . filesize($fileName));
|
||||
ob_clean();
|
||||
ob_end_flush();
|
||||
readfile($fileName);
|
||||
unlink(self::TEMP_DIR . 'blacklist.log');
|
||||
exit();
|
||||
} else {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'title' => helper::translate('Configuration'),
|
||||
'view' => 'index',
|
||||
'notification' => helper::translate('Aucune liste noire à télécharger'),
|
||||
'state' => false
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Réinitialiser les ip blacklistées
|
||||
*/
|
||||
|
||||
public function blacklistReset()
|
||||
{
|
||||
// Action interdite
|
||||
if (
|
||||
$this->getUser('permission', __CLASS__, __FUNCTION__) !== true
|
||||
) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'access' => false
|
||||
]);
|
||||
} else {
|
||||
if (file_exists(self::DATA_DIR . 'blacklist.json')) {
|
||||
$this->setData(['blacklist', []]);
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'title' => helper::translate('Configuration'),
|
||||
'view' => 'index',
|
||||
'notification' => helper::translate('Liste noire réinitialisée avec succès'),
|
||||
'state' => true
|
||||
]);
|
||||
} else {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'title' => helper::translate('Configuration'),
|
||||
'view' => 'index',
|
||||
'notification' => helper::translate('Aucune liste noire à effacer'),
|
||||
'state' => false
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupération des backups auto dans le gestionnaire de fichiers
|
||||
*/
|
||||
public function copyBackups()
|
||||
{
|
||||
// Action interdite
|
||||
if (
|
||||
$this->getUser('permission', __CLASS__, __FUNCTION__) !== true
|
||||
) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'access' => false
|
||||
]);
|
||||
} else {
|
||||
|
||||
$success = $this->copyDir(self::BACKUP_DIR, self::FILE_DIR . 'source/backup');
|
||||
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'title' => helper::translate('Configuration'),
|
||||
'view' => 'index',
|
||||
'notification' => $success ? helper::translate('Copie terminée avec succès') : helper::translate('Copie terminée avec des erreurs'),
|
||||
'state' => $success
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Vider le dosser des sauvegardes automatisées
|
||||
*/
|
||||
public function delBackups()
|
||||
{
|
||||
// Action interdite
|
||||
if (
|
||||
$this->getUser('permission', __CLASS__, __FUNCTION__) !== true
|
||||
) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'access' => false
|
||||
]);
|
||||
} else {
|
||||
$path = realpath(self::BACKUP_DIR);
|
||||
$success = $fail = 0;
|
||||
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)) as $filename) {
|
||||
if (strpos($filename, '.zip')) {
|
||||
|
||||
$r = unlink($filename);
|
||||
$success = $r === true ? $success + 1 : $success;
|
||||
$fail = $r === false ? $fail + 1 : $fail;
|
||||
}
|
||||
}
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'title' => helper::translate('Configuration'),
|
||||
'view' => 'index',
|
||||
'notification' => $success . helper::translate('Fichiers effacés') . ' - ' . helper::translate('Échecs') . ': ' . $fail,
|
||||
'state' => true
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
BIN
core/module/config/ressource/ajax-loader.png
Normal file
BIN
core/module/config/ressource/ajax-loader.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.3 KiB |
18
core/module/config/view/backup/backup.css
Normal file
18
core/module/config/view/backup/backup.css
Normal file
@ -0,0 +1,18 @@
|
||||
/**
|
||||
* 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
|
||||
* @author Frédéric Tempez <frederic.tempez@outlook.com>
|
||||
* @copyright Copyright (C) 2018-2023, Frédéric Tempez
|
||||
* @license CC Attribution-NonCommercial-NoDerivatives 4.0 International
|
||||
* @link http://zwiicms.fr/
|
||||
*/
|
||||
|
||||
/** NE PAS EFFACER
|
||||
* admin.css
|
||||
*/
|
||||
|
12
core/module/config/view/backup/backup.js.php
Normal file
12
core/module/config/view/backup/backup.js.php
Normal file
@ -0,0 +1,12 @@
|
||||
/**
|
||||
* 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 Frédéric Tempez <frederic.tempez@outlook.com>
|
||||
* @copyright Copyright (C) 2018-2023, Frédéric Tempez
|
||||
* @license CC Attribution-NonCommercial-NoDerivatives 4.0 International
|
||||
* @link http://zwiicms.fr/
|
||||
*/
|
||||
$(document).ready((function(){$("#configBackupForm").submit((function(e){e.preventDefault();var url="<?php echo helper::baseUrl() . $this->getUrl(0); ?>/backup",message_success="<?php echo helper::translate('Sauvegarde générée avec succès.'); ?>",message_error="<?php echo helper::translate('Erreur : sauvegarde non générée !'); ?>",message_title="<?php echo helper::translate('Sauvegarder'); ?>";$.ajax({type:"POST",url:url,data:$("form").serialize(),success:function(data){$("body, .button").css("cursor","default"),core.alert(message_success)},error:function(data){$("body, .button").css("cursor","default"),core.alert(message_error)},complete:function(){$("#configBackupSubmit").removeClass("disabled").prop("disabled",!1),$("#configBackupSubmit").removeClass("uniqueSubmission").prop("uniqueSubmission",!1),$("#configBackupSubmit span").removeClass("zwiico-spin animate-spin"),$("#configBackupSubmit span").addClass("zwiico-check zwiico-margin-right").text(message_title)}})})),$("#configBackupSubmit").on("click",(function(){if($("input[name=configBackupOption]").is(":checked")){var message_warning="<?php echo helper::translate('La sauvegarde des fichiers peut prendre du temps. Continuer ?'); ?>";return core.confirm(message_warning,(function(){$("body, .button").css("cursor","wait"),$("form#configBackupForm").submit()}))}}))}));
|
36
core/module/config/view/backup/backup.php
Normal file
36
core/module/config/view/backup/backup.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php echo template::formOpen('configBackupForm'); ?>
|
||||
<div class="row">
|
||||
<div class="col1">
|
||||
<?php echo template::button('configBackupBack', [
|
||||
'class' => 'buttonGrey',
|
||||
'href' => helper::baseUrl() . 'config',
|
||||
'value' => template::ico('left')
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col2 offset9">
|
||||
<?php echo template::submit('configBackupSubmit', [
|
||||
'value' => 'Sauvegarder',
|
||||
'uniqueSubmission' => true
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<div class="block">
|
||||
<h4><?php echo helper::translate('Paramètres de la sauvegarde'); ?>
|
||||
</h4>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<?php echo template::checkbox('configBackupOption', true, 'Inclure le contenu du gestionnaire de fichiers', [
|
||||
'checked' => true,
|
||||
'help' => 'Si le contenu du gestionnaire de fichiers est très volumineux, mieux vaut une copie par FTP.'
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col12">
|
||||
<em>L'archive est générée dans <a href="<?php echo helper::baseUrl(false); ?>core/vendor/filemanager/dialog.php?fldr=backup&type=0&akey=<?php echo md5_file(self::DATA_DIR . 'core.json'); ?>&lang=<?php echo $this->getData(['user', $this->getUser('id'), 'language']);?>" data-lity>le dossier Backup</a> du gestionnaire de fichiers.</em>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php echo template::formClose(); ?>
|
134
core/module/config/view/connect/connect.php
Normal file
134
core/module/config/view/connect/connect.php
Normal file
@ -0,0 +1,134 @@
|
||||
<div id="connectContainer" class="tabContent">
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<div class="block">
|
||||
<h4><?php echo helper::translate('Sécurité de la connexion'); ?>
|
||||
<!--<span id="specialeHelpButton" class="helpDisplayButton">
|
||||
<a href="https://doc.zwiicms.fr/connexion" target="_blank" title="Cliquer pour consulter l'aide en ligne">
|
||||
<?php // echo template::ico('help', ['margin' => 'left']); ?>
|
||||
</a>
|
||||
</span>-->
|
||||
</h4>
|
||||
|
||||
<div class="row">
|
||||
<div class="col4">
|
||||
<?php echo template::checkbox('connectShowPassword', true, 'Dévoiler le mot de passe', [
|
||||
'checked' => $this->getData(['config', 'connect', 'showPassword']),
|
||||
'help' => 'Le survol d\'une icône de l\'écran de connexion affiche temporairement le mot de passe.'
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col4">
|
||||
<?php echo template::checkbox('connectAutoDisconnect', true, 'Déconnexion automatique', [
|
||||
'checked' => $this->getData(['config', 'connect', 'autoDisconnect']),
|
||||
'help' => 'Déconnecte les sessions ouvertes précédemment sur d\'autres navigateurs ou terminaux. Activation recommandée.'
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col4">
|
||||
<?php echo template::checkbox('connectRedirectLogin', true, 'Redirection vers la connexion', [
|
||||
'checked' => $this->getData(['config', 'connect', 'redirectLogin']),
|
||||
'help' => 'Cette redirection ne concerne que les pages d\'administration du site.'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col3">
|
||||
<?php echo template::select('connectAttempt', $module::$connectAttempt, [
|
||||
'label' => 'Limitation des tentatives',
|
||||
'selected' => $this->getData(['config', 'connect', 'attempt'])
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col3">
|
||||
<?php echo template::select('connectTimeout', $module::$connectTimeout, [
|
||||
'label' => 'Blocage après échecs',
|
||||
'selected' => $this->getData(['config', 'connect', 'timeout'])
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col3 verticalAlignBottom">
|
||||
<label id="helpBlacklist"><?php echo helper::translate('Liste noire'); ?>
|
||||
<?php echo template::help(
|
||||
'La liste noire énumère les tentatives de connexion à partir de comptes inexistants. Sont stockés : la date, l\'heure, le nom du compte et l\'IP.
|
||||
Après le nombre de tentatives autorisées, l\'IP et le compte sont bloqués.'
|
||||
);
|
||||
?>
|
||||
</label>
|
||||
<?php echo template::button('ConnectBlackListDownload', [
|
||||
'href' => helper::baseUrl() . 'config/blacklistDownload',
|
||||
'value' => 'Télécharger la liste',
|
||||
'ico' => 'download'
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col3 verticalAlignBottom">
|
||||
<?php echo template::button('CnnectBlackListReset', [
|
||||
'class' => 'buttonRed',
|
||||
'href' => helper::baseUrl() . 'config/blacklistReset',
|
||||
'value' => 'Réinitialiser la liste',
|
||||
'ico' => 'trash'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col3">
|
||||
<?php echo template::checkbox('connectCaptcha', true, 'Captcha à la connexion', [
|
||||
'checked' => $this->getData(['config', 'connect', 'captcha'])
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col3">
|
||||
<?php echo template::checkbox('connectCaptchaStrong', true, 'Captcha complexe', [
|
||||
'checked' => $this->getData(['config', 'connect', 'captchaStrong']),
|
||||
'help' => 'Option recommandée pour sécuriser la connexion. S\'applique à tous les captchas du site. Le captcha simple se limite à une addition de nombres de 0 à 10. Le captcha complexe utilise quatre opérations de nombres de 0 à 20. Activation recommandée.'
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col3">
|
||||
<?php echo template::select('connectCaptchaType', $module::$captchaTypes, [
|
||||
'label' => 'Type de captcha',
|
||||
'selected' => $this->getData(['config', 'connect', 'captchaType'])
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<div class="block">
|
||||
<h4><?php echo helper::translate('Journalisation'); ?>
|
||||
<!--<span id="specialeHelpButton" class="helpDisplayButton">
|
||||
<a href="https://doc.zwiicms.fr/journalisation" target="_blank" title="Cliquer pour consulter l'aide en ligne">
|
||||
<?php // echo template::ico('help', ['margin' => 'left']); ?>
|
||||
</a>
|
||||
</span>
|
||||
-->
|
||||
</h4>
|
||||
<div class="row">
|
||||
<div class="col3">
|
||||
<?php echo template::checkbox('connectLog', true, 'Activer la journalisation', [
|
||||
'checked' => $this->getData(['config', 'connect', 'log'])
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col3">
|
||||
<?php echo template::select('connectAnonymousIp', $module::$anonIP, [
|
||||
'label' => 'Anonymat des adresses IP',
|
||||
'selected' => $this->getData(['config', 'connect', 'anonymousIp']),
|
||||
'help' => 'La règlementation française impose un anonymat de niveau 2'
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col3 verticalAlignBottom">
|
||||
<?php echo template::button('ConfigLogDownload', [
|
||||
'href' => helper::baseUrl() . 'config/logDownload',
|
||||
'value' => 'Télécharger le journal',
|
||||
'ico' => 'download'
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col3 verticalAlignBottom">
|
||||
<?php echo template::button('ConnectLogReset', [
|
||||
'class' => 'buttonRed',
|
||||
'href' => helper::baseUrl() . 'config/logReset',
|
||||
'value' => 'Réinitialiser le journal',
|
||||
'ico' => 'trash'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
67
core/module/config/view/index/index.css
Normal file
67
core/module/config/view/index/index.css
Normal file
@ -0,0 +1,67 @@
|
||||
/**
|
||||
* 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
|
||||
* @author Frédéric Tempez <frederic.tempez@outlook.com>
|
||||
* @copyright Copyright (C) 2018-2023, Frédéric Tempez
|
||||
* @license CC Attribution-NonCommercial-NoDerivatives 4.0 International
|
||||
* @link http://zwiicms.fr/
|
||||
*/
|
||||
|
||||
|
||||
/** NE PAS EFFACER
|
||||
* admin.css
|
||||
*/
|
||||
|
||||
#setupContainer {
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
.buttonNotice {
|
||||
border: 2px solid red !important;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
/* Style the tab */
|
||||
.tab {
|
||||
margin-top: 1.8em;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tab~.tabContent {
|
||||
margin-top: -10px;
|
||||
}
|
||||
|
||||
.buttonTab {
|
||||
display: inline-block;
|
||||
transition: 0.3s;
|
||||
border-radius: 10px 10px 0px 0px;
|
||||
width: 160px;
|
||||
margin: 0 1px;
|
||||
}
|
||||
|
||||
.buttonTab:hover {
|
||||
filter: saturate(200%);
|
||||
}
|
||||
|
||||
.activeButton {
|
||||
background-color: #00BFFF;
|
||||
}
|
||||
|
||||
.greenInfo, .redInfo {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.greenInfo {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.redInfo {
|
||||
color: red;
|
||||
}
|
335
core/module/config/view/index/index.js.php
Normal file
335
core/module/config/view/index/index.js.php
Normal file
@ -0,0 +1,335 @@
|
||||
/**
|
||||
* 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 Frédéric Tempez <frederic.tempez@outlook.com>
|
||||
* @copyright Copyright (C) 2018-2023, Frédéric Tempez
|
||||
* @license CC Attribution-NonCommercial-NoDerivatives 4.0 International
|
||||
* @link http://zwiicms.fr/
|
||||
*/
|
||||
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
/**
|
||||
* Confirmation de suppression
|
||||
*/
|
||||
$("#configBackupDelButton").on("click", function () {
|
||||
var _this = $(this);
|
||||
var message_warning = "<?php echo helper::translate('Supprimer toutes les sauvegardes automatiques ?'); ?>";
|
||||
return core.confirm(message_warning, function () {
|
||||
$(location).attr("href", _this.attr("href"));
|
||||
});
|
||||
});
|
||||
|
||||
// Positionnement inital des options
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Afficher et masquer options smtp
|
||||
*/
|
||||
if ($("input[name=smtpEnable]").is(':checked')) {
|
||||
$("#smtpParam").addClass("disabled");
|
||||
$("#smtpParam").slideDown();
|
||||
} else {
|
||||
$("#smtpParam").removeClass("disabled");
|
||||
$("#smtpParam").slideUp();
|
||||
}
|
||||
/**
|
||||
* Afficher et masquer options Auth
|
||||
*/
|
||||
|
||||
if ($("select[name=smtpAuth]").val() == true) {
|
||||
$("#smtpAuthParam").addClass("disabled");
|
||||
$("#smtpAuthParam").slideDown();
|
||||
} else {
|
||||
$("#smtpAuthParam").removeClass("disabled");
|
||||
$("#smtpAuthParam").slideUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Afficher et masquer les options de captcha
|
||||
*/
|
||||
|
||||
if ($("input[name=connectCaptcha]").is(':checked')) {
|
||||
$("#connectCaptchaStrongWrapper").addClass("disabled");
|
||||
$("#connectCaptchaStrongWrapper").slideDown();
|
||||
$("#connectCaptchaTypeWrapper").addClass("disabled");
|
||||
$("#connectCaptchaTypeWrapper").slideDown();
|
||||
} else {
|
||||
$("#connectCaptchaStrongWrapper").removeClass("disabled");
|
||||
$("#connectCaptchaStrongWrapper").slideUp();
|
||||
$("#connectCaptchaTypeWrapper").removeClass("disabled");
|
||||
$("#connectCaptchaTypeWrapper").slideUp();
|
||||
$("#connectCaptchaStrong").prop("checked", false);
|
||||
}
|
||||
|
||||
var configLayout = getCookie("configLayout");
|
||||
if (configLayout == null) {
|
||||
configLayout = "setup";
|
||||
setCookie("configLayout", "setup");
|
||||
}
|
||||
$("#localeContainer").hide();
|
||||
$("#socialContainer").hide();
|
||||
$("#connectContainer").hide();
|
||||
$("#networkContainer").hide();
|
||||
$("#setupContainer").hide();
|
||||
$("#" + configLayout + "Container").show();
|
||||
$("#config" + capitalizeFirstLetter(configLayout) + "Button").addClass("activeButton");
|
||||
|
||||
|
||||
// Gestion des événements
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Afficher et masquer options smtp
|
||||
*/
|
||||
$("input[name=smtpEnable]").on("change", function () {
|
||||
if ($("input[name=smtpEnable]").is(':checked')) {
|
||||
$("#smtpParam").addClass("disabled");
|
||||
$("#smtpParam").slideDown();
|
||||
} else {
|
||||
$("#smtpParam").removeClass("disabled");
|
||||
$("#smtpParam").slideUp();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Afficher et masquer options Auth
|
||||
*/
|
||||
|
||||
$("select[name=smtpAuth]").on("change", function () {
|
||||
if ($("select[name=smtpAuth]").val() == true) {
|
||||
$("#smtpAuthParam").addClass("disabled");
|
||||
$("#smtpAuthParam").slideDown();
|
||||
} else {
|
||||
$("#smtpAuthParam").removeClass("disabled");
|
||||
$("#smtpAuthParam").slideUp();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Options de blocage de connexions
|
||||
* Contrôle la cohérence des sélections et interdit une seule valeur Aucune
|
||||
*/
|
||||
$("select[name=connectAttempt]").on("change", function () {
|
||||
if ($("select[name=connectAttempt]").val() === "999") {
|
||||
$("select[name=connectTimeout]").val(0);
|
||||
} else {
|
||||
if ($("select[name=connectTimeout]").val() === "0") {
|
||||
$("select[name=connectTimeout]").val(300);
|
||||
}
|
||||
}
|
||||
});
|
||||
$("select[name=connectTimeout]").on("change", function () {
|
||||
if ($("select[name=connectTimeout]").val() === "0") {
|
||||
$("select[name=connectAttempt]").val(999);
|
||||
} else {
|
||||
if ($("select[name=connectAttempt]").val() === "999") {
|
||||
$("select[name=connectAttempt]").val(3);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Captcha strong si captcha sélectionné
|
||||
*/
|
||||
$("input[name=connectCaptcha]").on("change", function () {
|
||||
|
||||
if ($("input[name=connectCaptcha]").is(':checked')) {
|
||||
$("#connectCaptchaStrongWrapper").addClass("disabled");
|
||||
$("#connectCaptchaStrongWrapper").slideDown();
|
||||
$("#connectCaptchaTypeWrapper").addClass("disabled");
|
||||
$("#connectCaptchaTypeWrapper").slideDown();
|
||||
|
||||
} else {
|
||||
$("#connectCaptchaStrongWrapper").removeClass("disabled");
|
||||
$("#connectCaptchaStrongWrapper").slideUp();
|
||||
$("#connectCaptchaTypeWrapper").removeClass("disabled");
|
||||
$("#connectCaptchaTypeWrapper").slideUp();
|
||||
$("#connectCaptchaStrong").prop("checked", false);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Sélection de la page de configuration à afficher
|
||||
*/
|
||||
$("#configLocaleButton").on("click", function () {
|
||||
$("#setupContainer").hide();
|
||||
$("#socialContainer").hide();
|
||||
$("#connectContainer").hide();
|
||||
$("#networkContainer").hide();
|
||||
$("#localeContainer").show();
|
||||
$("#configSetupButton").removeClass("activeButton");
|
||||
$("#configLocaleButton").addClass("activeButton");
|
||||
$("#configSocialButton").removeClass("activeButton");
|
||||
$("#configConnectButton").removeClass("activeButton");
|
||||
$("#configNetworkButton").removeClass("activeButton");
|
||||
setCookie("configLayout", "locale");
|
||||
});
|
||||
$("#configSetupButton").on("click", function () {
|
||||
$("#localeContainer").hide();
|
||||
$("#socialContainer").hide();
|
||||
$("#connectContainer").hide();
|
||||
$("#networkContainer").hide();
|
||||
$("#setupContainer").show();
|
||||
$("#configSetupButton").addClass("activeButton");
|
||||
$("#configLocaleButton").removeClass("activeButton");
|
||||
$("#configSocialButton").removeClass("activeButton");
|
||||
$("#configConnectButton").removeClass("activeButton");
|
||||
$("#configNetworkButton").removeClass("activeButton");
|
||||
setCookie("configLayout", "setup");
|
||||
});
|
||||
|
||||
$("#configSocialButton").on("click", function () {
|
||||
$("#connectContainer").hide();
|
||||
$("#setupContainer").hide();
|
||||
$("#localeContainer").hide();
|
||||
$("#networkContainer").hide();
|
||||
$("#socialContainer").show();
|
||||
$("#configSetupButton").removeClass("activeButton");
|
||||
$("#configLocaleButton").removeClass("activeButton");
|
||||
$("#configSocialButton").addClass("activeButton");
|
||||
$("#configConnectButton").removeClass("activeButton");
|
||||
$("#configNetworkButton").removeClass("activeButton");
|
||||
setCookie("configLayout", "social");
|
||||
});
|
||||
$("#configConnectButton").on("click", function () {
|
||||
$("#setupContainer").hide();
|
||||
$("#localeContainer").hide();
|
||||
$("#socialContainer").hide();
|
||||
$("#networkContainer").hide();
|
||||
$("#connectContainer").show();
|
||||
$("#configSetupButton").removeClass("activeButton");
|
||||
$("#configLocaleButton").removeClass("activeButton");
|
||||
$("#configSocialButton").removeClass("activeButton");
|
||||
$("#configConnectButton").addClass("activeButton");
|
||||
$("#configNetworkButton").removeClass("activeButton");
|
||||
setCookie("configLayout", "connect");
|
||||
});
|
||||
$("#configNetworkButton").on("click", function () {
|
||||
$("#setupContainer").hide();
|
||||
$("#localeContainer").hide();
|
||||
$("#socialContainer").hide();
|
||||
$("#connectContainer").hide();
|
||||
$("#networkContainer").show();
|
||||
$("#configSetupButton").removeClass("activeButton");
|
||||
$("#configLocaleButton").removeClass("activeButton");
|
||||
$("#configSocialButton").removeClass("activeButton");
|
||||
$("#configConnectButton").removeClass("activeButton");
|
||||
$("#configNetworkButton").addClass("activeButton");
|
||||
setCookie("configLayout", "network");
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Aspect de la souris
|
||||
*/
|
||||
$("#socialMetaImage, #socialSiteMap, #configBackupCopyButton").click(function (event) {
|
||||
$('body, .button').css('cursor', 'wait');
|
||||
});
|
||||
|
||||
|
||||
// Mise en évidence des erreurs de saisie dans les boutons de sélection
|
||||
var containers = ["setup", "locale", "social", "connect", "network"];
|
||||
$.each(containers, function (index, value) {
|
||||
var a = $("div#" + value + "Container").find("input.notice").not(".displayNone");
|
||||
if (a.length > 0) {
|
||||
$("#config" + capitalizeFirstLetter(value) + "Button").addClass("buttonNotice");
|
||||
} else {
|
||||
$("#config" + capitalizeFirstLetter(value) + "Button").removeClass("buttonNotice");
|
||||
}
|
||||
});
|
||||
|
||||
// Contrôle l'image Open Screen Graph
|
||||
// Type d'image
|
||||
$("span#screenType").each(function(){
|
||||
var text = $(this).text();
|
||||
if (text.includes("jpg") || text.includes("jpeg") || text.includes("png")) {
|
||||
$(this).css("color", "green");
|
||||
} else {
|
||||
$(this).css("color", "red");
|
||||
}
|
||||
});
|
||||
// La largeur
|
||||
$("span#screenWide").each(function(){
|
||||
var screenId = parseInt($(this).text());
|
||||
if (screenId >= 1200) {
|
||||
$(this).css("color", "green");
|
||||
} else {
|
||||
$(this).css("color", "red");
|
||||
}
|
||||
});
|
||||
// La hauteur
|
||||
$("span#screenHeight").each(function(){
|
||||
var screenId = parseInt($(this).text());
|
||||
if (screenId >= 630) {
|
||||
$(this).css("color", "green");
|
||||
} else {
|
||||
$(this).css("color", "red");
|
||||
}
|
||||
});
|
||||
// Le ratio
|
||||
$('span#screenRatio').each(function(){
|
||||
var ratio = parseFloat($(this).text());
|
||||
if (ratio >= 1.90 && ratio <= 1.92) {
|
||||
$(this).css("color", "green");
|
||||
$("#screenFract").css("color", "green");
|
||||
} else {
|
||||
$(this).css("color", "red");
|
||||
$("#screenFract").css("color", "red");
|
||||
}
|
||||
});
|
||||
// Le poids
|
||||
$('span#screenWeight').each(function(index){
|
||||
var weight = parseFloat($(this).text());
|
||||
var fileType = $('span#screenType').eq(index).text();
|
||||
if ((fileType === "jpg" || fileType === "jpeg") && weight < 5000000) {
|
||||
$(this).css("color", "green");
|
||||
} else {
|
||||
$(this).css("color", "red");
|
||||
}
|
||||
});
|
||||
|
||||
$('span#screenWeight').each(function(index){
|
||||
var weight = parseFloat($(this).text());
|
||||
var fileType = $('span#screenType').eq(index).text();
|
||||
|
||||
if (fileType === "png" && weight <= 1000000) {
|
||||
$(this).css("color", "green");
|
||||
} else {
|
||||
$(this).css("color", "red");
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
function setCookie(name, value, days) {
|
||||
var expires = "";
|
||||
if (days) {
|
||||
var date = new Date();
|
||||
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
||||
expires = "; expires=" + date.toUTCString();
|
||||
}
|
||||
document.cookie = name + "=" + (value || "") + expires + "; path=/; samesite=lax";
|
||||
}
|
||||
|
||||
function getCookie(name) {
|
||||
var nameEQ = name + "=";
|
||||
var ca = document.cookie.split(';');
|
||||
for (var i = 0; i < ca.length; i++) {
|
||||
var c = ca[i];
|
||||
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
|
||||
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Define function to capitalize the first letter of a string
|
||||
function capitalizeFirstLetter(string) {
|
||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||
}
|
54
core/module/config/view/index/index.php
Normal file
54
core/module/config/view/index/index.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php echo template::formOpen('configForm'); ?>
|
||||
<div class="row">
|
||||
<div class="col1">
|
||||
<?php echo template::button('configBack', [
|
||||
'class' => 'buttonGrey',
|
||||
'href' => helper::baseUrl(false),
|
||||
'value' => template::ico('home')
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col1">
|
||||
<?php /**echo template::button('configHelp', [
|
||||
'class' => 'buttonHelp',
|
||||
'href' => 'https://doc.zwiicms.fr/configuration-du-site',
|
||||
'target' => '_blank',
|
||||
'value' => template::ico('help'),
|
||||
'help' => 'Consulter l\'aide en ligne'
|
||||
]); */?>
|
||||
</div>
|
||||
<div class="col2 offset8">
|
||||
<?php echo template::submit('Submit'); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab">
|
||||
<?php echo template::button('configLocaleButton', [
|
||||
'value' => 'Localisation',
|
||||
'class' => 'buttonTab'
|
||||
]); ?>
|
||||
<?php echo template::button('configSetupButton', [
|
||||
'value' => 'Configuration',
|
||||
'class' => 'buttonTab'
|
||||
]); ?>
|
||||
<?php echo template::button('configSocialButton', [
|
||||
'value' => 'Référencement',
|
||||
'class' => 'buttonTab'
|
||||
]); ?>
|
||||
|
||||
<?php echo template::button('configConnectButton', [
|
||||
'value' => 'Connexion',
|
||||
'class' => 'buttonTab'
|
||||
]); ?>
|
||||
|
||||
<?php echo template::button('configNetworkButton', [
|
||||
'value' => 'Réseau',
|
||||
'class' => 'buttonTab'
|
||||
]); ?>
|
||||
|
||||
</div>
|
||||
<?php include('core/module/config/view/locale/locale.php') ?>
|
||||
<?php include('core/module/config/view/setup/setup.php') ?>
|
||||
<?php include('core/module/config/view/social/social.php') ?>
|
||||
<?php include('core/module/config/view/connect/connect.php') ?>
|
||||
<?php include('core/module/config/view/network/network.php') ?>
|
||||
<?php echo template::formClose(); ?>
|
17
core/module/config/view/locale/locale.css
Normal file
17
core/module/config/view/locale/locale.css
Normal file
@ -0,0 +1,17 @@
|
||||
/**
|
||||
* 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
|
||||
* @author Frédéric Tempez <frederic.tempez@outlook.com>
|
||||
* @copyright Copyright (C) 2018-2023, Frédéric Tempez
|
||||
* @license CC Attribution-NonCommercial-NoDerivatives 4.0 International
|
||||
* @link http://zwiicms.fr/
|
||||
*/
|
||||
|
||||
/** NE PAS EFFACER
|
||||
* admin.css
|
||||
*/
|
203
core/module/config/view/locale/locale.php
Normal file
203
core/module/config/view/locale/locale.php
Normal file
@ -0,0 +1,203 @@
|
||||
<div id="localeContainer" class="tabContent">
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<div class="block">
|
||||
<h4>
|
||||
<?php echo helper::translate('Identité du site'); ?>
|
||||
<!--<span id="localeHelpButton" class="helpDisplayButton" title="Cliquer pour consulter l'aide en ligne">
|
||||
<a href="https://doc.zwiicms.fr/localisation-et-identite" target="_blank">
|
||||
<?php //echo template::ico('help', ['margin' => 'left']); ?>
|
||||
</a>
|
||||
</span>-->
|
||||
</h4>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<?php echo template::text('configLocaleTitle', [
|
||||
'label' => 'Titre',
|
||||
'value' => $this->getData(['config', 'title']),
|
||||
'help' => 'Il apparaît dans la barre de titre et les partages sur les réseaux sociaux.'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<?php echo template::textarea('configLocaleMetaDescription', [
|
||||
'label' => 'Description',
|
||||
'value' => $this->getData(['config', 'metaDescription']),
|
||||
'help' => 'La description d\'une page participe à son référencement, chaque page doit disposer d\'une description différente.'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<div class="block">
|
||||
<h4>
|
||||
<?php echo helper::translate('Assignation des pages spéciales') ?>
|
||||
<!--<span id="localeHelpButton" class="helpDisplayButton" title="Cliquer pour consulter l'aide en ligne">
|
||||
<a href="https://doc.zwiicms.fr/localisation-et-identite" target="_blank">
|
||||
<?php //echo template::ico('help', ['margin' => 'left']); ?>
|
||||
</a>
|
||||
</span>-->
|
||||
</h4>
|
||||
<div class="row">
|
||||
<div class="col4">
|
||||
<?php echo template::select('configLocaleHomePageId', helper::arrayColumn($module::$pagesList, 'title', 'SORT_ASC'), [
|
||||
'label' => 'Accueil',
|
||||
'selected' => $this->getData(['config', 'homePageId']),
|
||||
'help' => 'La première page que vos visiteurs verront.'
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col4">
|
||||
<?php echo template::select('configLocalePage403', array_merge(['none' => 'Page par défaut'], helper::arrayColumn($module::$orphansList, 'title', 'SORT_ASC')), [
|
||||
'label' => 'Accès interdit, erreur 403',
|
||||
'selected' => $this->getData(['config', 'page403']),
|
||||
'help' => 'Cette page ne doit pas apparaître dans l\'arborescence du menu. Créez une page orpheline.'
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col4">
|
||||
<?php echo template::select('configLocalePage404', array_merge(['none' => 'Page par défaut'], helper::arrayColumn($module::$orphansList, 'title', 'SORT_ASC')), [
|
||||
'label' => 'Page inexistante, erreur 404',
|
||||
'selected' => $this->getData(['config', 'page404']),
|
||||
'help' => 'Cette page ne doit pas apparaître dans l\'arborescence du menu. Créez une page orpheline.'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col4">
|
||||
<?php echo template::select('configLocaleLegalPageId', array_merge(['none' => 'Aucune'], helper::arrayColumn($module::$pagesList, 'title', 'SORT_ASC')), [
|
||||
'label' => 'Mentions légales',
|
||||
'selected' => $this->getData(['config', 'legalPageId']),
|
||||
'help' => 'Les mentions légales sont obligatoires en France. Une option du pied de page ajoute un lien discret vers cette page.'
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col4">
|
||||
<?php echo template::select('configLocaleSearchPageId', array_merge(['none' => 'Aucune'], helper::arrayColumn($module::$pagesList, 'title', 'SORT_ASC')), [
|
||||
'label' => 'Recherche dans le site',
|
||||
'selected' => $this->getData(['config', 'searchPageId']),
|
||||
'help' => 'Sélectionnez une page contenant le module \'Recherche\'. Une option du pied de page ajoute un lien discret vers cette page.'
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col4">
|
||||
<?php
|
||||
echo template::select('configLocalePage302', array_merge(['none' => 'Page par défaut'], helper::arrayColumn($module::$orphansList, 'title', 'SORT_ASC')), [
|
||||
'label' => 'Site en maintenance',
|
||||
'selected' => $this->getData(['config', 'page302']),
|
||||
'help' => 'Cette page ne doit pas apparaître dans l\'arborescence du menu. Créez une page orpheline.'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<div class="block">
|
||||
<h4>
|
||||
<?php echo helper::translate('Étiquettes des pages spéciales'); ?>
|
||||
<!--<span id="labelHelpButton" class="helpDisplayButton" title="Cliquer pour consulter l'aide en ligne">
|
||||
<a href="https://doc.zwiicms.fr/etiquettes-des-pages-speciales" target="_blank">
|
||||
<?php //echo template::ico('help', ['margin' => 'left']); ?>
|
||||
</a>
|
||||
</span>-->
|
||||
</h4>
|
||||
<div class="row">
|
||||
<div class="col4">
|
||||
<?php echo template::text('configLocalePoweredPageLabel', [
|
||||
'label' => 'Motorisé par',
|
||||
'placeholder' => 'Motorisé par',
|
||||
'value' => $this->getData(['config', 'poweredPageLabel']),
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col4">
|
||||
<?php echo template::text('configLocaleLegalPageLabel', [
|
||||
'label' => 'Mentions légales',
|
||||
'placeholder' => 'Mentions légales',
|
||||
'value' => $this->getData(['config', 'legalPageLabel']),
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col4">
|
||||
<?php echo template::text('configLocaleSearchPageLabel', [
|
||||
'label' => 'Rechercher',
|
||||
'placeholder' => 'Rechercher',
|
||||
'value' => $this->getData(['config', 'searchPageLabel']),
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col4 offset2">
|
||||
<?php echo template::text('configLocaleSitemapPageLabel', [
|
||||
'label' => 'Plan du site',
|
||||
'placeholder' => 'Plan du site',
|
||||
'value' => $this->getData(['config', 'sitemapPageLabel']),
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col4">
|
||||
<?php echo template::text('configLocaleCookiesFooterText', [
|
||||
'label' => 'Cookies',
|
||||
'value' => $this->getData(['config', 'cookiesFooterText']),
|
||||
'placeHolder' => 'Cookies'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<div class="block">
|
||||
<h4>
|
||||
<?php echo helper::translate('Message d\'acceptation des Cookies'); ?>
|
||||
<!--<span id="specialeHelpButton" class="helpDisplayButton" title="Cliquer pour consulter l'aide en ligne">
|
||||
<a href="https://doc.zwiicms.fr/cookies" target="_blank">
|
||||
<?php //echo template::ico('help', ['margin' => 'left']); ?>
|
||||
</a>
|
||||
</span>-->
|
||||
</h4>
|
||||
<div class="row">
|
||||
<div class="col4">
|
||||
<?php echo template::text('configLocaleCookiesTitleText', [
|
||||
'label' => 'Titre',
|
||||
'value' => $this->getData(['config', 'cookies', 'cookiesFooterText']),
|
||||
'placeHolder' => 'Cookies essentiels'
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col4">
|
||||
<?php echo template::text('configLocaleCookiesButtonText', [
|
||||
'label' => 'Bouton de validation',
|
||||
'value' => $this->getData(['config', 'cookies', 'buttonValidLabel']),
|
||||
'placeHolder' => 'J\'ai compris'
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col4">
|
||||
<?php echo template::text('configLocaleCookiesFooterText', [
|
||||
'label' => 'Texte dans le pied de page',
|
||||
'value' => $this->getData(['config', 'cookies', 'cookiesFooterText']),
|
||||
'placeHolder' => 'Cookies'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col8">
|
||||
<?php echo template::textarea('configLocaleCookiesZwiiText', [
|
||||
'help' => 'Saisissez le message pour les cookies déposés par ZwiiCMS, nécessaires au fonctionnement et qui ne nécessitent pas de consentement.',
|
||||
'label' => 'Cookies Zwii',
|
||||
'value' => $this->getData(['config', 'cookies', 'mainLabel']),
|
||||
'placeHolder' => 'Ce site utilise des cookies nécessaires à son fonctionnement, ils permettent de fluidifier son fonctionnement par exemple en mémorisant les données de connexion, la langue que vous avez choisie ou la validation de ce message.'
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col4">
|
||||
<?php echo template::text('configLocaleCookiesLinkMlText', [
|
||||
'help' => 'Saisissez le texte du lien vers les mentions légales,la page doit être définie dans la configuration du site.',
|
||||
'label' => 'Lien page des mentions légales.',
|
||||
'value' => $this->getData(['config', 'cookies', 'linkLegalLabel']),
|
||||
'placeHolder' => 'Consulter les mentions légales'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
115
core/module/config/view/network/network.php
Normal file
115
core/module/config/view/network/network.php
Normal file
@ -0,0 +1,115 @@
|
||||
<div id="networkContainer" class="tabContent">
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<div class="block">
|
||||
<h4>
|
||||
<?php echo helper::translate('Paramètres'); ?>
|
||||
<!--<span id="specialeHelpButton" class="helpDisplayButton">
|
||||
<a href="https://doc.zwiicms.fr/reseau" target="_blank" title="Cliquer pour consulter l'aide en ligne">
|
||||
<?php //echo template::ico('help', ['margin' => 'left']); ?>
|
||||
</a>
|
||||
</span>-->
|
||||
</h4>
|
||||
<div class="row">
|
||||
<div class="col2">
|
||||
<?php echo template::select('configProxyType', $module::$proxyType, [
|
||||
'label' => 'Type de proxy',
|
||||
'selected' => $this->getData(['config', 'proxyType'])
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col8">
|
||||
<?php echo template::text('configProxyUrl', [
|
||||
'label' => 'Adresse du proxy',
|
||||
'placeholder' => 'cache.proxy.fr',
|
||||
'value' => $this->getData(['config', 'proxyUrl'])
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col2">
|
||||
<?php echo template::text('configProxyPort', [
|
||||
'label' => 'Port du proxy',
|
||||
'placeholder' => '6060',
|
||||
'value' => $this->getData(['config', 'proxyPort'])
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<div class="block">
|
||||
<h4>
|
||||
<?php echo helper::translate('SMTP'); ?>
|
||||
<!--<span id="specialeHelpButton" class="helpDisplayButton">
|
||||
<a href="https://doc.zwiicms.fr/smtp" target="_blank" title="Cliquer pour consulter l'aide en ligne">
|
||||
<?php //echo template::ico('help', ['margin' => 'left']); ?>
|
||||
</a>
|
||||
</span>-->
|
||||
</h4>
|
||||
<div class="row">
|
||||
<div class="col6">
|
||||
<?php echo template::text('smtpFrom', [
|
||||
'label' => 'Expéditeur',
|
||||
'placeholder' => 'no-reply@host',
|
||||
'value' => $this->getData(['config', 'smtp', 'from']),
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<?php echo template::checkbox('smtpEnable', true, 'SMTP personnalisé', [
|
||||
'checked' => $this->getData(['config', 'smtp', 'enable']),
|
||||
'help' => 'Paramètres à utiliser lorsque votre hébergeur ne propose pas la fonctionnalité d\'envoi de mail.'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div id="smtpParam">
|
||||
<div class="row">
|
||||
<div class="col8">
|
||||
<?php echo template::text('smtpHost', [
|
||||
'label' => 'Adresse SMTP',
|
||||
'placeholder' => 'smtp.fr',
|
||||
'value' => $this->getData(['config', 'smtp', 'host'])
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col2">
|
||||
<?php echo template::text('smtpPort', [
|
||||
'label' => 'Port SMTP',
|
||||
'placeholder' => '589',
|
||||
'value' => $this->getData(['config', 'smtp', 'port'])
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col2">
|
||||
<?php echo template::select('smtpAuth', $module::$SMTPauth, [
|
||||
'label' => 'Authentification',
|
||||
'selected' => $this->getData(['config', 'smtp', 'auth'])
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div id="smtpAuthParam">
|
||||
<div class="row">
|
||||
<div class="col5">
|
||||
<?php echo template::text('smtpUsername', [
|
||||
'label' => 'Nom utilisateur',
|
||||
'value' => $this->getData(['config', 'smtp', 'username'])
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col5">
|
||||
<?php echo template::password('smtpPassword', [
|
||||
'label' => 'Mot de passe',
|
||||
'autocomplete' => 'off',
|
||||
'value' => $this->getData(['config', 'smtp', 'password'])
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col2">
|
||||
<?php echo template::select('smtpSecure', $module::$SMTPEnc, [
|
||||
'label' => 'Sécurité',
|
||||
'selected' => $this->getData(['config', 'smtp', 'secure'])
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
18
core/module/config/view/restore/restore.css
Normal file
18
core/module/config/view/restore/restore.css
Normal file
@ -0,0 +1,18 @@
|
||||
/**
|
||||
* 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
|
||||
* @author Frédéric Tempez <frederic.tempez@outlook.com>
|
||||
* @copyright Copyright (C) 2018-2023, Frédéric Tempez
|
||||
* @license CC Attribution-NonCommercial-NoDerivatives 4.0 International
|
||||
* @link http://zwiicms.fr/
|
||||
*/
|
||||
|
||||
|
||||
/** NE PAS EFFACER
|
||||
* admin.css
|
||||
*/
|
12
core/module/config/view/restore/restore.js.php
Normal file
12
core/module/config/view/restore/restore.js.php
Normal file
@ -0,0 +1,12 @@
|
||||
/**
|
||||
* 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 Frédéric Tempez <frederic.tempez@outlook.com>
|
||||
* @copyright Copyright (C) 2018-2023, Frédéric Tempez
|
||||
* @license CC Attribution-NonCommercial-NoDerivatives 4.0 International
|
||||
* @link http://zwiicms.fr/
|
||||
*/
|
||||
$(document).ready((function(){$("#configRestoreSubmit").click((function(event){$("body, .button").css("cursor","wait")}))}));
|
43
core/module/config/view/restore/restore.php
Normal file
43
core/module/config/view/restore/restore.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php echo template::formOpen('configRestoreForm'); ?>
|
||||
<div class="row">
|
||||
<div class="col1">
|
||||
<?php echo template::button('configRestoreBack', [
|
||||
'class' => 'buttonGrey',
|
||||
'href' => helper::baseUrl() . 'config',
|
||||
'value' => template::ico('left')
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col2 offset8">
|
||||
<?php echo template::submit('configRestoreSubmit', [
|
||||
'value' => 'Restaurer',
|
||||
'uniqueSubmission' => true,
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<div class="block">
|
||||
<h4>
|
||||
<?php echo helper::translate('Archive à restaurer'); ?>
|
||||
</h4>
|
||||
<div class="row">
|
||||
<div class="col10 offset1">
|
||||
<div class="row">
|
||||
<?php echo template::file('configRestoreImportFile', [
|
||||
'label' => 'Sélectionnez une archive au format ZIP',
|
||||
'language' => $this->getData(['user', $this->getUser('id'), 'language']),
|
||||
'type' => 2,
|
||||
'help' => 'L\'archive a été déposée dans le gestionnaire de fichiers. Les archives inférieures à la version 9 ne sont pas acceptées.'
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="row">
|
||||
<?php echo template::checkbox('configRestoreImportUser', true, 'Préserver les comptes des utilisateurs déjà installés', [
|
||||
'checked' => true
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php echo template::formClose(); ?>
|
18
core/module/config/view/script/script.css
Normal file
18
core/module/config/view/script/script.css
Normal file
@ -0,0 +1,18 @@
|
||||
/**
|
||||
* 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
|
||||
* @author Frédéric Tempez <frederic.tempez@outlook.com>
|
||||
* @copyright Copyright (C) 2018-2023, Frédéric Tempez
|
||||
* @license CC Attribution-NonCommercial-NoDerivatives 4.0 International
|
||||
* @link http://zwiicms.fr/
|
||||
*/
|
||||
|
||||
|
||||
/** NE PAS EFFACER
|
||||
* admin.css
|
||||
*/
|
37
core/module/config/view/script/script.php
Normal file
37
core/module/config/view/script/script.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php echo template::formOpen('configScript'); ?>
|
||||
<div class="row">
|
||||
<div class="col1">
|
||||
<?php echo template::button('configManageBack', [
|
||||
'class' => 'buttonGrey',
|
||||
'href' => helper::baseUrl() . 'config',
|
||||
'value' => template::ico('left')
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col2 offset8">
|
||||
<?php echo template::submit('configManageSubmit', [
|
||||
'value' => 'Valider',
|
||||
'ico' => 'check'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php if ($this->geturl(2) === 'head') : ?>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<?php echo template::textarea('configScriptHead', [
|
||||
'value' => file_exists(self::DATA_DIR . 'head.inc.html') ? file_get_contents(self::DATA_DIR . 'head.inc.html') : '',
|
||||
'class' => 'editor'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<?php if ($this->geturl(2) === 'body') : ?>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<?php echo template::textarea('configScriptBody', [
|
||||
'value' => file_exists(self::DATA_DIR . 'body.inc.html') ? file_get_contents(self::DATA_DIR . 'body.inc.html') : '',
|
||||
'class' => 'editor'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<?php echo template::formClose(); ?>
|
213
core/module/config/view/setup/setup.php
Normal file
213
core/module/config/view/setup/setup.php
Normal file
@ -0,0 +1,213 @@
|
||||
<div id="setupContainer" class="tabContent">
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<div class="block">
|
||||
<h4><?php echo helper::translate('Paramètres'); ?>
|
||||
<!--<span id="setupHelpButton" class="helpDisplayButton">
|
||||
<a href="https://doc.zwiicms.fr/parametres" target="_blank" title="Cliquer pour consulter l'aide en ligne">
|
||||
<?php //echo template::ico('help', ['margin' => 'left']);
|
||||
?>
|
||||
</a>-->
|
||||
</span>
|
||||
</h4>
|
||||
<div class="row">
|
||||
<div class="col4">
|
||||
<?php echo template::file('configFavicon', [
|
||||
'type' => 1,
|
||||
'language' => $this->getData(['user', $this->getUser('id'), 'language']),
|
||||
'help' => 'Pensez à supprimer le cache de votre navigateur si la favicon ne change pas.',
|
||||
'label' => 'Favicon',
|
||||
'value' => $this->getData(['config', 'favicon'])
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col4">
|
||||
<?php echo template::file('configFaviconDark', [
|
||||
'type' => 1,
|
||||
'language' => $this->getData(['user', $this->getUser('id'), 'language']),
|
||||
'help' => 'Sélectionnez une icône adaptée à un thème sombre.<br>Pensez à supprimer le cache de votre navigateur si la favicon ne change pas.',
|
||||
'label' => 'Favicon thème sombre',
|
||||
'value' => $this->getData(['config', 'faviconDark'])
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col4">
|
||||
<?php echo template::select('configTimezone', $module::$timezones, [
|
||||
'label' => 'Fuseau horaire',
|
||||
'selected' => $this->getData(['config', 'timezone']),
|
||||
'help' => 'Le fuseau horaire est utile au bon référencement'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col6">
|
||||
<?php echo template::checkbox('configCookieConsent', true, 'Message de consentement aux cookies', [
|
||||
'checked' => $this->getData(['config', 'cookieConsent']),
|
||||
'help' => 'Activation obligatoire selon les lois françaises sauf si vous utilisez votre propre système de consentement.'
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col6">
|
||||
<?php echo template::checkbox('configRewrite', true, 'Apache URL intelligentes', [
|
||||
'checked' => helper::checkRewrite(),
|
||||
'help' => 'Supprime le point d\'interrogation dans les URL, l\'option est indisponible avec les autres serveurs Web',
|
||||
'disabled' => stripos($_SERVER["SERVER_SOFTWARE"], 'nginx')
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<div class="block">
|
||||
<h4><?php echo helper::translate('Mise à jour automatisée'); ?>
|
||||
<!--<span id="updateHelpButton" class="helpDisplayButton">
|
||||
<a href="https://doc.zwiicms.fr/mise-a-jour" target="_blank" title="Cliquer pour consulter l'aide en ligne">
|
||||
<?php //echo template::ico('help', ['margin' => 'left']);
|
||||
?>
|
||||
</a>
|
||||
</span>-->
|
||||
</h4>
|
||||
<div class="row">
|
||||
<div class="col6">
|
||||
<?php echo template::checkbox('configAutoUpdate', true, 'Rechercher une mise à jour en ligne', [
|
||||
'checked' => $this->getData(['config', 'autoUpdate']),
|
||||
'help' => 'La vérification est quotidienne. Option désactivée si la configuration du serveur ne le permet pas.',
|
||||
'disabled' => empty(helper::getOnlineVersion(common::ZWII_UPDATE_CHANNEL))
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col6">
|
||||
<?php echo template::checkbox('configAutoUpdateHtaccess', true, 'Préserver le fichier htaccess racine', [
|
||||
'checked' => $this->getData(['config', 'autoUpdateHtaccess']),
|
||||
'help' => 'Lors d\'une mise à jour automatique, conserve le fichier htaccess de la racine du site.',
|
||||
'disabled' => empty(helper::getOnlineVersion(common::ZWII_UPDATE_CHANNEL))
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col3">
|
||||
<?php echo template::select('configAutoUpdateDelay', $module::$updateDelay, [
|
||||
'label' => 'Fréquence de recherche',
|
||||
'selected' => $this->getData(['config', 'autoUpdateDelay']),
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col3 offset1 verticalAlignBottom">
|
||||
<pre>Version installée : <strong><?php echo common::ZWII_VERSION ; ?></strong></pre>
|
||||
<pre>Version en ligne : <strong><?php echo helper::getOnlineVersion(common::ZWII_UPDATE_CHANNEL) ; ?></strong></pre>
|
||||
</div>
|
||||
<div class="col3 offset2 verticalAlignBottom">
|
||||
<?php echo template::button('configUpdateForced', [
|
||||
'ico' => 'download-cloud',
|
||||
'href' => helper::baseUrl() . 'install/update',
|
||||
'value' => $module::$updateButtonText,
|
||||
'class' => 'buttonRed',
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<div class="block">
|
||||
<h4><?php echo helper::translate('Maintenance'); ?>
|
||||
<!--<span id="maintenanceHelpButton" class="helpDisplayButton">
|
||||
<a href="https://doc.zwiicms.fr/mode-maintenance" target="_blank" title="Cliquer pour consulter l'aide en ligne">
|
||||
<?php //echo template::ico('help', ['margin' => 'left']);
|
||||
?>
|
||||
</a>
|
||||
</span>-->
|
||||
</h4>
|
||||
<div class="row">
|
||||
<div class="col6">
|
||||
<?php echo template::checkbox('configAutoBackup', true, 'Sauvegarde automatique quotidienne du site', [
|
||||
'checked' => $this->getData(['config', 'autoBackup']),
|
||||
'help' => 'Une archive du dossier /site/data est conservée pendant 30 jours. Activation recommandée'
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col6">
|
||||
<?php echo template::checkbox('configMaintenance', true, 'Site en maintenance', [
|
||||
'checked' => $this->getData(['config', 'maintenance'])
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col4 offset1">
|
||||
<?php echo template::button('configBackupButton', [
|
||||
'href' => helper::baseUrl() . 'config/backup',
|
||||
'value' => 'Sauvegarder les données du site',
|
||||
'ico' => 'download-cloud'
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col4 offset1">
|
||||
<?php echo template::button('configRestoreButton', [
|
||||
'href' => helper::baseUrl() . 'config/restore',
|
||||
'value' => 'Restaurer les données du site',
|
||||
'ico' => 'upload-cloud'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col4 offset1">
|
||||
<?php echo template::button('configBackupCopyButton', [
|
||||
'href' => helper::baseUrl() . 'config/copyBackups',
|
||||
'value' => 'Copier sauvegardes auto',
|
||||
'ico' => 'docs'
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col4 offset1">
|
||||
<?php echo template::button('configBackupDelButton', [
|
||||
'href' => helper::baseUrl() . 'config/delBackups',
|
||||
'value' => 'Vider dossier sauvegardes auto',
|
||||
'ico' => 'trash',
|
||||
'class' => 'buttonRed'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<div class="block">
|
||||
<h4><?php echo helper::translate('Scripts externes'); ?>
|
||||
<!--<span id="specialeHelpButton" class="helpDisplayButton">
|
||||
<a href="https://doc.zwiicms.fr/scripts-externes" target="_blank" title="Cliquer pour consulter l'aide en ligne">
|
||||
<?php //echo template::ico('help', ['margin' => 'left']);
|
||||
?>
|
||||
</a>
|
||||
</span>-->
|
||||
</h4>
|
||||
<div class="row">
|
||||
<div class="col4 offset1 verticalAlignBottom">
|
||||
<?php echo template::button('socialScriptHead', [
|
||||
'href' => helper::baseUrl() . 'config/script/head',
|
||||
'value' => 'Script dans head',
|
||||
'ico' => 'pencil'
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col4 offset1 verticalAlignBottom">
|
||||
<?php echo template::button('socialScriptBody', [
|
||||
'href' => helper::baseUrl() . 'config/script/body',
|
||||
'value' => 'Script dans body',
|
||||
'ico' => 'pencil'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<div class="block">
|
||||
<h4>ZwiiCMS <a href="https://zwiicms.fr" target="_blank">Site Web</a> - <a href="https://forum.zwiicms.fr" target="_blank">Forum</a>
|
||||
</h4>
|
||||
<div class="row textAlignCenter">
|
||||
<div class="col12">
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-nd/4.0/88x31.png" /></a>
|
||||
<p>Cette œuvre est mise à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/4.0/">Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Pas de Modification 4.0 International.</a></p>
|
||||
<p>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.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
188
core/module/config/view/social/social.php
Normal file
188
core/module/config/view/social/social.php
Normal file
@ -0,0 +1,188 @@
|
||||
<div id="socialContainer" class="tabContent">
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<div class="block">
|
||||
<h4>
|
||||
<?php echo helper::translate('Capture d\'écran Open Graph'); ?>
|
||||
<!--<span id="specialeHelpButton" class="helpDisplayButton">
|
||||
<a href="https://doc.zwiicms.fr/referencement" target="_blank" title="Cliquer pour consulter l'aide en ligne">
|
||||
<?php //echo template::ico('help', ['margin' => 'left']); ?>
|
||||
</a>
|
||||
</span>-->
|
||||
</h4>
|
||||
<div class="row">
|
||||
<div class="col6">
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<?php echo template::file('seoOpenGraphImage', [
|
||||
'language' => $this->getData(['user', $this->getUser('id'), 'language']),
|
||||
'label' => 'Image Open Graph',
|
||||
'value' => $this->getData(['config', 'seo', 'openGraphImage']),
|
||||
'type' => 1,
|
||||
'help' => sprintf('%s : JPG - PNG<br />', helper::translate('Format')) .
|
||||
sprintf('%s : 1200 x 630 pixels<br />', helper::translate('Dimensions minimales')) .
|
||||
sprintf('%s : 1.91:1<br />', helper::translate('Ratio')) .
|
||||
sprintf('%s : %s, %s<br />', helper::translate('Taille maximale du fichier'), helper::translate('5 Mo pour les images JPEG'), helper::translate('1 Mo pour les images PNG'))
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col10 textAlignCenter">
|
||||
<?php if( $module::$imageOpenGraph['type']): ?>
|
||||
<p>
|
||||
<?php echo sprintf('%s : <span id="screenType">%s</span>', helper::translate('Format'), $module::$imageOpenGraph['type']); ?>
|
||||
</p>
|
||||
<p>
|
||||
<?php echo sprintf('%s : <span id="screenWide">%s</span> x <span id="screenHeight">%s</span> pixels', helper::translate('Dimensions minimales'), $module::$imageOpenGraph['wide'], $module::$imageOpenGraph['height'] ); ?>
|
||||
</p>
|
||||
<p>
|
||||
<?php echo sprintf('%s : <span id="screenRatio">%s</span><span id="screenFract">:1</span>' , helper::translate('Ratio'), round($module::$imageOpenGraph['ratio'], 2)); ?>
|
||||
</p>
|
||||
<p>
|
||||
<?php echo sprintf('%s : <span id="screenWeight">%s</span>', helper::translate('Poids'), $module::$imageOpenGraph['size']); ?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col6">
|
||||
<?php if (
|
||||
$this->getData(['config', 'seo', 'openGraphImage']) &&
|
||||
file_exists(self::FILE_DIR . 'source/' . $this->getData(['config', 'seo', 'openGraphImage']))
|
||||
): ?>
|
||||
<img
|
||||
src="<?php echo self::FILE_DIR . 'source/' . $this->getData(['config', 'seo', 'openGraphImage']); ?>" />
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<div class="block">
|
||||
<h4>
|
||||
<?php echo helper::translate('Référencement'); ?>
|
||||
</h4>
|
||||
<div class="row">
|
||||
<div class="col4 offset1">
|
||||
<?php echo template::button('socialSiteMap', [
|
||||
'href' => helper::baseUrl() . 'config/sitemap',
|
||||
'value' => 'Générer sitemap.xml et robots.txt'
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col4 offset1">
|
||||
<?php echo template::checkbox('seoRobots', true, 'Autoriser les robots à référencer le site', [
|
||||
'checked' => $this->getData(['config', 'seo', 'robots'])
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<div class="block">
|
||||
<h4>
|
||||
<?php echo helper::translate('Réseaux sociaux'); ?>
|
||||
<!--<span id="specialeHelpButton" class="helpDisplayButton">
|
||||
<a href="https://doc.zwiicms.fr/reseaux-sociaux" target="_blank" title="Cliquer pour consulter l'aide en ligne">
|
||||
<?php //echo template::ico('help', ['margin' => 'left']); ?>
|
||||
</a>
|
||||
</span>-->
|
||||
</h4>
|
||||
<div class="row">
|
||||
<div class="col3">
|
||||
<?php echo template::text('socialFacebookId', [
|
||||
'help' => 'Saisissez votre ID : https://www.facebook.com/[ID].',
|
||||
'label' => template::ico('facebook', ['margin' => 'right']) . 'Facebook',
|
||||
'value' => $this->getData(['config', 'social', 'facebookId'])
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col3">
|
||||
<?php echo template::text('socialInstagramId', [
|
||||
'help' => 'Saisissez votre ID : https://www.instagram.com/[ID].',
|
||||
'label' => template::ico('instagram', ['margin' => 'right']) . 'Instagram',
|
||||
'value' => $this->getData(['config', 'social', 'instagramId'])
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col3">
|
||||
<?php echo template::text('socialTwitterId', [
|
||||
'help' => 'Saisissez votre ID : https://twitter.com/[ID].',
|
||||
'label' => template::ico('twitter', ['margin' => 'right']) . 'Twitter',
|
||||
'value' => $this->getData(['config', 'social', 'twitterId'])
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col3">
|
||||
<?php echo template::text('socialRedditId', [
|
||||
'help' => 'Saisissez votre ID Reddit : https://www.reddit.com/user/[ID].',
|
||||
'label' => template::ico('reddit', ['margin' => 'right']) . 'Reddit',
|
||||
'value' => $this->getData(['config', 'social', 'redditId'])
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col3">
|
||||
<?php echo template::text('socialYoutubeId', [
|
||||
'help' => 'ID de la chaîne : https://www.youtube.com/channel/[ID].',
|
||||
'label' => template::ico('youtube', ['margin' => 'right']) . 'Chaîne Youtube',
|
||||
'value' => $this->getData(['config', 'social', 'youtubeId'])
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col3">
|
||||
<?php echo template::text('socialYoutubeUserId', [
|
||||
'help' => 'Saisissez votre ID Utilisateur : https://www.youtube.com/user/[ID].',
|
||||
'label' => template::ico('youtube', ['margin' => 'right']) . 'Youtube',
|
||||
'value' => $this->getData(['config', 'social', 'youtubeUserId'])
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col3">
|
||||
<?php echo template::text('socialVimeoId', [
|
||||
'help' => 'Saisissez votre ID Viemo : https://vimeo.com/[ID].',
|
||||
'label' => template::ico('vimeo', ['margin' => 'right']) . 'Vimeo',
|
||||
'value' => $this->getData(['config', 'social', 'vimeoId'])
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col3">
|
||||
<?php echo template::text('socialPinterestId', [
|
||||
'help' => 'Saisissez votre ID : https://pinterest.com/[ID].',
|
||||
'label' => template::ico('pinterest', ['margin' => 'right']) . 'Pinterest',
|
||||
'value' => $this->getData(['config', 'social', 'pinterestId'])
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col3">
|
||||
<?php echo template::text('socialLinkedinId', [
|
||||
'help' => 'Saisissez votre ID Linkedin : https://fr.linkedin.com/in/[ID].',
|
||||
'label' => template::ico('linkedin', ['margin' => 'right']) . 'Linkedin',
|
||||
'value' => $this->getData(['config', 'social', 'linkedinId'])
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col3">
|
||||
<?php echo template::text('socialGithubId', [
|
||||
'help' => 'Saisissez votre ID Github : https://github.com/[ID].',
|
||||
'label' => template::ico('github', ['margin' => 'right']) . 'Github',
|
||||
'value' => $this->getData(['config', 'social', 'githubId'])
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col3">
|
||||
<?php echo template::text('socialTwitchId', [
|
||||
'help' => 'Saisissez votre ID Twitch : https://www.twitch.tv/[ID].',
|
||||
'label' => template::ico('twitch', ['margin' => 'right']) . 'Twitch',
|
||||
'value' => $this->getData(['config', 'social', 'twitchId'])
|
||||
]); ?>
|
||||
</div>
|
||||
|
||||
<div class="col3">
|
||||
<?php echo template::text('socialSteamId', [
|
||||
'help' => 'Saisissez votre ID Viemo : https://steamcommunity.com/id/[ID].',
|
||||
'label' => template::ico('steam', ['margin' => 'right']) . 'Steam',
|
||||
'value' => $this->getData(['config', 'social', 'steamId'])
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
50
core/module/dashboard/dashboard.php
Normal file
50
core/module/dashboard/dashboard.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?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
|
||||
* @author Frédéric Tempez <frederic.tempez@outlook.com>
|
||||
* @copyright Copyright (C) 2018-2023, Frédéric Tempez
|
||||
* @license CC Attribution-NonCommercial-NoDerivatives 4.0 International
|
||||
* @link http://zwiicms.fr/
|
||||
*/
|
||||
|
||||
class dashboard extends common
|
||||
{
|
||||
|
||||
public static $actions = [
|
||||
'index' => self::GROUP_ADMIN,
|
||||
];
|
||||
|
||||
|
||||
|
||||
public static $infos = [];
|
||||
|
||||
/**
|
||||
* Dashboard
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
||||
self::$infos['webserver'] = $_SERVER['SERVER_SOFTWARE'];
|
||||
self::$infos['php']['version'] = phpversion();
|
||||
self::$infos['php']['extension'] = get_loaded_extensions();
|
||||
|
||||
self::$infos['system']['memory'] = memory_get_usage() . ' octets';
|
||||
self::$infos['system']['peek'] = 'Pic de mémoire utilisée : ' . memory_get_peak_usage() . ' octets';
|
||||
|
||||
$loadAverage = sys_getloadavg();
|
||||
self::$infos['system']['charge'] = 'Charge moyenne (1 min / 5 min / 15 min) : ' . implode(' / ', $loadAverage) . '</P>';
|
||||
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'title' => helper::translate('Tableau de bord'),
|
||||
'view' => 'index'
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
54
core/module/dashboard/view/index/index.php
Normal file
54
core/module/dashboard/view/index/index.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php echo template::formOpen('dashboard'); ?>
|
||||
<div class="row">
|
||||
<div class="col1">
|
||||
<?php echo template::button('dashboardFormBack', [
|
||||
'class' => 'buttonGrey',
|
||||
'href' => helper::baseUrl(false),
|
||||
'value' => template::ico('home')
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<div class="block">
|
||||
<h4>
|
||||
<?php echo helper::translate('Système'); ?>
|
||||
</h4>
|
||||
<div class="row">
|
||||
<div class="col6">
|
||||
<p>
|
||||
<?php echo helper::translate('Serveur Web'); ?>
|
||||
</p>
|
||||
<p>
|
||||
<?php echo $module::$infos['webserver']; ?>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col6">
|
||||
<p>
|
||||
<?php echo helper::translate('PHP') . ' ' . $module::$infos['php']['version']; ?>
|
||||
</p>
|
||||
<p>
|
||||
<?php echo implode(' - ', $module::$infos['php']['extension']); ?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<p>
|
||||
<?php echo helper::translate('Mémoire'); ?>
|
||||
</p>
|
||||
<p>
|
||||
<?php echo $module::$infos['system']['memory']; ?>
|
||||
</p>
|
||||
<p>
|
||||
<?php echo $module::$infos['system']['charge']; ?>
|
||||
</p>
|
||||
<p>
|
||||
<?php echo $module::$infos['system']['peek']; ?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
480
core/module/install/install.php
Normal file
480
core/module/install/install.php
Normal file
@ -0,0 +1,480 @@
|
||||
<?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
|
||||
* @author Frédéric Tempez <frederic.tempez@outlook.com>
|
||||
* @copyright Copyright (C) 2018-2023, Frédéric Tempez
|
||||
* @license CC Attribution-NonCommercial-NoDerivatives 4.0 International
|
||||
* @link http://zwiicms.fr/
|
||||
*/
|
||||
|
||||
|
||||
class install extends common
|
||||
{
|
||||
|
||||
public static $actions = [
|
||||
'index' => self::GROUP_VISITOR,
|
||||
"postinstall" => self::GROUP_VISITOR,
|
||||
'steps' => self::GROUP_ADMIN,
|
||||
'update' => self::GROUP_ADMIN
|
||||
];
|
||||
|
||||
// Type de proxy
|
||||
public static $proxyType = [
|
||||
'tcp://' => 'TCP',
|
||||
'http://' => 'HTTP'
|
||||
];
|
||||
|
||||
// Thèmes proposés à l'installation
|
||||
public static $themes = [];
|
||||
|
||||
public static $newVersion;
|
||||
|
||||
// Fichiers des Interface
|
||||
public static $i18nFiles = [];
|
||||
|
||||
/**
|
||||
* Pré-installation - choix de la langue
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
// Accès refusé
|
||||
if ($this->getData(['user']) !== []) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'access' => false
|
||||
]);
|
||||
}
|
||||
|
||||
// Soumission du formulaire
|
||||
if (
|
||||
//$this->getUser('permission', __CLASS__, __FUNCTION__) === true &&
|
||||
$this->isPost()
|
||||
) {
|
||||
|
||||
$lang = $this->getInput('installLanguage');
|
||||
// Pour la suite de l'installation
|
||||
// setcookie('ZWII_UI', $lang, time() + 3600, helper::baseUrl(false, false), '', false, false);
|
||||
|
||||
$_SESSION['ZWII_UI'] = $this->getInput('installLanguage');
|
||||
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'redirect' => helper::baseUrl() . 'install/postinstall'
|
||||
]);
|
||||
}
|
||||
|
||||
// Liste des langues UI disponibles
|
||||
if (is_dir(self::I18N_DIR)) {
|
||||
foreach ($this->getData(['language']) as $lang => $value) {
|
||||
self::$i18nFiles[$lang] = self::$languages[$lang];
|
||||
}
|
||||
}
|
||||
|
||||
$this->addOutput([
|
||||
'display' => self::DISPLAY_LAYOUT_LIGHT,
|
||||
'title' => helper::translate('ZwiiCMS Installation'),
|
||||
'view' => 'index'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* post Installation
|
||||
*/
|
||||
public function postInstall()
|
||||
{
|
||||
// Accès refusé
|
||||
if ($this->getData(['user']) !== []) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'access' => false
|
||||
]);
|
||||
}
|
||||
// Accès autorisé
|
||||
else {
|
||||
// Soumission du formulaire
|
||||
if (
|
||||
//$this->getUser('permission', __CLASS__, __FUNCTION__) !== true &&
|
||||
$this->isPost()
|
||||
) {
|
||||
|
||||
$success = true;
|
||||
|
||||
// Double vérification pour le mot de passe
|
||||
if ($this->getInput('installPassword', helper::FILTER_STRING_SHORT, true) !== $this->getInput('installConfirmPassword', helper::FILTER_STRING_SHORT, true)) {
|
||||
self::$inputNotices['installConfirmPassword'] = 'Incorrect';
|
||||
$success = false;
|
||||
}
|
||||
// Utilisateur
|
||||
$userFirstname = $this->getInput('installFirstname', helper::FILTER_STRING_SHORT, true);
|
||||
$userLastname = $this->getInput('installLastname', helper::FILTER_STRING_SHORT, true);
|
||||
$userMail = $this->getInput('installMail', helper::FILTER_MAIL, true);
|
||||
$userId = $this->getInput('installId', helper::FILTER_ID, true);
|
||||
|
||||
// Validation de la langue transmise
|
||||
self::$i18nUI = $_SESSION['ZWII_UI'];
|
||||
self::$i18nUI = array_key_exists(self::$i18nUI, self::$languages) ? self::$i18nUI : 'fr_FR';
|
||||
// par défaut le contenu est la langue d'installation
|
||||
$_SESSION['ZWII_CONTENT'] = self::$i18nUI;
|
||||
|
||||
// Création du dossier de langue avec le marqueur de langue par défaut
|
||||
if (!is_dir(self::DATA_DIR . $_SESSION['ZWII_CONTENT'])) {
|
||||
mkdir(self::DATA_DIR . $_SESSION['ZWII_CONTENT']);
|
||||
touch(self::DATA_DIR . $_SESSION['ZWII_CONTENT'] . '/.default');
|
||||
}
|
||||
|
||||
// Installation du site de test
|
||||
if (
|
||||
$this->getInput('installDefaultData', helper::FILTER_BOOLEAN) === false
|
||||
&& $_SESSION['ZWII_CONTENT'] === 'fr_FR'
|
||||
) {
|
||||
$sample = true;
|
||||
}
|
||||
$this->initData('page', $_SESSION['ZWII_CONTENT'], $sample);
|
||||
$this->initData('module', $_SESSION['ZWII_CONTENT'], $sample);
|
||||
$this->initData('locale', $_SESSION['ZWII_CONTENT'], $sample);
|
||||
|
||||
// Création de l'utilisateur si les données sont complétées.
|
||||
// success retour de l'enregistrement des données
|
||||
$this->setData([
|
||||
'user',
|
||||
$userId,
|
||||
[
|
||||
'firstname' => $userFirstname,
|
||||
'forgot' => 0,
|
||||
'group' => self::GROUP_ADMIN,
|
||||
'lastname' => $userLastname,
|
||||
'pseudo' => 'Admin',
|
||||
'signature' => 1,
|
||||
'mail' => $userMail,
|
||||
'password' => $this->getInput('installPassword', helper::FILTER_PASSWORD, true),
|
||||
'language' => $_SESSION['ZWII_CONTENT']
|
||||
]
|
||||
]);
|
||||
|
||||
// Envoie le mail
|
||||
// Sent contient true si réussite sinon code erreur d'envoi en clair
|
||||
$this->sendMail(
|
||||
$userMail,
|
||||
'Installation de votre site',
|
||||
'Bonjour' . ' <strong>' . $userFirstname . ' ' . $userLastname . '</strong>,<br><br>' .
|
||||
'Voici les détails de votre installation.<br><br>' .
|
||||
'<strong>URL du site :</strong> <a href="' . helper::baseUrl(false) . '" target="_blank">' . helper::baseUrl(false) . '</a><br>' .
|
||||
'<strong>Identifiant du compte :</strong> ' . $this->getInput('installId') . '<br>',
|
||||
null,
|
||||
'localhost'
|
||||
);
|
||||
|
||||
// Nettoyage fr par défaut
|
||||
if (
|
||||
$_SESSION['ZWII_CONTENT'] !== 'fr_FR'
|
||||
) {
|
||||
if (is_dir(self::DATA_DIR . 'fr_FR'))
|
||||
$this->deleteDir(self::DATA_DIR . 'fr_FR');
|
||||
}
|
||||
|
||||
// Sauvegarder la configuration du Proxy
|
||||
$this->setData(['config', 'proxyType', $this->getInput('installProxyType')]);
|
||||
$this->setData(['config', 'proxyUrl', $this->getInput('installProxyUrl')]);
|
||||
$this->setData(['config', 'proxyPort', $this->getInput('installProxyPort', helper::FILTER_INT)]);
|
||||
|
||||
// Images exemples livrées dans tous les cas
|
||||
try {
|
||||
// Décompression dans le dossier de fichier temporaires
|
||||
if (file_exists(self::TEMP_DIR . 'files.tar.gz')) {
|
||||
unlink(self::TEMP_DIR . 'files.tar.gz');
|
||||
}
|
||||
if (file_exists(self::TEMP_DIR . 'files.tar')) {
|
||||
unlink(self::TEMP_DIR . 'files.tar');
|
||||
}
|
||||
copy('core/module/install/ressource/files.tar.gz', self::TEMP_DIR . 'files.tar.gz');
|
||||
$pharData = new PharData(self::TEMP_DIR . 'files.tar.gz');
|
||||
$pharData->decompress();
|
||||
// Installation
|
||||
$pharData->extractTo(__DIR__ . '/../../../', null, true);
|
||||
} catch (Exception $e) {
|
||||
$success = $e->getMessage();
|
||||
}
|
||||
|
||||
// Nettoyage
|
||||
unlink(self::TEMP_DIR . 'files.tar.gz');
|
||||
unlink(self::TEMP_DIR . 'files.tar');
|
||||
|
||||
// Créer le dossier des fontes
|
||||
if (!is_dir(self::DATA_DIR . 'font')) {
|
||||
mkdir(self::DATA_DIR . 'font');
|
||||
}
|
||||
|
||||
// Installation du thème sélectionné
|
||||
$dataThemes = json_decode(file_get_contents('core/module/install/ressource/themes/themes.json'), true);
|
||||
$dataThemes = $dataThemes['themes'];
|
||||
$themeFilename = $dataThemes[$this->getInput('installTheme', helper::FILTER_STRING_SHORT)]['filename'];
|
||||
if ($themeFilename !== '') {
|
||||
$theme = new theme;
|
||||
$theme->import('core/module/install/ressource/themes/' . $themeFilename);
|
||||
}
|
||||
|
||||
// Copie des thèmes dans les fichiers
|
||||
if (!is_dir(self::FILE_DIR . 'source/theme')) {
|
||||
mkdir(self::FILE_DIR . 'source/theme');
|
||||
}
|
||||
$this->copyDir('core/module/install/ressource/themes', self::FILE_DIR . 'source/theme');
|
||||
unlink(self::FILE_DIR . 'source/theme/themes.json');
|
||||
|
||||
// Copie des langues de l'UI et génération de la base de données
|
||||
if (is_dir(self::I18N_DIR) === false) {
|
||||
mkdir(self::I18N_DIR);
|
||||
}
|
||||
|
||||
// Créer la base de données des langues
|
||||
// copy('core/module/install/ressource/i18n/language.json', self::DATA_DIR . 'language.json');
|
||||
$this->copyDir('core/module/install/ressource/i18n', self::I18N_DIR);
|
||||
// unlink(self::I18N_DIR . 'language.json');
|
||||
|
||||
// Fixe l'adresse from pour les envois d'email
|
||||
$this->setData(['config', 'smtp', 'from', 'no-reply@' . str_replace('www.', '', $_SERVER['HTTP_HOST'])]);
|
||||
|
||||
// Supprimé à cause de l'écrasement des bases
|
||||
//$this->setData(['module', 'blog', 'posts', 'mon-premier-article', 'userId', $userId]);
|
||||
//$this->setData(['module', 'blog', 'posts', 'mon-deuxieme-article', 'userId', $userId]);
|
||||
//$this->setData(['module', 'blog', 'posts', 'mon-troisieme-article', 'userId', $userId]);
|
||||
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'redirect' => helper::baseUrl(),
|
||||
'notification' => helper::translate('Installation terminée'),
|
||||
'state' => true
|
||||
]);
|
||||
}
|
||||
|
||||
// Affichage du formulaire
|
||||
|
||||
// Récupération de la liste des thèmes
|
||||
$dataThemes = json_decode(file_get_contents('core/module/install/ressource/themes/themes.json'), true);
|
||||
$dataThemes = $dataThemes['themes'];
|
||||
self::$themes = helper::arrayColumn($dataThemes, 'name');
|
||||
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'display' => self::DISPLAY_LAYOUT_LIGHT,
|
||||
'title' => helper::translate('ZwiiCMS Installation'),
|
||||
'view' => 'postinstall'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Étapes de mise à jour
|
||||
*/
|
||||
public function steps()
|
||||
{
|
||||
// Action interdite
|
||||
if (
|
||||
$this->getUser('permission', __CLASS__, __FUNCTION__) !== true
|
||||
) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'access' => false
|
||||
]);
|
||||
} else {
|
||||
switch ($this->getInput('step', helper::FILTER_INT)) {
|
||||
// Préparation
|
||||
case 1:
|
||||
$success = true;
|
||||
$message = '';
|
||||
// RAZ la mise à jour auto
|
||||
$this->setData(['core', 'updateAvailable', false]);
|
||||
// Backup du dossier Data
|
||||
helper::autoBackup(self::BACKUP_DIR, ['backup', 'tmp', 'file']);
|
||||
// Sauvegarde htaccess
|
||||
if ($this->getData(['config', 'autoUpdateHtaccess'])) {
|
||||
$success = copy('.htaccess', '.htaccess' . '.bak');
|
||||
$message = $success ? '' : 'Erreur de copie du fichier htaccess';
|
||||
}
|
||||
// Nettoyage des fichiers d'installation précédents
|
||||
if (file_exists(self::TEMP_DIR . 'update.tar.gz') && $success) {
|
||||
$success = unlink(self::TEMP_DIR . 'update.tar.gz');
|
||||
$message = $success ? '' : 'Impossible d\'effacer la mise à jour précédente';
|
||||
}
|
||||
if (file_exists(self::TEMP_DIR . 'update.tar') && $success) {
|
||||
$success = unlink(self::TEMP_DIR . 'update.tar');
|
||||
$message = $success ? '' : 'Impossible d\'effacer la mise à jour précédente';
|
||||
}
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'display' => self::DISPLAY_JSON,
|
||||
'content' => [
|
||||
'success' => $success,
|
||||
'data' => $success ? null : json_encode($message, JSON_UNESCAPED_UNICODE)
|
||||
]
|
||||
]);
|
||||
break;
|
||||
// Téléchargement
|
||||
case 2:
|
||||
file_put_contents(self::TEMP_DIR . 'update.tar.gz', helper::getUrlContents(common::ZWII_UPDATE_URL . common::ZWII_UPDATE_CHANNEL . '/update.tar.gz'));
|
||||
$md5origin = helper::getUrlContents(common::ZWII_UPDATE_URL . common::ZWII_UPDATE_CHANNEL . '/update.md5');
|
||||
$md5origin = explode(' ', $md5origin);
|
||||
$md5target = md5_file(self::TEMP_DIR . 'update.tar.gz');
|
||||
// Vérifier si les checksums correspondent
|
||||
if ($md5origin[0] === $md5target) {
|
||||
$success = true;
|
||||
$message = "";
|
||||
} else {
|
||||
$success = false;
|
||||
$message = json_encode('Erreur de téléchargement ou de somme de contrôle', JSON_UNESCAPED_UNICODE);
|
||||
if (file_exists(self::TEMP_DIR . 'update.tar.gz')) {
|
||||
unlink(self::TEMP_DIR . 'update.tar.gz');
|
||||
http_response_code(500);
|
||||
}
|
||||
}
|
||||
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'display' => self::DISPLAY_JSON,
|
||||
'content' => [
|
||||
'success' => $success,
|
||||
'data' => $message
|
||||
]
|
||||
]);
|
||||
break;
|
||||
// Installation
|
||||
case 3:
|
||||
$success = true;
|
||||
// Check la réécriture d'URL avant d'écraser les fichiers
|
||||
$rewrite = helper::checkRewrite();
|
||||
// Décompression et installation
|
||||
try {
|
||||
// Décompression dans le dossier de fichier temporaires
|
||||
$pharData = new PharData(self::TEMP_DIR . 'update.tar.gz');
|
||||
$pharData->decompress();
|
||||
// Installation
|
||||
$pharData->extractTo(__DIR__ . '/../../../', null, true);
|
||||
} catch (Exception $e) {
|
||||
$success = false;
|
||||
http_response_code(500);
|
||||
}
|
||||
// Nettoyage du dossier
|
||||
if (file_exists(self::TEMP_DIR . 'update.tar.gz')) {
|
||||
unlink(self::TEMP_DIR . 'update.tar.gz');
|
||||
}
|
||||
if (file_exists(self::TEMP_DIR . 'update.tar')) {
|
||||
unlink(self::TEMP_DIR . 'update.tar');
|
||||
}
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'display' => self::DISPLAY_JSON,
|
||||
'content' => [
|
||||
'success' => $success,
|
||||
'data' => $rewrite
|
||||
]
|
||||
]);
|
||||
break;
|
||||
// Configuration
|
||||
case 4:
|
||||
$success = true;
|
||||
$message = '';
|
||||
$rewrite = $this->getInput('data');
|
||||
|
||||
/**
|
||||
* Restaure le fichier htaccess
|
||||
*/
|
||||
// Recopie htaccess
|
||||
if (
|
||||
$this->getData(['config', 'autoUpdateHtaccess']) === true
|
||||
) {
|
||||
// L'écraser avec le backup
|
||||
$success = copy('.htaccess.bak', '.htaccess');
|
||||
if ($success === false) {
|
||||
$message = helper::translate('La copie de sauvegarde du fichier htaccess n\'a pas été restaurée !');
|
||||
http_response_code(500);
|
||||
}
|
||||
// Effacer le backup
|
||||
unlink('.htaccess.bak');
|
||||
} else {
|
||||
/**
|
||||
* Restaure la réécriture d'URL
|
||||
*/
|
||||
if ($rewrite === 'true') { // Ajout des lignes dans le .htaccess
|
||||
$fileContent = file_get_contents('.htaccess');
|
||||
$rewriteData = PHP_EOL .
|
||||
'# URL rewriting' . PHP_EOL .
|
||||
'<IfModule mod_rewrite.c>' . PHP_EOL .
|
||||
"\tRewriteEngine on" . PHP_EOL .
|
||||
"\tRewriteBase " . helper::baseUrl(false, false) . PHP_EOL .
|
||||
"\tRewriteCond %{REQUEST_FILENAME} !-f" . PHP_EOL .
|
||||
"\tRewriteCond %{REQUEST_FILENAME} !-d" . PHP_EOL .
|
||||
"\tRewriteRule ^(.*)$ index.php?$1 [L]" . PHP_EOL .
|
||||
'</IfModule>' . PHP_EOL .
|
||||
'# URL rewriting' . PHP_EOL;
|
||||
$fileContent = str_replace('# URL rewriting', $rewriteData, $fileContent);
|
||||
$success = file_put_contents(
|
||||
'.htaccess',
|
||||
$fileContent
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Met à jour les dictionnaires des langues depuis les nouveaux modèles installés
|
||||
*/
|
||||
require_once('core/module/install/ressource/defaultdata.php');
|
||||
$installedLanguages = $this->getData(['language']);
|
||||
$defaultLanguages = init::$defaultData['language'];
|
||||
foreach ($installedLanguages as $key => $value) {
|
||||
|
||||
//var_dump( $defaultLanguages[$key]['date'] > $value['date'] );
|
||||
if (
|
||||
isset($defaultLanguages[$key]['date']) &&
|
||||
$defaultLanguages[$key]['date'] > $value['date'] &&
|
||||
isset($defaultLanguages[$key]['version']) &&
|
||||
$defaultLanguages[$key]['version'] >= $value['version']
|
||||
|
||||
) {
|
||||
copy('core/module/install/ressource/i18n/' . $key . '.json', self::I18N_DIR . $key . '.json');
|
||||
$this->setData(['language', $key, $defaultLanguages[$key]]);
|
||||
}
|
||||
}
|
||||
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'display' => self::DISPLAY_JSON,
|
||||
'content' => [
|
||||
'success' => $success,
|
||||
'data' => json_encode($message, JSON_UNESCAPED_UNICODE)
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mise à jour
|
||||
*/
|
||||
public function update()
|
||||
{
|
||||
// Action interdite
|
||||
if (
|
||||
$this->getUser('permission', __CLASS__, __FUNCTION__) !== true
|
||||
) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'access' => false
|
||||
]);
|
||||
} else {
|
||||
// Nouvelle version
|
||||
self::$newVersion = helper::getUrlContents(common::ZWII_UPDATE_URL . common::ZWII_UPDATE_CHANNEL . '/version');
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'display' => self::DISPLAY_LAYOUT_LIGHT,
|
||||
'title' => helper::translate('Mise à jour'),
|
||||
'view' => 'update'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
10
core/module/install/ressource/.htaccess
Normal file
10
core/module/install/ressource/.htaccess
Normal file
@ -0,0 +1,10 @@
|
||||
# Bloque l'accès aux données
|
||||
<Files *.json>
|
||||
Order deny,allow
|
||||
Deny from all
|
||||
</Files>
|
||||
# Bloque l'accès htaccess
|
||||
<Files .htaccess>
|
||||
Order deny,allow
|
||||
Deny from all
|
||||
</Files>
|
1615
core/module/install/ressource/defaultdata.php
Normal file
1615
core/module/install/ressource/defaultdata.php
Normal file
File diff suppressed because it is too large
Load Diff
BIN
core/module/install/ressource/files.tar.gz
Normal file
BIN
core/module/install/ressource/files.tar.gz
Normal file
Binary file not shown.
690
core/module/install/ressource/i18n/en_EN.json
Normal file
690
core/module/install/ressource/i18n/en_EN.json
Normal file
@ -0,0 +1,690 @@
|
||||
{
|
||||
"'Ne pas afficher' crée une page orpheline non accessible par le biais des menus.": "'Do not display' creates an orphan page not accessible through menus.",
|
||||
"'Sauvegarder et télécharger les données du module": "'Save and download module data",
|
||||
"1 jour": "1 jour",
|
||||
"1/4 : Préparation...": "1/4: preparation ...",
|
||||
"10 minutes": "10 minutes",
|
||||
"10 tentatives": "10 attempts",
|
||||
"14 jours": "14 days",
|
||||
"15 minutes": "15 minutes",
|
||||
"2 jours": "2 days",
|
||||
"2/4 : Téléchargement...": "2/4: Download ...",
|
||||
"3 tentatives": "3 attempts",
|
||||
"3/4 : Installation...": "3/4 : Installation...",
|
||||
"4 jours": "4 days",
|
||||
"4/4 : Configuration...": "4/4 : Setup...",
|
||||
"5 minutes": "5 minutes",
|
||||
"5 tentatives": "5 attempts",
|
||||
"7 jours": "7 days",
|
||||
"Accueil": "Homepage",
|
||||
"Accède au site": "Access to the site",
|
||||
"Accède aux pages réservées": "Access to restricted pages",
|
||||
"Accède aux pages réservées et à un dossier partagé": "Access to restricted pages and a shared folder",
|
||||
"Accès bloqué %d minutes": "Blocked access %d minutes",
|
||||
"Accès désactivé": "Access disabled",
|
||||
"Accès interdit, erreur 403": "Access prohibited, error 403",
|
||||
"Action interdite": "Prohibited action",
|
||||
"Activation obligatoire selon les lois françaises sauf si vous utilisez votre propre système de consentement.": "Compulsory activation according to French laws unless you use your own consent system.",
|
||||
"Activer": "Enable",
|
||||
"Activer la journalisation": "Activate journalization",
|
||||
"Actualiser": "Update",
|
||||
"Adaptation": "Adaptation",
|
||||
"Administrateur": "Administrator",
|
||||
"Administration": "Administration",
|
||||
"Adresse SMTP": "SMTP Address",
|
||||
"Adresse du proxy": "Proxy address",
|
||||
"Adresse électronique": "email address",
|
||||
"Affectation": "Assignment",
|
||||
"Affiche le nom de la page parente suivi du nom de la page, le titre ne doit pas être masqué.": "Displays the name of the parent page followed by the page name, the title should not be hidden.",
|
||||
"Affiche les icônes de gestion du compte et de déconnexion des membres simples connectés": "Displays account management and logout icons for logged-in regular members",
|
||||
"Afin d'assurer le bon fonctionnement de Zwii, veuillez ne pas fermer cette page avant la fin de l'opération.": "In order to ensure the proper functioning of Zwii, please do not close this page before the end of the operation.",
|
||||
"Aide": "Help",
|
||||
"Ajouter": "Add",
|
||||
"Ajouter un profil": "Add Profile",
|
||||
"Ajouter un utilisateur": "Add a user",
|
||||
"Ajouter une fonte": "Add a cast iron",
|
||||
"Alignement": "Alignment",
|
||||
"Aligner la bannière avec le contenu": "Align the banner with the contents",
|
||||
"Ancien mot de passe": "Old Password",
|
||||
"Anonymat des adresses IP": "Anonymity of IP addresses",
|
||||
"Apache URL intelligent": "Intelligent Apache URL",
|
||||
"Apache URL intelligentes": "Intelligent Apache URL",
|
||||
"Apparence": "Appearance",
|
||||
"Appliquer": "Apply",
|
||||
"Approuver un commentaire": "Approve Comment",
|
||||
"Après": "After",
|
||||
"Après la bannière": "After the banner",
|
||||
"Après le contenu de la page": "After the content of the page",
|
||||
"Archive": "Archive",
|
||||
"Archive ZIP": "Zip archive",
|
||||
"Archive copiée dans le dossier Modules du gestionnaire de fichier": "Archive copied in the Modules folder",
|
||||
"Archive de thème invalide": "Invalid theme archive",
|
||||
"Archive invalide": "Invalid archive",
|
||||
"Archive invalide, l'écriture dans le dossier core est interdite": "Invalid archive, writing in the core file is prohibited",
|
||||
"Archive invalide, le descripteur est absent": "Invalid archive, the descriptor is absent",
|
||||
"Archive invalide, le fichier de classe est absent": "Invalide archive, the class file is absent",
|
||||
"Archive invalide, les dossiers ne correspondent pas au descripteur": "Invalid archive, the files do not correspond to the descriptor",
|
||||
"Archive non spécifiée ou introuvable": "Archive not specified or not found",
|
||||
"Archive à restaurer": "Archive to restore",
|
||||
"Arrière plan": "Background",
|
||||
"Arrière plan des blocs": "Blocks background",
|
||||
"Arrière plan des champs": "Fields background",
|
||||
"Arrondi des angles": "Rounding of angles",
|
||||
"Au centre": "Center",
|
||||
"Au début": "At first",
|
||||
"Au milieu au centre": "In the middle in the center",
|
||||
"Au milieu à droite": "In the middle right",
|
||||
"Au milieu à gauche": "In the middle on the left",
|
||||
"Au-dessus du site": "Above the site",
|
||||
"Aucun": "None",
|
||||
"Aucun dossier": "No Folder",
|
||||
"Aucun fichier journal à télécharger": "No log file to download",
|
||||
"Aucun journal à effacer": "No log file to erase",
|
||||
"Aucun menu": "No menu",
|
||||
"Aucune": "None",
|
||||
"Aucune liste noire à effacer": "No blacklist to erase",
|
||||
"Aucune liste noire à télécharger": "No blacklist to download",
|
||||
"Auteur :": "Author:",
|
||||
"Authentification": "Authentication",
|
||||
"Automatique": "Automatique",
|
||||
"Autoriser les robots à référencer le site": "Allow robots to reference the site",
|
||||
"Autorisé": "Allowed",
|
||||
"Avant la bannière": "Before the banner",
|
||||
"Avant le contenu de la page": "Before the content of the page",
|
||||
"Background": "Background",
|
||||
"Banni": "Ban",
|
||||
"Bannière": "Banner",
|
||||
"Bannière cliquable": "Clickable banner",
|
||||
"Barre 1/3 - page 2/3": "Sidebar 1/3 - page 2/3",
|
||||
"Barre 1/4 - page 1/2 - barre 1/4": "Sidebar 1/4 - page 1/2 - Sidebar 1/4",
|
||||
"Barre 1/4 - page 3/4": "Sidebar 1/4 - page 3/4",
|
||||
"Barre 2/12 - page 7/12 - barre 3/12": "Sidebar 2/12 - page 7/12 - Sidebar 3/12",
|
||||
"Barre 3/12 - page 7/12 - barre 2/12": "Sidebar 3/12 - page 7/12 - Sidebar 2/12",
|
||||
"Barre de membre": "Member bar",
|
||||
"Barre latérale": "Sidebar",
|
||||
"Barre latérale droite :": "Right sidebar:",
|
||||
"Barre latérale gauche :": "Left sidebar:",
|
||||
"Barres latérales": "Side bars",
|
||||
"Bienvenue %s %s": "Welcome %s %s",
|
||||
"Blocage après échecs": "Blocking after chess",
|
||||
"Blog": "Blog",
|
||||
"Bords arrondis": "Rounded edges",
|
||||
"Bordure des blocs": "Blocks border",
|
||||
"Bordure des champs": "Fields border",
|
||||
"Bouton Aide": "Help button",
|
||||
"Bouton Standard": "Standard button",
|
||||
"Bouton de validation": "Validation button",
|
||||
"Bouton effacement": "Delete button",
|
||||
"Bouton retour": "Return button",
|
||||
"Bouton standard": "Standard button",
|
||||
"Bouton validation": "Validation button",
|
||||
"Boutons": "Buttons",
|
||||
"Caché": "Hidden",
|
||||
"Cachée": "Hidden",
|
||||
"Captcha complexe": "Complex captcha",
|
||||
"Captcha à la connexion": "Captcha at connecting",
|
||||
"Captcha, identifiant ou mot de passe incorrects": "Incorrect captcha, login or password",
|
||||
"Capture d'écran Open Graph": "Open Graph screenshot",
|
||||
"Capture d'écran générée avec succès": "Successful generated screenshot",
|
||||
"Casse": "Case",
|
||||
"Catalogue": "Store",
|
||||
"Catégorie": "Category",
|
||||
"Ce membre pourra téléverser ou télécharger des fichiers dans le dossier 'partage' et ses sous-dossiers": "This member upload or download files in the 'Sharing' folder and its subfolders",
|
||||
"Cette page ne doit pas apparaître dans l'arborescence du menu. Créez une page orpheline.": "This page should not appear in the menu tree. Create an orphan page.",
|
||||
"Cette redirection ne concerne que les pages d'administration du site.": "This redirection only concerns the administration pages of the site.",
|
||||
"Chaîne Youtube": "Youtube channel",
|
||||
"Chiffres": "Numbers",
|
||||
"Cible": "Target",
|
||||
"Cliquez sur une zone afin d'accéder à ses options de personnalisation.": "Click on an area to access its customization options.",
|
||||
"Commentaire": "Comment",
|
||||
"Complète": "Complete",
|
||||
"Compte administrateur": "Administrator account",
|
||||
"Compte de l'utilisateur": "User Account",
|
||||
"Compte verrouillé": "Locked",
|
||||
"Configuration": "Setup",
|
||||
"Configuration du module": "Module setup",
|
||||
"Configurer": "Configure",
|
||||
"Configurer mon compte": "Set up my account",
|
||||
"Confirmation": "Confirmation",
|
||||
"Confirmer la suppression de cet utilisateur": "Confirm the deletion of this user",
|
||||
"Confirmer la dissociation du module de cette page": "Confirm the dissociation of the module of this page",
|
||||
"Confirmer la désinstallation du module": "Confirm the uninstalling of the module",
|
||||
"Confirmer la suppression de cet utilisateur": "Confirm the deletion of this user",
|
||||
"Confirmer la suppression de cette langue": "Confirm deletion of this language",
|
||||
"Confirmer la suppression de la page": "Confirm the deletion of the page",
|
||||
"Confirmer la suppression des données du module": "Confirm the deletion of module data",
|
||||
"Confirmez-vous la suppression de cette page ?": "Do you confirm the deletion of this page?",
|
||||
"Connexion": "Connection",
|
||||
"Consulter l'aide en ligne": "Online help",
|
||||
"Contents": "Contents",
|
||||
"Contenu": "Contents",
|
||||
"Contenu HTML": "HTML contents",
|
||||
"Contenu avancé": "Advanced contents",
|
||||
"Contenu du menu vertical": "Vertical menu content",
|
||||
"Contrôle total": "Full control",
|
||||
"Cookies": "Cookies",
|
||||
"Cookies Zwii": "Cookies Zwii",
|
||||
"Copie de contenus localisés": "Localized content copy",
|
||||
"Copie de sites inter-langues": "Copy of inter-language sites",
|
||||
"Copie des traductions rédigées": "Copy of written translations",
|
||||
"Copie terminée avec des erreurs": "Copy finished with errors",
|
||||
"Copie terminée avec succès": "Copy successfully completed",
|
||||
"Copier": "Copy",
|
||||
"Copier sauvegardes auto": "Copy auto backups",
|
||||
"Couleur de fond automatique": "Automatic background color",
|
||||
"Couleur icône haut de page": "Color of top page icon",
|
||||
"Couleur texte page active": "Active page text color",
|
||||
"Couleur unie ou papier-peint": "United color or wallpaper",
|
||||
"Couleur visible en l'absence d'une image.<br />Le curseur horizontal règle le niveau de transparence.": "Visible color in the absence of an image. <br /> The horizontal cursor regulates the level of transparency.",
|
||||
"Couleur visible en l'absence d'une image.<br />Le curseur horizontal règle le niveau de transparence. La couleur du texte est automatique.": "Visible color in the absence of an image. <br /> The horizontal cursor regulates the level of transparency. The color of the text is automatic.",
|
||||
"Couleurs": "Colors",
|
||||
"Dans le site": "Into the site",
|
||||
"Dans quelle langue utiliserez-vous Zwii ?": "In which language will you use Zwii?",
|
||||
"Date": "Date",
|
||||
"Description": "Site description",
|
||||
"Disponible si le consentement des cookies est activé.": "Available if cookie consent is enabled.",
|
||||
"Disposition": "Layout",
|
||||
"Données %s copiées vers %s": "Data %s copied to %s",
|
||||
"Données des modules": "Module data",
|
||||
"Données importées": "Imported data",
|
||||
"Dossier": "Folder",
|
||||
"Droits sur les dossiers": "Folder authorizations",
|
||||
"Droits sur les fichiers": "File authorizations",
|
||||
"Dupliquer": "Duplicate",
|
||||
"Dupliquer la page": "Duplicate the page",
|
||||
"Déconnecte les sessions ouvertes précédemment sur d'autres navigateurs ou terminaux. Activation recommandée.": "Disconnects the previously opened sessions on other browsers or terminals. Recommended activation.",
|
||||
"Déconnecter": "Disconnect",
|
||||
"Déconnexion !": "Logout!",
|
||||
"Déconnexion automatique": "Automatic disconnection",
|
||||
"Définir par défaut": "Set as default",
|
||||
"Dévoiler le mot de passe": "Reveal the password",
|
||||
"Effacer": "Delete",
|
||||
"Effacer la page": "Delete the page",
|
||||
"Effacer tous les commentaires": "Delete all Comments",
|
||||
"Effacer toutes les statistiques": "Delete all statistics",
|
||||
"Effacer un commentaire": "Delete Comment",
|
||||
"Effacer une catégorie": "Delete category",
|
||||
"Emplacement :": "Location:",
|
||||
"Emplacement dans le menu": "Location in the menu",
|
||||
"En bas au centre": "Down in the center",
|
||||
"En bas à droite": "At the bottom right",
|
||||
"En bas à gauche": "At the bottom left",
|
||||
"En cas de changement de module, les données du module précédent seront supprimées.": "In the event of a module change, data from the previous module will be deleted.",
|
||||
"En dessous du site": "Below the site",
|
||||
"En haut au centre": "Top in the center",
|
||||
"En haut à droite": "Top right",
|
||||
"En haut à gauche": "On the top corner left",
|
||||
"En position libre ajoutez le module en plaçant [MODULE] à l'endroit voulu dans votre page.": "In free position add the module by placing [module] to the desired location in your page.",
|
||||
"En-dehors du site": "Outside the site",
|
||||
"Enregistrer": "Save",
|
||||
"Envoyer un message de confirmation": "Send a confirmation message",
|
||||
"Erreur : sauvegarde non générée !": "Error: non-generated backup!",
|
||||
"Erreur d'URL": "URL error",
|
||||
"Erreur d'extraction, vérifiez les permissions": "Extraction error, check permissions",
|
||||
"Erreur de copie": "Copy error",
|
||||
"Erreur de copie, vérifiez les permissions": "Copy error, check permissions",
|
||||
"Erreur de lecture, vérifiez les permissions": "Reading error, check permissions",
|
||||
"Erreur inconnue": "unknown error",
|
||||
"Erreur inconnue, le module n'est pas installé": "Unknown error, the module is not installed",
|
||||
"Export CSV": "Export CSV",
|
||||
"Expéditeur": "From",
|
||||
"Extension": "Extension",
|
||||
"Extraire": "Extract",
|
||||
"Facebook": "Facebook",
|
||||
"Famille": "Family",
|
||||
"Favicon thème sombre": "Dark theme favicon",
|
||||
"Feuille de style spécifique à la page.": "Style sheet specific to the page.",
|
||||
"Fichiers": "Files",
|
||||
"Fichiers effacés": "Erased files",
|
||||
"Fil d'Ariane dans le titre": "Breadcrumb in the title",
|
||||
"Fond du sous-menu": "Background of the submenu",
|
||||
"FontId": "FontId",
|
||||
"Fonte": "Font",
|
||||
"Fonte actualisée": "Update",
|
||||
"Fonte créée": "Font created",
|
||||
"Fonte en ligne": "Online font",
|
||||
"Fonte installée": "Installed font",
|
||||
"Fonte non créée, ressource absente !": "Font not created, absent resource!",
|
||||
"Fonte supprimée": "Font deleted",
|
||||
"Fontes": "Fonts",
|
||||
"Format incorrect": "Wrong format",
|
||||
"Formulaire": "Form",
|
||||
"Fréquence de recherche": "Search frequency",
|
||||
"Fuseau horaire": "Time zone",
|
||||
"Gabarits de page - Barre latérale": "Page templates - Sidebar",
|
||||
"Gestion": "Management",
|
||||
"Gestion des modules": "Module management",
|
||||
"Gestion des thèmes": "Themes management",
|
||||
"Gestionnaire de fichiers": "File Manager",
|
||||
"Github": "Github",
|
||||
"Grande": "Large",
|
||||
"Grande (220%)": "Grande (220%)",
|
||||
"Grande (300px)": "Grande (300px)",
|
||||
"Gras": "Fetter",
|
||||
"Groupe": "Group",
|
||||
"Groupe associé": "Associated Group",
|
||||
"Groupe requis pour accéder à la page :": "Group required to access the page:",
|
||||
"Groupes": "Groups",
|
||||
"Générer sitemap.xml et robots.txt": "Generate sitemap.xml and robots.txt",
|
||||
"Générer une capture Open Graph": "Generate an Open Graph capture",
|
||||
"Gérer les catégories": "Manage categories",
|
||||
"Gérer les commentaires": "Manage comments",
|
||||
"Gérer les données": "Manage Data",
|
||||
"Hauteur": "Height:",
|
||||
"Hauteur de l'image": "Image Height",
|
||||
"Hauteur de l'image sélectionnée": "Selected Image Height",
|
||||
"Hauteur maximale": "Maximum height",
|
||||
"ID de la chaîne : https://www.youtube.com/channel/[ID].": "Channel ID: https://www.youtube.com/channel/ [ID].",
|
||||
"Icône": "Icon",
|
||||
"Icône avec bulle de texte": "Icon with text bubble",
|
||||
"Icône haut de page, couleur arrière-plan": "Top page icon, background color",
|
||||
"Identifiant": "Identifier",
|
||||
"Identifiant (sans espace ni majuscule)": "Identifier (without space or capital letters)",
|
||||
"Identité": "Identity",
|
||||
"Identité de la fonte": "Identity of the font",
|
||||
"Identité du site": "Site identity",
|
||||
"Il apparaît dans la barre de titre et les partages sur les réseaux sociaux.": "It appears in the title bar and sharing on social networks.",
|
||||
"Image": "Image",
|
||||
"Image étirée (100% 100%)": "Stretched image (100% 100%)",
|
||||
"Important": "Important",
|
||||
"Importante": "Important",
|
||||
"Importation d'utilisateurs": "Import of users",
|
||||
"Importation de fichier plat CSV": "CSV flat file import",
|
||||
"Importation effectuée": "Import done",
|
||||
"Importer": "Import",
|
||||
"Importer dans": "Import into",
|
||||
"Importer des utilisateurs en masse": "Import mass users",
|
||||
"Impossible d'ouvrir l'archive": "Impossible to open the archive",
|
||||
"Impossible de modifier votre propre groupe.": "Unable to modify your own group.",
|
||||
"Impossible de soumettre le formulaire, car il contient des erreurs": "Unable to submit the form, as it contains errors",
|
||||
"Impossible de supprimer une page contenant des pages enfants": "Unable to delete a page containing children's pages",
|
||||
"Impossible de supprimer votre propre compte": "Unable to delete your own account",
|
||||
"Inclure le contenu du gestionnaire de fichiers": "Include the content of the file manager",
|
||||
"Incorrect": "Incorrect",
|
||||
"Informations": "Informations",
|
||||
"Instagram": "Instagram",
|
||||
"Installation terminée": "Installation completed",
|
||||
"Installer": "Install",
|
||||
"Installer depuis le catalogue en ligne": "Install from the online catalog",
|
||||
"Installer depuis une archive": "Install from an archive",
|
||||
"Installer les données d'un module": "Install a module data",
|
||||
"Installer ou mettre à jour un module téléchargé": "Install or update a downloaded module",
|
||||
"Installer un module": "Install a module",
|
||||
"Installer un thème archivé (site ou administration)": "Install an archived theme (site or administration)",
|
||||
"Instructions JS ou jquery spécifiques à la page.": "JS or JQuery instructions specific to the page.",
|
||||
"Interface": "Interface",
|
||||
"Jeton invalide": "Invalid token",
|
||||
"Journal réinitialisé avec succès": "Log file successfully reset",
|
||||
"Journalisation": "Journalization",
|
||||
"L'archive a été déposée dans le gestionnaire de fichiers. Les archives inférieures à la version 9 ne sont pas acceptées.": "The archive was deposited in the file manager. Archives below version 9 are not accepted.",
|
||||
"L'identifiant est défini lors de la création du compte, il ne peut pas être modifié.": "The identifier is defined when creating the account, it cannot be changed.",
|
||||
"La carte du site a été mise à jour": "The site card has been updated",
|
||||
"La copie de sauvegarde du fichier htaccess n'a pas été restaurée !": "Backup copy of htaccess file has not been restored!",
|
||||
"La description d'une page participe à son référencement, chaque page doit disposer d'une description différente.": "The description of a page participates in its referencing, each page must have a different description.",
|
||||
"La page %s est ouverte par l'utilisateur %s": "Page %s opened by user %s",
|
||||
"La page demandée n'existe pas ou est introuvable (erreur 404)": "This page does not exists (error 404)",
|
||||
"La page est affichée dans un menu horizontal mais pas dans le menu vertical d'une barre latérale.": "The page is displayed in a horizontal menu but not in the vertical menu of a sidebar.",
|
||||
"La première page que vos visiteurs verront.": "The first page that your visitors will see.",
|
||||
"La règlementation française impose un anonymat de niveau 2": "French regulations require level 2 anonymity",
|
||||
"La réécriture d'URL n'a pas été restaurée !": "URL rewriting has not been restored!",
|
||||
"La sauvegarde des fichiers peut prendre du temps. Continuer ?": "The backup of the files can take time. Continue?",
|
||||
"La suppression a échoué": "The deletion failed",
|
||||
"La version installée est plus récente": "The installed version is more recent",
|
||||
"La vérification est quotidienne. Option désactivée si la configuration du serveur ne le permet pas.": "The verification is daily. Option deactivated if the server configuration does not allow it.",
|
||||
"Langue de l'administration": "Language of administration",
|
||||
"Langue du site par défaut": "Default site language",
|
||||
"Langue par défaut": "Default language",
|
||||
"Langues": "Languages",
|
||||
"Langues disponibles": "Available languages",
|
||||
"Langues installées": "Installed languages",
|
||||
"Largeur": "Width",
|
||||
"Largeur de l'image": "Image Width",
|
||||
"Largeur du site": "Site Width",
|
||||
"Le curseur horizontal règle le niveau de transparence, le placer tout à la gauche pour un surlignement invisible.": "The horizontal cursor regulates the level of transparency, place it on the left for invisible highlights.",
|
||||
"Le curseur horizontal règle le niveau de transparence.": "The horizontal cursor regulates the level of transparency.",
|
||||
"Le fuseau horaire est utile au bon référencement": "The time zone is useful for the right SEO",
|
||||
"Le menu accessoire est aligné à droite de la barre de menu, c'est un emplacement réservé aux drapeaux et au bouton de connexion.": "The accessory menu is aligned to the right of the menu bar, it is a place reserved for flags and the login button.",
|
||||
"Le menu horizontal intégral": "The full horizontal menu",
|
||||
"Le module %s a été %s": "The module %s was %s",
|
||||
"Le module %s de la page %s a été supprimé": "The %s module of the %s has been deleted",
|
||||
"Le module %s est désinstallé, il reste peut-être des données dans %s": "The module %s is uninstalled, there may be data in %s",
|
||||
"Le sous-menu de la page parente": "The parent page submenu",
|
||||
"Le survol d'une icône de l'écran de connexion affiche temporairement le mot de passe.": "Flyover of an icon on the connection screen temporarily displays the password.",
|
||||
"Le titre court est affiché dans les menus. Il peut être identique au titre de la page.": "The short title is displayed in the menus. It can be identical to the page title.",
|
||||
"Les langues sélectionnées sont identiques": "The selected languages are identical",
|
||||
"Les mentions légales sont obligatoires en France. Une option du pied de page ajoute un lien discret vers cette page.": "Legal notices are compulsory in France. An option of the footer adds a discrete link to this page.",
|
||||
"Les modifications que vous avez apportées ne seront peut-être pas enregistrées.": "The changes you have made may not be recorded.",
|
||||
"Les tailles des polices de la bannière, de menu et de pied de page sont proportionnelles à cette taille.": "The font sizes of the banner, menu and footer are proportional to this size.",
|
||||
"Lettres": "Letters",
|
||||
"Libre": "Libre",
|
||||
"Licence :": "Licence:",
|
||||
"Lien de connexion": "Login link",
|
||||
"Lien page des mentions légales.": "Link of legal notices.",
|
||||
"Liens": "Links",
|
||||
"Limitation des tentatives": "Limitation of attempts",
|
||||
"Limitée au site": "Limited to the site",
|
||||
"Linkedin": "Linkedin",
|
||||
"Liste noire": "Blacklist",
|
||||
"Liste noire réinitialisée avec succès": "Blacklist successfully reset",
|
||||
"Lors d'une mise à jour automatique, conserve le fichier htaccess de la racine du site.": "During an automatic update, keeps the htaccess file of the site root.",
|
||||
"Léger": "Light",
|
||||
"Légère": "Light",
|
||||
"Maigre": "Lean",
|
||||
"Maintenance": "Maintenance",
|
||||
"Majuscule à chaque mot": "Capper with each word",
|
||||
"Majuscules": "Capital letters",
|
||||
"Marges verticales": "Vertical margins",
|
||||
"Masquer la bannière en écran réduit": "Hide the banner in reduced screen",
|
||||
"Masquer la page et les pages enfants dans le menu d'une barre latérale": "Hide the page and children's pages in the menu of a sidebar",
|
||||
"Masquer les pages enfants dans le menu horizontal": "Hide children's pages in the horizontal menu",
|
||||
"Membre": "Member",
|
||||
"Membre avec droit de partage": "Member with sharing rights",
|
||||
"Membre simple": "Simple member",
|
||||
"Mentions légales": "Legal notice",
|
||||
"Menu": "Menu",
|
||||
"Menu accessoire": "Accessory menu",
|
||||
"Menu burger dans écran réduit": "Burger menu in reduced screen",
|
||||
"Menu standard": "Standard menu",
|
||||
"Message d'acceptation des Cookies": "Cookie acceptance message",
|
||||
"Message de consentement aux cookies": "Cookie consent message",
|
||||
"Mettre à jour": "Update",
|
||||
"Mettre à jour le module orphelin": "Update the orphan module",
|
||||
"Minuscules": "Tiny",
|
||||
"Mise en forme des titres": "Formatting of titles",
|
||||
"Mise en forme du texte": "Text formatting",
|
||||
"Mise en forme du titre": "Title formatting",
|
||||
"Mise en page": "Layout",
|
||||
"Mise à jour": "Update",
|
||||
"Mise à jour automatisée": "Automated update",
|
||||
"Mise à jour de ZwiiCMS": "Zwiicms update",
|
||||
"Mise à jour terminée avec succès.": "Successful update completed.",
|
||||
"Modifications enregistrées": "Modifications recorded",
|
||||
"Module": "Module",
|
||||
"Module de la page": "Page module",
|
||||
"Modules": "Modules",
|
||||
"Modules configurés": "Configured modules",
|
||||
"Modules installés": "Installed modules",
|
||||
"Modules orphelins": "Orphaned modules",
|
||||
"Mot de passe": "Password",
|
||||
"Mot de passe oublié": "Forgot your password",
|
||||
"Mot de passe perdu": "Lost password",
|
||||
"Motorisé par": "Powered by",
|
||||
"Moyen": "Medium",
|
||||
"Moyenne": "Medium",
|
||||
"Moyenne (200%)": "Average (200%)",
|
||||
"Moyenne (200px)": "Average (200px)",
|
||||
"Méta-description": "Meta-description",
|
||||
"Méta-titre": "Meta title",
|
||||
"Ne pas afficher": "Do not display",
|
||||
"Ne pas charger l'exemple de site (utilisateurs avancés)": "Do not load the example of a site (advanced users)",
|
||||
"Ne pas répéter": "Do not repeat",
|
||||
"Ne pas saisir les balises": "Don't type tags",
|
||||
"News": "",
|
||||
"Niveau 1 (192.168.12.x)": "Level 1 (192.168.12.x)",
|
||||
"Niveau 2 (192.168.x.x)": "Level 2 (192.168.x.x)",
|
||||
"Niveau 3 (192.x.x.x)": "Level 3 (192.x.x.x)",
|
||||
"Nom": "Last Name",
|
||||
"Nom Prénom": "Last name First Name",
|
||||
"Nom du profil": "Profile Name",
|
||||
"Nom utilisateur": "Username",
|
||||
"Non": "No",
|
||||
"Non tronquée": "Unmanned",
|
||||
"Notre site est actuellement en maintenance. Nous sommes désolés pour la gêne occasionnée et faisons notre possible pour être rapidement de retour.": "Our site is currently under maintenance. We are sorry for the inconvenience caused and do our best to be quickly back.",
|
||||
"Nouveau contenu localisé": "New localized content",
|
||||
"Nouveau mot de passe": "New Password",
|
||||
"Nouveau mot de passe enregistré": "New password recorded",
|
||||
"Nouvel utilisateur": "New user",
|
||||
"Nouvelle page créée": "New page created",
|
||||
"Nouvelle page ou barre latérale": "New page or sidebar",
|
||||
"Obligatoire": "Missing",
|
||||
"Ombre": "Shadow",
|
||||
"Option active en mode déconnecté uniquement, les pages enfants sont visibles et accessibles.": "Active option in disconnected mode only, children's pages are visible and accessible.",
|
||||
"Option recommandée pour sécuriser la connexion. S'applique à tous les captchas du site. Le captcha simple se limite à une addition de nombres de 0 à 10. Le captcha complexe utilise quatre opérations de nombres de 0 à 20. Activation recommandée.": "Recommended option to secure the connection. Applies to all the Captchas of the site. Simple Captcha is limited to an addition of numbers from 0 to 10. Complex Captcha uses four numbers of 0 to 20. Recommended activation.",
|
||||
"Options": "Options",
|
||||
"Options avancées": "Advanced options",
|
||||
"Origine": "Origin",
|
||||
"Oui": "Yes",
|
||||
"Page": "Page",
|
||||
"Page 2/3 - barre 1/3": "Page 2/3 - Sidebar 1/3",
|
||||
"Page 3/4 - barre 1/4": "Page 3/4 - Sidebar 1/4",
|
||||
"Page associée": "Associated page",
|
||||
"Page de recherche": "Search page",
|
||||
"Page dupliquée": "Duplicate page",
|
||||
"Page et module dupliqués": "Duplicated page and module",
|
||||
"Page inexistante, erreur 404": "Page non-existent, error 404",
|
||||
"Page non cliquable": "Non-clickable page",
|
||||
"Page parent": "Parent page",
|
||||
"Page standard": "Standard page",
|
||||
"Page supprimée": "Deleted page",
|
||||
"Pages dans le menu": "Pages in the menu",
|
||||
"Pages du site": "Site pages",
|
||||
"Pages et les modules de": "Pages and modules of",
|
||||
"Pages orphelines": "Orphan pages",
|
||||
"Papier peint": "Wallpaper",
|
||||
"Par défaut le menu est affiché APRES le contenu de la page. Pour le positionner à un emplacement précis, insérez [MENU] dans le contenu de la page.": "By default the menu is displayed after the content of the page. To position it at a specific location, insert [MENU] into the content of the page.",
|
||||
"Paramètres": "Settings",
|
||||
"Paramètres de la localisation": "Location parameters",
|
||||
"Paramètres de la sauvegarde": "Backup settings",
|
||||
"Paramètres du profil": "Profile Settings",
|
||||
"Paramètres à utiliser lorsque votre hébergeur ne propose pas la fonctionnalité d'envoi de mail.": "Settings to use when your host does not offer the mail sending feature.",
|
||||
"Pas de marge au-dessus et en dessous du site": "No margin above and below the site",
|
||||
"Pensez à supprimer le cache de votre navigateur si la favicon ne change pas.": "Remember to delete your browser's cache if the favicon does not change.",
|
||||
"Permission": "Permission",
|
||||
"Permission et référencement": "Permission and SEO",
|
||||
"Permissions": "Permissions",
|
||||
"Permissions sur les dossiers": "Folder Permissions",
|
||||
"Permissions sur les fichiers": "File Permissions",
|
||||
"Permissions sur les pages": "Page Permissions",
|
||||
"Petite": "Small",
|
||||
"Petite (150px)": "Small (150px)",
|
||||
"Petite (180%)": "Petite (180%)",
|
||||
"Pied de page": "Footer",
|
||||
"Pinterest": "Pinterest",
|
||||
"Plan du site": "Sitemap",
|
||||
"Police des titres": "Titles font",
|
||||
"Police du texte": "Text font",
|
||||
"Port SMTP": "SMTP port",
|
||||
"Port du proxy": "Proxy port",
|
||||
"Position": "Position",
|
||||
"Position du module": "Position of the module",
|
||||
"Pour définir la page comme barre latérale, choisissez l'option dans la liste.": "To define the page as a sidebar, choose the option from the list.",
|
||||
"Presse Papier": "Clipboard",
|
||||
"Presse papier": "Clipboard",
|
||||
"Profils des groupes": "Group Profiles",
|
||||
"Proportionnelle à la taille définie dans le site.": "Proportional to that defined in the site.",
|
||||
"Prénom": "First name",
|
||||
"Prénom Nom": "Firstname name",
|
||||
"Préparation de la mise à jour": "Preparation of the update",
|
||||
"Préserver le fichier htaccess racine": "Preserve the root htaccess file",
|
||||
"Préserver les comptes des utilisateurs déjà installés": "Preserve user accounts already installed",
|
||||
"Prévenir l'utilisateur par mail": "Prevent the user by email",
|
||||
"Prévisualiser": "Preview",
|
||||
"Pseudo": "Pseudo",
|
||||
"Rang 9 > rang 1. Le profil de rang 1 n'est pas modifiable.": "Rank 9 > Rank 1. The profile of Rank 1 is not editable.",
|
||||
"Ratio": "Ratio",
|
||||
"Ratio :": "Ratio:",
|
||||
"Recherche": "Search",
|
||||
"Recherche dans le site": "Search on the site",
|
||||
"Rechercher": "Search",
|
||||
"Rechercher une mise à jour en ligne": "Search for an online update",
|
||||
"Redirection": "Redirection",
|
||||
"Redirection vers la connexion": "Redirection to connection",
|
||||
"Renommer": "Rename",
|
||||
"Renseignez les champs ci-dessous pour finaliser l'installation.": "Fill in the fields below to finalize the installation.",
|
||||
"Responsive (contain)": "Responsive (contain)",
|
||||
"Responsive (cover)": "Responsive (cover)",
|
||||
"Restauration des bases de données absentes": "Restoring missing databases",
|
||||
"Restauration effectuée avec succès": "Restoration successfully completed",
|
||||
"Restaurer": "Restore",
|
||||
"Restaurer les données du site": "Restore site data",
|
||||
"Rester connecté sur ce navigateur": "Stay connected on this browser",
|
||||
"Retour": "Return",
|
||||
"Rien à importer, erreur de format ou fichier incorrect": "Nothing to import, format error or incorrect file",
|
||||
"Rédacteur": "Editor",
|
||||
"Référencement": "SEO",
|
||||
"Réinitialisation du mot de passe": "Reset password",
|
||||
"Réinitialiser avec le thème par défaut": "Reset with the default theme",
|
||||
"Réinitialiser la feuille de style": "Reset the style sheet",
|
||||
"Réinitialiser la liste": "Reset the list",
|
||||
"Réinitialiser le journal": "Reset the log file",
|
||||
"Réinstaller": "Reinstall",
|
||||
"Répétition": "Repetition",
|
||||
"Réseau": "Network",
|
||||
"Réseaux sociaux": "Social networks",
|
||||
"S'ouvre dans un nouvel onglet": "Opens in a new tab",
|
||||
"SMTP": "SMTP",
|
||||
"SMTP personnalisé": "Custom SMTP",
|
||||
"Saisir la clé, puis valider le formulaire avant de cliquer sur le bouton de génération": "Enter the key, then validate the form before clicking on the generation button",
|
||||
"Saisissez le Titre de gestion des cookies.": "Enter the title of the cookie management window.",
|
||||
"Saisissez le message pour les cookies déposés par ZwiiCMS, nécessaires au fonctionnement et qui ne nécessitent pas de consentement.": "Enter the message for cookies set by Zwiicms, necessary for operation and which do not require consent.",
|
||||
"Saisissez le texte du lien vers les mentions légales,la page doit être définie dans la configuration du site.": "Enter the text of the link to the legal notices, the page must be defined in the site configuration.",
|
||||
"Saisissez votre ID : https://pinterest.com/[ID].": "Enter your ID: https://pinterest.com/[ID].",
|
||||
"Saisissez votre ID : https://twitter.com/[ID].": "Enter your ID: https://twitter.com/[ID].",
|
||||
"Saisissez votre ID : https://www.facebook.com/[ID].": "Enter your ID: https://www.facebook.com/).",
|
||||
"Saisissez votre ID : https://www.instagram.com/[ID].": "Enter your ID: https://www.instagram.com/ [ID].",
|
||||
"Saisissez votre ID Github : https://github.com/[ID].": "Enter your GitHub ID: https://github.com/[ID].",
|
||||
"Saisissez votre ID Linkedin : https://fr.linkedin.com/in/[ID].": "Enter your LinkedIn ID: https://fr.linkedin.com/in/[ID].",
|
||||
"Saisissez votre ID Utilisateur : https://www.youtube.com/user/[ID].": "Enter your user ID: https://www.youtube.com/user/ [ID].",
|
||||
"Sauvegarde": "Backup",
|
||||
"Sauvegarde automatique quotidienne du site": "Daily automatic backup of the site",
|
||||
"Sauvegarde du thème dans le": "Backup of the theme in the",
|
||||
"Sauvegarde générée avec succès.": "Successfully generated backup.",
|
||||
"Sauvegarder": "Backup",
|
||||
"Sauvegarder et télécharger le module": "Save and download the module",
|
||||
"Sauvegarder le module dans le gestionnaire de fichiers": "Save the module in the file manager",
|
||||
"Sauvegarder les données du module dans le gestionnaire de fichiers": "Save module data in the file manager",
|
||||
"Sauvegarder les données du site": "Save site data",
|
||||
"Script dans body": "Script in body",
|
||||
"Script dans head": "Script in head",
|
||||
"Scripts externes": "External scripts",
|
||||
"Se déconnecter": "Logout",
|
||||
"Service en ligne inaccessible": "Inaccessible online service",
|
||||
"Seul un administrateur peut se connecter lors d'une maintenance": "Only an administrator can login during maintenance",
|
||||
"Si le contenu du gestionnaire de fichiers est très volumineux, mieux vaut une copie par FTP.": "If the content of the file manager is very large, it is better to copy by FTP.",
|
||||
"Signature": "Signature",
|
||||
"Site": "Site",
|
||||
"Site en maintenance": "Site under maintenance",
|
||||
"Size": "Size",
|
||||
"Source": "Source",
|
||||
"Standard": "Standard",
|
||||
"Style": "Style",
|
||||
"Suppression interdite": "Deletion prohibited",
|
||||
"Suppression interdite, page active dans la configuration du site": "Deletion prohibited, active page in site configuration",
|
||||
"Supprime le point d'interrogation dans les URL, l'option est indisponible avec les autres serveurs Web": "Deletes the question mark in the URLs, the option is unavailable with other web servers",
|
||||
"Supprimer": "Delete",
|
||||
"Supprimer la page": "Delete the page",
|
||||
"Supprimer le module": "Delete the module",
|
||||
"Supprimer toutes les sauvegardes automatiques ?": "Remove all automatic backups?",
|
||||
"Sur l'axe horizontal": "On the horizontal axis",
|
||||
"Sur l'axe vertical": "On the vertical axis",
|
||||
"Sur les deux axes": "On both axes",
|
||||
"Sécurité": "Security",
|
||||
"Sécurité de la connexion": "Connection security",
|
||||
"Sécurité désactivée": "Safety deactivated",
|
||||
"Sélectionner un fichier": "Select a file",
|
||||
"Sélectionnez au moins un contenu à afficher": "Select at least one content to display",
|
||||
"Sélectionnez la langue à copier vers une langue cible": "Select the language to copy to a target language",
|
||||
"Sélectionnez une icône adaptée à un thème sombre.<br>Pensez à supprimer le cache de votre navigateur si la favicon ne change pas.": "Select an icon adapted to a dark theme. <br> Remember to delete your browser's cache if the favicon does not change.",
|
||||
"Sélectionnez une image ou une icône de petite dimension": "Select a small image or icon",
|
||||
"Sélectionnez une langue": "Select a language",
|
||||
"Sélectionnez une page contenant le module 'Recherche'. Une option du pied de page ajoute un lien discret vers cette page.": "Select a page containing the 'research' module. An option of the footer adds a discrete link to this page.",
|
||||
"Sélectionnez une page pour activer": "Select a page to activate",
|
||||
"Séparateur": "Separator",
|
||||
"Taille": "Size",
|
||||
"Text": "Text",
|
||||
"Texte": "Text",
|
||||
"Thème": "Theme",
|
||||
"Thème de l'administration": "Administration theme",
|
||||
"Thème du site": "Site theme",
|
||||
"Thème importé": "Imported theme",
|
||||
"Thèmes": "Themes",
|
||||
"Titre": "Title",
|
||||
"Titre court": "Short title",
|
||||
"Titre masqué": "Masked title",
|
||||
"Titre masqué dans la page": "Masked hidden in the page",
|
||||
"Titres": "Titles",
|
||||
"Tous les dossiers": "All Folders",
|
||||
"Tous les droits d'édition des contenus": "All content editing rights",
|
||||
"Tout Effacer": "Clear All",
|
||||
"Traduction supprimée": "Translation deleted",
|
||||
"Très grande": "Very large",
|
||||
"Très grande (240%)": "Very large (240%)",
|
||||
"Très grande (400px)": "Very large (400px)",
|
||||
"Très important": "Very important",
|
||||
"Très importante": "Very important",
|
||||
"Très léger": "Very light",
|
||||
"Très légère": "Very light",
|
||||
"Très petite": "Very small",
|
||||
"Très petite (100px) ": "Very small (100px)",
|
||||
"Très petite (160%)": "Very small (160%)",
|
||||
"Twitter": "Twitter",
|
||||
"Type de captcha": "Type of Captcha",
|
||||
"Type de proxy": "Proxy type",
|
||||
"Téléchargement et validation de l'archive": "Download and validation of the archive",
|
||||
"Télécharger": "Download",
|
||||
"Télécharger la liste": "Download list",
|
||||
"Télécharger le journal": "Download logs",
|
||||
"Télécharger le module dans le gestionnaire de fichiers": "Download the module in the file manager",
|
||||
"Téléverser": "Upload",
|
||||
"URL incorrecte": "Incorrect url",
|
||||
"Un mail a été envoyé pour confirmer la réinitialisation": "An email was sent to confirm the reset",
|
||||
"Une archive du dossier /site/data est conservée pendant 30 jours. Activation recommandée": "An archive of the file /site/data is kept for 30 days. Recommended activation",
|
||||
"Une erreur est survenue lors de l'étape :": "An error occurred during the stage:",
|
||||
"Url du fichier de fonte": "Font file URL",
|
||||
"Utilisateur inexistant": "Non-existent user",
|
||||
"Utilisateur supprimé": "User deleted",
|
||||
"Utilisateurs": "Users",
|
||||
"Valider": "To validate",
|
||||
"Version": "Version",
|
||||
"Version n°": "Version n°",
|
||||
"Vider dossier sauvegardes auto": "Empty auto backup files",
|
||||
"Visiteur": "Visitor",
|
||||
"Vous n'êtes pas autorisé à consulter cette page (erreur 403)": "You are not authorised to view this page (error 403)",
|
||||
"Youtube": "Youtube",
|
||||
"ZwiiCMS - Installation": "ZwiiCMS - Installation",
|
||||
"actualisé": "updated",
|
||||
"favicon.ico": "favicon.ico",
|
||||
"faviconDark.ico": "favicondark.ico",
|
||||
"gestionnaire de fichiers": "file manager",
|
||||
"installé": "installed",
|
||||
"jour": "day",
|
||||
"jours": "days",
|
||||
"sauvegardé avec succès": "successfully saved",
|
||||
"vers ZwiiCMS": "to ZwiiCMS",
|
||||
"À droite": "Right",
|
||||
"À gauche": "Left",
|
||||
"À l'emplacement du mot clé [MODULE] dans la page": "At the location of the keyword [MODULE] on the page",
|
||||
"Échec de l'écriture, vérifiez les permissions": "Failure of writing, check permissions",
|
||||
"Échecs": "Fail",
|
||||
"Éditer": "Edit",
|
||||
"Éditer la page": "Edit the page",
|
||||
"Éditer les dialogues": "Edit dialogs",
|
||||
"Éditer une catégorie": "Edit category",
|
||||
"Éditeur": "Editor",
|
||||
"Éditeur CSS": "CSS editor",
|
||||
"Éditeur JS": "JS editor",
|
||||
"Éditeur de script %s": "Script editor %s",
|
||||
"Éditeur de script dans Body": "Script editor in Body",
|
||||
"Éditeur de script dans Head": "Script editor in Head",
|
||||
"Éditeur simple": "Simple editor",
|
||||
"Édition des pages": "Page editing",
|
||||
"Édition du profil %s": "Edit Profile %s",
|
||||
"Éléments": "Items",
|
||||
"Étendu sur la page": "Spread across the page",
|
||||
"Étiquettes des pages spéciales": "Special pages labels",
|
||||
"Dimensions minimales": "Minimum dimensions",
|
||||
"Taille maximale du fichier": "Maximum file size",
|
||||
"5 Mo pour les images JPEG": "5 MB for JPEG images",
|
||||
"1 Mo pour les images PNG": "1 MB for PNG images",
|
||||
"Poids": "Weight",
|
||||
"Supprimer ce profil ?": "Delete this profile?",
|
||||
"Masqué": "Hidden",
|
||||
"Haut de page": "Top of Page",
|
||||
"Bas de page": "Bottom of Page",
|
||||
"Petit triangle": "Small Triangle",
|
||||
"Grand triangle": "Large Triangle",
|
||||
"Flèche": "Arrow",
|
||||
"Modèle": "Template",
|
||||
"Bouton de navigation droit": "Right Navigation Button",
|
||||
"Bouton de navigation gauche": "Left Navigation Button"
|
||||
}
|
690
core/module/install/ressource/i18n/es.json
Normal file
690
core/module/install/ressource/i18n/es.json
Normal file
@ -0,0 +1,690 @@
|
||||
{
|
||||
"'Ne pas afficher' crée une page orpheline non accessible par le biais des menus.": "'No mostrar' crea una página huérfana a la que no se puede acceder a través de los menús.",
|
||||
"'Sauvegarder et télécharger les données du module": "Guardar y descargar de los datos del módulo",
|
||||
"1 jour": "1 Jour",
|
||||
"1/4 : Préparation...": "1/4: Preparando...",
|
||||
"10 minutes": "10 minutos",
|
||||
"10 tentatives": "6 intentos",
|
||||
"14 jours": "14 dias",
|
||||
"15 minutes": "15 minutos",
|
||||
"2 jours": "2 dias",
|
||||
"2/4 : Téléchargement...": "2/4: Descargando...",
|
||||
"3 tentatives": "3 intentos",
|
||||
"3/4 : Installation...": "3/4: Instalando...",
|
||||
"4 jours": "4 días",
|
||||
"4/4 : Configuration...": "4/4: Configuración...",
|
||||
"5 minutes": "5 minutos",
|
||||
"5 tentatives": "5 intentos",
|
||||
"7 jours": "7 días",
|
||||
"Accueil": "Inicio",
|
||||
"Accède au site": "Acceso al sitio",
|
||||
"Accède aux pages réservées": "Acceso a páginas restringidas",
|
||||
"Accède aux pages réservées et à un dossier partagé": "Acceso a páginas restringidas y una carpeta compartida",
|
||||
"Accès bloqué %d minutes": "Acceso bloqueado minutos",
|
||||
"Accès désactivé": "Acceso desactivado",
|
||||
"Accès interdit, erreur 403": "Acceso denegado, error 403",
|
||||
"Action interdite": "Acción no permitida",
|
||||
"Activation obligatoire selon les lois françaises sauf si vous utilisez votre propre système de consentement.": "Activación obligatoria según las leyes francesas a menos que utilice su propio sistema de consentimiento.",
|
||||
"Activer": "Activar",
|
||||
"Activer la journalisation": "Habilitar registro",
|
||||
"Actualiser": "Actualizar",
|
||||
"Adaptation": "Adaptación",
|
||||
"Administrateur": "Administrador",
|
||||
"Administration": "Administración",
|
||||
"Adresse SMTP": "Dirección SMTP",
|
||||
"Adresse du proxy": "Dirección proxy",
|
||||
"Adresse électronique": "Correo electrónico",
|
||||
"Affectation": "Asignación",
|
||||
"Affiche le nom de la page parente suivi du nom de la page, le titre ne doit pas être masqué.": "Mostrar el nombre de la página principal seguido del nombre de la página, el título no debe ocultarse.",
|
||||
"Affiche les icônes de gestion du compte et de déconnexion des membres simples connectés": "Muestra los iconos de gestión de cuenta y cierre de sesión para miembros regulares conectados",
|
||||
"Afin d'assurer le bon fonctionnement de Zwii, veuillez ne pas fermer cette page avant la fin de l'opération.": "Para garantizar el correcto funcionamiento de Zwii, no cierre esta página antes de que se complete la operación",
|
||||
"Aide": "Ayuda",
|
||||
"Ajouter": "Agregar",
|
||||
"Ajouter un profil": "Agregar un perfil",
|
||||
"Ajouter un utilisateur": "Agregar usuario",
|
||||
"Ajouter une fonte": "Añadir tipografía",
|
||||
"Alignement": "Alineación de contenido",
|
||||
"Aligner la bannière avec le contenu": "Alinear el banner con el contenido",
|
||||
"Ancien mot de passe": "Antigua contraseña",
|
||||
"Anonymat des adresses IP": "Anonimato de la dirección IP",
|
||||
"Apache URL intelligent": "URL inteligente de Apache",
|
||||
"Apache URL intelligentes": "URL inteligentes de Apache",
|
||||
"Apparence": "Apariencia",
|
||||
"Appliquer": "Aplicar",
|
||||
"Approuver un commentaire": "Aprobar comentarios",
|
||||
"Après": "Después",
|
||||
"Après la bannière": "Después del banner",
|
||||
"Après le contenu de la page": "Después del contenido de la página",
|
||||
"Archive": "Archivo",
|
||||
"Archive ZIP": "Archivo ZIP",
|
||||
"Archive copiée dans le dossier Modules du gestionnaire de fichier": "Archivo copiado a la carpeta Módulos del administrador de archivos",
|
||||
"Archive de thème invalide": "Archivo de tema no válido",
|
||||
"Archive invalide": "Archivo no válido",
|
||||
"Archive invalide, l'écriture dans le dossier core est interdite": "Archivo no válido, está prohibido escribir en la carpeta core",
|
||||
"Archive invalide, le descripteur est absent": "Archivo no válido, falta el descriptor",
|
||||
"Archive invalide, le fichier de classe est absent": "Archivo no válido, falta el archivo de clase",
|
||||
"Archive invalide, les dossiers ne correspondent pas au descripteur": "Archivo no válido, las carpetas no coinciden con el descriptor",
|
||||
"Archive non spécifiée ou introuvable": "Archivo no especificado o no encontrado",
|
||||
"Archive à restaurer": "Archivo para restaurar",
|
||||
"Arrière plan": "Fondo",
|
||||
"Arrière plan des blocs": "Fondo de bloques",
|
||||
"Arrière plan des champs": "Fondo de zona",
|
||||
"Arrondi des angles": "Redondeo de ángulos",
|
||||
"Au centre": "En el centro",
|
||||
"Au début": "Al principio",
|
||||
"Au milieu au centre": "En el medio en el centro",
|
||||
"Au milieu à droite": "En el medio derecho",
|
||||
"Au milieu à gauche": "En el medio a la izquierda",
|
||||
"Au-dessus du site": "Por encima del sitio",
|
||||
"Aucun": "Ninguno",
|
||||
"Aucun dossier": "Sin carpeta",
|
||||
"Aucun fichier journal à télécharger": "No hay archivos de registro para descargar",
|
||||
"Aucun journal à effacer": "No hay registros para borrar",
|
||||
"Aucun menu": "Ningún menú",
|
||||
"Aucune": "Ninguna",
|
||||
"Aucune liste noire à effacer": "No hay lista negra para borrar",
|
||||
"Aucune liste noire à télécharger": "No hay lista negra para descargar",
|
||||
"Auteur :": "Autor",
|
||||
"Authentification": "Autenticación",
|
||||
"Automatique": "Automáquica",
|
||||
"Autoriser les robots à référencer le site": "Permitir que los robots hagan referencia al sitio",
|
||||
"Autorisé": "Autorizado",
|
||||
"Avant la bannière": "Antes del banner",
|
||||
"Avant le contenu de la page": "Antes del contenido de la página",
|
||||
"Background": "Fondo",
|
||||
"Banni": "Prohibición",
|
||||
"Bannière": "Banner",
|
||||
"Bannière cliquable": "Banner",
|
||||
"Barre 1/3 - page 2/3": "Barra 1/3 - página 2/3",
|
||||
"Barre 1/4 - page 1/2 - barre 1/4": "Barra 1/4 - página 1/2 - Barra 1/4",
|
||||
"Barre 1/4 - page 3/4": "Barra 1/4 - página 3/4",
|
||||
"Barre 2/12 - page 7/12 - barre 3/12": "Barra 2/12 - página 7/12 - Barra 3/12",
|
||||
"Barre 3/12 - page 7/12 - barre 2/12": "Barra 3/12 - página 7/12 - Barra 2/12",
|
||||
"Barre de membre": "Barra de miembro",
|
||||
"Barre latérale": "Barra lateral",
|
||||
"Barre latérale droite :": "Barra lateral derecha:",
|
||||
"Barre latérale gauche :": "Barra lateral izquierda:",
|
||||
"Barres latérales": "Barras laterales",
|
||||
"Bienvenue %s %s": "Bienvenido %s %s",
|
||||
"Blocage après échecs": "Bloquear después de fallar",
|
||||
"Blog": "Blog",
|
||||
"Bords arrondis": "Bordes redondeados",
|
||||
"Bordure des blocs": "Borde de bloques",
|
||||
"Bordure des champs": "Borde de zona",
|
||||
"Bouton Aide": "Boton de ayuda",
|
||||
"Bouton Standard": "Botón estándar",
|
||||
"Bouton de validation": "Botón Validación",
|
||||
"Bouton effacement": "Botón Eliminar",
|
||||
"Bouton retour": "Botón de retroceso",
|
||||
"Bouton standard": "Botón estándar",
|
||||
"Bouton validation": "Botón de validación",
|
||||
"Boutons": "Botones",
|
||||
"Caché": "Oculto",
|
||||
"Cachée": "Oculto",
|
||||
"Captcha complexe": "Captcha complejo",
|
||||
"Captcha à la connexion": "Captcha al iniciar sesión",
|
||||
"Captcha, identifiant ou mot de passe incorrects": "Captcha, nombre de usuario o contraseña incorrecta",
|
||||
"Capture d'écran Open Graph": "Captura de pantalla de Open Graph",
|
||||
"Capture d'écran générée avec succès": "Captura de pantalla generada con éxito",
|
||||
"Casse": "Roto",
|
||||
"Catalogue": "Catálogo",
|
||||
"Catégorie": "Categoría",
|
||||
"Ce membre pourra téléverser ou télécharger des fichiers dans le dossier 'partage' et ses sous-dossiers": "Este miembro podrá cargar o descargar archivos en la carpeta 'compartir' y sus subcarpetas",
|
||||
"Cette page ne doit pas apparaître dans l'arborescence du menu. Créez une page orpheline.": "Esta página no debería aparecer en el árbol del menú. Crear una página huérfana.",
|
||||
"Cette redirection ne concerne que les pages d'administration du site.": "Esta redirección solo afecta a las páginas de administración del sitio.",
|
||||
"Chaîne Youtube": "Canal de Youtube",
|
||||
"Chiffres": "Cifras",
|
||||
"Cible": "Objetivo",
|
||||
"Cliquez sur une zone afin d'accéder à ses options de personnalisation.": "Haga clic en un área para acceder a sus opciones de personalización.",
|
||||
"Commentaire": "Comentario",
|
||||
"Complète": "sin truncar",
|
||||
"Compte administrateur": "Cuenta de administrador",
|
||||
"Compte de l'utilisateur": "Cuenta de usuario",
|
||||
"Compte verrouillé": "Cuenta bloqueada",
|
||||
"Configuration": "Configuración",
|
||||
"Configuration du module": "Configuración del módulo",
|
||||
"Configurer": "Configurar",
|
||||
"Configurer mon compte": "Configurar mi cuenta",
|
||||
"Confirmation": "Confirmación",
|
||||
"Confirmer la suppression de cet utilisateur": "Confirmar eliminación de este usuario",
|
||||
"Confirmer la dissociation du module de cette page": "Confirmar desvincular módulo de esta página",
|
||||
"Confirmer la désinstallation du module": "Confirmar la desinstalación del módulo",
|
||||
"Confirmer la suppression de cet utilisateur": "Confirme la eliminación de este usuario",
|
||||
"Confirmer la suppression de cette langue": "Confirmar eliminación de este idioma",
|
||||
"Confirmer la suppression de la page": "Confirmar la eliminación de la página",
|
||||
"Confirmer la suppression des données du module": "Confirmar la eliminación de datos del módulo",
|
||||
"Confirmez-vous la suppression de cette page ?": "¿Confirma la eliminación de esta página?",
|
||||
"Connexion": "Conexión",
|
||||
"Consulter l'aide en ligne": "Consultar la ayuda en línea",
|
||||
"Contents": "Contenido",
|
||||
"Contenu": "Contenido",
|
||||
"Contenu HTML": "Contenido HTML",
|
||||
"Contenu avancé": "Contenido avanzado",
|
||||
"Contenu du menu vertical": "Contenido del menú vertical",
|
||||
"Contrôle total": "Control total",
|
||||
"Cookies": "Cookies",
|
||||
"Cookies Zwii": "Cookies Zwii",
|
||||
"Copie de contenus localisés": "Copia de contenidos localizados",
|
||||
"Copie de sites inter-langues": "Copia del sitio multilingües",
|
||||
"Copie des traductions rédigées": "Copia de traducciones redactadas",
|
||||
"Copie terminée avec des erreurs": "Copia completada con errores",
|
||||
"Copie terminée avec succès": "Copia completada con éxito",
|
||||
"Copier": "Copiar",
|
||||
"Copier sauvegardes auto": "Copiar guardados automáticos",
|
||||
"Couleur de fond automatique": "Color de fondo automático",
|
||||
"Couleur icône haut de page": "Color del icono superior de la página",
|
||||
"Couleur texte page active": "Color del texto de página activa",
|
||||
"Couleur unie ou papier-peint": "Color unido o papel tapiz",
|
||||
"Couleur visible en l'absence d'une image.<br />Le curseur horizontal règle le niveau de transparence.": "Color visible en ausencia de una imagen.<br />El control deslizante horizontal ajusta el nivel de transparencia.",
|
||||
"Couleur visible en l'absence d'une image.<br />Le curseur horizontal règle le niveau de transparence. La couleur du texte est automatique.": "Color visible en ausencia de una imagen.<br />El control deslizante horizontal ajusta el nivel de transparencia. El color del texto es automático.",
|
||||
"Couleurs": "Colores",
|
||||
"Dans le site": "En el sitio",
|
||||
"Dans quelle langue utiliserez-vous Zwii ?": "¿En qué idioma usará Zwii?",
|
||||
"Date": "fecha",
|
||||
"Description": "Descripción del sitio",
|
||||
"Disponible si le consentement des cookies est activé.": "Disponible si se ha otorgado el consentimiento de las cookies.",
|
||||
"Disposition": "Arreglo",
|
||||
"Données %s copiées vers %s": "Datos %s copiados hacia %s",
|
||||
"Données des modules": "Datos de los módulos",
|
||||
"Données importées": "Datos importados",
|
||||
"Dossier": "Carpeta",
|
||||
"Droits sur les dossiers": "Derechos de las carpetas",
|
||||
"Droits sur les fichiers": "Derechos de los archivos",
|
||||
"Dupliquer": "Duplicar",
|
||||
"Dupliquer la page": "Duplicar la página",
|
||||
"Déconnecte les sessions ouvertes précédemment sur d'autres navigateurs ou terminaux. Activation recommandée.": "Desconecte sesiones abiertas previamente en otros navegadores o dispositivos. Activación recomendada.",
|
||||
"Déconnecter": "Desconectar",
|
||||
"Déconnexion !": "¡Cerrar sesión!",
|
||||
"Déconnexion automatique": "Cierre de sesión automático",
|
||||
"Définir par défaut": "Establecer como predeterminado",
|
||||
"Dévoiler le mot de passe": "Revelar la contraseña",
|
||||
"Effacer": "Borrar",
|
||||
"Effacer la page": "Borrar página",
|
||||
"Effacer tous les commentaires": "Borrar todos los comentarios",
|
||||
"Effacer toutes les statistiques": "Borrar todas las estadísticas",
|
||||
"Effacer un commentaire": "Borrar el comentario",
|
||||
"Effacer une catégorie": "Borrar categoría",
|
||||
"Emplacement :": "Ubicación",
|
||||
"Emplacement dans le menu": "Ubicación en el menú",
|
||||
"En bas au centre": "Abajo en el centro",
|
||||
"En bas à droite": "Abajo a la derecha",
|
||||
"En bas à gauche": "Abajo a la izquierda",
|
||||
"En cas de changement de module, les données du module précédent seront supprimées.": "Al cambiar de módulo se borrarán los datos del módulo anterior.",
|
||||
"En dessous du site": "Debajo del sitio",
|
||||
"En haut au centre": "Cubra en el centro",
|
||||
"En haut à droite": "Arriba a la derecha",
|
||||
"En haut à gauche": "Arriba a la izquierda",
|
||||
"En position libre ajoutez le module en plaçant [MODULE] à l'endroit voulu dans votre page.": "En posición libre agregue el módulo colocando [MODULE] en la ubicación deseada en su página.",
|
||||
"En-dehors du site": "Fuera del sitio",
|
||||
"Enregistrer": "Registrar",
|
||||
"Envoyer un message de confirmation": "Enviar mensaje de confirmación",
|
||||
"Erreur : sauvegarde non générée !": "Error: copia de seguridad no generada!",
|
||||
"Erreur d'URL": "Error de URL",
|
||||
"Erreur d'extraction, vérifiez les permissions": "Error de extracción, verifique los permisos",
|
||||
"Erreur de copie": "Error de copia",
|
||||
"Erreur de copie, vérifiez les permissions": "error de copia, verifique las permisiones",
|
||||
"Erreur de lecture, vérifiez les permissions": "Error de lectura, verifique los permisos",
|
||||
"Erreur inconnue": "error desconocido",
|
||||
"Erreur inconnue, le module n'est pas installé": "Error desconocido, el módulo no está instalado",
|
||||
"Export CSV": "Exportar CSV",
|
||||
"Expéditeur": "Remitente",
|
||||
"Extension": "Extensión",
|
||||
"Extraire": "Extraer",
|
||||
"Facebook": "Facebook",
|
||||
"Famille": "Vínculo",
|
||||
"Favicon thème sombre": "favicon de tema oscuro",
|
||||
"Feuille de style spécifique à la page.": "Hoja de estilo específica de la página.",
|
||||
"Fichiers": "Archivos",
|
||||
"Fichiers effacés": "archivos borrados",
|
||||
"Fil d'Ariane dans le titre": "Migas de pan en el título",
|
||||
"Fond du sous-menu": "Fondo del submenú",
|
||||
"FontId": "ID de fuente",
|
||||
"Fonte": "Fuente",
|
||||
"Fonte actualisée": "fuente actualizada",
|
||||
"Fonte créée": "Fuente creada",
|
||||
"Fonte en ligne": "Tipografía en línea",
|
||||
"Fonte installée": "Tipografía instalada",
|
||||
"Fonte non créée, ressource absente !": "¡Fuente no creada, por falta recurso!",
|
||||
"Fonte supprimée": "Fuente eliminada",
|
||||
"Fontes": "Tipografias",
|
||||
"Format incorrect": "Formato incorrecto",
|
||||
"Formulaire": "Formulario",
|
||||
"Fréquence de recherche": "Frecuencia de búsqueda",
|
||||
"Fuseau horaire": "Zona horaria",
|
||||
"Gabarits de page - Barre latérale": "Patrón de página - Barra lateral",
|
||||
"Gestion": "Administrar",
|
||||
"Gestion des modules": "Gestión de módulos",
|
||||
"Gestion des thèmes": "Gestión de temas",
|
||||
"Gestionnaire de fichiers": "Administrador de archivos",
|
||||
"Github": "Github",
|
||||
"Grande": "Grande",
|
||||
"Grande (220%)": "Grande (220%)",
|
||||
"Grande (300px)": "Grande (300px)",
|
||||
"Gras": "Negrita",
|
||||
"Groupe": "Grupo",
|
||||
"Groupe associé": "Grupo asociado",
|
||||
"Groupe requis pour accéder à la page :": "Grupo necesario para acceder a la página:",
|
||||
"Groupes": "Grupos",
|
||||
"Générer sitemap.xml et robots.txt": "Generar sitemap.xml y robots.txt",
|
||||
"Générer une capture Open Graph": "Generar una captura de Open Graph",
|
||||
"Gérer les catégories": "Gestionar categorías",
|
||||
"Gérer les commentaires": "Administrar comentarios",
|
||||
"Gérer les données": "Administrar datos",
|
||||
"Hauteur": "Altura",
|
||||
"Hauteur de l'image": "Altura de la imagen",
|
||||
"Hauteur de l'image sélectionnée": "Altura de la imagen seleccionada",
|
||||
"Hauteur maximale": "Altura máxima",
|
||||
"ID de la chaîne : https://www.youtube.com/channel/[ID].": "ID del canal: https://www.youtube.com/channel/[ID].",
|
||||
"Icône": "Icono",
|
||||
"Icône avec bulle de texte": "Icono con burbuja de texto",
|
||||
"Icône haut de page, couleur arrière-plan": "Icono superior de la página, color de fondo",
|
||||
"Identifiant": "Identificación",
|
||||
"Identifiant (sans espace ni majuscule)": "Identificación (sin espacios ni mayúsculas)",
|
||||
"Identité": "Identificación",
|
||||
"Identité de la fonte": "Identidad de tipografía",
|
||||
"Identité du site": "identidad del sitio",
|
||||
"Il apparaît dans la barre de titre et les partages sur les réseaux sociaux.": "Aparece en la barra de título y se comparte en redes sociales.",
|
||||
"Image": "Imagen",
|
||||
"Image étirée (100% 100%)": "Imagen estirada (100% 100%)",
|
||||
"Important": "Importante",
|
||||
"Importante": "Importante",
|
||||
"Importation d'utilisateurs": "Importación de usuarios",
|
||||
"Importation de fichier plat CSV": "Importar archivo plano CSV",
|
||||
"Importation effectuée": "Importación realizada",
|
||||
"Importer": "Importar",
|
||||
"Importer dans": "Importar a",
|
||||
"Importer des utilisateurs en masse": "Importar usuarios de forma masiva",
|
||||
"Impossible d'ouvrir l'archive": "No se puede abrir el archivo",
|
||||
"Impossible de modifier votre propre groupe.": "No puede editar su propio grupo.",
|
||||
"Impossible de soumettre le formulaire, car il contient des erreurs": "No se puede enviar el formulario porque contiene errores",
|
||||
"Impossible de supprimer une page contenant des pages enfants": "No se puede eliminar una página que contiene páginas secundarias",
|
||||
"Impossible de supprimer votre propre compte": "No puede eliminar su propia cuenta",
|
||||
"Inclure le contenu du gestionnaire de fichiers": "Incluir el contenido del administrador de archivos",
|
||||
"Incorrect": "Incorrecto",
|
||||
"Informations": "Información",
|
||||
"Instagram": "Instagram",
|
||||
"Installation terminée": "instalación completa",
|
||||
"Installer": "Instalar",
|
||||
"Installer depuis le catalogue en ligne": "Instalar desde el archivo en línea",
|
||||
"Installer depuis une archive": "Instalar desde un archivo",
|
||||
"Installer les données d'un module": "Instalar datos de un módulo",
|
||||
"Installer ou mettre à jour un module téléchargé": "Instalar o actualizar un módulo descargado",
|
||||
"Installer un module": "Instalar un módulo",
|
||||
"Installer un thème archivé (site ou administration)": "Instalar un tema archivado (sitio o administración)",
|
||||
"Instructions JS ou jquery spécifiques à la page.": "Instrucciones JS o jquery específicas de la página.",
|
||||
"Interface": "Idiomas interfaz",
|
||||
"Jeton invalide": "Simbolo no valido",
|
||||
"Journal réinitialisé avec succès": "Registro reiniciado con éxito",
|
||||
"Journalisation": "Inicio sesión",
|
||||
"L'archive a été déposée dans le gestionnaire de fichiers. Les archives inférieures à la version 9 ne sont pas acceptées.": "El archivo ha sido depositado en el administrador de archivos. No se aceptan archivos inferiores a la versión 9.",
|
||||
"L'identifiant est défini lors de la création du compte, il ne peut pas être modifié.": "El identificador se define al crear la cuenta, no se puede modificar.",
|
||||
"La carte du site a été mise à jour": "El mapa del sitio ha sido actualizado.",
|
||||
"La copie de sauvegarde du fichier htaccess n'a pas été restaurée !": "¡La copia de seguridad del archivo htaccess no ha sido restaurada!",
|
||||
"La description d'une page participe à son référencement, chaque page doit disposer d'une description différente.": "La descripción de una página participa en su referenciación, cada página debe tener una descripción diferente.",
|
||||
"La page %s est ouverte par l'utilisateur %s": "La página %s ha sido abierta por el usuario %s",
|
||||
"La page demandée n'existe pas ou est introuvable (erreur 404)": "La page demandée n'existe pas ou est introuvable (erreur 404)",
|
||||
"La page est affichée dans un menu horizontal mais pas dans le menu vertical d'une barre latérale.": "La página se muestra en un menú horizontal pero no en el menú vertical de una barra lateral.",
|
||||
"La première page que vos visiteurs verront.": "La primera página que verán tus visitantes.",
|
||||
"La règlementation française impose un anonymat de niveau 2": "La normativa francesa impone el anonimato de nivel 2",
|
||||
"La réécriture d'URL n'a pas été restaurée !": "¡La reescritura de URL no ha sido restaurada!",
|
||||
"La sauvegarde des fichiers peut prendre du temps. Continuer ?": "La copia de seguridad de los archivos puede tardar un poco. ¿Desea continuar?",
|
||||
"La suppression a échoué": "Eliminación fallida",
|
||||
"La version installée est plus récente": "La versión instalada es más nueva.",
|
||||
"La vérification est quotidienne. Option désactivée si la configuration du serveur ne le permet pas.": "La comprobación es diaria. Opción deshabilitada si la configuración del servidor no lo permite.",
|
||||
"Langue de l'administration": "Idioma de la administración",
|
||||
"Langue du site par défaut": "Idioma predeterminado del sitio",
|
||||
"Langue par défaut": "Idioma predeterminado",
|
||||
"Langues": "Idiomas",
|
||||
"Langues disponibles": "Idiomas Disponibles",
|
||||
"Langues installées": "Idiomas instalados",
|
||||
"Largeur": "Anchura o Ancho",
|
||||
"Largeur de l'image": "Ancho de la imagen",
|
||||
"Largeur du site": "Ancho del sitio",
|
||||
"Le curseur horizontal règle le niveau de transparence, le placer tout à la gauche pour un surlignement invisible.": "El control deslizante horizontal establece el nivel de transparencia, colóquelo completamente hacia la izquierda para obtener un resaltado invisible.",
|
||||
"Le curseur horizontal règle le niveau de transparence.": "El cursor horizontal regula el nivel de transparencia.",
|
||||
"Le fuseau horaire est utile au bon référencement": "La zona horaria es útil para una buena referencia",
|
||||
"Le menu accessoire est aligné à droite de la barre de menu, c'est un emplacement réservé aux drapeaux et au bouton de connexion.": "El menù accesorio está alineado a la derecha de la barra de menú, es un marcador de posición para las banderas y el botón de inicio de sesión",
|
||||
"Le menu horizontal intégral": "El menú horizontal completo",
|
||||
"Le module %s a été %s": "El módulo %s ha sido %s",
|
||||
"Le module %s de la page %s a été supprimé": "Se eliminó el módulo %s de la página %s",
|
||||
"Le module %s est désinstallé, il reste peut-être des données dans %s": "El módulo %s está desinstalado, es posible que queden datos en %s",
|
||||
"Le sous-menu de la page parente": "El submenú de la página principal",
|
||||
"Le survol d'une icône de l'écran de connexion affiche temporairement le mot de passe.": "Al pasar el cursor sobre un ícono de la pantalla de inicio de sesión, se muestra temporalmente la contraseña",
|
||||
"Le titre court est affiché dans les menus. Il peut être identique au titre de la page.": "El título corto se muestra en los menús. Puede ser el mismo que el título de la página.",
|
||||
"Les langues sélectionnées sont identiques": "Los idiomas seleccionados son idénticos",
|
||||
"Les mentions légales sont obligatoires en France. Une option du pied de page ajoute un lien discret vers cette page.": "Los avisos legales son obligatorios en Francia. Una opción en el pie de página agrega un enlace discreto a esta página.",
|
||||
"Les modifications que vous avez apportées ne seront peut-être pas enregistrées.": "Es posible que no se guarden los cambios realizados.",
|
||||
"Les tailles des polices de la bannière, de menu et de pied de page sont proportionnelles à cette taille.": "Los tamaños de fuente del banner, menú y pie de página son proporcionales a este tamaño.",
|
||||
"Lettres": "Letras",
|
||||
"Libre": "Libre",
|
||||
"Licence :": "Licencia",
|
||||
"Lien de connexion": "Enlace de inicio de sesión",
|
||||
"Lien page des mentions légales.": "Enlace página aviso legal.",
|
||||
"Liens": "Enlaces",
|
||||
"Limitation des tentatives": "Limitación de intentos",
|
||||
"Limitée au site": "Limitado al sitio",
|
||||
"Linkedin": "Linkedin",
|
||||
"Liste noire": "Lista negra",
|
||||
"Liste noire réinitialisée avec succès": "Lista negra restablecida con éxito",
|
||||
"Lors d'une mise à jour automatique, conserve le fichier htaccess de la racine du site.": "Durante una actualización automática, mantenga el archivo htaccess de la raíz del sitio.",
|
||||
"Léger": "Ligero",
|
||||
"Légère": "Ligera",
|
||||
"Maigre": "Delgado",
|
||||
"Maintenance": "Mantenimiento",
|
||||
"Majuscule à chaque mot": "Capper con cada palabra",
|
||||
"Majuscules": "Letras mayúsculas",
|
||||
"Marges verticales": "Márgenes verticales",
|
||||
"Masquer la bannière en écran réduit": "Ocultar el banner en pantalla reducida",
|
||||
"Masquer la page et les pages enfants dans le menu d'une barre latérale": "Ocultar página y páginas secundarias en un menú de la barra lateral",
|
||||
"Masquer les pages enfants dans le menu horizontal": "Ocultar páginas secundarias en el menú horizontal",
|
||||
"Membre": "Miembro",
|
||||
"Membre avec droit de partage": "Miembro con derecho de compartir",
|
||||
"Membre simple": "Miembro simple",
|
||||
"Mentions légales": "Notas legales",
|
||||
"Menu": "Menù",
|
||||
"Menu accessoire": "Menú accesorio",
|
||||
"Menu burger dans écran réduit": "Menú hamburguesa en pantalla reducida",
|
||||
"Menu standard": "Menú estándar",
|
||||
"Message d'acceptation des Cookies": "Mensaje de aceptación de cookies",
|
||||
"Message de consentement aux cookies": "Mensaje de consentimiento de cookies",
|
||||
"Mettre à jour": "Actualizar",
|
||||
"Mettre à jour le module orphelin": "Actualizar módulo huérfano",
|
||||
"Minuscules": "Diminuto",
|
||||
"Mise en forme des titres": "Formato de título",
|
||||
"Mise en forme du texte": "Formato de texto",
|
||||
"Mise en forme du titre": "Formato de título",
|
||||
"Mise en page": "Diseño",
|
||||
"Mise à jour": "actualización",
|
||||
"Mise à jour automatisée": "Actualización automática",
|
||||
"Mise à jour de ZwiiCMS": "Actualización de ZwiiCMS",
|
||||
"Mise à jour terminée avec succès.": "Actualización completada con éxito.",
|
||||
"Modifications enregistrées": "Cambios guardados",
|
||||
"Module": "Módulo",
|
||||
"Module de la page": "Módulo de página",
|
||||
"Modules": "Módulos",
|
||||
"Modules configurés": "Módulos Configurados",
|
||||
"Modules installés": "Módulos instalados",
|
||||
"Modules orphelins": "Módulos huérfanos",
|
||||
"Mot de passe": "Contraseña",
|
||||
"Mot de passe oublié": "Contraseña olvidada",
|
||||
"Mot de passe perdu": "Contraseña perdida",
|
||||
"Motorisé par": "Motorizado por",
|
||||
"Moyen": "Medio",
|
||||
"Moyenne": "Media",
|
||||
"Moyenne (200%)": "Promedio (200%)",
|
||||
"Moyenne (200px)": "Promedio (200px)",
|
||||
"Méta-description": "Meta-descripción",
|
||||
"Méta-titre": "Meta-título",
|
||||
"Ne pas afficher": "No se muestra",
|
||||
"Ne pas charger l'exemple de site (utilisateurs avancés)": "No cargar sitio de muestra (usuarios avanzados)",
|
||||
"Ne pas répéter": "No repitas",
|
||||
"Ne pas saisir les balises": "No ingrese las etiquetas",
|
||||
"News": "Noticias",
|
||||
"Niveau 1 (192.168.12.x)": "Nivel 1 (192.168.12.x)",
|
||||
"Niveau 2 (192.168.x.x)": "Nivel 2 (192.168.x.x)",
|
||||
"Niveau 3 (192.x.x.x)": "Nivel 3 (192.x.x.x)",
|
||||
"Nom": "Nombre",
|
||||
"Nom Prénom": "Apellido nombre",
|
||||
"Nom du profil": "Nombre del perfil",
|
||||
"Nom utilisateur": "Nombre de usuario",
|
||||
"Non": "No",
|
||||
"Non tronquée": "Sin personal",
|
||||
"Notre site est actuellement en maintenance. Nous sommes désolés pour la gêne occasionnée et faisons notre possible pour être rapidement de retour.": "Nuestro sitio está actualmente en mantenimiento. Lamentamos las molestias y estamos haciendo todo lo posible para regresar lo antes posible",
|
||||
"Nouveau contenu localisé": "Nuevo contenido localizado",
|
||||
"Nouveau mot de passe": "Nueva contraseña",
|
||||
"Nouveau mot de passe enregistré": "Nueva contraseña guardada",
|
||||
"Nouvel utilisateur": "Nuevo usuario",
|
||||
"Nouvelle page créée": "Nueva página creada",
|
||||
"Nouvelle page ou barre latérale": "Nueva página o barra lateral",
|
||||
"Obligatoire": "Obligatorio",
|
||||
"Ombre": "Sombra",
|
||||
"Option active en mode déconnecté uniquement, les pages enfants sont visibles et accessibles.": "Opción activa solo en modo fuera de línea, las páginas secundarias son visibles y accesibles.",
|
||||
"Option recommandée pour sécuriser la connexion. S'applique à tous les captchas du site. Le captcha simple se limite à une addition de nombres de 0 à 10. Le captcha complexe utilise quatre opérations de nombres de 0 à 20. Activation recommandée.": "Opción recomendada para asegurar la conexión. Se aplica a todos los captchas en el sitio. El captcha simple está limitado a una suma de números del 0 al 10. El captcha complejo usa cuatro operaciones de números del 0 al 20. Activación recomendada.",
|
||||
"Options": "Opciones",
|
||||
"Options avancées": "Opciones avanzadas",
|
||||
"Origine": "Origen",
|
||||
"Oui": "Sí",
|
||||
"Page": "Página",
|
||||
"Page 2/3 - barre 1/3": "página 2/3 - Barra 1/3",
|
||||
"Page 3/4 - barre 1/4": "página 3/4 - Barra 1/4",
|
||||
"Page associée": "Página asociada",
|
||||
"Page de recherche": "Página de búsqueda",
|
||||
"Page dupliquée": "Página duplicada",
|
||||
"Page et module dupliqués": "Página y módulo duplicados",
|
||||
"Page inexistante, erreur 404": "La página no existe, error 404",
|
||||
"Page non cliquable": "No se puede hacer clic en la página",
|
||||
"Page parent": "Página principal",
|
||||
"Page standard": "Página estándar",
|
||||
"Page supprimée": "página eliminada",
|
||||
"Pages dans le menu": "Páginas del menú",
|
||||
"Pages du site": "Páginas del sitio",
|
||||
"Pages et les modules de": "Páginas y módulos",
|
||||
"Pages orphelines": "Páginas huérfanas",
|
||||
"Papier peint": "Color de fondo",
|
||||
"Par défaut le menu est affiché APRES le contenu de la page. Pour le positionner à un emplacement précis, insérez [MENU] dans le contenu de la page.": "Por defecto, el menú se muestra DESPUÉS del contenido de la página. Para colocarlo en una ubicación específica, inserte [MENÚ] en el contenido de la página.",
|
||||
"Paramètres": "Configuraciones",
|
||||
"Paramètres de la localisation": "Configuración de la ubicación",
|
||||
"Paramètres de la sauvegarde": "Configuración de copia de seguridad",
|
||||
"Paramètres du profil": "Configuración del perfil",
|
||||
"Paramètres à utiliser lorsque votre hébergeur ne propose pas la fonctionnalité d'envoi de mail.": "Configuraciones para usar cuando su host no ofrece la funcionalidad para enviar correo.",
|
||||
"Pas de marge au-dessus et en dessous du site": "Sin margen encima y debajo del sitio",
|
||||
"Pensez à supprimer le cache de votre navigateur si la favicon ne change pas.": "Recuerde eliminar el caché de su navegador si el favicon no cambia.",
|
||||
"Permission": "Permiso",
|
||||
"Permission et référencement": "Permiso y referenciación",
|
||||
"Permissions": "Permisos",
|
||||
"Permissions sur les dossiers": "Permisos de las carpetas",
|
||||
"Permissions sur les fichiers": "Permisos de los archivos",
|
||||
"Permissions sur les pages": "Permisos de las páginas",
|
||||
"Petite": "Pequeño",
|
||||
"Petite (150px)": "Pequeño (150px)",
|
||||
"Petite (180%)": "Petite (180%)",
|
||||
"Pied de page": "Pie de página",
|
||||
"Pinterest": "Pinterest",
|
||||
"Plan du site": "Mapa del sitio",
|
||||
"Police des titres": "Tipografía del titulo",
|
||||
"Police du texte": "Tipografía del texto",
|
||||
"Port SMTP": "Puerto SMTP",
|
||||
"Port du proxy": "Puerto proxy",
|
||||
"Position": "Posición",
|
||||
"Position du module": "Posición del módulo",
|
||||
"Pour définir la page comme barre latérale, choisissez l'option dans la liste.": "Para configurar la página como barra lateral, elija la opción de la lista.",
|
||||
"Presse Papier": "Portapapeles",
|
||||
"Presse papier": "Portapapeles",
|
||||
"Profils des groupes": "Perfiles de grupos",
|
||||
"Proportionnelle à la taille définie dans le site.": "Proporcional a la definida en el sitio.",
|
||||
"Prénom": "Nombre de pila",
|
||||
"Prénom Nom": "Nombre Apellido",
|
||||
"Préparation de la mise à jour": "Preparáción de la actualización",
|
||||
"Préserver le fichier htaccess racine": "Conservar archivo raíz htaccess",
|
||||
"Préserver les comptes des utilisateurs déjà installés": "Conservar las cuentas de usuario ya instaladas",
|
||||
"Prévenir l'utilisateur par mail": "Notificar al usuario por correo electrónico",
|
||||
"Prévisualiser": "Previsualizar",
|
||||
"Pseudo": "Apodo",
|
||||
"Rang 9 > rang 1. Le profil de rang 1 n'est pas modifiable.": "Rango 9 > rango 1. El perfil del rango 1 no se puede modificar.",
|
||||
"Ratio": "Proporción",
|
||||
"Ratio :": "Relación",
|
||||
"Recherche": "Buscar",
|
||||
"Recherche dans le site": "Buscar en el sitio",
|
||||
"Rechercher": "Buscar",
|
||||
"Rechercher une mise à jour en ligne": "Buscar una actualización en línea",
|
||||
"Redirection": "Redirección",
|
||||
"Redirection vers la connexion": "Redirección hacia conexión",
|
||||
"Renommer": "Renombrar",
|
||||
"Renseignez les champs ci-dessous pour finaliser l'installation.": "Complete las zonas a continuación para terminar la instalación.",
|
||||
"Responsive (contain)": "Responsivo (contener)",
|
||||
"Responsive (cover)": "Responsivo (cobertura)",
|
||||
"Restauration des bases de données absentes": "Restauración de bases de datos faltantes",
|
||||
"Restauration effectuée avec succès": "Restauración completada con éxito",
|
||||
"Restaurer": "Restaurar",
|
||||
"Restaurer les données du site": "Restaurar datos del sitio",
|
||||
"Rester connecté sur ce navigateur": "Permanecer conectado en este navegador",
|
||||
"Retour": "Retroceder",
|
||||
"Rien à importer, erreur de format ou fichier incorrect": "Nada que importar, error de formato o archivo incorrecto",
|
||||
"Rédacteur": "Editor",
|
||||
"Référencement": "Referenciación",
|
||||
"Réinitialisation du mot de passe": "Restablecer la contraseña de usuario",
|
||||
"Réinitialiser avec le thème par défaut": "establecer tema predeterminado",
|
||||
"Réinitialiser la feuille de style": "Restablecer hoja de estilo",
|
||||
"Réinitialiser la liste": "Restablecer lista",
|
||||
"Réinitialiser le journal": "Restablecer registro",
|
||||
"Réinstaller": "Reinstalar",
|
||||
"Répétition": "Repetición",
|
||||
"Réseau": "La red",
|
||||
"Réseaux sociaux": "Redes sociales",
|
||||
"S'ouvre dans un nouvel onglet": "Se abre en una nueva pestaña",
|
||||
"SMTP": "SMTP",
|
||||
"SMTP personnalisé": "SMTP personalizado",
|
||||
"Saisir la clé, puis valider le formulaire avant de cliquer sur le bouton de génération": "Ingrese la clave, luego valide el formulario antes de hacer clic en el botón generar",
|
||||
"Saisissez le Titre de gestion des cookies.": "Introduce el título de la ventana de gestión de cookies.",
|
||||
"Saisissez le message pour les cookies déposés par ZwiiCMS, nécessaires au fonctionnement et qui ne nécessitent pas de consentement.": "Ingrese el mensaje para las cookies colocadas por ZwiiCMS, necesarias para su funcionamiento y que no requieren consentimiento.",
|
||||
"Saisissez le texte du lien vers les mentions légales,la page doit être définie dans la configuration du site.": "Ingrese el texto del enlace a los avisos legales, la página debe estar definida en la configuración del sitio.",
|
||||
"Saisissez votre ID : https://pinterest.com/[ID].": "Ingrese su ID: https://pinterest.com/[ID].",
|
||||
"Saisissez votre ID : https://twitter.com/[ID].": "Ingrese su ID: https://twitter.com/[ID].",
|
||||
"Saisissez votre ID : https://www.facebook.com/[ID].": "Ingrese su ID: https://www.facebook.com/[ID].",
|
||||
"Saisissez votre ID : https://www.instagram.com/[ID].": "Ingrese su ID: https://www.instagram.com/[ID].",
|
||||
"Saisissez votre ID Github : https://github.com/[ID].": "Ingrese su ID de Github: https://github.com/[ID].",
|
||||
"Saisissez votre ID Linkedin : https://fr.linkedin.com/in/[ID].": "Ingrese su ID de Linkedin: https://fr.linkedin.com/in/[ID].",
|
||||
"Saisissez votre ID Utilisateur : https://www.youtube.com/user/[ID].": "Ingrese su ID de usuario: https://www.youtube.com/user/[ID].",
|
||||
"Sauvegarde": "Salvaguardad",
|
||||
"Sauvegarde automatique quotidienne du site": "Copia de seguridad diaria automática del sitio",
|
||||
"Sauvegarde du thème dans le": "Guardando tema en el",
|
||||
"Sauvegarde générée avec succès.": "Copia de seguridad generada con éxito",
|
||||
"Sauvegarder": "Para salvaguardar",
|
||||
"Sauvegarder et télécharger le module": "Guardar y descargar módulo",
|
||||
"Sauvegarder le module dans le gestionnaire de fichiers": "Guardar módulo en el administrador de archivos",
|
||||
"Sauvegarder les données du module dans le gestionnaire de fichiers": "Guardar de los datos del módulo en el administrador de archivos",
|
||||
"Sauvegarder les données du site": "Guardar datos del sitio",
|
||||
"Script dans body": "Script en el body",
|
||||
"Script dans head": "Script en el head",
|
||||
"Scripts externes": "Guiones externos",
|
||||
"Se déconnecter": "Desconectarse",
|
||||
"Service en ligne inaccessible": "Servicio en línea inaccesible",
|
||||
"Seul un administrateur peut se connecter lors d'une maintenance": "Solo un administrador puede iniciar sesión durante un mantenimiento",
|
||||
"Si le contenu du gestionnaire de fichiers est très volumineux, mieux vaut une copie par FTP.": "Si el contenido del administrador de archivos es muy grande, es mejor copiar por FTP.",
|
||||
"Signature": "Firma",
|
||||
"Site": "Idiomas instalados",
|
||||
"Site en maintenance": "Sitio en mantenimiento",
|
||||
"Size": "Tamaño",
|
||||
"Source": "Fuente",
|
||||
"Standard": "Estándar",
|
||||
"Style": "Estilo",
|
||||
"Suppression interdite": "Borrado prohibido",
|
||||
"Suppression interdite, page active dans la configuration du site": "Eliminación prohibida, página activa en la configuración del sitio",
|
||||
"Supprime le point d'interrogation dans les URL, l'option est indisponible avec les autres serveurs Web": "Eliminar el signo de interrogación en las URL, la opción no está disponible con otros servidores web",
|
||||
"Supprimer": "Borrar",
|
||||
"Supprimer la page": "Eliminar página",
|
||||
"Supprimer le module": "Eliminar módulo",
|
||||
"Supprimer toutes les sauvegardes automatiques ?": "¿Eliminar todos los guardados automáticos?",
|
||||
"Sur l'axe horizontal": "En el eje horizontal",
|
||||
"Sur l'axe vertical": "En el eje vertical",
|
||||
"Sur les deux axes": "En ambos hachas",
|
||||
"Sécurité": "Seguridad",
|
||||
"Sécurité de la connexion": "Seguridad de la conexión",
|
||||
"Sécurité désactivée": "Seguridad desactivada",
|
||||
"Sélectionner un fichier": "Seleccione un archivo",
|
||||
"Sélectionnez au moins un contenu à afficher": "Seleccione al menos un contenido para mostrar",
|
||||
"Sélectionnez la langue à copier vers une langue cible": "Seleccione el idioma para copiar hacia oyto idioma",
|
||||
"Sélectionnez une icône adaptée à un thème sombre.<br>Pensez à supprimer le cache de votre navigateur si la favicon ne change pas.": "Seleccione un ícono adecuado para un tema oscuro.<br>Recuerde eliminar el caché de su navegador si el favicon no cambia",
|
||||
"Sélectionnez une image ou une icône de petite dimension": "Seleccione una imagen o icono pequeño",
|
||||
"Sélectionnez une langue": "Seleccione un idioma",
|
||||
"Sélectionnez une page contenant le module 'Recherche'. Une option du pied de page ajoute un lien discret vers cette page.": "Seleccione una página que contenga el módulo 'Buscar'. Una opción de pie de página agrega un enlace discreto a esta página.",
|
||||
"Sélectionnez une page pour activer": "Seleccione una página para activar",
|
||||
"Séparateur": "Separador",
|
||||
"Taille": "Tamaño",
|
||||
"Text": "Texto",
|
||||
"Texte": "Texto",
|
||||
"Thème": "Tema",
|
||||
"Thème de l'administration": "Tema de administración",
|
||||
"Thème du site": "Tema del sitio",
|
||||
"Thème importé": "Tema importado",
|
||||
"Thèmes": "Temas",
|
||||
"Titre": "Título",
|
||||
"Titre court": "Título corto",
|
||||
"Titre masqué": "Título enmascarado",
|
||||
"Titre masqué dans la page": "Título oculto en la página",
|
||||
"Titres": "Títulos",
|
||||
"Tous les dossiers": "Todas las carpetas",
|
||||
"Tous les droits d'édition des contenus": "Todos los derechos de edición de contenido",
|
||||
"Tout Effacer": "Borrar todo",
|
||||
"Traduction supprimée": "Traducción eliminada",
|
||||
"Très grande": "Muy grande",
|
||||
"Très grande (240%)": "Muy grande (240%)",
|
||||
"Très grande (400px)": "Muy grande (400px)",
|
||||
"Très important": "Muy importante",
|
||||
"Très importante": "Muy importante",
|
||||
"Très léger": "Muy ligero",
|
||||
"Très légère": "Muy ligera",
|
||||
"Très petite": "Muy pequeño",
|
||||
"Très petite (100px) ": "Muy pequeño (100px)",
|
||||
"Très petite (160%)": "Muy pequeño (160%)",
|
||||
"Twitter": "Twitter",
|
||||
"Type de captcha": "Tipo de captcha",
|
||||
"Type de proxy": "Tipo de proxy",
|
||||
"Téléchargement et validation de l'archive": "Descarga y validación del archivo",
|
||||
"Télécharger": "Descargar",
|
||||
"Télécharger la liste": "Descargar la revista",
|
||||
"Télécharger le journal": "Descargar la revista",
|
||||
"Télécharger le module dans le gestionnaire de fichiers": "Descargar módulo al administrador de archivos",
|
||||
"Téléverser": "Subir",
|
||||
"URL incorrecte": "URL incorrecta",
|
||||
"Un mail a été envoyé pour confirmer la réinitialisation": "Se ha enviado un correo electrónico para confirmar el restablecimiento.",
|
||||
"Une archive du dossier /site/data est conservée pendant 30 jours. Activation recommandée": "Un archivo que contiene la carpeta /site/data se conserva durante 30 días. Activación recomendada .",
|
||||
"Une erreur est survenue lors de l'étape :": "Ocurrió un error durante el proceso",
|
||||
"Url du fichier de fonte": "Url del archivo de tipo de letra",
|
||||
"Utilisateur inexistant": "Usuario inexistente",
|
||||
"Utilisateur supprimé": "Usuario eliminado",
|
||||
"Utilisateurs": "Usuarios",
|
||||
"Valider": "Validar",
|
||||
"Version": "Versión",
|
||||
"Version n°": "Número de versión",
|
||||
"Vider dossier sauvegardes auto": "Carpeta de autoguardado vacía",
|
||||
"Visiteur": "Visitante",
|
||||
"Vous n'êtes pas autorisé à consulter cette page (erreur 403)": "No está autorizado para ver esta página (error 403)",
|
||||
"Youtube": "YouTube",
|
||||
"ZwiiCMS - Installation": "ZwiiCMS - Instalación",
|
||||
"actualisé": "actualizado",
|
||||
"favicon.ico": "Recuerde borrar el caché de su navegador si el favicon no cambia.",
|
||||
"faviconDark.ico": "faviconDark.ico",
|
||||
"gestionnaire de fichiers": "administrador de archivos",
|
||||
"installé": "instalado",
|
||||
"jour": "día",
|
||||
"jours": "días",
|
||||
"sauvegardé avec succès": "Guardado exitosamente",
|
||||
"vers ZwiiCMS": "Hacia ZwiiCMS",
|
||||
"À droite": "A la derecha",
|
||||
"À gauche": "A la izquierda",
|
||||
"À l'emplacement du mot clé [MODULE] dans la page": "En la ubicación de la palabra clave [MODULE] en la página",
|
||||
"Échec de l'écriture, vérifiez les permissions": "Escritura fallida, verifique los permisos",
|
||||
"Échecs": "Fracasos",
|
||||
"Éditer": "Editar",
|
||||
"Éditer la page": "Editar página",
|
||||
"Éditer les dialogues": "Editar los diálogos",
|
||||
"Éditer une catégorie": "Editar categoría",
|
||||
"Éditeur": "Editor",
|
||||
"Éditeur CSS": "Editor de CSS",
|
||||
"Éditeur JS": "Editor de JS",
|
||||
"Éditeur de script %s": "Editor de script %s",
|
||||
"Éditeur de script dans Body": "Éditor del script en el Body",
|
||||
"Éditeur de script dans Head": "Éditor del script en el Head",
|
||||
"Éditeur simple": "Editor simple",
|
||||
"Édition des pages": "Edición de páginas",
|
||||
"Édition du profil %s": "Edición del perfil %s",
|
||||
"Éléments": "Elementos",
|
||||
"Étendu sur la page": "Extendido en la página",
|
||||
"Étiquettes des pages spéciales": "Etiquetas de páginas especiales",
|
||||
"Dimensions minimales": "Dimensiones mínimas",
|
||||
"Taille maximale du fichier": "Tamaño máximo de archivo",
|
||||
"5 Mo pour les images JPEG": "5 MB para imágenes JPEG",
|
||||
"1 Mo pour les images PNG": "1 MB para imágenes PNG",
|
||||
"Poids": "Peso",
|
||||
"Supprimer ce profil ?": "¿Eliminar este perfil?",
|
||||
"Masqué": "Oculto",
|
||||
"Haut de page": "Parte superior de la página",
|
||||
"Bas de page": "Parte inferior de la página",
|
||||
"Petit triangle": "Triángulo pequeño",
|
||||
"Grand triangle": "Triángulo grande",
|
||||
"Flèche": "Flecha",
|
||||
"Modèle": "Plantilla",
|
||||
"Bouton de navigation droit": "Botón de navegación derecha",
|
||||
"Bouton de navigation gauche": "Botón de navegación izquierda"
|
||||
}
|
690
core/module/install/ressource/i18n/fr_FR.json
Normal file
690
core/module/install/ressource/i18n/fr_FR.json
Normal file
@ -0,0 +1,690 @@
|
||||
{
|
||||
"'Ne pas afficher' crée une page orpheline non accessible par le biais des menus.": "",
|
||||
"'Sauvegarder et télécharger les données du module": "",
|
||||
"1 jour": "",
|
||||
"1/4 : Préparation...": "",
|
||||
"10 minutes": "",
|
||||
"10 tentatives": "",
|
||||
"14 jours": "",
|
||||
"15 minutes": "",
|
||||
"2 jours": "",
|
||||
"2/4 : Téléchargement...": "",
|
||||
"3 tentatives": "",
|
||||
"3/4 : Installation...": "",
|
||||
"4 jours": "",
|
||||
"4/4 : Configuration...": "",
|
||||
"5 minutes": "",
|
||||
"5 tentatives": "",
|
||||
"7 jours": "",
|
||||
"Accueil": "",
|
||||
"Accède au site": "",
|
||||
"Accède aux pages réservées": "",
|
||||
"Accède aux pages réservées et à un dossier partagé": "",
|
||||
"Accès bloqué %d minutes": "",
|
||||
"Accès désactivé": "",
|
||||
"Accès interdit, erreur 403": "",
|
||||
"Action interdite": "",
|
||||
"Activation obligatoire selon les lois françaises sauf si vous utilisez votre propre système de consentement.": "",
|
||||
"Activer": "",
|
||||
"Activer la journalisation": "",
|
||||
"Actualiser": "",
|
||||
"Adaptation": "",
|
||||
"Administrateur": "",
|
||||
"Administration": "",
|
||||
"Adresse SMTP": "",
|
||||
"Adresse du proxy": "",
|
||||
"Adresse électronique": "",
|
||||
"Affectation": "",
|
||||
"Affiche le nom de la page parente suivi du nom de la page, le titre ne doit pas être masqué.": "",
|
||||
"Affiche les icônes de gestion du compte et de déconnexion des membres simples connectés": "",
|
||||
"Afin d'assurer le bon fonctionnement de Zwii, veuillez ne pas fermer cette page avant la fin de l'opération.": "",
|
||||
"Aide": "",
|
||||
"Ajouter": "",
|
||||
"Ajouter un profil": "",
|
||||
"Ajouter un utilisateur": "",
|
||||
"Ajouter une fonte": "",
|
||||
"Alignement": "",
|
||||
"Aligner la bannière avec le contenu": "",
|
||||
"Ancien mot de passe": "",
|
||||
"Anonymat des adresses IP": "",
|
||||
"Apache URL intelligent": "",
|
||||
"Apache URL intelligentes": "",
|
||||
"Apparence": "",
|
||||
"Appliquer": "",
|
||||
"Approuver un commentaire": "",
|
||||
"Après": "",
|
||||
"Après la bannière": "",
|
||||
"Après le contenu de la page": "",
|
||||
"Archive": "",
|
||||
"Archive ZIP": "",
|
||||
"Archive copiée dans le dossier Modules du gestionnaire de fichier": "",
|
||||
"Archive de thème invalide": "",
|
||||
"Archive invalide": "",
|
||||
"Archive invalide, l'écriture dans le dossier core est interdite": "",
|
||||
"Archive invalide, le descripteur est absent": "",
|
||||
"Archive invalide, le fichier de classe est absent": "",
|
||||
"Archive invalide, les dossiers ne correspondent pas au descripteur": "",
|
||||
"Archive non spécifiée ou introuvable": "",
|
||||
"Archive à restaurer": "",
|
||||
"Arrière plan": "",
|
||||
"Arrière plan des blocs": "",
|
||||
"Arrière plan des champs": "",
|
||||
"Arrondi des angles": "",
|
||||
"Au centre": "",
|
||||
"Au début": "",
|
||||
"Au milieu au centre": "",
|
||||
"Au milieu à droite": "",
|
||||
"Au milieu à gauche": "",
|
||||
"Au-dessus du site": "",
|
||||
"Aucun": "",
|
||||
"Aucun dossier": "",
|
||||
"Aucun fichier journal à télécharger": "",
|
||||
"Aucun journal à effacer": "",
|
||||
"Aucun menu": "",
|
||||
"Aucune": "",
|
||||
"Aucune liste noire à effacer": "",
|
||||
"Aucune liste noire à télécharger": "",
|
||||
"Auteur :": "",
|
||||
"Authentification": "",
|
||||
"Automatique": "",
|
||||
"Autoriser les robots à référencer le site": "",
|
||||
"Autorisé": "",
|
||||
"Avant la bannière": "",
|
||||
"Avant le contenu de la page": "",
|
||||
"Background": "",
|
||||
"Banni": "",
|
||||
"Bannière": "",
|
||||
"Bannière cliquable": "",
|
||||
"Barre 1/3 - page 2/3": "",
|
||||
"Barre 1/4 - page 1/2 - barre 1/4": "",
|
||||
"Barre 1/4 - page 3/4": "",
|
||||
"Barre 2/12 - page 7/12 - barre 3/12": "",
|
||||
"Barre 3/12 - page 7/12 - barre 2/12": "",
|
||||
"Barre de membre": "",
|
||||
"Barre latérale": "",
|
||||
"Barre latérale droite :": "",
|
||||
"Barre latérale gauche :": "",
|
||||
"Barres latérales": "",
|
||||
"Bienvenue %s %s": "",
|
||||
"Blocage après échecs": "",
|
||||
"Blog": "",
|
||||
"Bords arrondis": "",
|
||||
"Bordure des blocs": "",
|
||||
"Bordure des champs": "",
|
||||
"Bouton Aide": "",
|
||||
"Bouton Standard": "",
|
||||
"Bouton de validation": "",
|
||||
"Bouton effacement": "",
|
||||
"Bouton retour": "",
|
||||
"Bouton standard": "",
|
||||
"Bouton validation": "",
|
||||
"Boutons": "",
|
||||
"Caché": "",
|
||||
"Cachée": "",
|
||||
"Captcha complexe": "",
|
||||
"Captcha à la connexion": "",
|
||||
"Captcha, identifiant ou mot de passe incorrects": "",
|
||||
"Capture d'écran Open Graph": "",
|
||||
"Capture d'écran générée avec succès": "",
|
||||
"Casse": "",
|
||||
"Catalogue": "",
|
||||
"Catégorie": "",
|
||||
"Ce membre pourra téléverser ou télécharger des fichiers dans le dossier 'partage' et ses sous-dossiers": "",
|
||||
"Cette page ne doit pas apparaître dans l'arborescence du menu. Créez une page orpheline.": "",
|
||||
"Cette redirection ne concerne que les pages d'administration du site.": "",
|
||||
"Chaîne Youtube": "",
|
||||
"Chiffres": "",
|
||||
"Cible": "",
|
||||
"Cliquez sur une zone afin d'accéder à ses options de personnalisation.": "",
|
||||
"Commentaire": "",
|
||||
"Complète": "",
|
||||
"Compte administrateur": "",
|
||||
"Compte de l'utilisateur": "",
|
||||
"Compte verrouillé": "",
|
||||
"Configuration": "",
|
||||
"Configuration du module": "",
|
||||
"Configurer": "",
|
||||
"Configurer mon compte": "",
|
||||
"Confirmation": "",
|
||||
"Confirmer la suppression de cet utilisateur": "",
|
||||
"Confirmer la dissociation du module de cette page": "",
|
||||
"Confirmer la désinstallation du module": "",
|
||||
"Confirmer la suppression de cet utilisateur": "",
|
||||
"Confirmer la suppression de cette langue": "",
|
||||
"Confirmer la suppression de la page": "",
|
||||
"Confirmer la suppression des données du module": "",
|
||||
"Confirmez-vous la suppression de cette page ?": "",
|
||||
"Connexion": "",
|
||||
"Consulter l'aide en ligne": "",
|
||||
"Contents": "",
|
||||
"Contenu": "",
|
||||
"Contenu HTML": "",
|
||||
"Contenu avancé": "",
|
||||
"Contenu du menu vertical": "",
|
||||
"Contrôle total": "",
|
||||
"Cookies": "",
|
||||
"Cookies Zwii": "",
|
||||
"Copie de contenus localisés": "",
|
||||
"Copie de sites inter-langues": "",
|
||||
"Copie des traductions rédigées": "",
|
||||
"Copie terminée avec des erreurs": "",
|
||||
"Copie terminée avec succès": "",
|
||||
"Copier": "",
|
||||
"Copier sauvegardes auto": "",
|
||||
"Couleur de fond automatique": "",
|
||||
"Couleur icône haut de page": "",
|
||||
"Couleur texte page active": "",
|
||||
"Couleur unie ou papier-peint": "",
|
||||
"Couleur visible en l'absence d'une image.<br />Le curseur horizontal règle le niveau de transparence.": "",
|
||||
"Couleur visible en l'absence d'une image.<br />Le curseur horizontal règle le niveau de transparence. La couleur du texte est automatique.": "",
|
||||
"Couleurs": "",
|
||||
"Dans le site": "",
|
||||
"Dans quelle langue utiliserez-vous Zwii ?": "",
|
||||
"Date": "",
|
||||
"Description": "",
|
||||
"Disponible si le consentement des cookies est activé.": "",
|
||||
"Disposition": "",
|
||||
"Données %s copiées vers %s": "",
|
||||
"Données des modules": "",
|
||||
"Données importées": "",
|
||||
"Dossier": "",
|
||||
"Droits sur les dossiers": "",
|
||||
"Droits sur les fichiers": "",
|
||||
"Dupliquer": "",
|
||||
"Dupliquer la page": "",
|
||||
"Déconnecte les sessions ouvertes précédemment sur d'autres navigateurs ou terminaux. Activation recommandée.": "",
|
||||
"Déconnecter": "",
|
||||
"Déconnexion !": "",
|
||||
"Déconnexion automatique": "",
|
||||
"Définir par défaut": "",
|
||||
"Dévoiler le mot de passe": "",
|
||||
"Effacer": "",
|
||||
"Effacer la page": "",
|
||||
"Effacer tous les commentaires": "",
|
||||
"Effacer toutes les statistiques": "",
|
||||
"Effacer un commentaire": "",
|
||||
"Effacer une catégorie": "",
|
||||
"Emplacement :": "",
|
||||
"Emplacement dans le menu": "",
|
||||
"En bas au centre": "",
|
||||
"En bas à droite": "",
|
||||
"En bas à gauche": "",
|
||||
"En cas de changement de module, les données du module précédent seront supprimées.": "",
|
||||
"En dessous du site": "",
|
||||
"En haut au centre": "",
|
||||
"En haut à droite": "",
|
||||
"En haut à gauche": "",
|
||||
"En position libre ajoutez le module en plaçant [MODULE] à l'endroit voulu dans votre page.": "",
|
||||
"En-dehors du site": "",
|
||||
"Enregistrer": "",
|
||||
"Envoyer un message de confirmation": "",
|
||||
"Erreur : sauvegarde non générée !": "",
|
||||
"Erreur d'URL": "",
|
||||
"Erreur d'extraction, vérifiez les permissions": "",
|
||||
"Erreur de copie": "",
|
||||
"Erreur de copie, vérifiez les permissions": "",
|
||||
"Erreur de lecture, vérifiez les permissions": "",
|
||||
"Erreur inconnue": "",
|
||||
"Erreur inconnue, le module n'est pas installé": "",
|
||||
"Export CSV": "",
|
||||
"Expéditeur": "",
|
||||
"Extension": "",
|
||||
"Extraire": "",
|
||||
"Facebook": "",
|
||||
"Famille": "",
|
||||
"Favicon thème sombre": "",
|
||||
"Feuille de style spécifique à la page.": "",
|
||||
"Fichiers": "",
|
||||
"Fichiers effacés": "",
|
||||
"Fil d'Ariane dans le titre": "",
|
||||
"Fond du sous-menu": "",
|
||||
"FontId": "",
|
||||
"Fonte": "",
|
||||
"Fonte actualisée": "",
|
||||
"Fonte créée": "",
|
||||
"Fonte en ligne": "",
|
||||
"Fonte installée": "",
|
||||
"Fonte non créée, ressource absente !": "",
|
||||
"Fonte supprimée": "",
|
||||
"Fontes": "",
|
||||
"Format incorrect": "",
|
||||
"Formulaire": "",
|
||||
"Fréquence de recherche": "",
|
||||
"Fuseau horaire": "",
|
||||
"Gabarits de page - Barre latérale": "",
|
||||
"Gestion": "",
|
||||
"Gestion des modules": "",
|
||||
"Gestion des thèmes": "",
|
||||
"Gestionnaire de fichiers": "",
|
||||
"Github": "",
|
||||
"Grande": "",
|
||||
"Grande (220%)": "",
|
||||
"Grande (300px)": "",
|
||||
"Gras": "",
|
||||
"Groupe": "",
|
||||
"Groupe associé": "",
|
||||
"Groupe requis pour accéder à la page :": "",
|
||||
"Groupes": "",
|
||||
"Générer sitemap.xml et robots.txt": "",
|
||||
"Générer une capture Open Graph": "",
|
||||
"Gérer les catégories": "",
|
||||
"Gérer les commentaires": "",
|
||||
"Gérer les données": "",
|
||||
"Hauteur": "",
|
||||
"Hauteur de l'image": "",
|
||||
"Hauteur de l'image sélectionnée": "",
|
||||
"Hauteur maximale": "",
|
||||
"ID de la chaîne : https://www.youtube.com/channel/[ID].": "",
|
||||
"Icône": "",
|
||||
"Icône avec bulle de texte": "",
|
||||
"Icône haut de page, couleur arrière-plan": "",
|
||||
"Identifiant": "",
|
||||
"Identifiant (sans espace ni majuscule)": "",
|
||||
"Identité": "",
|
||||
"Identité de la fonte": "",
|
||||
"Identité du site": "",
|
||||
"Il apparaît dans la barre de titre et les partages sur les réseaux sociaux.": "",
|
||||
"Image": "",
|
||||
"Image étirée (100% 100%)": "",
|
||||
"Important": "",
|
||||
"Importante": "",
|
||||
"Importation d'utilisateurs": "",
|
||||
"Importation de fichier plat CSV": "",
|
||||
"Importation effectuée": "",
|
||||
"Importer": "",
|
||||
"Importer dans": "",
|
||||
"Importer des utilisateurs en masse": "",
|
||||
"Impossible d'ouvrir l'archive": "",
|
||||
"Impossible de modifier votre propre groupe.": "",
|
||||
"Impossible de soumettre le formulaire, car il contient des erreurs": "",
|
||||
"Impossible de supprimer une page contenant des pages enfants": "",
|
||||
"Impossible de supprimer votre propre compte": "",
|
||||
"Inclure le contenu du gestionnaire de fichiers": "",
|
||||
"Incorrect": "",
|
||||
"Informations": "",
|
||||
"Instagram": "",
|
||||
"Installation terminée": "",
|
||||
"Installer": "",
|
||||
"Installer depuis le catalogue en ligne": "",
|
||||
"Installer depuis une archive": "",
|
||||
"Installer les données d'un module": "",
|
||||
"Installer ou mettre à jour un module téléchargé": "",
|
||||
"Installer un module": "",
|
||||
"Installer un thème archivé (site ou administration)": "",
|
||||
"Instructions JS ou jquery spécifiques à la page.": "",
|
||||
"Interface": "",
|
||||
"Jeton invalide": "",
|
||||
"Journal réinitialisé avec succès": "",
|
||||
"Journalisation": "",
|
||||
"L'archive a été déposée dans le gestionnaire de fichiers. Les archives inférieures à la version 9 ne sont pas acceptées.": "",
|
||||
"L'identifiant est défini lors de la création du compte, il ne peut pas être modifié.": "",
|
||||
"La carte du site a été mise à jour": "",
|
||||
"La copie de sauvegarde du fichier htaccess n'a pas été restaurée !": "",
|
||||
"La description d'une page participe à son référencement, chaque page doit disposer d'une description différente.": "",
|
||||
"La page %s est ouverte par l'utilisateur %s": "",
|
||||
"La page demandée n'existe pas ou est introuvable (erreur 404)": "",
|
||||
"La page est affichée dans un menu horizontal mais pas dans le menu vertical d'une barre latérale.": "",
|
||||
"La première page que vos visiteurs verront.": "",
|
||||
"La règlementation française impose un anonymat de niveau 2": "",
|
||||
"La réécriture d'URL n'a pas été restaurée !": "",
|
||||
"La sauvegarde des fichiers peut prendre du temps. Continuer ?": "",
|
||||
"La suppression a échoué": "",
|
||||
"La version installée est plus récente": "",
|
||||
"La vérification est quotidienne. Option désactivée si la configuration du serveur ne le permet pas.": "",
|
||||
"Langue de l'administration": "",
|
||||
"Langue du site par défaut": "",
|
||||
"Langue par défaut": "",
|
||||
"Langues": "",
|
||||
"Langues disponibles": "",
|
||||
"Langues installées": "",
|
||||
"Largeur": "",
|
||||
"Largeur de l'image": "",
|
||||
"Largeur du site": "",
|
||||
"Le curseur horizontal règle le niveau de transparence, le placer tout à la gauche pour un surlignement invisible.": "",
|
||||
"Le curseur horizontal règle le niveau de transparence.": "",
|
||||
"Le fuseau horaire est utile au bon référencement": "",
|
||||
"Le menu accessoire est aligné à droite de la barre de menu, c'est un emplacement réservé aux drapeaux et au bouton de connexion.": "",
|
||||
"Le menu horizontal intégral": "",
|
||||
"Le module %s a été %s": "",
|
||||
"Le module %s de la page %s a été supprimé": "",
|
||||
"Le module %s est désinstallé, il reste peut-être des données dans %s": "",
|
||||
"Le sous-menu de la page parente": "",
|
||||
"Le survol d'une icône de l'écran de connexion affiche temporairement le mot de passe.": "",
|
||||
"Le titre court est affiché dans les menus. Il peut être identique au titre de la page.": "",
|
||||
"Les langues sélectionnées sont identiques": "",
|
||||
"Les mentions légales sont obligatoires en France. Une option du pied de page ajoute un lien discret vers cette page.": "",
|
||||
"Les modifications que vous avez apportées ne seront peut-être pas enregistrées.": "",
|
||||
"Les tailles des polices de la bannière, de menu et de pied de page sont proportionnelles à cette taille.": "",
|
||||
"Lettres": "",
|
||||
"Libre": "",
|
||||
"Licence :": "",
|
||||
"Lien de connexion": "",
|
||||
"Lien page des mentions légales.": "",
|
||||
"Liens": "",
|
||||
"Limitation des tentatives": "",
|
||||
"Limitée au site": "",
|
||||
"Linkedin": "",
|
||||
"Liste noire": "",
|
||||
"Liste noire réinitialisée avec succès": "",
|
||||
"Lors d'une mise à jour automatique, conserve le fichier htaccess de la racine du site.": "",
|
||||
"Léger": "",
|
||||
"Légère": "",
|
||||
"Maigre": "",
|
||||
"Maintenance": "",
|
||||
"Majuscule à chaque mot": "",
|
||||
"Majuscules": "",
|
||||
"Marges verticales": "",
|
||||
"Masquer la bannière en écran réduit": "",
|
||||
"Masquer la page et les pages enfants dans le menu d'une barre latérale": "",
|
||||
"Masquer les pages enfants dans le menu horizontal": "",
|
||||
"Membre": "",
|
||||
"Membre avec droit de partage": "",
|
||||
"Membre simple": "",
|
||||
"Mentions légales": "",
|
||||
"Menu": "",
|
||||
"Menu accessoire": "",
|
||||
"Menu burger dans écran réduit": "",
|
||||
"Menu standard": "",
|
||||
"Message d'acceptation des Cookies": "",
|
||||
"Message de consentement aux cookies": "",
|
||||
"Mettre à jour": "",
|
||||
"Mettre à jour le module orphelin": "",
|
||||
"Minuscules": "",
|
||||
"Mise en forme des titres": "",
|
||||
"Mise en forme du texte": "",
|
||||
"Mise en forme du titre": "",
|
||||
"Mise en page": "",
|
||||
"Mise à jour": "",
|
||||
"Mise à jour automatisée": "",
|
||||
"Mise à jour de ZwiiCMS": "",
|
||||
"Mise à jour terminée avec succès.": "",
|
||||
"Modifications enregistrées": "",
|
||||
"Module": "",
|
||||
"Module de la page": "",
|
||||
"Modules": "",
|
||||
"Modules configurés": "",
|
||||
"Modules installés": "",
|
||||
"Modules orphelins": "",
|
||||
"Mot de passe": "",
|
||||
"Mot de passe oublié": "",
|
||||
"Mot de passe perdu": "",
|
||||
"Motorisé par": "",
|
||||
"Moyen": "",
|
||||
"Moyenne": "",
|
||||
"Moyenne (200%)": "",
|
||||
"Moyenne (200px)": "",
|
||||
"Méta-description": "",
|
||||
"Méta-titre": "",
|
||||
"Ne pas afficher": "",
|
||||
"Ne pas charger l'exemple de site (utilisateurs avancés)": "",
|
||||
"Ne pas répéter": "",
|
||||
"Ne pas saisir les balises": "",
|
||||
"News": "",
|
||||
"Niveau 1 (192.168.12.x)": "",
|
||||
"Niveau 2 (192.168.x.x)": "",
|
||||
"Niveau 3 (192.x.x.x)": "",
|
||||
"Nom": "",
|
||||
"Nom Prénom": "",
|
||||
"Nom du profil": "",
|
||||
"Nom utilisateur": "",
|
||||
"Non": "",
|
||||
"Non tronquée": "",
|
||||
"Notre site est actuellement en maintenance. Nous sommes désolés pour la gêne occasionnée et faisons notre possible pour être rapidement de retour.": "",
|
||||
"Nouveau contenu localisé": "",
|
||||
"Nouveau mot de passe": "",
|
||||
"Nouveau mot de passe enregistré": "",
|
||||
"Nouvel utilisateur": "",
|
||||
"Nouvelle page créée": "",
|
||||
"Nouvelle page ou barre latérale": "",
|
||||
"Obligatoire": "",
|
||||
"Ombre": "",
|
||||
"Option active en mode déconnecté uniquement, les pages enfants sont visibles et accessibles.": "",
|
||||
"Option recommandée pour sécuriser la connexion. S'applique à tous les captchas du site. Le captcha simple se limite à une addition de nombres de 0 à 10. Le captcha complexe utilise quatre opérations de nombres de 0 à 20. Activation recommandée.": "",
|
||||
"Options": "",
|
||||
"Options avancées": "",
|
||||
"Origine": "",
|
||||
"Oui": "",
|
||||
"Page": "",
|
||||
"Page 2/3 - barre 1/3": "",
|
||||
"Page 3/4 - barre 1/4": "",
|
||||
"Page associée": "",
|
||||
"Page de recherche": "",
|
||||
"Page dupliquée": "",
|
||||
"Page et module dupliqués": "",
|
||||
"Page inexistante, erreur 404": "",
|
||||
"Page non cliquable": "",
|
||||
"Page parent": "",
|
||||
"Page standard": "",
|
||||
"Page supprimée": "",
|
||||
"Pages dans le menu": "",
|
||||
"Pages du site": "",
|
||||
"Pages et les modules de": "",
|
||||
"Pages orphelines": "",
|
||||
"Papier peint": "",
|
||||
"Par défaut le menu est affiché APRES le contenu de la page. Pour le positionner à un emplacement précis, insérez [MENU] dans le contenu de la page.": "",
|
||||
"Paramètres": "",
|
||||
"Paramètres de la localisation": "",
|
||||
"Paramètres de la sauvegarde": "",
|
||||
"Paramètres du profil": "",
|
||||
"Paramètres à utiliser lorsque votre hébergeur ne propose pas la fonctionnalité d'envoi de mail.": "",
|
||||
"Pas de marge au-dessus et en dessous du site": "",
|
||||
"Pensez à supprimer le cache de votre navigateur si la favicon ne change pas.": "",
|
||||
"Permission": "",
|
||||
"Permission et référencement": "",
|
||||
"Permissions": "",
|
||||
"Permissions sur les dossiers": "",
|
||||
"Permissions sur les fichiers": "",
|
||||
"Permissions sur les pages": "",
|
||||
"Petite": "",
|
||||
"Petite (150px)": "",
|
||||
"Petite (180%)": "",
|
||||
"Pied de page": "",
|
||||
"Pinterest": "",
|
||||
"Plan du site": "",
|
||||
"Police des titres": "",
|
||||
"Police du texte": "",
|
||||
"Port SMTP": "",
|
||||
"Port du proxy": "",
|
||||
"Position": "",
|
||||
"Position du module": "",
|
||||
"Pour définir la page comme barre latérale, choisissez l'option dans la liste.": "",
|
||||
"Presse Papier": "",
|
||||
"Presse papier": "",
|
||||
"Profils des groupes": "",
|
||||
"Proportionnelle à la taille définie dans le site.": "",
|
||||
"Prénom": "",
|
||||
"Prénom Nom": "",
|
||||
"Préparation de la mise à jour": "",
|
||||
"Préserver le fichier htaccess racine": "",
|
||||
"Préserver les comptes des utilisateurs déjà installés": "",
|
||||
"Prévenir l'utilisateur par mail": "",
|
||||
"Prévisualiser": "",
|
||||
"Pseudo": "",
|
||||
"Rang 9 > rang 1. Le profil de rang 1 n'est pas modifiable.": "",
|
||||
"Ratio": "",
|
||||
"Ratio :": "",
|
||||
"Recherche": "",
|
||||
"Recherche dans le site": "",
|
||||
"Rechercher": "",
|
||||
"Rechercher une mise à jour en ligne": "",
|
||||
"Redirection": "",
|
||||
"Redirection vers la connexion": "",
|
||||
"Renommer": "",
|
||||
"Renseignez les champs ci-dessous pour finaliser l'installation.": "",
|
||||
"Responsive (contain)": "",
|
||||
"Responsive (cover)": "",
|
||||
"Restauration des bases de données absentes": "",
|
||||
"Restauration effectuée avec succès": "",
|
||||
"Restaurer": "",
|
||||
"Restaurer les données du site": "",
|
||||
"Rester connecté sur ce navigateur": "",
|
||||
"Retour": "",
|
||||
"Rien à importer, erreur de format ou fichier incorrect": "",
|
||||
"Rédacteur": "",
|
||||
"Référencement": "",
|
||||
"Réinitialisation du mot de passe": "",
|
||||
"Réinitialiser avec le thème par défaut": "",
|
||||
"Réinitialiser la feuille de style": "",
|
||||
"Réinitialiser la liste": "",
|
||||
"Réinitialiser le journal": "",
|
||||
"Réinstaller": "",
|
||||
"Répétition": "",
|
||||
"Réseau": "",
|
||||
"Réseaux sociaux": "",
|
||||
"S'ouvre dans un nouvel onglet": "",
|
||||
"SMTP": "",
|
||||
"SMTP personnalisé": "",
|
||||
"Saisir la clé, puis valider le formulaire avant de cliquer sur le bouton de génération": "",
|
||||
"Saisissez le Titre de gestion des cookies.": "",
|
||||
"Saisissez le message pour les cookies déposés par ZwiiCMS, nécessaires au fonctionnement et qui ne nécessitent pas de consentement.": "",
|
||||
"Saisissez le texte du lien vers les mentions légales,la page doit être définie dans la configuration du site.": "",
|
||||
"Saisissez votre ID : https://pinterest.com/[ID].": "",
|
||||
"Saisissez votre ID : https://twitter.com/[ID].": "",
|
||||
"Saisissez votre ID : https://www.facebook.com/[ID].": "",
|
||||
"Saisissez votre ID : https://www.instagram.com/[ID].": "",
|
||||
"Saisissez votre ID Github : https://github.com/[ID].": "",
|
||||
"Saisissez votre ID Linkedin : https://fr.linkedin.com/in/[ID].": "",
|
||||
"Saisissez votre ID Utilisateur : https://www.youtube.com/user/[ID].": "",
|
||||
"Sauvegarde": "",
|
||||
"Sauvegarde automatique quotidienne du site": "",
|
||||
"Sauvegarde du thème dans le": "",
|
||||
"Sauvegarde générée avec succès.": "",
|
||||
"Sauvegarder": "",
|
||||
"Sauvegarder et télécharger le module": "",
|
||||
"Sauvegarder le module dans le gestionnaire de fichiers": "",
|
||||
"Sauvegarder les données du module dans le gestionnaire de fichiers": "",
|
||||
"Sauvegarder les données du site": "",
|
||||
"Script dans body": "",
|
||||
"Script dans head": "",
|
||||
"Scripts externes": "",
|
||||
"Se déconnecter": "",
|
||||
"Service en ligne inaccessible": "",
|
||||
"Seul un administrateur peut se connecter lors d'une maintenance": "",
|
||||
"Si le contenu du gestionnaire de fichiers est très volumineux, mieux vaut une copie par FTP.": "",
|
||||
"Signature": "",
|
||||
"Site": "",
|
||||
"Site en maintenance": "",
|
||||
"Size": "",
|
||||
"Source": "",
|
||||
"Standard": "",
|
||||
"Style": "",
|
||||
"Suppression interdite": "",
|
||||
"Suppression interdite, page active dans la configuration du site": "",
|
||||
"Supprime le point d'interrogation dans les URL, l'option est indisponible avec les autres serveurs Web": "",
|
||||
"Supprimer": "",
|
||||
"Supprimer la page": "",
|
||||
"Supprimer le module": "",
|
||||
"Supprimer toutes les sauvegardes automatiques ?": "",
|
||||
"Sur l'axe horizontal": "",
|
||||
"Sur l'axe vertical": "",
|
||||
"Sur les deux axes": "",
|
||||
"Sécurité": "",
|
||||
"Sécurité de la connexion": "",
|
||||
"Sécurité désactivée": "",
|
||||
"Sélectionner un fichier": "",
|
||||
"Sélectionnez au moins un contenu à afficher": "",
|
||||
"Sélectionnez la langue à copier vers une langue cible": "",
|
||||
"Sélectionnez une icône adaptée à un thème sombre.<br>Pensez à supprimer le cache de votre navigateur si la favicon ne change pas.": "",
|
||||
"Sélectionnez une image ou une icône de petite dimension": "",
|
||||
"Sélectionnez une langue": "",
|
||||
"Sélectionnez une page contenant le module 'Recherche'. Une option du pied de page ajoute un lien discret vers cette page.": "",
|
||||
"Sélectionnez une page pour activer": "",
|
||||
"Séparateur": "",
|
||||
"Taille": "",
|
||||
"Text": "",
|
||||
"Texte": "",
|
||||
"Thème": "",
|
||||
"Thème de l'administration": "",
|
||||
"Thème du site": "",
|
||||
"Thème importé": "",
|
||||
"Thèmes": "",
|
||||
"Titre": "",
|
||||
"Titre court": "",
|
||||
"Titre masqué": "",
|
||||
"Titre masqué dans la page": "",
|
||||
"Titres": "",
|
||||
"Tous les dossiers": "",
|
||||
"Tous les droits d'édition des contenus": "",
|
||||
"Tout Effacer": "",
|
||||
"Traduction supprimée": "",
|
||||
"Très grande": "",
|
||||
"Très grande (240%)": "",
|
||||
"Très grande (400px)": "",
|
||||
"Très important": "",
|
||||
"Très importante": "",
|
||||
"Très léger": "",
|
||||
"Très légère": "",
|
||||
"Très petite": "",
|
||||
"Très petite (100px) ": "",
|
||||
"Très petite (160%)": "",
|
||||
"Twitter": "",
|
||||
"Type de captcha": "",
|
||||
"Type de proxy": "",
|
||||
"Téléchargement et validation de l'archive": "",
|
||||
"Télécharger": "",
|
||||
"Télécharger la liste": "",
|
||||
"Télécharger le journal": "",
|
||||
"Télécharger le module dans le gestionnaire de fichiers": "",
|
||||
"Téléverser": "",
|
||||
"URL incorrecte": "",
|
||||
"Un mail a été envoyé pour confirmer la réinitialisation": "",
|
||||
"Une archive du dossier /site/data est conservée pendant 30 jours. Activation recommandée": "",
|
||||
"Une erreur est survenue lors de l'étape :": "",
|
||||
"Url du fichier de fonte": "",
|
||||
"Utilisateur inexistant": "",
|
||||
"Utilisateur supprimé": "",
|
||||
"Utilisateurs": "",
|
||||
"Valider": "",
|
||||
"Version": "",
|
||||
"Version n°": "",
|
||||
"Vider dossier sauvegardes auto": "",
|
||||
"Visiteur": "",
|
||||
"Vous n'êtes pas autorisé à consulter cette page (erreur 403)": "",
|
||||
"Youtube": "",
|
||||
"ZwiiCMS - Installation": "",
|
||||
"actualisé": "",
|
||||
"favicon.ico": "",
|
||||
"faviconDark.ico": "",
|
||||
"gestionnaire de fichiers": "",
|
||||
"installé": "",
|
||||
"jour": "",
|
||||
"jours": "",
|
||||
"sauvegardé avec succès": "",
|
||||
"vers ZwiiCMS": "",
|
||||
"À droite": "",
|
||||
"À gauche": "",
|
||||
"À l'emplacement du mot clé [MODULE] dans la page": "",
|
||||
"Échec de l'écriture, vérifiez les permissions": "",
|
||||
"Échecs": "",
|
||||
"Éditer": "",
|
||||
"Éditer la page": "",
|
||||
"Éditer les dialogues": "",
|
||||
"Éditer une catégorie": "",
|
||||
"Éditeur": "",
|
||||
"Éditeur CSS": "",
|
||||
"Éditeur JS": "",
|
||||
"Éditeur de script %s": "",
|
||||
"Éditeur de script dans Body": "",
|
||||
"Éditeur de script dans Head": "",
|
||||
"Éditeur simple": "",
|
||||
"Édition des pages": "",
|
||||
"Édition du profil %s": "",
|
||||
"Éléments": "",
|
||||
"Étendu sur la page": "",
|
||||
"Étiquettes des pages spéciales": "",
|
||||
"Dimensions minimales": "",
|
||||
"Taille maximale du fichier": "",
|
||||
"5 Mo pour les images JPEG": "",
|
||||
"1 Mo pour les images PNG": "",
|
||||
"Poids": "",
|
||||
"Supprimer ce profil ?": "",
|
||||
"Masqué": "",
|
||||
"Haut de page": "",
|
||||
"Bas de page": "",
|
||||
"Petit triangle": "",
|
||||
"Grand triangle": "",
|
||||
"Flèche": "",
|
||||
"Modèle": "",
|
||||
"Bouton de navigation droit": "",
|
||||
"Bouton de navigation gauche": ""
|
||||
}
|
BIN
core/module/install/ressource/themes/theme_affaire.zip
Normal file
BIN
core/module/install/ressource/themes/theme_affaire.zip
Normal file
Binary file not shown.
BIN
core/module/install/ressource/themes/theme_moderne.zip
Normal file
BIN
core/module/install/ressource/themes/theme_moderne.zip
Normal file
Binary file not shown.
BIN
core/module/install/ressource/themes/theme_old_facebook.zip
Normal file
BIN
core/module/install/ressource/themes/theme_old_facebook.zip
Normal file
Binary file not shown.
BIN
core/module/install/ressource/themes/theme_orange_black.zip
Normal file
BIN
core/module/install/ressource/themes/theme_orange_black.zip
Normal file
Binary file not shown.
24
core/module/install/ressource/themes/themes.json
Normal file
24
core/module/install/ressource/themes/themes.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"themes": {
|
||||
"defaut": {
|
||||
"name": "Le thème par défaut, ambiance bleu et montagne",
|
||||
"filename": ""
|
||||
},
|
||||
"moderne": {
|
||||
"name": "Thème avec la nouvelle bannière personnalisable",
|
||||
"filename": "theme_moderne.zip"
|
||||
},
|
||||
"affaire": {
|
||||
"name": "Thème affaire, bannière centre d'appel, ambiance prune",
|
||||
"filename": "theme_affaire.zip"
|
||||
},
|
||||
"black": {
|
||||
"name": "Thème de nuit, ambiance nocturne",
|
||||
"filename": "theme_orange_black.zip"
|
||||
},
|
||||
"facebook": {
|
||||
"name": "Thème Facebook ancienne génération, pas de bannière, menu fixe fond bleu",
|
||||
"filename": "theme_old_facebook.zip"
|
||||
}
|
||||
}
|
||||
}
|
0
core/module/install/view/index/index.css
Normal file
0
core/module/install/view/index/index.css
Normal file
20
core/module/install/view/index/index.php
Normal file
20
core/module/install/view/index/index.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php echo template::formOpen('installForm'); ?>
|
||||
<h3>
|
||||
<?php echo helper::translate('Dans quelle langue utiliserez-vous Zwii ?'); ?>
|
||||
</h3>
|
||||
<div class="row">
|
||||
<div class="col6 offset3">
|
||||
<?php echo template::select('installLanguage', $module::$i18nFiles, [
|
||||
'label' => 'Langues installées',
|
||||
'selected' => array_key_exists ('fr_FR', $module::$i18nFiles) ? 'fr_FR': reset($module::$i18nFiles),
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col3 offset9">
|
||||
<?php echo template::submit('installSubmit', [
|
||||
'value' => 'Suivant'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php echo template::formClose(); ?>
|
22
core/module/install/view/postinstall/postinstall.css
Normal file
22
core/module/install/view/postinstall/postinstall.css
Normal file
@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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
|
||||
* @author Frédéric Tempez <frederic.tempez@outlook.com>
|
||||
* @copyright Copyright (C) 2018-2023, Frédéric Tempez
|
||||
* @license CC Attribution-NonCommercial-NoDerivatives 4.0 International
|
||||
* @link http://zwiicms.fr/
|
||||
*/
|
||||
|
||||
|
||||
/** NE PAS EFFACER
|
||||
* admin.css
|
||||
*/
|
||||
|
||||
.title {
|
||||
font-weight: bold;
|
||||
}
|
13
core/module/install/view/postinstall/postinstall.js.php
Normal file
13
core/module/install/view/postinstall/postinstall.js.php
Normal file
@ -0,0 +1,13 @@
|
||||
/**
|
||||
* 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
|
||||
* @author Frédéric Tempez <frederic.tempez@outlook.com>
|
||||
* @copyright Copyright (C) 2018-2023, Frédéric Tempez
|
||||
* @license CC Attribution-NonCommercial-NoDerivatives 4.0 International
|
||||
* @link http://zwiicms.fr/
|
||||
*/
|
||||
$("#installId").on("change keydown keyup",(function(event){var userId=$(this).val();if(8!==event.keyCode&&37!==event.keyCode&&39!==event.keyCode&&46!==event.keyCode&&window.getSelection().toString()!==userId){var searchReplace={"á":"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","Á":"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","'":"-",'"':"-"," ":"-"};userId=(userId=userId.replace(/[áàâäãåçéèêëíìîïñóòôöõúùûüýÿ'" ]/gi,(function(match){return searchReplace[match]}))).replace(/[^a-z0-9-]/gi,""),$(this).val(userId)}}));
|
122
core/module/install/view/postinstall/postinstall.php
Normal file
122
core/module/install/view/postinstall/postinstall.php
Normal file
@ -0,0 +1,122 @@
|
||||
<p>
|
||||
<?php echo helper::translate('Renseignez les champs ci-dessous pour finaliser l\'installation.'); ?>
|
||||
</p>
|
||||
<?php echo template::formOpen('installForm'); ?>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<details open>
|
||||
<summary>
|
||||
<span class="title">
|
||||
<?php echo helper::translate('Compte administrateur'); ?>
|
||||
</span>
|
||||
</summary>
|
||||
<div class="row">
|
||||
<div class="col6">
|
||||
<?php echo template::text('installFirstname', [
|
||||
'autocomplete' => 'off',
|
||||
'label' => 'Prénom'
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col6">
|
||||
<?php echo template::text('installLastname', [
|
||||
'autocomplete' => 'off',
|
||||
'label' => 'Nom'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col6">
|
||||
<?php echo template::text('installId', [
|
||||
'autocomplete' => 'off',
|
||||
'label' => 'Identifiant'
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col6">
|
||||
<?php echo template::mail('installMail', [
|
||||
'autocomplete' => 'off',
|
||||
'label' => 'Adresse électronique'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col6">
|
||||
<?php echo template::password('installPassword', [
|
||||
'autocomplete' => 'off',
|
||||
'label' => 'Mot de passe'
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col6">
|
||||
<?php echo template::password('installConfirmPassword', [
|
||||
'autocomplete' => 'off',
|
||||
'label' => 'Confirmation'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<details close>
|
||||
<summary>
|
||||
<span class="title">
|
||||
<?php echo helper::translate('Options avancées'); ?>
|
||||
</span>
|
||||
</summary>
|
||||
<?php if ($_SESSION['ZWII_UI'] === 'fr_FR'): ?>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<?php echo template::checkbox('installDefaultData', true, 'Ne pas charger l\'exemple de site (utilisateurs avancés)', [
|
||||
'checked' => false
|
||||
]);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="row">
|
||||
<div class="col3">
|
||||
<?php echo template::select('installProxyType', $module::$proxyType, [
|
||||
'label' => 'Type de proxy'
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col6">
|
||||
<?php echo template::text('installProxyUrl', [
|
||||
'label' => 'Adresse du proxy',
|
||||
'placeholder' => 'cache.proxy.fr'
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col3">
|
||||
<?php echo template::text('installProxyPort', [
|
||||
'label' => 'Port du proxy',
|
||||
'placeholder' => '6060'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<?php echo template::select('installTheme', $module::$themes, [
|
||||
'label' => 'Thème'
|
||||
]); ?>
|
||||
<?php echo template::hidden('installLanguage', [
|
||||
'value' => $this->getUrl(2)
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
<div class="row">
|
||||
<div class="col2">
|
||||
<?php echo template::button('installPrevious', [
|
||||
'class' => 'buttonGrey',
|
||||
'href' => helper::baseUrl(true) . '?install',
|
||||
'value' => template::ico('left')
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col3 offset7">
|
||||
<?php echo template::submit('installSubmit', [
|
||||
'value' => 'Installer'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php echo template::formClose(); ?>
|
18
core/module/install/view/update/update.css
Normal file
18
core/module/install/view/update/update.css
Normal file
@ -0,0 +1,18 @@
|
||||
/**
|
||||
* 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
|
||||
* @author Frédéric Tempez <frederic.tempez@outlook.com>
|
||||
* @copyright Copyright (C) 2018-2023, Frédéric Tempez
|
||||
* @license CC Attribution-NonCommercial-NoDerivatives 4.0 International
|
||||
* @link http://zwiicms.fr/
|
||||
*/
|
||||
|
||||
|
||||
/** NE PAS EFFACER
|
||||
* admin.css
|
||||
*/
|
75
core/module/install/view/update/update.js.php
Normal file
75
core/module/install/view/update/update.js.php
Normal file
@ -0,0 +1,75 @@
|
||||
function step(i, data) {
|
||||
var errors = ["<?php echo helper::translate('Préparation de la mise à jour'); ?>", "<?php echo helper::translate('Téléchargement et validation de l\'archive'); ?>", "<?php echo helper::translate('Installation'); ?>", "<?php echo helper::translate('Configuration'); ?>"];
|
||||
$(".installUpdateProgressText").hide(), $(".installUpdateProgressText[data-id=" + i + "]").show();
|
||||
|
||||
$("body").css("cursor", "wait");
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "<?php echo helper::baseUrl(false); ?>?install/steps",
|
||||
data: {
|
||||
step: i,
|
||||
data: data
|
||||
},
|
||||
success: function (result) {
|
||||
// if (result.success != "1") { // Vérification de la propriété "success"
|
||||
// Appel de la fonction de gestion d'erreur
|
||||
// showError(i, result, errors);
|
||||
// return;
|
||||
//}
|
||||
setTimeout((function () {
|
||||
if (4 === i) {
|
||||
$("#installUpdateSuccess").show();
|
||||
$("body").css("cursor", "default");
|
||||
$("#installUpdateEnd").removeClass("disabled");
|
||||
$("#installUpdateProgress").hide();
|
||||
} else {
|
||||
step(i + 1, result.data);
|
||||
}
|
||||
}), 2e3)
|
||||
},
|
||||
error: function (xhr) {
|
||||
// Balance tout dans la console
|
||||
console.log(i);
|
||||
console.log(xhr.responseText);
|
||||
console.log(errors);
|
||||
// Appel de la fonction de gestion d'erreur
|
||||
showError(i, xhr.responseText, errors);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showError(step, message, errors) {
|
||||
$("body").css("cursor", "default");
|
||||
$("#installUpdateErrorStep").text(errors[step] + " (étape n°" + step + ")");
|
||||
$("#installUpdateError").show();
|
||||
$("#installUpdateEnd").removeClass("disabled");
|
||||
$("#installUpdateProgress").hide();
|
||||
|
||||
// Vérifier si l'accolade ouvrante est trouvée et qu'elle n'est pas en première position
|
||||
if (typeof message !== 'object') {
|
||||
|
||||
// Trouver la position du premier "{" pour repérer le début du tableau
|
||||
const startOfArray = message.indexOf('{');
|
||||
|
||||
// Extraire le message du warning jusqu'au début du tableau
|
||||
const warningMessage = message.substring(0, startOfArray).trim();
|
||||
|
||||
// Extraire le tableau JSON entre les accolades
|
||||
const jsonString = message.substring(startOfArray);
|
||||
const jsonData = JSON.parse(jsonString);
|
||||
|
||||
// Afficher les résultats
|
||||
$("#installUpdateErrorMessage").html("<strong>Détails de l'erreur :</strong><br> " +
|
||||
jsonData.data.replace(/^"(.*)"$/, '$1') +
|
||||
"<br>" +
|
||||
warningMessage.replace(/<[^p].*?>/g, ""));
|
||||
} else {
|
||||
// Vous pouvez également faire quelque chose d'autre ici, par exemple, afficher un message à l'utilisateur, etc.
|
||||
$("#installUpdateErrorMessage").html(message);
|
||||
}
|
||||
}
|
||||
|
||||
$(window).on("load", function () {
|
||||
step(1, null);
|
||||
});
|
56
core/module/install/view/update/update.php
Normal file
56
core/module/install/view/update/update.php
Normal file
@ -0,0 +1,56 @@
|
||||
<div id="updateContainer">
|
||||
<p><strong>
|
||||
<?php echo helper::translate('Mise à jour de ZwiiCMS'); ?>
|
||||
|
||||
<?php echo self::ZWII_VERSION; ?>
|
||||
<?php echo helper::translate('vers ZwiiCMS'); ?>
|
||||
|
||||
<?php echo $module::$newVersion; ?>.
|
||||
</strong></p>
|
||||
<p>
|
||||
<?php echo helper::translate('Afin d\'assurer le bon fonctionnement de Zwii, veuillez ne pas fermer cette page avant la fin de l\'opération.'); ?>
|
||||
</p>
|
||||
<div class="row">
|
||||
<div class="col9 verticalAlignMiddle">
|
||||
<div id="installUpdateProgress">
|
||||
<?php echo template::ico('spin', ['animate' => true]); ?>
|
||||
<span class="installUpdateProgressText" data-id="1">
|
||||
<?php echo helper::translate('1/4 : Préparation...'); ?>
|
||||
</span>
|
||||
<span class="installUpdateProgressText displayNone" data-id="2">
|
||||
<?php echo helper::translate('2/4 : Téléchargement...'); ?>
|
||||
</span>
|
||||
<span class="installUpdateProgressText displayNone" data-id="3">
|
||||
<?php echo helper::translate('3/4 : Installation...'); ?>
|
||||
</span>
|
||||
<span class="installUpdateProgressText displayNone" data-id="4">
|
||||
<?php echo helper::translate('4/4 : Configuration...'); ?>
|
||||
</span>
|
||||
</div>
|
||||
<div id="installUpdateError" class="message colorRed displayNone">
|
||||
<?php echo template::ico('cancel'); ?>
|
||||
<strong>
|
||||
<?php echo helper::translate('Une erreur est survenue lors de l\'étape :') . '<br>'; ?>
|
||||
<span id="installUpdateErrorStep"> </span>.
|
||||
</strong>
|
||||
</div>
|
||||
<div id="installUpdateSuccess" class="message colorGreen displayNone">
|
||||
<?php echo template::ico('check'); ?>
|
||||
<?php echo helper::translate('Mise à jour terminée avec succès.'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col3 verticalAlignTop">
|
||||
<?php echo template::button('installUpdateEnd', [
|
||||
'value' => 'Terminer',
|
||||
'href' => helper::baseUrl() . 'config',
|
||||
'ico' => 'check',
|
||||
'class' => 'disabled'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<p><em><span class="colorRed" id="installUpdateErrorMessage"></span></em></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
699
core/module/language/language.php
Normal file
699
core/module/language/language.php
Normal file
@ -0,0 +1,699 @@
|
||||
<?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
|
||||
* @author Frédéric Tempez <frederic.tempez@outlook.com>
|
||||
* @copyright Copyright (C) 2018-2023, Frédéric Tempez
|
||||
* @license CC Attribution-NonCommercial-NoDerivatives 4.0 International
|
||||
* @link http://zwiicms.fr/
|
||||
*/
|
||||
|
||||
class language extends common
|
||||
{
|
||||
|
||||
// URL langues de l'UI en ligne
|
||||
const ZWII_UI_URL = 'https://forge.chapril.org/ZwiiCMS-Team/zwiicms-translations/raw/branch/master/v13/';
|
||||
|
||||
public static $actions = [
|
||||
'index' => self::GROUP_ADMIN,
|
||||
'copy' => self::GROUP_ADMIN,
|
||||
'add' => self::GROUP_ADMIN,
|
||||
// Ajouter une langue de contenu
|
||||
'edit' => self::GROUP_ADMIN,
|
||||
// Éditer une langue de l'UI
|
||||
'locale' => self::GROUP_ADMIN,
|
||||
// Éditer une langue de contenu
|
||||
'delete' => self::GROUP_ADMIN,
|
||||
// Effacer une langue de contenu ou de l'interface
|
||||
'content' => self::GROUP_VISITOR,
|
||||
'update' => self::GROUP_ADMIN,
|
||||
'default' => self::GROUP_ADMIN
|
||||
];
|
||||
|
||||
const PAGINATION = '20';
|
||||
|
||||
// Language contents
|
||||
public static $translateOptions = [];
|
||||
|
||||
// Page pour la configuration dans la langue
|
||||
public static $pagesList = [];
|
||||
public static $orphansList = [];
|
||||
public static $pages = '';
|
||||
|
||||
// Liste des langues installées
|
||||
public static $languagesUiInstalled = [];
|
||||
public static $languagesInstalled = [];
|
||||
public static $languagesStore = [];
|
||||
public static $dialogues = [];
|
||||
|
||||
// Liste des langues cibles
|
||||
public static $languagesTarget = [];
|
||||
|
||||
// Activation du bouton de copie
|
||||
public static $siteCopy = true;
|
||||
|
||||
// Localisation en cours d'édition
|
||||
public static $locales = [];
|
||||
|
||||
//UI
|
||||
// Fichiers des langues de l'interface
|
||||
public static $i18nFiles = [];
|
||||
|
||||
/**
|
||||
* Met à jour les traduction du site depuis le store
|
||||
*/
|
||||
public function update()
|
||||
{
|
||||
if (
|
||||
$this->getUser('permission', __CLASS__, __FUNCTION__) !== true
|
||||
) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'access' => false
|
||||
]);
|
||||
} else {
|
||||
$lang = $this->getUrl(2);
|
||||
// Action interdite ou URl avec le code langue incorrecte
|
||||
if (
|
||||
array_key_exists($lang, self::$languages) === false
|
||||
) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'redirect' => helper::baseUrl() . 'language',
|
||||
'state' => false,
|
||||
'notification' => helper::translate('Action interdite')
|
||||
]);
|
||||
}
|
||||
|
||||
// Télécharger le descripteur en ligne
|
||||
$languageData = json_decode(helper::getUrlContents(self::ZWII_UI_URL . $lang . '.json'), true);
|
||||
$descripteur = json_decode(helper::getUrlContents(self::ZWII_UI_URL . 'language.json'), true);
|
||||
$success = false;
|
||||
if (
|
||||
is_array($languageData) &&
|
||||
is_array($descripteur['language'][$lang])
|
||||
) {
|
||||
if ($this->setData(['language', $lang, $descripteur['language'][$lang]])) {
|
||||
$success = file_put_contents(self::I18N_DIR . $lang . '.json', json_encode($languageData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||
$success = is_int($success) ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'redirect' => helper::baseUrl() . 'language',
|
||||
'notification' => $success ? helper::translate('Copie terminée avec succès') : 'Copie terminée avec des erreurs',
|
||||
'state' => $success
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration avancée des langues
|
||||
*/
|
||||
public function copy()
|
||||
{
|
||||
// Soumission du formulaire
|
||||
if (
|
||||
$this->getUser('permission', __CLASS__, __FUNCTION__) === true &&
|
||||
$this->isPost()
|
||||
) {
|
||||
// Initialisation
|
||||
$success = false;
|
||||
$copyFrom = $this->getInput('translateFormCopySource');
|
||||
$toCreate = $this->getInput('translateFormCopyTarget');
|
||||
if ($copyFrom !== $toCreate) {
|
||||
// Création du dossier
|
||||
if (is_dir(self::DATA_DIR . $toCreate) === false) { // Si le dossier est déjà créé
|
||||
$success = mkdir(self::DATA_DIR . $toCreate, 0755);
|
||||
$success = mkdir(self::DATA_DIR . $toCreate . '/content', 0755);
|
||||
} else {
|
||||
$success = true;
|
||||
}
|
||||
// Copier les données par défaut
|
||||
$success = (copy(self::DATA_DIR . $copyFrom . '/locale.json', self::DATA_DIR . $toCreate . '/locale.json') === true && $success === true) ? true : false;
|
||||
$success = (copy(self::DATA_DIR . $copyFrom . '/module.json', self::DATA_DIR . $toCreate . '/module.json') === true && $success === true) ? true : false;
|
||||
$success = (copy(self::DATA_DIR . $copyFrom . '/page.json', self::DATA_DIR . $toCreate . '/page.json') === true && $success === true) ? true : false;
|
||||
$success = ($this->copyDir(self::DATA_DIR . $copyFrom . '/content', self::DATA_DIR . $toCreate . '/content') === true && $success === true) ? true : false;
|
||||
// Enregistrer la langue
|
||||
if ($success) {
|
||||
$notification = sprintf(helper::translate('Données %s copiées vers %s'), self::$languages[$copyFrom], self::$languages[$toCreate]);
|
||||
} else {
|
||||
$notification = helper::translate('Erreur de copie, vérifiez les permissions');
|
||||
}
|
||||
} else {
|
||||
$success = false;
|
||||
$notification = helper::translate('Les langues sélectionnées sont identiques');
|
||||
}
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'notification' => $notification,
|
||||
'title' => 'Utilitaire de copie',
|
||||
'view' => 'index',
|
||||
'state' => $success
|
||||
]);
|
||||
}
|
||||
|
||||
// Tableau des langues installées
|
||||
foreach (self::$languages as $key => $value) {
|
||||
// tableau des langues installées
|
||||
if (is_dir(self::DATA_DIR . $key)) {
|
||||
self::$languagesTarget[$key] = self::$languages[$key];
|
||||
}
|
||||
}
|
||||
|
||||
// Langues cibles fr en plus
|
||||
self::$languagesInstalled = self::$languagesTarget;
|
||||
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'title' => helper::translate('Copie de contenus localisés'),
|
||||
'view' => 'copy'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------------------------------------
|
||||
// Langues du site
|
||||
// --------------------------------------------------------------------------------------------------
|
||||
|
||||
foreach (self::$languages as $key => $value) {
|
||||
// tableau des langues installées
|
||||
if (is_dir(self::DATA_DIR . $key)) {
|
||||
if (
|
||||
file_exists(self::DATA_DIR . $key . '/page.json') &&
|
||||
file_exists(self::DATA_DIR . $key . '/module.json') &&
|
||||
file_exists(self::DATA_DIR . $key . '/locale.json')
|
||||
) {
|
||||
if (file_exists(self::DATA_DIR . $key . '/.default')) {
|
||||
$messageLocale = helper::translate('Langue par défaut');
|
||||
} elseif (isset($_SESSION['ZWII_CONTENT']) && $_SESSION['ZWII_CONTENT'] === $key) {
|
||||
$messageLocale = helper::translate('Langue du site sélectionnée');
|
||||
} else {
|
||||
$messageLocale = '';
|
||||
}
|
||||
self::$languagesInstalled[] = [
|
||||
template::flag($key, '20 %') . ' ' . $value . ' (' . $key . ')',
|
||||
$messageLocale,
|
||||
template::button('translateContentLanguageLocaleEdit' . $key, [
|
||||
'class' => file_exists(self::DATA_DIR . $key . '/locale.json') ? '' : ' disabled',
|
||||
'href' => helper::baseUrl() . $this->getUrl(0) . '/locale/' . $key,
|
||||
'value' => template::ico('pencil'),
|
||||
'help' => 'Éditer'
|
||||
]),
|
||||
template::button('translateContentLanguageLocaleDelete' . $key, [
|
||||
'class' => 'translateDelete buttonRed' . ($messageLocale ? ' disabled' : ''),
|
||||
'href' => helper::baseUrl() . $this->getUrl(0) . '/delete/locale/' . $key,
|
||||
'value' => template::ico('trash'),
|
||||
'help' => 'Supprimer',
|
||||
])
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// Activation du bouton de copie
|
||||
self::$siteCopy = count(self::$languagesInstalled) > 1 ? false : true;
|
||||
|
||||
// --------------------------------------------------------------------------------------------------
|
||||
// Langues de l'UI
|
||||
// --------------------------------------------------------------------------------------------------
|
||||
|
||||
// Langues attachées à des utilisateurs non effaçables
|
||||
$usersUI = [];
|
||||
$users = $this->getData(['user']);
|
||||
foreach ($users as $key => $value) {
|
||||
array_push($usersUI, $this->getData(['user', $key, 'language']));
|
||||
}
|
||||
|
||||
// Langues installées
|
||||
$installedUI = $this->getData(['language']);
|
||||
|
||||
if (array_key_exists('language', $installedUI)) {
|
||||
$installedUI = $installedUI['language'];
|
||||
}
|
||||
|
||||
// Langues disponibles en ligne
|
||||
$storeUI = json_decode(helper::getUrlContents(self::ZWII_UI_URL . 'language.json'), true);
|
||||
$storeUI = $storeUI['language'];
|
||||
|
||||
// Construction du tableau à partir des langues disponibles dans le store
|
||||
foreach ($installedUI as $file => $value) {
|
||||
// La langue est-elle référencée ?
|
||||
if (array_key_exists(basename($file, '.json'), $installedUI)) {
|
||||
// La langue est déjà installée
|
||||
self::$languagesUiInstalled[$file] = [
|
||||
template::flag($file, '20 %') . ' ' . self::$languages[$file],
|
||||
$value['version'],
|
||||
helper::dateUTF8('%d/%m/%Y', $value['date']),
|
||||
//self::$i18nUI === $file ? helper::translate('Interface') : '',
|
||||
'',
|
||||
/*
|
||||
template::button('translateContentLanguageUIEdit' . $file, [
|
||||
'href' => helper::baseUrl() . $this->getUrl(0) . '/edit/' . $file,
|
||||
'value' => template::ico('pencil'),
|
||||
'help' => 'Éditer',
|
||||
'disabled' => 'fr_FR' === $file
|
||||
]),
|
||||
*/
|
||||
|
||||
template::button('translateContentLanguageUIDownload' . $file, [
|
||||
'class' => version_compare($installedUI[$file]['version'], $storeUI[$file]['version']) < 0 ? 'buttonGreen' : '',
|
||||
'href' => helper::baseUrl() . $this->getUrl(0) . '/update/' . $file,
|
||||
'value' => template::ico('update'),
|
||||
'help' => 'Mettre à jour',
|
||||
]),
|
||||
template::button('translateContentLanguageUIDelete' . $file, [
|
||||
'class' => 'translateDelete buttonRed' . (in_array($file, $usersUI) ? ' disabled' : ''),
|
||||
'href' => helper::baseUrl() . $this->getUrl(0) . '/delete/ui/' . $file,
|
||||
'value' => template::ico('trash'),
|
||||
'help' => 'Supprimer',
|
||||
]),
|
||||
];
|
||||
}
|
||||
}
|
||||
// Construction du tableau à partir des langues disponibles dans le store
|
||||
foreach ($storeUI as $file => $value) {
|
||||
|
||||
// La langue est-elle installée ?
|
||||
if (array_key_exists($file, $installedUI) === false) {
|
||||
self::$languagesStore[$file] = [
|
||||
template::flag($file, '20 %') . ' ' . self::$languages[$file],
|
||||
$value['version'],
|
||||
helper::dateUTF8('%d/%m/%Y', $value['date']),
|
||||
'',
|
||||
template::button('translateContentLanguageUIDownload' . $file, [
|
||||
'class' => 'buttonGreen',
|
||||
'href' => helper::baseUrl() . $this->getUrl(0) . '/update/' . $file,
|
||||
'value' => template::ico('shopping-basket'),
|
||||
'help' => 'Installer',
|
||||
])
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'title' => helper::translate('Langues'),
|
||||
'view' => 'index'
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* Ajouter une langue de contenu
|
||||
*/
|
||||
|
||||
public function add()
|
||||
{
|
||||
|
||||
// Soumission du formulaire
|
||||
if (
|
||||
$this->getUser('permission', __CLASS__, __FUNCTION__) === true &&
|
||||
$this->isPost()
|
||||
) {
|
||||
|
||||
$lang = $this->getInput('translateAddContent');
|
||||
|
||||
// Constructeur pour cette langue
|
||||
$this->jsonDB($lang);
|
||||
|
||||
// Création du contenu
|
||||
$this->initData('page', $lang);
|
||||
$this->initData('module', $lang);
|
||||
$this->initData('locale', $lang);
|
||||
|
||||
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'redirect' => helper::baseUrl() . 'language',
|
||||
'notification' => helper::translate('Modifications enregistrées'),
|
||||
'state' => true
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
// Préparation de l'affichage du formulaire
|
||||
//-----------------------------------------
|
||||
|
||||
// Tableau des langues non installées
|
||||
foreach (self::$languages as $key => $value) {
|
||||
if (!is_dir(self::DATA_DIR . $key))
|
||||
self::$i18nFiles[$key] = $value;
|
||||
}
|
||||
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'title' => helper::translate('Nouveau contenu localisé'),
|
||||
'view' => 'add'
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Edition des paramètres de la langue de contenu
|
||||
*/
|
||||
public function locale()
|
||||
{
|
||||
// Action interdite ou URl avec le code langue incorrecte
|
||||
$lang = $this->getUrl(2);
|
||||
if (
|
||||
array_key_exists($lang, self::$languages) === false
|
||||
) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'redirect' => helper::baseUrl() . 'language',
|
||||
'state' => false,
|
||||
'notification' => helper::translate('Action interdite')
|
||||
]);
|
||||
}
|
||||
|
||||
// Soumission du formulaire
|
||||
if (
|
||||
$this->getUser('permission', __CLASS__, __FUNCTION__) === true &&
|
||||
$this->isPost()
|
||||
) {
|
||||
|
||||
// Sauvegarder les locales
|
||||
$data = [
|
||||
'locale' => [
|
||||
'homePageId' => $this->getInput('localeHomePageId', helper::FILTER_ID, true),
|
||||
'page404' => $this->getInput('localePage404'),
|
||||
'page403' => $this->getInput('localePage403'),
|
||||
'page302' => $this->getInput('localePage302'),
|
||||
'legalPageId' => $this->getInput('localeLegalPageId'),
|
||||
'searchPageId' => $this->getInput('localeSearchPageId'),
|
||||
'poweredPageLabel' => empty($this->getInput('localePoweredPageLabel', helper::FILTER_STRING_SHORT)) ? 'Motorisé par' : $this->getInput('localePoweredPageLabel', helper::FILTER_STRING_SHORT),
|
||||
'searchPageLabel' => empty($this->getInput('localeSearchPageLabel', helper::FILTER_STRING_SHORT)) ? 'Rechercher' : $this->getInput('localeSearchPageLabel', helper::FILTER_STRING_SHORT),
|
||||
'legalPageLabel' => empty($this->getInput('localeLegalPageLabel', helper::FILTER_STRING_SHORT)) ? 'Mentions légales' : $this->getInput('localeLegalPageLabel', helper::FILTER_STRING_SHORT),
|
||||
'sitemapPageLabel' => empty($this->getInput('localeSitemapPageLabel', helper::FILTER_STRING_SHORT)) ? 'Plan du site' : $this->getInput('localeSitemapPageLabel', helper::FILTER_STRING_SHORT),
|
||||
'metaDescription' => $this->getInput('localeMetaDescription', helper::FILTER_STRING_LONG, true),
|
||||
'title' => $this->getInput('localeTitle', helper::FILTER_STRING_SHORT, true),
|
||||
'cookies' => [
|
||||
// Les champs sont obligatoires si l'option consentement des cookies est active
|
||||
'mainLabel' => $this->getInput('localeCookiesZwiiText', helper::FILTER_STRING_LONG, $this->getInput('configCookieConsent', helper::FILTER_BOOLEAN)),
|
||||
'titleLabel' => $this->getInput('localeCookiesTitleText', helper::FILTER_STRING_SHORT, $this->getInput('configCookieConsent', helper::FILTER_BOOLEAN)),
|
||||
'linkLegalLabel' => $this->getInput('localeCookiesLinkMlText', helper::FILTER_STRING_SHORT, $this->getInput('configCookieConsent', helper::FILTER_BOOLEAN)),
|
||||
'cookiesFooterText' => $this->getInput('localeCookiesFooterText', helper::FILTER_STRING_SHORT, $this->getInput('configCookieConsent', helper::FILTER_BOOLEAN)),
|
||||
'buttonValidLabel' => $this->getInput('localeCookiesButtonText', helper::FILTER_STRING_SHORT, $this->getInput('configCookieConsent', helper::FILTER_BOOLEAN))
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
// Sauvegarde hors méthodes si la langue n'est pas celle de l'UI
|
||||
if ($lang === self::$i18nContent) {
|
||||
// Enregistrer les données par lecture directe du formulaire
|
||||
$this->setData(['locale', $data['locale']]);
|
||||
} else {
|
||||
// Sauver sur le disque
|
||||
file_put_contents(self::DATA_DIR . $lang . '/locale.json', json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT), LOCK_EX);
|
||||
}
|
||||
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'redirect' => helper::baseUrl() . $this->getUrl(),
|
||||
'notification' => helper::translate('Modifications enregistrées'),
|
||||
'state' => true
|
||||
]);
|
||||
}
|
||||
|
||||
// Préparation de l'affichage du formulaire
|
||||
//-----------------------------------------
|
||||
|
||||
// La locale est-elle celle de la langue de l'UI ?
|
||||
if ($lang === self::$i18nContent) {
|
||||
self::$locales[$lang]['locale'] = $this->getData(['locale']);
|
||||
} else {
|
||||
// Lire les locales sans passer par les méthodes
|
||||
self::$locales[$lang] = json_decode(file_get_contents(self::DATA_DIR . $lang . '/locale.json'), true);
|
||||
}
|
||||
|
||||
// Générer la liste des pages disponibles
|
||||
self::$pagesList = $this->getData(['page']);
|
||||
foreach (self::$pagesList as $page => $pageId) {
|
||||
if (
|
||||
$this->getData(['page', $page, 'block']) === 'bar' ||
|
||||
$this->getData(['page', $page, 'disable']) === true
|
||||
) {
|
||||
unset(self::$pagesList[$page]);
|
||||
}
|
||||
}
|
||||
|
||||
self::$orphansList = $this->getData(['page']);
|
||||
foreach (self::$orphansList as $page => $pageId) {
|
||||
if (
|
||||
$this->getData(['page', $page, 'block']) === 'bar' ||
|
||||
$this->getData(['page', $page, 'disable']) === true ||
|
||||
$this->getdata(['page', $page, 'position']) !== 0
|
||||
) {
|
||||
unset(self::$orphansList[$page]);
|
||||
}
|
||||
}
|
||||
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'title' => helper::translate('Paramètres de la localisation') . ' ' . template::flag($lang, '20 %'),
|
||||
'view' => 'locale'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Edition de la langue de l'interface
|
||||
*/
|
||||
public function edit()
|
||||
{
|
||||
$lang = $this->getUrl(2);
|
||||
// Action interdite ou URl avec le code langue incorrecte
|
||||
if (
|
||||
array_key_exists($lang, self::$languages) === false
|
||||
) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'redirect' => helper::baseUrl() . 'language',
|
||||
'state' => false,
|
||||
'notification' => helper::translate('Action interdite')
|
||||
]);
|
||||
}
|
||||
// Soumission du formulaire
|
||||
if (
|
||||
$this->getUser('permission', __CLASS__, __FUNCTION__) === true &&
|
||||
$this->isPost()
|
||||
) {
|
||||
|
||||
// Sauvegarder les champs de la langue
|
||||
$data = json_decode(file_get_contents(self::I18N_DIR . $lang . '.json'), true);
|
||||
foreach ($data as $key => $value) {
|
||||
$target = $this->getInput('translateString' . array_search($key, array_keys($data)));
|
||||
if (empty($target) === false) {
|
||||
$data[$key] = $target;
|
||||
}
|
||||
}
|
||||
file_put_contents(self::I18N_DIR . $lang . '.json', json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT), LOCK_EX);
|
||||
|
||||
// Mettre à jour le descripteur
|
||||
$this->setData([
|
||||
'language',
|
||||
$lang,
|
||||
[
|
||||
'version' => $this->getInput('translateEditVersion'),
|
||||
'date' => $this->getInput('translateEditDate', helper::FILTER_DATETIME),
|
||||
]
|
||||
]);
|
||||
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'notification' => helper::translate('Modifications enregistrées'),
|
||||
'redirect' => helper::baseUrl() . 'language',
|
||||
'state' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
// Construction du formulaire
|
||||
|
||||
// Chargement des dialogue de la langue cible
|
||||
if (!isset($data)) {
|
||||
$data = json_decode(file_get_contents(self::I18N_DIR . $this->getUrl(2) . '.json'), true);
|
||||
}
|
||||
|
||||
// Ajout des champs absents selon la langue de référence
|
||||
$dataFr = json_decode(file_get_contents(self::I18N_DIR . 'fr_FR.json'), true);
|
||||
foreach ($dataFr as $key => $value) {
|
||||
if (!array_key_exists($key, $data)) {
|
||||
$data[$key] = '';
|
||||
}
|
||||
}
|
||||
file_put_contents(self::I18N_DIR . $lang . '.json', json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT), LOCK_EX);
|
||||
|
||||
// Tableau des chaines à traduire dans la langue sélectionnée
|
||||
foreach ($data as $key => $value) {
|
||||
$dialogues[] = ['source' => $key, 'target' => $value];
|
||||
}
|
||||
|
||||
// Pagination
|
||||
$pagination = helper::pagination($dialogues, $this->getUrl(), self::PAGINATION);
|
||||
|
||||
// Liste des pages
|
||||
self::$pages = $pagination['pages'];
|
||||
|
||||
// Articles en fonction de la pagination
|
||||
for ($i = $pagination['first']; $i < $pagination['last']; $i++) {
|
||||
self::$dialogues[$i] = $dialogues[$i];
|
||||
}
|
||||
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'title' => helper::translate('Éditer les dialogues') . ' ' . template::flag($lang, '20 %'),
|
||||
'view' => 'edit',
|
||||
'vendor' => [
|
||||
'flatpickr',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/***
|
||||
* Effacer une langue de contenu
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
if (
|
||||
$this->getUser('permission', __CLASS__, __FUNCTION__) !== true
|
||||
) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'access' => false
|
||||
]);
|
||||
} else {
|
||||
// Action interdite ou URl avec le code langue incorrecte
|
||||
$target = $this->getUrl(2);
|
||||
$lang = $this->getUrl(3);
|
||||
if (
|
||||
array_key_exists($lang, self::$languages) === false
|
||||
) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'redirect' => helper::baseUrl() . 'language',
|
||||
'state' => false,
|
||||
'notification' => helper::translate('Action interdite')
|
||||
]);
|
||||
}
|
||||
switch ($target) {
|
||||
case 'locale':
|
||||
$success = false;
|
||||
// Effacement d'une site dans une langue
|
||||
if (is_dir(self::DATA_DIR . $lang) === true) {
|
||||
$success = $this->deleteDir(self::DATA_DIR . $lang);
|
||||
}
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'redirect' => helper::baseUrl() . 'language',
|
||||
'notification' => $success ? helper::translate('Traduction supprimée') : helper::translate('Erreur inconnue'),
|
||||
'state' => $success
|
||||
]);
|
||||
break;
|
||||
|
||||
case 'ui':
|
||||
$success = false;
|
||||
// Effacement d'une langue de l'interface
|
||||
if (file_exists(self::I18N_DIR . $lang . '.json') === true) {
|
||||
$this->deleteData(['language', $lang]);
|
||||
$success = unlink(self::I18N_DIR . $lang . '.json');
|
||||
}
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'redirect' => helper::baseUrl() . 'language',
|
||||
'notification' => $success ? helper::translate('Traduction supprimée') : helper::translate('Erreur inconnue'),
|
||||
'state' => $success
|
||||
]);
|
||||
break;
|
||||
default:
|
||||
# Do nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Modifie la langue du site par défaut
|
||||
*
|
||||
*/
|
||||
public function default()
|
||||
{
|
||||
if (
|
||||
$this->getUser('permission', __CLASS__, __FUNCTION__) !== true
|
||||
) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'access' => false
|
||||
]);
|
||||
} else {
|
||||
// Action interdite ou URl avec le code langue incorrecte
|
||||
$lang = $this->getUrl(2);
|
||||
if (
|
||||
array_key_exists($lang, self::$languages) === false
|
||||
) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'redirect' => helper::baseUrl() . 'language',
|
||||
'state' => false,
|
||||
'notification' => helper::translate('Action interdite')
|
||||
]);
|
||||
}
|
||||
|
||||
foreach (self::$languages as $key => $value) {
|
||||
if (file_exists(self::DATA_DIR . $key . '/.default')) {
|
||||
unlink(self::DATA_DIR . $key . '/.default');
|
||||
touch(self::DATA_DIR . $lang . '/.default');
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'notification' => helper::translate('Modifications enregistrées'),
|
||||
'redirect' => helper::baseUrl() . 'language',
|
||||
'state' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Traitement du changement de langue
|
||||
* Fonction utilisée par le noyau
|
||||
*/
|
||||
public function content()
|
||||
{
|
||||
// Langue sélectionnée
|
||||
$lang = $this->getUrl(2);
|
||||
/**
|
||||
* Changement de la langue si
|
||||
* différe de la langue active
|
||||
* déjà initialisée
|
||||
* fait partie des langues installées
|
||||
*/
|
||||
|
||||
if (
|
||||
is_dir(self::DATA_DIR . $lang) &&
|
||||
array_key_exists($lang, self::$languages) === true
|
||||
) {
|
||||
|
||||
// Stocker la sélection
|
||||
$_SESSION['ZWII_CONTENT'] = $lang;
|
||||
}
|
||||
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'redirect' => helper::baseUrl()
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
20
core/module/language/view/add/add.css
Normal file
20
core/module/language/view/add/add.css
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* 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
|
||||
* @author Frédéric Tempez <frederic.tempez@outlook.com>
|
||||
* @copyright Copyright (C) 2018-2023, Frédéric Tempez
|
||||
* @license CC Attribution-NonCommercial-NoDerivatives 4.0 International
|
||||
* @link http://zwiicms.fr/
|
||||
*/
|
||||
|
||||
|
||||
/** @import url("site/data/admin.css"); */
|
||||
|
||||
/** NE PAS EFFACER
|
||||
* admin.css
|
||||
*/
|
29
core/module/language/view/add/add.php
Normal file
29
core/module/language/view/add/add.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php echo template::formOpen('translateAddForm'); ?>
|
||||
<div class="row">
|
||||
<div class="col1">
|
||||
<?php echo template::button('translateFormBack', [
|
||||
'class' => 'buttonGrey',
|
||||
'href' => helper::baseUrl() . 'language',
|
||||
'value' => template::ico('left')
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col2 offset9">
|
||||
<?php echo template::submit('translateFormSubmit'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<div class="block">
|
||||
<h4><?php echo helper::translate('Sélectionnez une langue'); ?>
|
||||
</h4>
|
||||
<div class="row">
|
||||
<div class="col4 offset4">
|
||||
<?php echo template::select('translateAddContent', $module::$i18nFiles, [
|
||||
'label' => 'Langues disponibles'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php echo template::formClose(); ?>
|
20
core/module/language/view/copy/copy.css
Normal file
20
core/module/language/view/copy/copy.css
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* 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
|
||||
* @author Frédéric Tempez <frederic.tempez@outlook.com>
|
||||
* @copyright Copyright (C) 2018-2023, Frédéric Tempez
|
||||
* @license CC Attribution-NonCommercial-NoDerivatives 4.0 International
|
||||
* @link http://zwiicms.fr/
|
||||
*/
|
||||
|
||||
|
||||
/** @import url("site/data/admin.css"); */
|
||||
|
||||
/** NE PAS EFFACER
|
||||
* admin.css
|
||||
*/
|
36
core/module/language/view/copy/copy.php
Normal file
36
core/module/language/view/copy/copy.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php echo template::formOpen('translateFormCopy'); ?>
|
||||
<div class="row">
|
||||
<div class="col1">
|
||||
<?php echo template::button('translateFormCopyBack', [
|
||||
'class' => 'buttonGrey',
|
||||
'href' => helper::baseUrl() . 'language',
|
||||
'value' => template::ico('left')
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col2 offset9">
|
||||
<?php echo template::submit('translateFormCopySubmit', [
|
||||
'value' => 'Copier'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<div class="block">
|
||||
<h4><?php echo helper::translate('Sélectionnez la langue à copier vers une langue cible'); ?>
|
||||
</h4>
|
||||
<div class="row">
|
||||
<div class="col6">
|
||||
<?php echo template::select('translateFormCopySource', $module::$languagesInstalled, [
|
||||
'label' => 'Source'
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col6">
|
||||
<?php echo template::select('translateFormCopyTarget', $module::$languagesTarget, [
|
||||
'label' => 'Cible'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php echo template::formClose(); ?>
|
20
core/module/language/view/edit/edit.css
Normal file
20
core/module/language/view/edit/edit.css
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* 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
|
||||
* @author Frédéric Tempez <frederic.tempez@outlook.com>
|
||||
* @copyright Copyright (C) 2018-2023, Frédéric Tempez
|
||||
* @license CC Attribution-NonCommercial-NoDerivatives 4.0 International
|
||||
* @link http://zwiicms.fr/
|
||||
*/
|
||||
|
||||
|
||||
/** @import url("site/data/admin.css"); */
|
||||
|
||||
/** NE PAS EFFACER
|
||||
* admin.css
|
||||
*/
|
59
core/module/language/view/edit/edit.php
Normal file
59
core/module/language/view/edit/edit.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php echo template::formOpen('translateUIForm'); ?>
|
||||
<div class="row">
|
||||
<div class="col1">
|
||||
<?php echo template::button('translateUIFormBack', [
|
||||
'class' => 'buttonGrey',
|
||||
'href' => helper::baseUrl() . 'language',
|
||||
'value' => template::ico('left')
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col2 offset9">
|
||||
<?php echo template::submit('translateUIFormSubmit'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<div class="block">
|
||||
<h4>
|
||||
<?php echo helper::translate('Paramètres'); ?>
|
||||
</h4>
|
||||
<div class="row">
|
||||
<div class="col6">
|
||||
<?php echo template::text('translateEditVersion', [
|
||||
'label' => 'Version n°',
|
||||
'value' => $this->getData(['language', $this->getUrl(2), 'version'])
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col6">
|
||||
<?php echo template::date('translateEditDate', [
|
||||
'label' => 'Date de publication',
|
||||
'type' => 'datetime-local',
|
||||
'value' => $this->getData(['language', $this->getUrl(2), 'date'])
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<div class="block">
|
||||
<div class="row">
|
||||
<?php foreach ($module::$dialogues as $key => $value) : ?>
|
||||
<div class="col6">
|
||||
<?php echo sprintf('%g -', $key); ?>
|
||||
<?php echo $value['source']; ?>
|
||||
</div>
|
||||
<div class="col6">
|
||||
<?php echo template::text('translateString' . $key, [
|
||||
'label' => '',
|
||||
'value' => $value['target']
|
||||
]); ?>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php echo $module::$pages; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php echo template::formClose(); ?>
|
54
core/module/language/view/index/index.css
Normal file
54
core/module/language/view/index/index.css
Normal file
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* 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
|
||||
* @author Frédéric Tempez <frederic.tempez@outlook.com>
|
||||
* @copyright Copyright (C) 2018-2023, Frédéric Tempez
|
||||
* @license CC Attribution-NonCommercial-NoDerivatives 4.0 International
|
||||
* @link http://zwiicms.fr/
|
||||
*/
|
||||
|
||||
|
||||
/** NE PAS EFFACER
|
||||
* admin.css
|
||||
*/
|
||||
|
||||
#setupContainer {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.buttonNotice {
|
||||
border: 2px solid red !important;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
/* Style the tab */
|
||||
.tab {
|
||||
margin-top: 1.8em;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tab ~ .tabContent {
|
||||
margin-top: -10px;
|
||||
}
|
||||
|
||||
.buttonTab {
|
||||
display: inline-block;
|
||||
transition: 0.3s;
|
||||
border-radius: 10px 10px 0px 0px;
|
||||
width: 160px;
|
||||
margin: 0 1px;
|
||||
}
|
||||
|
||||
.buttonTab:hover {
|
||||
filter: saturate(200%);
|
||||
}
|
||||
|
||||
.activeButton {
|
||||
background-color: #00BFFF;
|
||||
}
|
88
core/module/language/view/index/index.js.php
Normal file
88
core/module/language/view/index/index.js.php
Normal file
@ -0,0 +1,88 @@
|
||||
/**
|
||||
* 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
|
||||
* @author Frédéric Tempez <frederic.tempez@outlook.com>
|
||||
* @copyright Copyright (C) 2018-2023, Frédéric Tempez
|
||||
* @license CC Attribution-NonCommercial-NoDerivatives 4.0 International
|
||||
* @link http://zwiicms.fr/
|
||||
*/
|
||||
|
||||
|
||||
$(document).ready(function() {
|
||||
var translateLayout = getCookie("translateLayout");
|
||||
if (translateLayout == null) {
|
||||
translateLayout = "content";
|
||||
setCookie("translateLayout", "content");
|
||||
|
||||
}
|
||||
$("#contentContainer").hide();
|
||||
$("#uiContainer").hide();
|
||||
$("#" + translateLayout + "Container").show();
|
||||
$("#translate" + capitalizeFirstLetter(translateLayout) + "Button").addClass("activeButton");
|
||||
|
||||
|
||||
});
|
||||
|
||||
// Sélecteur de fonctions
|
||||
|
||||
$("#translateUiButton").on("click", function() {
|
||||
$("#contentContainer").hide();
|
||||
$("#uiContainer").show();
|
||||
$(this).addClass("activeButton");
|
||||
$("#translateContentButton").removeClass("activeButton");
|
||||
setCookie("translateLayout", "ui");
|
||||
|
||||
});
|
||||
$("#translateContentButton").on("click", function() {
|
||||
$("#uiContainer").hide();
|
||||
$("#contentContainer").show();
|
||||
$(this).addClass("activeButton");
|
||||
$("#translateUiButton").removeClass("activeButton");
|
||||
setCookie("translateLayout", "content");
|
||||
// Afficher les boutons liés au contenu
|
||||
$(".contentButtonContainer").show();
|
||||
});
|
||||
|
||||
/**
|
||||
* Confirmation de suppression
|
||||
*/
|
||||
$(".translateDelete").on("click", function() {
|
||||
var _this = $(this);
|
||||
var message_delete = "<?php echo helper::translate('Confirmer la suppression de cette langue'); ?>";
|
||||
return core.confirm(message_delete, function() {
|
||||
$(location).attr("href", _this.attr("href"));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
// Fonctions
|
||||
function setCookie(name, value, days) {
|
||||
var expires = "";
|
||||
if (days) {
|
||||
var date = new Date();
|
||||
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
||||
expires = "; expires=" + date.toUTCString();
|
||||
}
|
||||
document.cookie = name + "=" + (value || "") + expires + "; path=/; samesite=lax";
|
||||
}
|
||||
|
||||
function getCookie(name) {
|
||||
var nameEQ = name + "=";
|
||||
var ca = document.cookie.split(';');
|
||||
for (var i = 0; i < ca.length; i++) {
|
||||
var c = ca[i];
|
||||
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
|
||||
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Define function to capitalize the first letter of a string
|
||||
function capitalizeFirstLetter(string) {
|
||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||
}
|
98
core/module/language/view/index/index.php
Normal file
98
core/module/language/view/index/index.php
Normal file
@ -0,0 +1,98 @@
|
||||
<?php echo template::formOpen('translateForm'); ?>
|
||||
<div class="row">
|
||||
<div class="col1">
|
||||
<?php echo template::button('translateFormBack', [
|
||||
'class' => 'buttonGrey',
|
||||
'href' => helper::baseUrl(),
|
||||
'value' => template::ico('left')
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col1">
|
||||
<?php /**echo template::button('translateHelp', [
|
||||
'href' => 'https://doc.zwiicms.fr/prise-en-charge-des-langues-etrangeres',
|
||||
'target' => '_blank',
|
||||
'value' => template::ico('help'),
|
||||
'class' => 'buttonHelp',
|
||||
'help' => 'Consulter l\'aide en ligne'
|
||||
]);*/?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab">
|
||||
<?php echo template::button('translateUiButton', [
|
||||
'value' => 'Interface',
|
||||
'class' => 'buttonTab'
|
||||
]); ?>
|
||||
<?php echo template::button('translateContentButton', [
|
||||
'value' => 'Site',
|
||||
'class' => 'buttonTab'
|
||||
]); ?>
|
||||
</div>
|
||||
|
||||
<div id="uiContainer" class="tabContent">
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<div class="block">
|
||||
<h4>
|
||||
<?php echo helper::translate('Langues installées'); ?>
|
||||
</h4>
|
||||
<?php if ($module::$languagesUiInstalled): ?>
|
||||
<?php echo template::table([2, 1, 1, 5, 1, 1], $module::$languagesUiInstalled, ['Langues', 'Version', 'Date', '', '', '']); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<div class="block">
|
||||
<h4>
|
||||
<?php echo helper::translate('Catalogue'); ?>
|
||||
</h4>
|
||||
<?php if ($module::$languagesStore): ?>
|
||||
<?php echo template::table([2, 1, 2, 6, 1], $module::$languagesStore, ['Langues', 'Version', 'Date', '', '']); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="contentContainer" class="tabContent">
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<div class="block">
|
||||
<h4>
|
||||
<?php echo helper::translate('Paramètres'); ?>
|
||||
</h4>
|
||||
<div class="col4 offset2">
|
||||
<?php echo template::button('translateButtonCopyContent', [
|
||||
'href' => helper::baseUrl() . 'language/copy',
|
||||
'ico' => 'docs',
|
||||
'disabled' => $module::$siteCopy,
|
||||
'value' => 'Copie de contenus localisés'
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col4">
|
||||
<?php echo template::button('translateButtonAddContent', [
|
||||
'href' => helper::baseUrl() . 'language/add',
|
||||
'ico' => 'plus',
|
||||
'class' => 'buttonGreen',
|
||||
'value' => 'Nouveau contenu localisé'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<div class="block">
|
||||
<h4>
|
||||
<?php echo helper::translate('Langues installées'); ?>
|
||||
</h4>
|
||||
<?php if ($module::$languagesInstalled): ?>
|
||||
<?php echo template::table([2, 6, 1, 1], $module::$languagesInstalled, ['Langues', '', '', '']); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php echo template::formClose(); ?>
|
0
core/module/language/view/store/store.php
Normal file
0
core/module/language/view/store/store.php
Normal file
1
core/module/language/view/update/update.php
Normal file
1
core/module/language/view/update/update.php
Normal file
@ -0,0 +1 @@
|
||||
<?php // Résolument vide
|
56
core/module/maintenance/maintenance.php
Normal file
56
core/module/maintenance/maintenance.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?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
|
||||
* @author Frédéric Tempez <frederic.tempez@outlook.com>
|
||||
* @copyright Copyright (C) 2018-2023, Frédéric Tempez
|
||||
* @license CC Attribution-NonCommercial-NoDerivatives 4.0 International
|
||||
* @link http://zwiicms.fr/
|
||||
*/
|
||||
|
||||
class maintenance extends common
|
||||
{
|
||||
|
||||
public static $actions = [
|
||||
'index' => self::GROUP_VISITOR
|
||||
];
|
||||
|
||||
/**
|
||||
* Maintenance
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
// Redirection vers l'accueil après rafraîchissement et que la maintenance est terminée.
|
||||
if ($this->getData(['config', 'maintenance']) == False) {
|
||||
header('Location:' . helper::baseUrl());
|
||||
exit();
|
||||
}
|
||||
// Page perso définie et existante
|
||||
if (
|
||||
$this->getData(['locale', 'page302']) !== 'none'
|
||||
and $this->getData(['page', $this->getData(['locale', 'page302'])])
|
||||
) {
|
||||
$this->addOutput([
|
||||
'display' => self::DISPLAY_LAYOUT_LIGHT,
|
||||
'title' => $this->getData(['page', $this->getData(['locale', 'page302']), 'hideTitle'])
|
||||
? ''
|
||||
: $this->getData(['page', $this->getData(['locale', 'page302']), 'title']),
|
||||
//'content' => $this->getdata(['page',$this->getData(['locale','page302']),'content']),
|
||||
'content' => $this->getPage($this->getData(['locale', 'page302']), self::$i18nContent),
|
||||
'view' => 'index'
|
||||
]);
|
||||
} else {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'display' => self::DISPLAY_LAYOUT_LIGHT,
|
||||
'title' => helper::translate('Maintenance en cours...'),
|
||||
'view' => 'index'
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
1
core/module/maintenance/view/index/index.css
Normal file
1
core/module/maintenance/view/index/index.css
Normal file
@ -0,0 +1 @@
|
||||
/* vide */
|
12
core/module/maintenance/view/index/index.php
Normal file
12
core/module/maintenance/view/index/index.php
Normal file
@ -0,0 +1,12 @@
|
||||
<p>
|
||||
<?php echo helper::translate('Notre site est actuellement en maintenance. Nous sommes désolés pour la gêne occasionnée et faisons notre possible pour être rapidement de retour.'); ?>
|
||||
</p>
|
||||
<div class="row">
|
||||
<div class="col4 offset8 textAlignCenter">
|
||||
<?php echo template::button('maintenanceLogin', [
|
||||
'value' => 'Connexion',
|
||||
'href' => helper::baseUrl() . 'user/login',
|
||||
'ico' => 'lock'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
671
core/module/page/page.php
Normal file
671
core/module/page/page.php
Normal file
@ -0,0 +1,671 @@
|
||||
<?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
|
||||
* @author Frédéric Tempez <frederic.tempez@outlook.com>
|
||||
* @copyright Copyright (C) 2018-2023, Frédéric Tempez
|
||||
* @license CC Attribution-NonCommercial-NoDerivatives 4.0 International
|
||||
* @link http://zwiicms.fr/
|
||||
*/
|
||||
|
||||
class page extends common
|
||||
{
|
||||
|
||||
public static $actions = [
|
||||
'add' => self::GROUP_EDITOR,
|
||||
'delete' => self::GROUP_EDITOR,
|
||||
'edit' => self::GROUP_EDITOR,
|
||||
'duplicate' => self::GROUP_EDITOR,
|
||||
'jsEditor' => self::GROUP_EDITOR,
|
||||
'cssEditor' => self::GROUP_EDITOR
|
||||
];
|
||||
public static $pagesNoParentId = [
|
||||
'' => 'Aucune'
|
||||
];
|
||||
public static $pagesBarId = [
|
||||
'' => 'Aucune'
|
||||
];
|
||||
public static $moduleIds = [];
|
||||
|
||||
public static $typeMenu = [
|
||||
'text' => 'Texte',
|
||||
'icon' => 'Icône',
|
||||
'icontitle' => 'Icône avec bulle de texte'
|
||||
];
|
||||
// Position du module
|
||||
public static $modulePosition = [
|
||||
'bottom' => 'Après le contenu de la page',
|
||||
'top' => 'Avant le contenu de la page',
|
||||
'free' => 'À l\'emplacement du mot clé [MODULE] dans la page'
|
||||
];
|
||||
public static $pageBlocks = [
|
||||
'12' => 'Page standard',
|
||||
'bar' => 'Barre latérale',
|
||||
'4-8' => 'Barre 1/3 - page 2/3',
|
||||
'8-4' => 'Page 2/3 - barre 1/3',
|
||||
'3-9' => 'Barre 1/4 - page 3/4',
|
||||
'9-3' => 'Page 3/4 - barre 1/4',
|
||||
'3-6-3' => 'Barre 1/4 - page 1/2 - barre 1/4',
|
||||
'2-7-3' => 'Barre 2/12 - page 7/12 - barre 3/12',
|
||||
'3-7-2' => 'Barre 3/12 - page 7/12 - barre 2/12',
|
||||
];
|
||||
public static $displayMenu = [
|
||||
'none' => 'Aucun menu',
|
||||
'parents' => 'Le menu horizontal intégral',
|
||||
'children' => 'Le sous-menu de la page parente'
|
||||
];
|
||||
public static $extraPosition = [
|
||||
false => 'Menu standard',
|
||||
true => 'Menu accessoire'
|
||||
];
|
||||
|
||||
public static $userProfils = [];
|
||||
|
||||
public static $navIconTemplate = [
|
||||
'dir' => 'Petit triangle',
|
||||
'open' => 'Grand triangle',
|
||||
'big' => 'Flèche',
|
||||
];
|
||||
|
||||
public static $navIconPosition = [
|
||||
'none' => 'Masqué',
|
||||
'top' => 'Haut de page',
|
||||
'bottom' => 'Bas de page',
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Duplication
|
||||
*/
|
||||
public function duplicate()
|
||||
{
|
||||
// Adresse sans le token
|
||||
$page = $this->getUrl(2);
|
||||
// La page n'existe pas
|
||||
if (
|
||||
$this->getUser('permission', __CLASS__, __FUNCTION__) !== true ||
|
||||
$this->getData(['page', $page]) === null
|
||||
) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'access' => false
|
||||
]);
|
||||
} else {
|
||||
// Duplication de la page
|
||||
$pageTitle = $this->getData(['page', $page, 'title']);
|
||||
$pageId = helper::increment(helper::filter($pageTitle, helper::FILTER_ID), $this->getData(['page']));
|
||||
$pageId = helper::increment($pageId, self::$coreModuleIds);
|
||||
$pageId = helper::increment($pageId, self::$moduleIds);
|
||||
$data = $this->getData([
|
||||
'page',
|
||||
$page
|
||||
]);
|
||||
// Ecriture
|
||||
$this->setData(['page', $pageId, $data]);
|
||||
$notification = helper::translate('Page dupliquée');
|
||||
// Duplication du module présent
|
||||
if ($this->getData(['page', $page, 'moduleId'])) {
|
||||
$data = $this->getData(['module', $page]);
|
||||
$this->setData(['module', $pageId, $data]);
|
||||
$notification = helper::translate('Page et module dupliqués');
|
||||
}
|
||||
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'redirect' => helper::baseUrl() . 'page/edit/' . $pageId,
|
||||
'notification' => $notification,
|
||||
'state' => true
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Création
|
||||
*/
|
||||
public function add()
|
||||
{
|
||||
if ($this->getUser('permission', __CLASS__, __FUNCTION__) !== true) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'access' => false
|
||||
]);
|
||||
} else {
|
||||
$pageTitle = 'Nouvelle page';
|
||||
$pageId = helper::increment(helper::filter($pageTitle, helper::FILTER_ID), $this->getData(['page']));
|
||||
$this->setData([
|
||||
'page',
|
||||
$pageId,
|
||||
[
|
||||
'typeMenu' => 'text',
|
||||
'iconUrl' => '',
|
||||
'disable' => false,
|
||||
'content' => $pageId . '.html',
|
||||
'hideTitle' => false,
|
||||
'breadCrumb' => false,
|
||||
'metaDescription' => '',
|
||||
'metaTitle' => '',
|
||||
'moduleId' => '',
|
||||
'parentPageId' => '',
|
||||
'modulePosition' => 'bottom',
|
||||
'position' => 0,
|
||||
'group' => self::GROUP_VISITOR,
|
||||
'targetBlank' => false,
|
||||
'title' => $pageTitle,
|
||||
'shortTitle' => $pageTitle,
|
||||
'block' => '12',
|
||||
'barLeft' => '',
|
||||
'barRight' => '',
|
||||
'navLeft' => 'none',
|
||||
'navRight' => 'none',
|
||||
'navTemplate' => 'dir',
|
||||
'displayMenu' => '0',
|
||||
'hideMenuSide' => false,
|
||||
'hideMenuHead' => false,
|
||||
'hideMenuChildren' => false,
|
||||
'js' => '',
|
||||
'css' => ''
|
||||
]
|
||||
]);
|
||||
// Creation du contenu de la page
|
||||
if (!is_dir(self::DATA_DIR . self::$i18nContent . '/content')) {
|
||||
mkdir(self::DATA_DIR . self::$i18nContent . '/content', 0755);
|
||||
}
|
||||
//file_put_contents(self::DATA_DIR . self::$i18nContent . '/content/' . $pageId . '.html', '<p>Contenu de votre nouvelle page.</p>');
|
||||
$this->setPage($pageId, '<p>Contenu de votre nouvelle page.</p>', self::$i18nContent);
|
||||
|
||||
// Met à jour le sitemap
|
||||
$this->updateSitemap();
|
||||
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'redirect' => helper::baseUrl() . $pageId,
|
||||
'notification' => helper::translate('Nouvelle page créée'),
|
||||
'state' => true
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Suppression
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
// $url prend l'adresse sans le token
|
||||
$page = $this->getUrl(2);
|
||||
// La page n'existe pas
|
||||
if (
|
||||
$this->getUser('permission', __CLASS__, __FUNCTION__) !== true ||
|
||||
$this->getData(['page', $page]) === null
|
||||
) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'access' => false
|
||||
]);
|
||||
}
|
||||
// Impossible de supprimer la page d'accueil
|
||||
elseif ($page === $this->getData(['locale', 'homePageId'])) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'redirect' => helper::baseUrl() . 'config',
|
||||
'notification' => helper::translate('Suppression interdite, page active dans la configuration du site')
|
||||
]);
|
||||
}
|
||||
// Impossible de supprimer la page affectée
|
||||
elseif ($page === $this->getData(['locale', 'searchPageId'])) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'redirect' => helper::baseUrl() . 'config',
|
||||
'notification' => helper::translate('Suppression interdite, page active dans la configuration du site')
|
||||
]);
|
||||
}
|
||||
// Impossible de supprimer la page affectée
|
||||
elseif ($page === $this->getData(['locale', 'legalPageId'])) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'redirect' => helper::baseUrl() . 'config',
|
||||
'notification' => helper::translate('Suppression interdite, page active dans la configuration du site')
|
||||
]);
|
||||
}
|
||||
// Impossible de supprimer la page affectée
|
||||
elseif ($page === $this->getData(['locale', 'page404'])) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'redirect' => helper::baseUrl() . 'config',
|
||||
'notification' => helper::translate('Suppression interdite, page active dans la configuration du site')
|
||||
]);
|
||||
}
|
||||
// Impossible de supprimer la page affectée
|
||||
elseif ($page === $this->getData(['locale', 'page403'])) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'redirect' => helper::baseUrl() . 'config',
|
||||
'notification' => helper::translate('Suppression interdite, page active dans la configuration du site')
|
||||
]);
|
||||
}
|
||||
// Impossible de supprimer la page affectée
|
||||
elseif ($page === $this->getData(['locale', 'page302'])) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'redirect' => helper::baseUrl() . 'config',
|
||||
'notification' => helper::translate('Suppression interdite, page active dans la configuration du site')
|
||||
]);
|
||||
}
|
||||
// Impossible de supprimer une page contenant des enfants
|
||||
elseif ($this->getHierarchy($page, null)) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'redirect' => helper::baseUrl() . 'page/edit/' . $page,
|
||||
'notification' => helper::translate('Impossible de supprimer une page contenant des pages enfants')
|
||||
]);
|
||||
}
|
||||
// Suppression
|
||||
else {
|
||||
// Effacer le dossier du module
|
||||
$moduleId = $this->getData(['page', $page, 'moduleId']);
|
||||
$modulesData = helper::getModules();
|
||||
if (
|
||||
array_key_exists($moduleId, $modulesData)
|
||||
&& is_dir($modulesData[$moduleId]['dataDirectory'] . $page)
|
||||
) {
|
||||
$this->deleteDir($modulesData[$moduleId]['dataDirectory'] . $page);
|
||||
}
|
||||
// Effacer la page
|
||||
$this->deleteData(['page', $page]);
|
||||
if (file_exists(self::DATA_DIR . self::$i18nContent . '/content/' . $page . '.html')) {
|
||||
unlink(self::DATA_DIR . self::$i18nContent . '/content/' . $page . '.html');
|
||||
}
|
||||
$this->deleteData(['module', $page]);
|
||||
|
||||
// Met à jour le sitemap
|
||||
$this->updateSitemap();
|
||||
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'redirect' => helper::baseUrl(false),
|
||||
'notification' => helper::translate('Page supprimée'),
|
||||
'state' => true
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Édition
|
||||
*/
|
||||
public function edit()
|
||||
{
|
||||
// La page n'existe pas
|
||||
if (
|
||||
$this->getUser('permission', __CLASS__, __FUNCTION__) !== true ||
|
||||
$this->getData(['page', $this->getUrl(2)]) === null
|
||||
) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'access' => false
|
||||
]);
|
||||
}
|
||||
// La page existe
|
||||
else {
|
||||
// Soumission du formulaire
|
||||
if (
|
||||
$this->getUser('permission', __CLASS__, __FUNCTION__) === true &&
|
||||
$this->isPost()
|
||||
) {
|
||||
// Si le Title n'est pas vide, premier test pour positionner la notification du champ obligatoire
|
||||
if ($this->getInput('pageEditTitle', helper::FILTER_ID, true) !== null && $this->getInput('pageEditTitle') !== '') {
|
||||
// Génére l'ID si le titre de la page a changé
|
||||
if ($this->getInput('pageEditTitle') !== $this->getData(['page', $this->getUrl(2), 'title'])) {
|
||||
$pageId = $this->getInput('pageEditTitle', helper::FILTER_ID, true);
|
||||
} else {
|
||||
$pageId = $this->getUrl(2);
|
||||
}
|
||||
// un dossier existe du même nom (erreur en cas de redirection)
|
||||
if (file_exists($pageId)) {
|
||||
$pageId = uniqid($pageId);
|
||||
}
|
||||
// Si l'id a changée
|
||||
if ($pageId !== $this->getUrl(2)) {
|
||||
// Incrémente le nouvel id de la page
|
||||
$pageId = helper::increment($pageId, $this->getData(['page']));
|
||||
$pageId = helper::increment($pageId, self::$coreModuleIds);
|
||||
$pageId = helper::increment($pageId, self::$moduleIds);
|
||||
// Met à jour les enfants
|
||||
foreach ($this->getHierarchy($this->getUrl(2), null) as $childrenPageId) {
|
||||
$this->setData(['page', $childrenPageId, 'parentPageId', $pageId]);
|
||||
}
|
||||
// Change l'id de page dans les données des modules
|
||||
if ($this->getData(['module', $this->getUrl(2)]) !== null) {
|
||||
$this->setData(['module', $pageId, $this->getData(['module', $this->getUrl(2)])]);
|
||||
$this->deleteData(['module', $this->getUrl(2)]);
|
||||
// Renommer le dossier du module
|
||||
$moduleId = $this->getData(['page', $this->getUrl(2), 'moduleId']);
|
||||
$modulesData = helper::getModules();
|
||||
if (is_dir($modulesData[$moduleId]['dataDirectory'] . $this->getUrl(2))) {
|
||||
// Placer la feuille de style dans un dossier au nom de la nouvelle instance
|
||||
mkdir($modulesData[$moduleId]['dataDirectory'] . $pageId, 0755);
|
||||
copy($modulesData[$moduleId]['dataDirectory'] . $this->getUrl(2), $modulesData[$moduleId]['dataDirectory'] . $pageId);
|
||||
$this->deleteDir($modulesData[$moduleId]['dataDirectory'] . $this->getUrl(2));
|
||||
// Mettre à jour le nom de la feuille de style
|
||||
$this->setData(['module', $pageId, 'theme', 'style', $modulesData[$moduleId]['dataDirectory'] . $pageId]);
|
||||
}
|
||||
}
|
||||
// Si la page correspond à la page d'accueil, change l'id dans la configuration du site
|
||||
if ($this->getData(['locale', 'homePageId']) === $this->getUrl(2)) {
|
||||
$this->setData(['locale', 'homePageId', $pageId]);
|
||||
}
|
||||
}
|
||||
// Supprime les données du module en cas de changement de module
|
||||
if ($this->getInput('pageEditModuleId') !== $this->getData(['page', $this->getUrl(2), 'moduleId'])) {
|
||||
$this->deleteData(['module', $pageId]);
|
||||
}
|
||||
// Supprime l'ancienne page si l'id a changée
|
||||
if ($pageId !== $this->getUrl(2)) {
|
||||
$this->deleteData(['page', $this->getUrl(2)]);
|
||||
if (file_exists(self::DATA_DIR . self::$i18nContent . '/content/' . $this->getUrl(2) . '.html')) {
|
||||
unlink(self::DATA_DIR . self::$i18nContent . '/content/' . $this->getUrl(2) . '.html');
|
||||
}
|
||||
}
|
||||
// Traitement des pages spéciales affectées dans la config :
|
||||
if ($this->getUrl(2) === $this->getData(['locale', 'legalPageId'])) {
|
||||
$this->setData(['locale', 'legalPageId', $pageId]);
|
||||
}
|
||||
if ($this->getUrl(2) === $this->getData(['locale', 'searchPageId'])) {
|
||||
$this->setData(['locale', 'searchPageId', $pageId]);
|
||||
}
|
||||
if ($this->getUrl(2) === $this->getData(['locale', 'page404'])) {
|
||||
$this->setData(['locale', 'page404', $pageId]);
|
||||
}
|
||||
if ($this->getUrl(2) === $this->getData(['locale', 'page403'])) {
|
||||
$this->setData(['locale', 'page403', $pageId]);
|
||||
}
|
||||
if ($this->getUrl(2) === $this->getData(['locale', 'page302'])) {
|
||||
$this->setData(['locale', 'page302', $pageId]);
|
||||
}
|
||||
// Si la page est une page enfant, actualise les positions des autres enfants du parent, sinon actualise les pages sans parents
|
||||
$lastPosition = 1;
|
||||
$hierarchy = $this->getInput('pageEditParentPageId') ? $this->getHierarchy($this->getInput('pageEditParentPageId')) : array_keys($this->getHierarchy());
|
||||
$position = $this->getInput('pageEditPosition', helper::FILTER_INT);
|
||||
$extraPosition = $this->getinput('pageEditExtraPosition', helper::FILTER_BOOLEAN);
|
||||
foreach ($hierarchy as $hierarchyPageId) {
|
||||
|
||||
// Ne traite que les pages du menu sélectionné
|
||||
if ($this->getData(['page', $hierarchyPageId, 'extraPosition']) === $extraPosition) {
|
||||
// Ignore la page en cours de modification
|
||||
if ($hierarchyPageId === $this->getUrl(2)) {
|
||||
continue;
|
||||
}
|
||||
// Incrémente de +1 pour laisser la place à la position de la page en cours de modification
|
||||
if ($lastPosition === $position) {
|
||||
$lastPosition++;
|
||||
}
|
||||
// Change la position
|
||||
$this->setData(['page', $hierarchyPageId, 'position', $lastPosition]);
|
||||
// Incrémente pour la prochaine position
|
||||
$lastPosition++;
|
||||
}
|
||||
}
|
||||
if ($this->getinput('pageEditBlock') !== 'bar') {
|
||||
$barLeft = $this->getinput('pageEditBarLeft');
|
||||
$barRight = $this->getinput('pageEditBarRight');
|
||||
$hideTitle = $this->getInput('pageEditHideTitle', helper::FILTER_BOOLEAN);
|
||||
} else {
|
||||
// Une barre ne peut pas avoir de barres
|
||||
$barLeft = "";
|
||||
$barRight = "";
|
||||
// Une barre est masquée
|
||||
$position = 0;
|
||||
$hideTitle = true;
|
||||
}
|
||||
// Une page parent devient orpheline, les pages enfants le devienne pour éviter une incohérence
|
||||
if (
|
||||
$position === 0 &&
|
||||
$position !== $this->getData(['page', $this->getUrl(2), 'position']) &&
|
||||
$this->getinput('pageEditBlock') !== 'bar'
|
||||
) {
|
||||
foreach ($this->getHierarchy($pageId) as $parentId => $childId) {
|
||||
if ($this->getData(['page', $childId, 'parentPageId']) === $pageId) {
|
||||
$this->setData(['page', $childId, 'position', 0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// La page est une barre latérale qui a été renommée : changer le nom de la barre dans les pages qui l'utilisent
|
||||
if ($this->getinput('pageEditBlock') === 'bar') {
|
||||
foreach ($this->getHierarchy() as $eachPageId => $parentId) {
|
||||
if ($this->getData(['page', $eachPageId, 'barRight']) === $this->getUrl(2)) {
|
||||
$this->setData(['page', $eachPageId, 'barRight', $pageId]);
|
||||
}
|
||||
if ($this->getData(['page', $eachPageId, 'barLeft']) === $this->getUrl(2)) {
|
||||
$this->setData(['page', $eachPageId, 'barLeft', $pageId]);
|
||||
}
|
||||
foreach ($parentId as $childId) {
|
||||
if ($this->getData(['page', $childId, 'barRight']) === $this->getUrl(2)) {
|
||||
$this->setData(['page', $childId, 'barRight', $pageId]);
|
||||
}
|
||||
if ($this->getData(['page', $childId, 'barLeft']) === $this->getUrl(2)) {
|
||||
$this->setData(['page', $childId, 'barLeft', $pageId]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Détermine le groupe selon que la page est une barre ou une page standard
|
||||
$group = $this->getinput('pageEditBlock') !== 'bar' ? $this->getInput('pageEditGroup', helper::FILTER_INT) : 0;
|
||||
|
||||
//Détermine le profil d'utilisateur en fonction du groupe sinon le groupe vaut 0
|
||||
$profil = 0;
|
||||
if (
|
||||
$this->getinput('pageEditBlock') !== 'bar' ||
|
||||
$group === 1 ||
|
||||
$group === 2
|
||||
) {
|
||||
$profil = $this->getInput('pageEditProfil' . $group, helper::FILTER_INT);
|
||||
}
|
||||
|
||||
// Modifie la page ou en crée une nouvelle si l'id a changé
|
||||
$this->setData([
|
||||
'page',
|
||||
$pageId,
|
||||
[
|
||||
'typeMenu' => $this->getinput('pageTypeMenu'),
|
||||
'iconUrl' => $this->getinput('pageIconUrl'),
|
||||
'disable' => $this->getinput('pageEditDisable', helper::FILTER_BOOLEAN),
|
||||
'content' => $pageId . '.html',
|
||||
'hideTitle' => $hideTitle,
|
||||
'breadCrumb' => $this->getInput('pageEditbreadCrumb', helper::FILTER_BOOLEAN),
|
||||
'metaDescription' => $this->getInput('pageEditMetaDescription', helper::FILTER_STRING_LONG),
|
||||
'metaTitle' => $this->getInput('pageEditMetaTitle'),
|
||||
'moduleId' => $this->getInput('pageEditModuleId'),
|
||||
'modulePosition' => $this->getInput('pageModulePosition'),
|
||||
'parentPageId' => $this->getInput('pageEditParentPageId'),
|
||||
'position' => $position,
|
||||
'group' => $group,
|
||||
'profil' => $profil,
|
||||
'targetBlank' => $this->getInput('pageEditTargetBlank', helper::FILTER_BOOLEAN),
|
||||
'title' => $this->getInput('pageEditTitle', helper::FILTER_STRING_SHORT),
|
||||
'shortTitle' => $this->getInput('pageEditShortTitle', helper::FILTER_STRING_SHORT, true),
|
||||
'block' => $this->getinput('pageEditBlock'),
|
||||
'barLeft' => $barLeft,
|
||||
'barRight' => $barRight,
|
||||
'navLeft' => $this->getInput('pageEditNavLeft'),
|
||||
'navRight' => $this->getInput('pageEditNavRight'),
|
||||
'navTemplate' => $this->getInput('pageEditNavTemplate'),
|
||||
'displayMenu' => $this->getinput('pageEditDisplayMenu'),
|
||||
'hideMenuSide' => $this->getinput('pageEditHideMenuSide', helper::FILTER_BOOLEAN),
|
||||
'hideMenuHead' => $this->getinput('pageEditHideMenuHead', helper::FILTER_BOOLEAN),
|
||||
'hideMenuChildren' => $this->getinput('pageEditHideMenuChildren', helper::FILTER_BOOLEAN),
|
||||
'extraPosition' => $this->getinput('pageEditExtraPosition', helper::FILTER_BOOLEAN),
|
||||
'css' => $this->getData(['page', $this->getUrl(2), 'css']) == null ? '' : $this->getData(['page', $this->getUrl(2), 'css']),
|
||||
'js' => $this->getData(['page', $this->getUrl(2), 'js']) == null ? '' : $this->getData(['page', $this->getUrl(2), 'js']),
|
||||
]
|
||||
]);
|
||||
|
||||
// Creation du contenu de la page
|
||||
if (!is_dir(self::DATA_DIR . self::$i18nContent . '/content')) {
|
||||
mkdir(self::DATA_DIR . self::$i18nContent . '/content', 0755);
|
||||
}
|
||||
$content = empty($this->getInput('pageEditContent', null)) ? '<p></p>' : str_replace('<p></p>', '<p> </p>', $this->getInput('pageEditContent', null));
|
||||
$this->setPage($pageId, $content, self::$i18nContent);
|
||||
|
||||
// Met à jour le sitemap
|
||||
$this->updateSitemap();
|
||||
|
||||
// Redirection vers la configuration
|
||||
if (
|
||||
$this->getInput('pageEditModuleRedirect', helper::FILTER_BOOLEAN)
|
||||
) {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'redirect' => helper::baseUrl() . $pageId . '/config',
|
||||
'state' => true
|
||||
]);
|
||||
// Redirection vers la page
|
||||
} else {
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'redirect' => helper::baseUrl() . $pageId,
|
||||
'notification' => helper::translate('Modifications enregistrées'),
|
||||
'state' => true
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Construction du formulaire
|
||||
|
||||
// Création du sélecteur de modules
|
||||
self::$moduleIds = [];
|
||||
foreach (helper::getModules() as $key => $values) {
|
||||
self::$moduleIds[$key] = $values['realName'] . ' (' . $key . ')';
|
||||
}
|
||||
self::$moduleIds = array_merge(['' => 'Aucun'], self::$moduleIds);
|
||||
|
||||
// Pages sans parent
|
||||
foreach ($this->getHierarchy() as $parentPageId => $childrenPageIds) {
|
||||
if ($parentPageId !== $this->getUrl(2)) {
|
||||
self::$pagesNoParentId[$parentPageId] = $this->getData(['page', $parentPageId, 'title']);
|
||||
}
|
||||
}
|
||||
// Pages barre latérales
|
||||
foreach ($this->getHierarchy(null, false, true) as $parentPageId => $childrenPageIds) {
|
||||
if (
|
||||
$parentPageId !== $this->getUrl(2) &&
|
||||
$this->getData(['page', $parentPageId, 'block']) === 'bar'
|
||||
) {
|
||||
self::$pagesBarId[$parentPageId] = $this->getData(['page', $parentPageId, 'title']);
|
||||
}
|
||||
}
|
||||
// Profils installés
|
||||
// Profils disponibles
|
||||
foreach ($this->getData(['profil']) as $profilId => $profilData) {
|
||||
if ($profilId < self::GROUP_MEMBER) {
|
||||
continue;
|
||||
}
|
||||
if ($profilId === self::GROUP_ADMIN) {
|
||||
self::$userProfils[$profilId][self::GROUP_ADMIN] = $profilData['name'];
|
||||
continue;
|
||||
}
|
||||
foreach ($profilData as $key => $value) {
|
||||
self::$userProfils[$profilId][$key] = $profilData[$key]['name'];
|
||||
}
|
||||
}
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'title' => $this->getData(['page', $this->getUrl(2), 'title']),
|
||||
'vendor' => [
|
||||
'tinymce'
|
||||
],
|
||||
'view' => 'edit'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Éditeur de feuille de style
|
||||
*/
|
||||
public function cssEditor()
|
||||
{
|
||||
// Soumission du formulaire
|
||||
if (
|
||||
$this->getUser('permission', __CLASS__, __FUNCTION__) === true &&
|
||||
$this->isPost()
|
||||
) {
|
||||
$css = $this->getInput('pageCssEditorContent', helper::FILTER_STRING_LONG) === null ? '' : $this->getInput('pageCssEditorContent', helper::FILTER_STRING_LONG);
|
||||
// Enregistre le CSS
|
||||
$this->setData([
|
||||
'page', $this->getUrl(2),
|
||||
'css',
|
||||
$css
|
||||
]);
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'notification' => helper::translate('Modifications enregistrées'),
|
||||
'redirect' => helper::baseUrl() . 'page/edit/' . $this->getUrl(2),
|
||||
'state' => true
|
||||
]);
|
||||
}
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'title' => helper::translate('Éditeur CSS'),
|
||||
'vendor' => [
|
||||
'codemirror'
|
||||
],
|
||||
'view' => 'cssEditor'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Éditeur de feuille de style
|
||||
*/
|
||||
public function jsEditor()
|
||||
{
|
||||
// Soumission du formulaire
|
||||
if (
|
||||
$this->getUser('permission', __CLASS__, __FUNCTION__) === true &&
|
||||
$this->isPost()
|
||||
) {
|
||||
$js = $this->getInput('pageJsEditorContent', helper::FILTER_STRING_LONG) === null ? '' : $this->getInput('pageJsEditorContent', helper::FILTER_STRING_LONG);
|
||||
// Enregistre le JS
|
||||
$this->setData([
|
||||
'page', $this->getUrl(2),
|
||||
'js',
|
||||
$js
|
||||
]);
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'notification' => helper::translate('Modifications enregistrées'),
|
||||
'redirect' => helper::baseUrl() . 'page/edit/' . $this->getUrl(2),
|
||||
'state' => true
|
||||
]);
|
||||
}
|
||||
// Valeurs en sortie
|
||||
$this->addOutput([
|
||||
'title' => helper::translate('Éditeur Js'),
|
||||
'vendor' => [
|
||||
'codemirror'
|
||||
],
|
||||
'view' => 'jsEditor'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne les informations sur les pages en omettant les clés CSS et JS qui occasionnent des bugs d'affichage dans l'éditeur de page
|
||||
* @return array tableau associatif des pages dans le menu
|
||||
*/
|
||||
public function getPageInfo()
|
||||
{
|
||||
$p = $this->getData(['page']);
|
||||
$d = array_map(function ($d) {
|
||||
unset($d["css"], $d["js"]);
|
||||
return $d;
|
||||
}, $p);
|
||||
return json_encode($d);
|
||||
|
||||
}
|
||||
}
|
18
core/module/page/view/cssEditor/cssEditor.css
Normal file
18
core/module/page/view/cssEditor/cssEditor.css
Normal file
@ -0,0 +1,18 @@
|
||||
/**
|
||||
* 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
|
||||
* @author Frédéric Tempez <frederic.tempez@outlook.com>
|
||||
* @copyright Copyright (C) 2018-2023, Frédéric Tempez
|
||||
* @license CC Attribution-NonCommercial-NoDerivatives 4.0 International
|
||||
* @link http://zwiicms.fr/
|
||||
*/
|
||||
|
||||
|
||||
/** NE PAS EFFACER
|
||||
* admin.css
|
||||
*/
|
22
core/module/page/view/cssEditor/cssEditor.php
Normal file
22
core/module/page/view/cssEditor/cssEditor.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php echo template::formOpen('pageCssEditorForm'); ?>
|
||||
<div class="row">
|
||||
<div class="col1">
|
||||
<?php echo template::button('pageCssEditorBack', [
|
||||
'class' => 'buttonGrey',
|
||||
'href' => helper::baseUrl() . 'page/edit/' . $this->getUrl(2),
|
||||
'value' => template::ico('left')
|
||||
]); ?>
|
||||
</div>
|
||||
<div class="col2 offset9">
|
||||
<?php echo template::submit('pageCssEditorSubmit'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col12">
|
||||
<?php echo template::textarea('pageCssEditorContent', [
|
||||
'value' => is_null($this->getData(['page', $this->getUrl(2), 'css'])) ? '' : $this->getData(['page', $this->getUrl(2), 'css']),
|
||||
'class' => 'editor'
|
||||
]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php echo template::formClose(); ?>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user