964 lines
31 KiB
PHP
964 lines
31 KiB
PHP
<?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-2024, 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,
|
|
'testmail' => 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 = [];
|
|
|
|
/**
|
|
* 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),
|
|
'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),
|
|
'mailAuth' => $this->getInput('connectAuthMail', helper::FILTER_INT),
|
|
]
|
|
]
|
|
]);
|
|
|
|
// Sauvegarde la position des onglets de la vue de l'utilisateur courant
|
|
$this->setData([
|
|
'user',
|
|
$this->getUser('id'),
|
|
'view',
|
|
[
|
|
'config' => $this->getInput('containerSelected'),
|
|
'page' => $this->getData(['user', $this->getUser('id'), 'view', 'page']),
|
|
]
|
|
]);
|
|
|
|
// 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 =
|
|
'# 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';
|
|
$fileContent = str_replace('# URL rewriting', $rewriteData, $fileContent);
|
|
$this->secure_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];
|
|
$this->secure_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('Mise à 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';
|
|
}
|
|
}
|
|
|
|
// 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') {
|
|
$this->secure_file_put_contents(self::DATA_DIR . 'head.inc.html', $this->getInput('configScriptHead', null));
|
|
}
|
|
if ($this->geturl(2) === 'body') {
|
|
$this->secure_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;
|
|
$this->secure_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;
|
|
$this->secure_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'], self::$i18nUI) . ' - ' . helper::dateUTF8('%H:%M', time(), self::$i18nUI);
|
|
$data .= $key . ';' . $item['ip'] . ';' . $item['connectFail'] . PHP_EOL;
|
|
}
|
|
$this->secure_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
|
|
]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fonction pour vérifier la présence du module de réécriture
|
|
* @return bool
|
|
*/
|
|
public function isModRewriteEnabled()
|
|
{
|
|
// Check if Apache and mod_rewrite is loaded
|
|
if (function_exists('apache_get_modules')) {
|
|
$modules = apache_get_modules();
|
|
return in_array('mod_rewrite', $modules);
|
|
} else {
|
|
// Fallback if not using Apache or unable to detect modules
|
|
return getenv('HTTP_MOD_REWRITE') == 'On' || getenv('REDIRECT_STATUS') == '200';
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Envoi un message de test
|
|
* @return void
|
|
*/
|
|
|
|
public function testmail()
|
|
{
|
|
$sent = $this->sendMail(
|
|
$this->getUser('mail'),
|
|
helper::translate('Test de la messagerie du site'),
|
|
'<strong>' . $this->getUser('firstname') . ' ' . $this->getUser('lastname') . '</strong>,<br><br>' .
|
|
'<h4>' . helper::translate('Il semblerait que votre messagerie fonctionne correctement !') . '</h4>',
|
|
null,
|
|
'no-reply@localhost'
|
|
);
|
|
if ($sent !== true) {
|
|
// Désactivation de l'authentification par email
|
|
$this->setData(['config', 'connect', 'mailAuth', 0]);
|
|
// Journalisation
|
|
$this->saveLog($sent);
|
|
}
|
|
// Valeurs en sortie
|
|
$this->addOutput([
|
|
'redirect' => helper::baseUrl() . 'config/' . $this->getUrl(2),
|
|
'state' => $sent === true ? true : false,
|
|
'notification' => $sent === true ? helper::translate('Message de test envoyé avec succès') : helper::translate('Message non envoyé')
|
|
]);
|
|
}
|
|
} |