Merge branch '10500' into extensions

This commit is contained in:
Fred Tempez 2021-03-03 14:19:42 +01:00
commit 8d6bda4629
124 changed files with 1955 additions and 945 deletions

View File

@ -1,12 +1,39 @@
# Changelog
## version 10.5.00
- Modifications :
- Gestion des modules dans l'interface d'administration.
## version 10.4.05
- Mise à jour :
- SiteMapGenerator 4.3.1
- Modifications :
- Bouton de remontée, position plus haute et zindex augmenté.
- Corrections :
- Marges du pied de page fixe placé en dehors du site.
- TinyMCE couleurs du sélecteur de paragraphe et de headers lorsque le fond est transparent.
- Thème administration, couleur du lien dans un bloc H4.
## version 10.4.04
- Correction :
- Module Blog : balise non fermée dans les commentaires.
- Modifications :
-Constantes de modules.
## version 10.4.03
- Corrections :
- En-tête html : absence de la langue.
- Suppression de la balise sémantique <article>.
- Génération image Opengraph, mauvaise redirection.
- Nouvelle structure de données articles de blog dans le sitemap.
## version 10.4.02
- Corrections :
- Thème : aperçu du site amélioré.
- Thème : rétablissement du contrôle de l'import d'une version ancienne d'un thème.
- Éditeur de texte : couleur de fond parasite quand une image en arrière-plan est sélectionnée.
## version 10.4.01
## version 10.4.01
Corrections :
- Module form, erreur de syntaxe.
- Chargement d'un thème, désactivation du contrôle des clés.
@ -65,7 +92,7 @@ Correction :
Corrections :
- Conflit page inactive et droit d'un membre.
- Module de recherche, correction dans les pages enfants.
- Module formulaire, perte des données en cas d'édition du fomulaire ou des champs.
- Module formulaire, perte des données en cas d'édition du formulaire ou des champs.
Modification :
- TinyMCE nettoyage init.js d'options non supportées.
@ -73,7 +100,7 @@ Modification :
Corrections :
- Configuration : persistance de l'ouverture des blocs.
- Réinitialisation du mot de passe :
- Remise à zéro du timer après renouvèlement du mot de passe.
- Remise à zéro du timer après renouvellement du mot de passe.
- Affichage de le fenêtre "Nouveau mot de passe" allégée.
- Redirection sur la page d'accueil.
- Modules news et blog : transparence icône RSS.

View File

@ -1,5 +1,5 @@
# ZwiiCMS 10.4.02
# ZwiiCMS 10.4.05
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.

View File

@ -1,540 +0,0 @@
<?php
namespace Icamys\SitemapGenerator;
class SitemapGenerator
{
const MAX_FILE_SIZE = 10485760;
const MAX_URLS_PER_SITEMAP = 50000;
const URL_PARAM_LOC = 0;
const URL_PARAM_LASTMOD = 1;
const URL_PARAM_CHANGEFREQ = 2;
const URL_PARAM_PRIORITY = 3;
/**
* Name of sitemap file
* @var string
* @access public
*/
public $sitemapFileName = "sitemap.xml";
/**
* Name of sitemap index file
* @var string
* @access public
*/
public $sitemapIndexFileName = "sitemap-index.xml";
/**
* Robots file name
* @var string
* @access public
*/
public $robotsFileName = "robots.txt";
/**
* Quantity of URLs per single sitemap file.
* According to specification max value is 50.000.
* If Your links are very long, sitemap file can be bigger than 10MB,
* in this case use smaller value.
* @var int
* @access public
*/
public $maxURLsPerSitemap = self::MAX_URLS_PER_SITEMAP;
/**
* Quantity of sitemaps per index file.
* According to specification max value is 50.000
* If Your index file is very long, index file can be bigger than 10MB,
* in this case use smaller value.
* @see http://www.sitemaps.org/protocol.html
* @var int
* @access public
*/
public $maxSitemaps = 50000;
/**
* 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
*/
public $createGZipFile = 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 = "1.0.0";
/**
* Search engines URLs
* @var array of strings
* @access private
*/
private $searchEngines = array(
array(
"http://search.yahooapis.com/SiteExplorerService/V1/updateNotification?appid=USERID&url=",
"http://search.yahooapis.com/SiteExplorerService/V1/ping?sitemap="
),
"http://www.google.com/webmasters/tools/ping?sitemap=",
"http://submissions.ask.com/ping?sitemap=",
"http://www.bing.com/webmaster/ping.aspx?siteMap="
);
/**
* Array with urls
* @var \SplFixedArray of strings
* @access private
*/
private $urls;
/**
* Array with sitemap
* @var array of strings
* @access private
*/
private $sitemaps;
/**
* Array with sitemap index
* @var array of strings
* @access private
*/
private $sitemapIndex;
/**
* Current sitemap full URL
* @var string
* @access private
*/
private $sitemapFullURL;
/**
* @var \DOMDocument
*/
private $document;
/**
* Constructor.
* @param string $baseURL You site URL, with / at the end.
* @param string|null $basePath Relative path where sitemap and robots should be stored.
*/
public function __construct($baseURL, $basePath = "")
{
$this->urls = new \SplFixedArray();
$this->baseURL = $baseURL;
$this->basePath = $basePath;
$this->document = new \DOMDocument("1.0");
$this->document->preserveWhiteSpace = false;
$this->document->formatOutput = true;
}
/**
* Use this to add many URL at one time.
* Each inside array can have 1 to 4 fields.
* @param $urlsArray
* @throws \InvalidArgumentException
*/
public function addUrls($urlsArray)
{
if (!is_array($urlsArray)) {
throw new \InvalidArgumentException("Array as argument should be given.");
}
foreach ($urlsArray as $url) {
$this->addUrl(
isset($url[0]) ? $url[0] : null,
isset($url[1]) ? $url[1] : null,
isset($url[2]) ? $url[2] : null,
isset($url[3]) ? $url[3] : null
);
}
}
/**
* Use this to add single URL to sitemap.
* @param string $url URL
* @param \DateTime $lastModified When it was modified, use ISO 8601
* @param string $changeFrequency How often search engines should revisit this URL
* @param string $priority Priority of URL on You site
* @see http://en.wikipedia.org/wiki/ISO_8601
* @see http://php.net/manual/en/function.date.php
* @throws \InvalidArgumentException
*/
public function addUrl($url, \DateTime $lastModified = null, $changeFrequency = null, $priority = null)
{
if ($url == null) {
throw new \InvalidArgumentException("URL is mandatory. At least one argument should be given.");
}
$urlLength = extension_loaded('mbstring') ? mb_strlen($url) : strlen($url);
if ($urlLength > 2048) {
throw new \InvalidArgumentException(
"URL length can't be bigger than 2048 characters.
Note, that precise url length check is guaranteed only using mb_string extension.
Make sure Your server allow to use mbstring extension."
);
}
$tmp = new \SplFixedArray(1);
$tmp[self::URL_PARAM_LOC] = $url;
if (isset($lastModified)) {
$tmp->setSize(2);
$tmp[self::URL_PARAM_LASTMOD] = $lastModified->format(\DateTime::ATOM);
}
if (isset($changeFrequency)) {
$tmp->setSize(3);
$tmp[self::URL_PARAM_CHANGEFREQ] = $changeFrequency;
}
if (isset($priority)) {
$tmp->setSize(4);
$tmp[self::URL_PARAM_PRIORITY] = $priority;
}
if ($this->urls->getSize() === 0) {
$this->urls->setSize(1);
} else {
if ($this->urls->getSize() === $this->urls->key()) {
$this->urls->setSize($this->urls->getSize() * 2);
}
}
$this->urls[$this->urls->key()] = $tmp;
$this->urls->next();
}
/**
* @throws \BadMethodCallException
* @throws \InvalidArgumentException
* @throws \LengthException
*/
public function createSitemap()
{
if (!isset($this->urls)) {
throw new \BadMethodCallException("To create sitemap, call addUrl or addUrls function first.");
}
if ($this->maxURLsPerSitemap > self::MAX_URLS_PER_SITEMAP) {
throw new \InvalidArgumentException(
"More than " . self::MAX_URLS_PER_SITEMAP . " URLs per single sitemap is not allowed."
);
}
$generatorInfo = '<!-- generated-on="' . date('c') . '" -->';
$sitemapHeader = '<?xml version="1.0" encoding="UTF-8"?>' . $generatorInfo . '
<urlset
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' . "\r\n" . '
xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9' . "\n" . '
http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"' . "\n" . '
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
</urlset>';
$sitemapIndexHeader = '<?xml version="1.0" encoding="UTF-8"?>' . $generatorInfo . '
<sitemapindex
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9
http://www.sitemaps.org/schemas/sitemap/0.9/siteindex.xsd"
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
</sitemapindex>';
$nullUrls = 0;
foreach ($this->urls as $url) {
if (is_null($url)) {
$nullUrls++;
}
}
$nonEmptyUrls = $this->urls->getSize() - $nullUrls;
$chunks = ceil($nonEmptyUrls / $this->maxURLsPerSitemap);
for ($chunkCounter = 0; $chunkCounter < $chunks; $chunkCounter++) {
$xml = new \SimpleXMLElement($sitemapHeader);
for ($urlCounter = $chunkCounter * $this->maxURLsPerSitemap;
$urlCounter < ($chunkCounter + 1) * $this->maxURLsPerSitemap && $urlCounter < $nonEmptyUrls;
$urlCounter++
) {
$row = $xml->addChild('url');
$row->addChild(
'loc',
htmlspecialchars($this->baseURL . $this->urls[$urlCounter][self::URL_PARAM_LOC], ENT_QUOTES, 'UTF-8')
);
if ($this->urls[$urlCounter]->getSize() > 1) {
$row->addChild('lastmod', $this->urls[$urlCounter][self::URL_PARAM_LASTMOD]);
}
if ($this->urls[$urlCounter]->getSize() > 2) {
$row->addChild('changefreq', $this->urls[$urlCounter][self::URL_PARAM_CHANGEFREQ]);
}
if ($this->urls[$urlCounter]->getSize() > 3) {
$row->addChild('priority', $this->urls[$urlCounter][self::URL_PARAM_PRIORITY]);
}
}
if (strlen($xml->asXML()) > self::MAX_FILE_SIZE) {
throw new \LengthException(
"Sitemap size equals to " . strlen($xml->asXML())
. " bytes is more than 10MB (" . self::MAX_FILE_SIZE . " bytes),
please decrease maxURLsPerSitemap variable."
);
}
$this->sitemaps[] = $xml->asXML();
}
if (count($this->sitemaps) > $this->maxSitemaps) {
throw new \LengthException(
"Sitemap index can contain {$this->maxSitemaps} sitemaps.
Perhaps You trying to submit too many maps."
);
}
if (count($this->sitemaps) > 1) {
for ($i = 0; $i < count($this->sitemaps); $i++) {
$this->sitemaps[$i] = array(
str_replace(".xml", ($i + 1) . ".xml", $this->sitemapFileName),
$this->sitemaps[$i]
);
}
$xml = new \SimpleXMLElement($sitemapIndexHeader);
foreach ($this->sitemaps as $sitemap) {
$row = $xml->addChild('sitemap');
$row->addChild('loc', $this->baseURL . "/" . $this->getSitemapFileName(htmlentities($sitemap[0])));
$row->addChild('lastmod', date('c'));
}
$this->sitemapFullURL = $this->baseURL . "/" . $this->sitemapIndexFileName;
$this->sitemapIndex = array(
$this->sitemapIndexFileName,
$xml->asXML()
);
} else {
$this->sitemapFullURL = $this->baseURL . "/" . $this->getSitemapFileName();
$this->sitemaps[0] = array(
$this->sitemapFileName,
$this->sitemaps[0]
);
}
}
/**
* Returns created sitemaps as array of strings.
* Use it You want to work with sitemap without saving it as files.
* @return array of strings
* @access public
*/
public function toArray()
{
if (isset($this->sitemapIndex)) {
return array_merge(array($this->sitemapIndex), $this->sitemaps);
} else {
return $this->sitemaps;
}
}
/**
* Will write sitemaps as files.
* @access public
* @throws \BadMethodCallException
*/
public function writeSitemap()
{
if (!isset($this->sitemaps)) {
throw new \BadMethodCallException("To write sitemap, call createSitemap function first.");
}
if (isset($this->sitemapIndex)) {
$this->document->loadXML($this->sitemapIndex[1]);
$this->writeFile($this->document->saveXML(), $this->basePath, $this->sitemapIndex[0], true);
foreach ($this->sitemaps as $sitemap) {
$this->writeFile($sitemap[1], $this->basePath, $sitemap[0]);
}
} else {
$this->document->loadXML($this->sitemaps[0][1]);
$this->writeFile($this->document->saveXML(), $this->basePath, $this->sitemaps[0][0], true);
$this->writeFile($this->sitemaps[0][1], $this->basePath, $this->sitemaps[0][0]);
}
}
private function getSitemapFileName($name = null)
{
if (!$name) {
$name = $this->sitemapFileName;
}
if ($this->createGZipFile) {
$name .= ".gz";
}
return $name;
}
/**
* Save file.
* @param string $content
* @param string $filePath
* @param string $fileName
* @param bool $noGzip
* @return bool
* @access private
*/
private function writeFile($content, $filePath, $fileName, $noGzip = false)
{
if (!$noGzip && $this->createGZipFile) {
return $this->writeGZipFile($content, $filePath, $fileName);
}
$file = fopen($filePath . $fileName, 'w');
fwrite($file, $content);
return fclose($file);
}
/**
* Save GZipped file.
* @param string $content
* @param string $filePath
* @param string $fileName
* @return bool
* @access private
*/
private function writeGZipFile($content, $filePath, $fileName)
{
$fileName .= '.gz';
$file = gzopen($filePath . $fileName, 'w');
gzwrite($file, $content);
return gzclose($file);
}
/**
* If robots.txt file exist, will update information about newly created sitemaps.
* If there is no robots.txt will, create one and put into it information about sitemaps.
* @access public
* @throws \BadMethodCallException
*/
public function updateRobots()
{
if (!isset($this->sitemaps)) {
throw new \BadMethodCallException("To update robots.txt, call createSitemap function first.");
}
$sampleRobotsFile = "User-agent: *\nAllow: /";
if (file_exists($this->basePath . $this->robotsFileName)) {
$robotsFile = explode("\n", file_get_contents($this->basePath . $this->robotsFileName));
$robotsFileContent = "";
foreach ($robotsFile as $key => $value) {
if (substr($value, 0, 8) == 'Sitemap:') {
unset($robotsFile[$key]);
} else {
$robotsFileContent .= $value . "\n";
}
}
$robotsFileContent .= "Sitemap: $this->sitemapFullURL";
if (!isset($this->sitemapIndex)) {
$robotsFileContent .= "\nSitemap: " . $this->getSitemapFileName($this->sitemapFullURL);
}
file_put_contents($this->basePath . $this->robotsFileName, $robotsFileContent);
} else {
$sampleRobotsFile = $sampleRobotsFile . "\n\nSitemap: " . $this->sitemapFullURL;
if (!isset($this->sitemapIndex)) {
$sampleRobotsFile .= "\nSitemap: " . $this->getSitemapFileName($this->sitemapFullURL);
}
file_put_contents($this->basePath . $this->robotsFileName, $sampleRobotsFile);
}
}
/**
* 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)
{
if (!isset($this->sitemaps)) {
throw new \BadMethodCallException("To submit sitemap, call createSitemap function first.");
}
if (!extension_loaded('curl')) {
throw new \BadMethodCallException("cURL library is needed to do submission.");
}
$searchEngines = $this->searchEngines;
$searchEngines[0] = isset($yahooAppId) ?
str_replace("USERID", $yahooAppId, $searchEngines[0][0]) :
$searchEngines[0][1];
$result = array();
for ($i = 0; $i < count($searchEngines); $i++) {
$submitSite = curl_init($searchEngines[$i] . htmlspecialchars($this->sitemapFullURL, ENT_QUOTES, 'UTF-8'));
curl_setopt($submitSite, CURLOPT_RETURNTRANSFER, true);
$responseContent = curl_exec($submitSite);
$response = curl_getinfo($submitSite);
$submitSiteShort = array_reverse(explode(".", parse_url($searchEngines[$i], PHP_URL_HOST)));
$result[] = array(
"site" => $submitSiteShort[1] . "." . $submitSiteShort[0],
"fullsite" => $searchEngines[$i] . htmlspecialchars($this->sitemapFullURL, ENT_QUOTES, 'UTF-8'),
"http_code" => $response['http_code'],
"message" => str_replace("\n", " ", strip_tags($responseContent))
);
}
return $result;
}
/**
* Returns array of URLs
*
* Converts internal SplFixedArray to array
* @return array
*/
public function getUrls()
{
$urls = $this->urls->toArray();
/**
* @var int $key
* @var \SplFixedArray $urlSplArr
*/
foreach ($urls as $key => $urlSplArr) {
if (!is_null($urlSplArr)) {
$urlArr = $urlSplArr->toArray();
$url = [];
foreach ($urlArr as $paramIndex => $paramValue) {
switch ($paramIndex) {
case static::URL_PARAM_LOC:
$url['loc'] = $paramValue;
break;
case static::URL_PARAM_CHANGEFREQ:
$url['changefreq'] = $paramValue;
break;
case static::URL_PARAM_LASTMOD:
$url['lastmod'] = $paramValue;
break;
case static::URL_PARAM_PRIORITY:
$url['priority'] = $paramValue;
break;
default:
break;
}
}
$urls[$key] = $url;
}
}
return $urls;
}
public function countUrls()
{
return $this->urls->getSize();
}
}

View File

@ -4,7 +4,9 @@ class autoload {
public static function autoloader () {
require_once 'core/class/helper.class.php';
require_once 'core/class/template.class.php';
require_once 'core/class/SitemapGenerator.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';

View File

@ -1,4 +1,5 @@
<?php
class helper {
/** Statut de la réécriture d'URL (pour éviter de lire le contenu du fichier .htaccess à chaque self::baseUrl()) */
@ -19,7 +20,7 @@ class helper {
/**
/**
* Récupérer l'adresse IP sans tenit compte du proxy
* @return string IP adress
* Cette focntion est utilisé par user
@ -127,6 +128,75 @@ class helper {
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)
&& $class_constants['DATADIRECTORY'] !== []
&& is_array($class_constants['DATADIRECTORY'])
) {
$dataDirectory = $value::DATADIRECTORY;
} else {
$dataDirectory = [];
}
// Affection
$modules [$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
@ -504,4 +574,4 @@ class helper {
return openssl_decrypt($encrypted_data, 'aes-256-cbc', $key, 0, $iv);
}
}
}

View 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);
}
}

View 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);
}
}

View 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.2";
/**
* 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;
}
}

View File

@ -1,11 +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 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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -1,15 +1,15 @@
<?php
/**
* This file is part of Zwii. *
* This file is part of Zwii.
* For full copyright and license information, please see the LICENSE
* file that was distributed with this source code.
*
* @author Rémi Jean <remi.jean@outlook.com>
* @copyright Copyright (C) 2008-2018, Rémi Jean
* @license GNU General Public License, version 3
* @author Frédéric Tempez <frederic.tempez@outlook.com>
* @copyright Copyright (C) 2018-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/
@ -44,7 +44,7 @@ class common {
const ACCESS_TIMER = 1800;
// Numéro de version
const ZWII_VERSION = '10.4.02';
const ZWII_VERSION = '10.5.00';
const ZWII_UPDATE_CHANNEL = "v10";
public static $actions = [];
@ -56,7 +56,8 @@ class common {
'sitemap',
'theme',
'user',
'translate'
'translate',
'addon'
];
public static $accessList = [
'user',
@ -603,7 +604,7 @@ class common {
$this->setData(['theme',$tempData['theme']]);
// Import des users sauvegardés si option active
if ($keepUsers === false
if ($keepUsers === false
AND $tempData['user'] !== NULL) {
$this->setData(['user',$tempData['user']]);
}
@ -740,22 +741,26 @@ class common {
$timezone = $this->getData(['config','timezone']);
$sitemap = new \Icamys\SitemapGenerator\SitemapGenerator(helper::baseurl());
$outputDir = getcwd();
$sitemap = new \Icamys\SitemapGenerator\SitemapGenerator(helper::baseurl(false),$outputDir);
// will create also compressed (gzipped) sitemap
$sitemap->createGZipFile = true;
$sitemap->enableCompression();
// determine how many urls should be put into one file
// according to standard protocol 50000 is maximum value (see http://www.sitemaps.org/protocol.html)
$sitemap->maxURLsPerSitemap = 50000;
$sitemap->setMaxUrlsPerSitemap(50000);
// sitemap file name
$sitemap->sitemapFileName = "sitemap.xml";
$sitemap->setSitemapFileName("sitemap.xml");
// Set the sitemap index file name
$sitemap->setSitemapIndexFileName("sitemap-index.xml");
$datetime = new DateTime(date('c'));
$datetime->format(DateTime::ATOM); // Updated ISO8601
// sitemap index file name
$sitemap->sitemapIndexFileName = "sitemap-index.xml";
foreach($this->getHierarchy(null, null, null) as $parentPageId => $childrenPageIds) {
// Exclure les barres et les pages non publiques et les pages masquées
if ($this->getData(['page',$parentPageId,'group']) !== 0 ||
@ -766,6 +771,16 @@ class common {
if ($this->getData(['page', $parentPageId, 'disable']) !== true ) {
$sitemap->addUrl ($parentPageId,$datetime);
}
// Articles du blog
if ($this->getData(['page', $parentPageId, 'moduleId']) === 'blog' &&
!empty($this->getData(['module',$parentPageId])) ) {
foreach($this->getData(['module',$parentPageId,'posts']) as $articleId => $article) {
if($this->getData(['module',$parentPageId,'posts',$articleId,'state']) === true) {
$date = $this->getData(['module',$parentPageId,'posts',$articleId,'publishedOn']);
$sitemap->addUrl( $parentPageId . '/' . $articleId , new DateTime("@{$date}",new DateTimeZone($timezone)));
}
}
}
// Sous-pages
foreach($childrenPageIds as $childKey) {
if ($this->getData(['page',$childKey,'group']) !== 0 || $this->getData(['page', $childKey, 'disable']) === true) {
@ -776,31 +791,28 @@ class common {
// La sous-page est un blog
if ($this->getData(['page', $childKey, 'moduleId']) === 'blog' &&
!empty($this->getData(['module',$childKey])) ) {
foreach($this->getData(['module',$childKey]) as $articleId => $article) {
if($this->getData(['module',$childKey,$articleId,'state']) === true) {
$date = $this->getData(['module',$childKey,$articleId,'publishedOn']);
foreach($this->getData(['module',$childKey,'posts']) as $articleId => $article) {
if($this->getData(['module',$childKey,'posts',$articleId,'state']) === true) {
$date = $this->getData(['module',$childKey,'posts',$articleId,'publishedOn']);
$sitemap->addUrl( $childKey . '/' . $articleId , new DateTime("@{$date}",new DateTimeZone($timezone)));
}
}
}
}
// Articles du blog
if ($this->getData(['page', $parentPageId, 'moduleId']) === 'blog' &&
!empty($this->getData(['module',$parentPageId])) ) {
foreach($this->getData(['module',$parentPageId]) as $articleId => $article) {
if($this->getData(['module',$parentPageId,$articleId,'state']) === true) {
$date = $this->getData(['module',$parentPageId,$articleId,'publishedOn']);
$sitemap->addUrl( $parentPageId . '/' . $articleId , new DateTime("@{$date}",new DateTimeZone($timezone)));
}
}
}
}
// generating internally a sitemap
$sitemap->createSitemap();
// Flush all stored urls from memory to the disk and close all necessary tags.
$sitemap->flush();
// writing early generated sitemap to file
$sitemap->writeSitemap();
// Move flushed files to their final location. Compress if the option is enabled.
$sitemap->finalize();
// Update robots.txt file in output directory or create a new one
$sitemap->updateRobots();
// Submit your sitemaps to Google, Yahoo, Bing and Ask.com
$sitemap->submitSitemap();
return(file_exists('sitemap.xml'));
@ -1008,11 +1020,43 @@ class common {
* @param string URL du dossier à supprimer
*/
public function removeDir ( $path ) {
foreach ( new DirectoryIterator($path) as $item ):
if ( $item->isFile() ) unlink($item->getRealPath());
foreach ( new DirectoryIterator($path) as $item ) {
if ( $item->isFile() ) @unlink($item->getRealPath());
if ( !$item->isDot() && $item->isDir() ) $this->removeDir($item->getRealPath());
endforeach;
rmdir($path);
}
return ( rmdir($path) );
}
/**
* Génère une archive d'un dossier et des sous-dossiers
* @param string fileName path et nom de l'archive
* @param string folder path à zipper
* @param array filter dossiers à exclure
*/
public function makeZip ($fileName, $folder, $filter ) {
$zip = new ZipArchive();
$zip->open($fileName, ZipArchive::CREATE | ZipArchive::OVERWRITE);
//$directory = 'site/';
$files = new RecursiveIteratorIterator(
new RecursiveCallbackFilterIterator(
new RecursiveDirectoryIterator(
$folder,
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($folder)) + 1);
$zip->addFile($filePath, $relativePath);
}
}
$zip->close();
}
/**
@ -1562,10 +1606,15 @@ class common {
$this->setData(['core', 'dataVersion', 10400]);
/**
* mettre à jour defaultdata
*/
}
// Version 10.4.05
if ($this->getData(['core', 'dataVersion']) < 10405) {
// Mise à jour forcée des thèmes
unlink (self::DATA_DIR . 'admin.css');
unlink (self::DATA_DIR . 'theme.css');
$this->setData(['core', 'dataVersion', 10405]);
}
}
}
@ -1652,14 +1701,14 @@ class core extends common {
$css .= 'body{font-family:"' . str_replace('+', ' ', $this->getData(['theme', 'text', 'font'])) . '",sans-serif}';
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']) . '}';
$css .= 'html, .mce-menu.mce-in.mce-animate {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)}';
$css .= 'body, .mce-menu.mce-in.mce-animate{background-color: rgba(0,0,0,0)}';
} else {
// Pas d'image couleur du body
$css .= 'html{background-color:' . $colors['normal'] . ';}';
$css .= 'html, .mce-menu.mce-in.mce-animate{background-color:' . $colors['normal'] . ';}';
// Même couleur dans le fond de l'éditeur
$css .= 'div.mce-edit-area{background-color:' . $colors['normal'] . ' !important}';
$css .= 'div.mce-edit-area {background-color:' . $colors['normal'] . ' !important}';
}
// Icône BacktoTop
$css .= '#backToTop {background-color:' .$this->getData(['theme', 'body', 'toTopbackgroundColor']). ';color:'.$this->getData(['theme', 'body', 'toTopColor']).';}';
@ -1667,7 +1716,7 @@ class core extends common {
$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:"' . str_replace('+', ' ', $this->getData(['theme', 'text', 'font'])) . '",sans-serif}';
$css .= 'div.mce-edit-area {font-family:"' . str_replace('+', ' ', $this->getData(['theme', 'text', 'font'])) . '",sans-serif}';
// Site dans TinyMCE
$css .= '.editorWysiwyg {background-color:' . $this->getData(['theme', 'site', 'backgroundColor']) . ';}';
//$css .= 'a:hover:not(.inputFile, button){color:' . $colors['darken'] . '}';
@ -1680,8 +1729,23 @@ class core extends common {
//$css .= '.button.buttonGrey,.button.buttonGrey:hover{color:' . $this->getData(['theme', 'text', 'textColor']) . '}';
$css .= '.container{max-width:' . $this->getData(['theme', 'site', 'width']) . '}';
$margin = $this->getData(['theme', 'site', 'margin']) ? '0' : '20px';
$css .= $this->getData(['theme', 'site', 'width']) === '100%' ? '#site.light{margin:5% auto !important;}#site{margin:0 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;}': "#site.light{margin: 5% auto !important;}#site{margin: " . $margin . " 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;}' : '';
// Marge supplémentaire lorsque le pied de page est fixe
if ( $this->getData(['theme', 'footer', 'fixed']) === true &&
$this->getData(['theme', 'footer', 'position']) === 'body') {
//$css .= '@media (min-width: 769px) { #site {margin-bottom: ' . ((str_replace ('px', '', $this->getData(['theme', 'footer', 'height']) ) * 2 ) + 31 ) . 'px}}';
//$css .= '@media (max-width: 768px) { #site {margin-bottom: ' . ((str_replace ('px', '', $this->getData(['theme', 'footer', 'height']) ) * 2 ) + 93 ) . 'px}}';
$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 0 ' . $marginBottomLarge . ' !important;}}@media (max-width: 768px) {#site{margin:0 auto 0 ' . $marginBottomSmall . ' !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'] . '}';
@ -1769,22 +1833,16 @@ class core extends common {
}
$css .= 'footer span, #footerText > p {color:' . $this->getData(['theme', 'footer', 'textColor']) . ';font-family:"' . str_replace('+', ' ', $this->getData(['theme', 'footer', 'font'])) . '",sans-serif;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 {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 .= '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']) . '}';
// Marge supplémentaire lorsque le pied de page est fixe
if ( $this->getData(['theme', 'footer', 'fixed']) === true &&
$this->getData(['theme', 'footer', 'position']) === 'body') {
$css .= "@media (min-width: 769px) { #site {margin-bottom: 100px;} }";
$css .= "@media (max-width: 768px) { #site {margin-bottom: 150px;} }";
}
// Enregistre la personnalisation
file_put_contents(self::DATA_DIR.'theme.css', $css);
// Effacer le cache pour tenir compte de la couleur de fond TinyMCE
@ -1802,7 +1860,7 @@ class core extends common {
$colors = helper::colorVariants($this->getData(['admin','backgroundColor']));
$css .= '#site{background-color:' . $colors['normal']. ';}';
$css .= '.row > div {font:' . $this->getData(['admin','fontSize']) . ' "' . $this->getData(['admin','fontText']) . '", sans-serif;}';
$css .= 'body h1, h2, h3, h4, h5, h6 {font-family:' . $this->getData(['admin','fontTitle' ]) . ', sans-serif;color:' . $this->getData(['admin','colorTitle' ]) . ';}';
$css .= 'body h1, h2, h3, h4 a, h5, h6 {font-family:' . $this->getData(['admin','fontTitle' ]) . ', sans-serif;color:' . $this->getData(['admin','colorTitle' ]) . ';}';
$css .= 'body:not(.editorWysiwyg),span .zwiico-help {color:' . $this->getData(['admin','colorText']) . ';}';
$colors = helper::colorVariants($this->getData(['admin','backgroundColorButton']));
$css .= 'input[type="checkbox"]:checked + label::before,.speechBubble{background-color:' . $colors['normal'] . ';color:' . $colors['text'] . ';}';
@ -2901,6 +2959,7 @@ class layout extends common {
$rightItems .= '<li><a href="' . helper::baseUrl() . 'user" data-tippy-content="Configurer les utilisateurs">' . template::ico('users') . '</a></li>';
$rightItems .= '<li><a href="' . helper::baseUrl() . 'theme" data-tippy-content="Personnaliser les thèmes">' . template::ico('brush') . '</a></li>';
//$rightItems .= '<li><a href="' . helper::baseUrl() . 'translate" data-tippy-content="Gestion des langues">' . template::ico('flag') . '</a></li>';
$rightItems .= '<li><a href="' . helper::baseUrl() . 'addon" data-tippy-content="Gérer les modules">' . template::ico('puzzle') . '</a></li>';
$rightItems .= '<li><a href="' . helper::baseUrl() . 'config" data-tippy-content="Configurer le site">' . template::ico('cog-alt') . '</a></li>';
// Mise à jour automatique
$today = mktime(0, 0, 0);

View File

@ -1,11 +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 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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -1,11 +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 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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/
@ -44,11 +45,11 @@ body {
body {
margin: 0px;
}
/*
#site {
margin: 0px auto;
}
*/
body>header {
margin: 0px 0px;
}
@ -476,12 +477,13 @@ td>.col12 {
#site {
overflow: hidden;
}
/* Dans theme.css
@media (min-width:768px) {
#site {
margin: 20px auto;
}
}
*/
/* Bannière */
@ -960,9 +962,9 @@ footer #footerSocials .zwiico-github:hover {
/* Remonter en haut */
#backToTop {
position: fixed;
z-index: 30;
z-index: 50;
right: 30px;
bottom: 50px;
bottom: 100px;
padding: 13px 16px 16px;
/*
Paramétré dans le thème (9.2.21)

View File

@ -1,11 +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 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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -1,7 +1,6 @@
<?php $layout = new layout($this);
$lan = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2); ?>
<?php $layout = new layout($this);?>
<!DOCTYPE html>
<html prefix="og: http://ogp.me/ns#" lang="<?php echo $lan;?>">
<html prefix="og: http://ogp.me/ns#" lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">

443
core/module/addon/addon.php Normal file
View File

@ -0,0 +1,443 @@
<?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-2021, Frédéric Tempez
* @author Sylvain Lelièvre <lelievresylvain@free.fr>
* @copyright Copyright (C) 2020-2021, Sylvain Lelièvre
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/
class addon extends common {
public static $actions = [
'index' => self::GROUP_ADMIN,
'moduleDelete' => self::GROUP_ADMIN,
'export' => self::GROUP_ADMIN,
'import' => self::GROUP_ADMIN
];
// Gestion des modules
public static $modInstal = [];
// pour tests
public static $valeur = [];
/*
* Effacement d'un module installé et non utilisé
*/
public function moduleDelete() {
// Jeton incorrect
if ($this->getUrl(3) !== $_SESSION['csrf']) {
// Valeurs en sortie
$this->addOutput([
'redirect' => helper::baseUrl() . 'addon',
'state' => false,
'notification' => 'Action non autorisée'
]);
}
else{
// Suppression des dossiers
$infoModules = helper::getModules();
$module = $this->getUrl(2);
//Liste des dossiers associés au module non effacés
$list = '';
foreach( $infoModules[$module]['dataDirectory'] as $moduleId){
if (strpos($moduleId,'module.json') === false && strpos($moduleId,'page.json') === false) {
$list === '' ? $list = self::DATA_DIR.$moduleId : $list .= ', '.self::DATA_DIR. $moduleId;
}
}
if( $this->removeDir('./module/'.$module ) === true){
$success = true;
if( $list === ''){
$notification = 'Module '.$module .' désinstallé';
}
else{
$notification = 'Module '.$module .' désinstallé, il reste des données dans '.$list;
}
}
else{
$success = false;
$notification = 'La suppression a échouée';
}
// Valeurs en sortie
$this->addOutput([
'redirect' => helper::baseUrl() . 'addon',
'notification' => $notification,
'state' => $success
]);
}
}
/**
* Gestion des modules
*/
public function index() {
// Lister les modules
// $infoModules[nom_module]['realName'], ['version'], ['update'], ['delete'], ['dataDirectory']
$infoModules = helper::getModules();
// Clés moduleIds dans les pages
$inPages = helper::arrayCollumn($this->getData(['page']),'moduleId', 'SORT_DESC');
foreach( $inPages as $key=>$value){
$inPagesTitle[ $this->getData(['page', $key, 'title' ]) ] = $value;
}
// Parcourir les données des modules
foreach ($infoModules as $key=>$value) {
// Construire le tableau de sortie
self::$modInstal[] = [
$key,
$infoModules[$key]['realName'],
$infoModules[$key]['version'],
implode(', ', array_keys($inPagesTitle,$key)),
//array_key_exists('delete',$infoModules[$key]) && $infoModules[$key]['delete'] === true && implode(', ',array_keys($inPages,$key)) === ''
$infoModules[$key]['delete'] === true && implode(', ',array_keys($inPages,$key)) === ''
? template::button('moduleDelete' . $key, [
'class' => 'moduleDelete buttonRed',
'href' => helper::baseUrl() . $this->getUrl(0) . '/moduleDelete/' . $key . '/' . $_SESSION['csrf'],
'value' => template::ico('cancel')
])
: '',
is_array($infoModules[$key]['dataDirectory']) && implode(', ',array_keys($inPages,$key)) !== ''
? template::button('moduleExport' . $key, [
'class' => 'buttonBlue',
'href' => helper::baseUrl(). $this->getUrl(0) . '/export/' . $key,// appel de fonction vaut exécution, utiliser un paramètre
'value' => template::ico('download')
])
: '',
is_array($infoModules[$key]['dataDirectory']) && implode(', ',array_keys($inPages,$key)) === ''
? template::button('moduleExport' . $key, [
'class' => 'buttonBlue',
'href' => helper::baseUrl(). $this->getUrl(0) . '/import/' . $key.'/' . $_SESSION['csrf'],// appel de fonction vaut exécution, utiliser un paramètre
'value' => template::ico('upload')
])
: ''
];
}
// Retour du formulaire ?
if($this->isPost()) {
// Installation d'un module
$success = true;
$checkValidMaj = $this->getInput('configModulesCheck', helper::FILTER_BOOLEAN);
$zipFilename = $this->getInput('configModulesInstallation', helper::FILTER_STRING_SHORT);
if( $zipFilename !== ''){
$tempFolder = 'datamodules';//uniqid();
$zip = new ZipArchive();
if ($zip->open(self::FILE_DIR.'source/'.$zipFilename) === TRUE) {
$notification = 'Archive ouverte';
mkdir (self::TEMP_DIR . $tempFolder);
$zip->extractTo(self::TEMP_DIR . $tempFolder );
// Archive de module ?
$success = false;
$notification = 'Ce n\'est pas l\'archive d\'un module !';
$moduleDir = self::TEMP_DIR . $tempFolder . '/module';
$moduleName = '';
if ( is_dir( $moduleDir )) {
// Lire le nom du module
if ($dh = opendir( $moduleDir )) {
while (($file = readdir($dh)) !== false) {
$moduleName = $file;
}
closedir($dh);
}
// Module normalisé ?
if( is_file( $moduleDir.'/'.$moduleName.'/'.$moduleName.'.php' ) AND is_file( $moduleDir.'/'.$moduleName.'/view/index/index.php' ) ){
// Lecture de la version et de la validation d'update du module pour validation de la mise à jour
// Pour une version <= version installée l'utilisateur doit cocher 'Mise à jour forcée'
$version = '0.0';
$update = '0.0';
$valUpdate = false;
$file = file_get_contents( $moduleDir.'/'.$moduleName.'/'.$moduleName.'.php');
$file = str_replace(' ','',$file);
$file = str_replace("\t",'',$file);
$pos1 = strpos($file, 'constVERSION');
if( $pos1 !== false){
$posdeb = strpos($file, "'", $pos1);
$posend = strpos($file, "'", $posdeb + 1);
$version = substr($file, $posdeb + 1, $posend - $posdeb - 1);
}
$pos1 = strpos($file, 'constUPDATE');
if( $pos1 !== false){
$posdeb = strpos($file, "'", $pos1);
$posend = strpos($file, "'", $posdeb + 1);
$update = substr($file, $posdeb + 1, $posend - $posdeb - 1);
}
// Si version actuelle >= version indiquée dans UPDATE la mise à jour est validée
if( $infoModules[$moduleName]['update'] >= $update ) $valUpdate = true;
// Module déjà installé ?
$moduleInstal = false;
foreach( self::$modInstal as $key=>$value){
if($moduleName === $value[0]){
$moduleInstal = true;
}
}
// Validation de la maj si autorisation du concepteur du module ET
// ( Version plus récente OU Check de forçage )
$valNewVersion = floatval($version);
$valInstalVersion = floatval( $infoModules[$moduleName]['version'] );
$newVersion = false;
if( $valNewVersion > $valInstalVersion ) $newVersion = true;
$validMaj = $valUpdate && ( $newVersion || $checkValidMaj);
// Nouvelle installation ou mise à jour du module
if( ! $moduleInstal || $validMaj ){
// Copie récursive des dossiers
$this -> custom_copy( self::TEMP_DIR . $tempFolder, './' );
$success = true;
if( ! $moduleInstal ){
$notification = 'Module '.$moduleName.' installé';
}
else{
$notification = 'Module '.$moduleName.' mis à jour';
}
}
else{
$success = false;
if( $valNewVersion == $valInstalVersion){
$notification = ' Version détectée '.$version.' = à celle installée '.$infoModules[$moduleName]['version'];
}
else{
$notification = ' Version détectée '.$version.' < à celle installée '.$infoModules[$moduleName]['version'];
}
if( $valUpdate === false){
if( $infoModules[$moduleName]['update'] === $update ){
$notification = ' Mise à jour par ce procédé interdite par le concepteur du module';
}
else{
$notification = ' Mise à jour par ce procédé interdite, votre version est trop ancienne';
}
}
}
}
}
// Supprimer le dossier temporaire même si le module est invalide
$this->removeDir(self::TEMP_DIR . $tempFolder);
$zip->close();
} else {
// erreur à l'ouverture
$success = false;
$notification = 'Impossible d\'ouvrir l\'archive';
}
}
$this->addOutput([
'redirect' => helper::baseUrl() . $this->getUrl(),
'notification' => $notification,
'state' => $success
]);
}
// Valeurs en sortie
$this->addOutput([
'title' => 'Gestion des modules',
'view' => 'index'
]);
}
/*
* Copie récursive de dossiers
*
*/
private function custom_copy($src, $dst) {
// open the source directory
$dir = opendir($src);
// Make the destination directory if not exist
if (!is_dir($dst)) {
mkdir($dst);
}
// Loop through the files in source directory
while( $file = readdir($dir) ) {
if (( $file != '.' ) && ( $file != '..' )) {
if ( is_dir($src . '/' . $file) ){
// Recursively calling custom copy function
// for sub directory
$this -> custom_copy($src . '/' . $file, $dst . '/' . $file);
}
else {
copy($src . '/' . $file, $dst . '/' . $file);
}
}
}
closedir($dir);
}
/*
* Export des données d'un module externes ou interne à module.json
*/
public function export(){
// Lire les données du module
$infoModules = helper::getModules();
// Créer un dossier par défaut
$tmpFolder = self::TEMP_DIR . uniqid();
//$tmpFolder = self::TEMP_DIR . 'test';
if (!is_dir($tmpFolder)) {
mkdir($tmpFolder);
}
// Clés moduleIds dans les pages
$inPages = helper::arrayCollumn($this->getData(['page']),'moduleId', 'SORT_DESC');
// Parcourir les pages utilisant le module
foreach (array_keys($inPages,$this->getUrl(2)) as $pageId) {
// Export des pages hébergeant le module
$pageContent[$pageId] = $this->getData(['page',$pageId]);
// Export de fr/module.json
$moduleId = 'fr/module.json';
// Création de l'arborescence des langues
// Pas de nom dossier de langue - dossier par défaut
$t = explode ('/',$moduleId);
if ( is_array($t)) {
$lang = 'fr';
} else {
$lang = $t[0];
}
// Créer le dossier si inexistant
if (!is_dir($tmpFolder . '/' . $lang)) {
mkdir ($tmpFolder . '/' . $lang);
}
// Sauvegarde si données non vides
$tmpData [$pageId] = $this->getData(['module',$pageId ]);
if ($tmpData [$pageId] !== null) {
file_put_contents($tmpFolder . '/' . $moduleId, json_encode($tmpData));
}
// Export des données localisées dans des dossiers
foreach ($infoModules[$this->getUrl(2)]['dataDirectory'] as $dirId) {
if ( file_exists(self::DATA_DIR . '/' . $dirId)
&& !file_exists($tmpFolder . '/' . $dirId ) ) {
$this->custom_copy ( self::DATA_DIR . '/' . $dirId, $tmpFolder . '/' . $dirId );
}
}
}
// Enregistrement des pages dans le dossier de langue identique à module
if (!file_exists($tmpFolder . '/' . $lang . '/page.json')) {
file_put_contents($tmpFolder . '/' . $lang . '/page.json', json_encode($pageContent));
}
// création du zip
$fileName = $this->getUrl(2) . '.zip';
$this->makeZip ($fileName, $tmpFolder, []);
if (file_exists($fileName)) {
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $fileName . '"');
header('Content-Length: ' . filesize($fileName));
readfile( $fileName);
// Valeurs en sortie
$this->addOutput([
'display' => self::DISPLAY_RAW
]);
unlink($fileName);
$this->removeDir($tmpFolder);
exit();
} else {
// Valeurs en sortie
$this->addOutput([
'redirect' => helper::baseUrl() . 'addon',
'notification' => 'Quelque chose s\'est mal passé',
'state' => false
]);
}
}
/*
* Importer des données d'un module externes ou interne à module.json
*/
public function import(){
// Jeton incorrect
if ($this->getUrl(3) !== $_SESSION['csrf']) {
// Valeurs en sortie
$this->addOutput([
'redirect' => helper::baseUrl() . 'addon',
'state' => false,
'notification' => 'Action non autorisée'
]);
}
else{
// Soumission du formulaire
if($this->isPost()) {
// Récupérer le fichier et le décompacter
$zipFilename = $this->getInput('addonImportFile', helper::FILTER_STRING_SHORT, true);
$tempFolder = uniqid();
mkdir (self::TEMP_DIR . $tempFolder);
$zip = new ZipArchive();
if ($zip->open(self::FILE_DIR . 'source/' . $zipFilename) === TRUE) {
$zip->extractTo(self::TEMP_DIR . $tempFolder );
}
// Import des données localisées page.json et module.json
// Pour chaque dossier localisé
$dataTarget = array();
$dataSource = array();
// Liste des pages de même nom dans l'archive et le site
$list = '';
foreach (self::$i18nList as $key=>$value) {
// Les Pages et les modules
foreach (['page','module'] as $fileTarget){
if (file_exists(self::TEMP_DIR . $tempFolder . '/' .$key . '/' . $fileTarget . '.json')) {
// Le dossier de langue existe
// faire la fusion
$dataSource = json_decode(file_get_contents(self::TEMP_DIR . $tempFolder . '/' .$key . '/' . $fileTarget . '.json'), true);
// Des pages de même nom que celles de l'archive existent
if( $fileTarget === 'page' ){
foreach( $dataSource as $keydataSource=>$valuedataSource ){
foreach( $this->getData(['page']) as $keypage=>$valuepage ){
if( $keydataSource === $keypage){
$list === '' ? $list .= ' '.$this->getData(['page', $keypage, 'title']) : $list .= ', '.$this->getData(['page', $keypage, 'title']);
}
}
}
}
$dataTarget = json_decode(file_get_contents(self::DATA_DIR . $key . '/' . $fileTarget . '.json'), true);
$data [$fileTarget] = array_merge($dataTarget[$fileTarget], $dataSource);
if( $list === ''){
file_put_contents(self::DATA_DIR . '/' .$key . '/' . $fileTarget . '.json', json_encode( $data ,JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT|LOCK_EX) );
}
// Supprimer les fichiers importés
unlink (self::TEMP_DIR . $tempFolder . '/' .$key . '/' . $fileTarget . '.json');
}
}
}
// Import des fichiers placés ailleurs que dans les dossiers localisés.
$this->custom_copy (self::TEMP_DIR . $tempFolder,self::DATA_DIR );
// Supprimer le dossier temporaire
$this->removeDir(self::TEMP_DIR . $tempFolder);
$zip->close();
if( $list !== '' ){
$success = false;
strpos( $list, ',') === false ? $notification = 'Import impossible la page suivante doit être renommée :'.$list : $notification = 'Import impossible les pages suivantes doivent être renommées :'.$list;
}
else{
$success = true;
$notification = 'Import réussi';
}
// Valeurs en sortie
$this->addOutput([
'redirect' => helper::baseUrl() . 'addon',
'state' => $success,
'notification' => $notification
]);
}
// Valeurs en sortie
$this->addOutput([
'title' => 'Importer des données de module',
'view' => 'import'
]);
}
}
}

View 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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/
/** NE PAS EFFACER
* admin.css
*/

View File

@ -0,0 +1,31 @@
<?php echo template::formOpen('addonImportForm'); ?>
<div class="row">
<div class="col2">
<?php echo template::button('addonImportBack', [
'class' => 'buttonGrey',
'href' => helper::baseUrl() . 'addon',
'ico' => 'left',
'value' => 'Retour'
]); ?>
</div>
<div class="col2 offset8">
<?php echo template::submit('addonImportSubmit', [
'value' => 'Appliquer'
]); ?>
</div>
</div>
<div class="row">
<div class="col12">
<div class="block">
<h4>Installer des données de module</h4>
<div class="row">
<div class="col6 offset3">
<?php echo template::file('addonImportFile', [
'label' => 'Archive ZIP :',
'type' => 2
]); ?>
</div>
</div>
</div>
</div>
</div>

View 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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/
/** NE PAS EFFACER
* admin.css
*/

View 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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/
/**
* Confirmation de suppression
*/
$(".moduleDelete").on("click", function() {
var _this = $(this);
return core.confirm("Êtes-vous sûr de vouloir supprimer, effacer ce module ?", function() {
$(location).attr("href", _this.attr("href"));
});
});

View File

@ -0,0 +1,46 @@
<?php echo template::formOpen('configModulesGestion'); ?>
<div class="row">
<div class="col2">
<?php echo template::button('configModulesBack', [
'class' => 'buttonGrey',
'href' => helper::baseUrl(),
'ico' => 'left',
'value' => 'Retour'
]); ?>
</div>
<div class="col2 offset8">
<?php echo template::submit('configModulesSubmit',[
'value' => 'Valider',
'ico' => 'check'
]); ?>
</div>
</div>
<div class="row">
<div class="col12">
<div class="block">
<h4>Installer ou mettre à jour un module </h4>
<div class="row">
<div class="col6 offset3">
<?php echo template::file('configModulesInstallation', [
'label' => 'Archive ZIP :',
'type' => 2
]); ?>
</div>
</div>
<div class="row">
<div class="col6">
<?php echo template::checkbox('configModulesCheck', true, 'Mise à jour forcée', [
'checked' => false,
'help' => 'Permet de forcer une mise à jour même si la version du module est inférieure ou égale à celle du module installé.',
]); ?>
</div>
</div>
</div>
</div>
</div>
<?php echo template::formClose(); ?>
<?php if($module::$modInstal): ?>
<?php echo template::table([2, 2, 2, 2, 1, 1, 1, 1], $module::$modInstal, ['Module installé', 'Alias', 'Version', 'Page(s)', 'Supprimer', 'Exporter', 'Importer']); ?>
<?php else: ?>
<?php echo template::speech('Aucun module installé.'); ?>
<?php endif; ?>

View File

@ -9,7 +9,7 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/
@ -30,7 +30,6 @@ class config extends common {
'logDownload'=> self::GROUP_ADMIN,
'blacklistReset' => self::GROUP_ADMIN,
'blacklistDownload' => self::GROUP_ADMIN
];
public static $timezones = [
@ -286,16 +285,20 @@ class config extends common {
$data = str_replace('_','/',$googlePagespeedData['lighthouseResult']['audits']['final-screenshot']['details']['data']);
$data = str_replace('-','+',$data);
$img = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $data));
$success = file_put_contents( self::FILE_DIR.'source/screenshot.jpg',$img) ;
// Effacer la miniature png
if (file_exists(self::FILE_DIR.'source/screenshot.png')) {
unlink (self::FILE_DIR.'source/screenshot.png');
// 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 = file_put_contents( self::FILE_DIR.'source/screenshot.jpg',$img) ;
}
// Valeurs en sortie
$this->addOutput([
'notification' => $success === false ? 'Service inaccessible ou erreur d\'écriture de l\'image' : 'Image générée avec succès',
'redirect' => helper::baseUrl() . 'advanced',
'redirect' => helper::baseUrl() . 'config/advanced',
'state' => $success === false ? false : true
]);
}
@ -376,13 +379,6 @@ class config extends common {
$this->getInput('configManageImportUser', helper::FILTER_BOOLEAN) === true) {
$this->setData(['user',$users]);
}
/*
if ($version === '9' ) {
$this->importData($this->getInput('configManageImportUser', helper::FILTER_BOOLEAN));
$this->setData(['core','dataVersion',0]);
}*/
// Met à jours les URL dans les contenus de page
// Message de notification
$notification = $success === true ? 'Restauration réalisée avec succès' : 'Erreur inconnue';
@ -453,12 +449,7 @@ class config extends common {
'state' => $success
]);
}
// Initialisation du screen - APPEL AUTO DESACTIVE POUR EVITER UN RALENTISSEMENT
/*
if (!file_exists(self::FILE_DIR.'source/screenshot.jpg')) {
$this->configMetaImage();
}
*/
// Valeurs en sortie
$this->addOutput([
'title' => 'Configuration',
@ -579,9 +570,10 @@ class config extends common {
// Générer robots.txt et sitemap
$this->generateFiles();
// Valeurs en sortie
$notification = $notification . 'Modifications enregistrées';
$this->addOutput([
'redirect' => helper::baseUrl() . $this->getUrl(),
'notification' => 'Modifications enregistrées',
'notification' => $notification,
'state' => $success
]);
}
@ -812,5 +804,4 @@ class config extends common {
}
return $newArray;
}
}

View File

@ -7,7 +7,7 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -5,7 +5,7 @@
* file that was distributed with this source code.
*
* @author Frédéric Tempez <frederic.tempez@outlook.com>
* @copyright Copyright (C) 2018-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -504,4 +504,5 @@
</div>
</div>
</div>
<?php echo template::formClose(); ?>

View File

@ -7,7 +7,7 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -5,7 +5,7 @@
* file that was distributed with this source code.
*
* @author Frédéric Tempez <frederic.tempez@outlook.com>
* @copyright Copyright (C) 2018-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -7,7 +7,7 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -90,7 +90,7 @@
<?php echo template::select('configSearchPageId', array_merge(['none' => 'Aucune'] , helper::arrayCollumn($pages, 'title', 'SORT_ASC') ) , [
'label' => 'Recherche dans le site',
'selected' => $this->getData(['locale', 'searchPageId']),
'help' => 'Sélectionner la page "Recherche" ou une page contenant le module "Recherche" permet d\'activer un lien dans le pied de page. '
'help' => 'Sélectionner la page "Recherche" ou une page contenant le module "Recherche". Une option du pied de page ajoute un lien discret vers cette page.'
]); ?>
</div>
</div>

View File

@ -7,7 +7,7 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -7,7 +7,7 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -2,12 +2,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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -1,11 +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 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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -7,7 +7,7 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -2,12 +2,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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -9,7 +9,7 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/
@ -29,15 +29,7 @@ class page extends common {
'' => 'Aucune'
];
public static $moduleIds = [];
// Nom des modules
public static $moduleNames = [
'news' => 'Nouvelles',
'blog' => 'Blog',
'form' => 'Formulaire',
'gallery' => 'Galerie',
'redirection' => 'Redirection',
'search' => 'Recherche'
];
public static $typeMenu = [
'text' => 'Texte',
'icon' => 'Icône',
@ -449,22 +441,7 @@ class page extends common {
]);
}
}
// Liste des modules
$moduleIds = [];
$iterator = new DirectoryIterator('module/');
foreach($iterator as $fileInfos) {
if(is_file($fileInfos->getPathname() . '/' . $fileInfos->getFilename() . '.php')) {
if (array_key_exists($fileInfos->getBasename(),self::$moduleNames)) {
$moduleIds[$fileInfos->getBasename()] = self::$moduleNames[$fileInfos->getBasename()];
} else {
$moduleIds[$fileInfos->getBasename()] = ucfirst($fileInfos->getBasename());
}
}
}
self::$moduleIds = $moduleIds;
asort(self::$moduleIds);
self::$moduleIds = array_merge( ['' => 'Aucun'] , self::$moduleIds);
// Pages sans parent
self::$moduleIds = array_merge( ['' => 'Aucun'] , helper::arrayCollumn(helper::getModules(),'realName','SORT_ASC')); // Pages sans parent
foreach($this->getHierarchy() as $parentPageId => $childrenPageIds) {
if($parentPageId !== $this->getUrl(2)) {
self::$pagesNoParentId[$parentPageId] = $this->getData(['page', $parentPageId, 'title']);

View File

@ -7,7 +7,7 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -7,7 +7,7 @@
* @author Rémi Jean <remi.jean@outlook.com>
* @copyright Copyright (C) 2008-2018, Rémi Jean
* @authorFrédéric Tempez <frederic.tempez@outlook.com>
* @copyright Copyright (C) 2018-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -54,7 +54,7 @@ echo template::formOpen('pageEditForm');
]); ?>
<?php echo template::hidden('pageEditModuleIdOld',['value' => $this->getData(['page', $this->getUrl(2), 'moduleId'])]); ?>
<?php echo template::hidden('pageEditModuleIdOldText',[
'value' => array_key_exists($this->getData(['page', $this->getUrl(2), 'moduleId']),$module::$moduleNames)? $module::$moduleNames[$this->getData(['page', $this->getUrl(2), 'moduleId'])] : ucfirst($this->getData(['page', $this->getUrl(2), 'moduleId']))
'value' => array_key_exists($this->getData(['page', $this->getUrl(2), 'moduleId']),$module::$moduleIds)? $module::$moduleIds[$this->getData(['page', $this->getUrl(2), 'moduleId'])] : ucfirst($this->getData(['page', $this->getUrl(2), 'moduleId']))
]); ?>
</div>
<div class="col3 verticalAlignBottom">

View File

@ -2,12 +2,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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -11,7 +11,7 @@
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
* @copyright : Frédéric Tempez <frederic.tempez@outlook.com>
* @copyright Copyright (C) 2018-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
*/
class theme extends common {
@ -692,7 +692,7 @@ class theme extends common {
*/
public function export() {
// Make zip
$zipFilename = $this->makezip($this->getUrl(2));
$zipFilename = $this->zipTheme($this->getUrl(2));
// Téléchargement du ZIP
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
@ -710,7 +710,7 @@ class theme extends common {
*/
public function save() {
// Make zip
$zipFilename = $this->makezip($this->getUrl(2));
$zipFilename = $this->zipTheme($this->getUrl(2));
// Téléchargement du ZIP
if (!is_dir(self::FILE_DIR.'source/theme')) {
mkdir(self::FILE_DIR.'source/theme');
@ -772,7 +772,7 @@ class theme extends common {
* construction du zip
* @param string $modele theme ou admin
*/
private function makezip($modele) {
private function zipTheme($modele) {
// Creation du dossier
$zipFilename = $modele . ' ' .date('d m Y').' '.date('H i s ').'.zip';
$zip = new ZipArchive();

View File

@ -7,7 +7,7 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -7,7 +7,7 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -1,11 +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 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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -1,5 +1,5 @@
/**
* This file is part of Zwii. *
* This file is part of Zwii.
* For full copyright and license information, please see the LICENSE
* file that was distributed with this source code.
*
@ -7,7 +7,7 @@
* @copyright Copyright (C) 2008-2018, Rémi Jean
* @license GNU General Public License, version 3
* @author Frédéric Tempez <frederic.tempez@outlook.com>
* @copyright Copyright (C) 2018-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @link http://zwiicms.fr/
*/

View File

@ -1,11 +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 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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -7,7 +7,7 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -8,7 +8,7 @@
* @copyright Copyright (C) 2008-2018, Rémi Jean
* @license GNU General Public License, version 3
* @author Frédéric Tempez <frederic.tempez@outlook.com>
* @copyright Copyright (C) 2018-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @link http://zwiicms.fr/
*/

View File

@ -7,7 +7,7 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -8,7 +8,7 @@
* @copyright Copyright (C) 2008-2018, Rémi Jean
* @license GNU General Public License, version 3
* @author Frédéric Tempez <frederic.tempez@outlook.com>
* @copyright Copyright (C) 2018-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @link http://zwiicms.fr/
*/

View File

@ -1,11 +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 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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -1,11 +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 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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -7,7 +7,7 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -1,11 +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 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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -7,7 +7,7 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -1,11 +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 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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -7,7 +7,7 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -1,11 +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 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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -2,12 +2,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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -7,7 +7,7 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -2,12 +2,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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -7,7 +7,7 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -1,11 +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 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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -7,7 +7,7 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -1,11 +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 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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -7,7 +7,7 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -7,7 +7,7 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -1,11 +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 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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -7,7 +7,7 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -1,8 +1,5 @@
.zwiico-plus-circled:before { content: '\2191'; } /* '↑' */
.zwiico-flag:before { content: '\2691'; } /* '⚑' */
.zwiico-mail:before { content: '\2709'; } /* '✉' */
.zwiico-divide:before { content: '\e05b'; } /* '' */
.zwiico-logout:before { content: '\e800'; } /* '' */
.zwiico-plus:before { content: '\e801'; } /* '' */
.zwiico-cancel:before { content: '\e802'; } /* '' */
@ -16,6 +13,7 @@
.zwiico-folder:before { content: '\e80a'; } /* '' */
.zwiico-users:before { content: '\e80b'; } /* '' */
.zwiico-left:before { content: '\e80c'; } /* '' */
.zwiico-mail:before { content: '\e80d'; } /* '' */
.zwiico-user:before { content: '\e80e'; } /* '' */
.zwiico-update:before { content: '\e80f'; } /* '' */
.zwiico-home:before { content: '\e810'; } /* '' */
@ -38,6 +36,8 @@
.zwiico-login:before { content: '\e821'; } /* '' */
.zwiico-lock:before { content: '\e822'; } /* '' */
.zwiico-mimi:before { content: '\e823'; } /* '' */
.zwiico-divide:before { content: '\e824'; } /* '' */
.zwiico-flag:before { content: '\e825'; } /* '' */
.zwiico-spin:before { content: '\e831'; } /* '' */
.zwiico-twitter:before { content: '\f099'; } /* '' */
.zwiico-facebook:before { content: '\f09a'; } /* '' */
@ -48,6 +48,7 @@
.zwiico-download-cloud:before { content: '\f0ed'; } /* '' */
.zwiico-upload-cloud:before { content: '\f0ee'; } /* '' */
.zwiico-code:before { content: '\f121'; } /* '' */
.zwiico-puzzle:before { content: '\f12e'; } /* '' */
.zwiico-youtube:before { content: '\f167'; } /* '' */
.zwiico-instagram:before { content: '\f16d'; } /* '' */
.zwiico-brush:before { content: '\f1fc'; } /* '' */

File diff suppressed because one or more lines are too long

View File

@ -1,8 +1,5 @@
.zwiico-plus-circled { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#x2191;&nbsp;'); }
.zwiico-flag { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#x2691;&nbsp;'); }
.zwiico-mail { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#x2709;&nbsp;'); }
.zwiico-divide { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe05b;&nbsp;'); }
.zwiico-logout { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe800;&nbsp;'); }
.zwiico-plus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe801;&nbsp;'); }
.zwiico-cancel { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe802;&nbsp;'); }
@ -16,6 +13,7 @@
.zwiico-folder { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe80a;&nbsp;'); }
.zwiico-users { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe80b;&nbsp;'); }
.zwiico-left { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe80c;&nbsp;'); }
.zwiico-mail { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe80d;&nbsp;'); }
.zwiico-user { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe80e;&nbsp;'); }
.zwiico-update { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe80f;&nbsp;'); }
.zwiico-home { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe810;&nbsp;'); }
@ -38,6 +36,8 @@
.zwiico-login { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe821;&nbsp;'); }
.zwiico-lock { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe822;&nbsp;'); }
.zwiico-mimi { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe823;&nbsp;'); }
.zwiico-divide { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe824;&nbsp;'); }
.zwiico-flag { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe825;&nbsp;'); }
.zwiico-spin { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe831;&nbsp;'); }
.zwiico-twitter { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf099;&nbsp;'); }
.zwiico-facebook { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf09a;&nbsp;'); }
@ -48,6 +48,7 @@
.zwiico-download-cloud { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0ed;&nbsp;'); }
.zwiico-upload-cloud { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0ee;&nbsp;'); }
.zwiico-code { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf121;&nbsp;'); }
.zwiico-puzzle { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf12e;&nbsp;'); }
.zwiico-youtube { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf167;&nbsp;'); }
.zwiico-instagram { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf16d;&nbsp;'); }
.zwiico-brush { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf1fc;&nbsp;'); }

View File

@ -11,9 +11,6 @@
}
.zwiico-plus-circled { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#x2191;&nbsp;'); }
.zwiico-flag { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#x2691;&nbsp;'); }
.zwiico-mail { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#x2709;&nbsp;'); }
.zwiico-divide { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe05b;&nbsp;'); }
.zwiico-logout { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe800;&nbsp;'); }
.zwiico-plus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe801;&nbsp;'); }
.zwiico-cancel { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe802;&nbsp;'); }
@ -27,6 +24,7 @@
.zwiico-folder { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe80a;&nbsp;'); }
.zwiico-users { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe80b;&nbsp;'); }
.zwiico-left { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe80c;&nbsp;'); }
.zwiico-mail { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe80d;&nbsp;'); }
.zwiico-user { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe80e;&nbsp;'); }
.zwiico-update { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe80f;&nbsp;'); }
.zwiico-home { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe810;&nbsp;'); }
@ -49,6 +47,8 @@
.zwiico-login { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe821;&nbsp;'); }
.zwiico-lock { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe822;&nbsp;'); }
.zwiico-mimi { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe823;&nbsp;'); }
.zwiico-divide { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe824;&nbsp;'); }
.zwiico-flag { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe825;&nbsp;'); }
.zwiico-spin { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe831;&nbsp;'); }
.zwiico-twitter { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf099;&nbsp;'); }
.zwiico-facebook { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf09a;&nbsp;'); }
@ -59,6 +59,7 @@
.zwiico-download-cloud { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0ed;&nbsp;'); }
.zwiico-upload-cloud { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0ee;&nbsp;'); }
.zwiico-code { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf121;&nbsp;'); }
.zwiico-puzzle { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf12e;&nbsp;'); }
.zwiico-youtube { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf167;&nbsp;'); }
.zwiico-instagram { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf16d;&nbsp;'); }
.zwiico-brush { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf1fc;&nbsp;'); }

View File

@ -1,11 +1,11 @@
@font-face {
font-family: 'zwiico';
src: url('../font/zwiico.eot?96515118');
src: url('../font/zwiico.eot?96515118#iefix') format('embedded-opentype'),
url('../font/zwiico.woff2?96515118') format('woff2'),
url('../font/zwiico.woff?96515118') format('woff'),
url('../font/zwiico.ttf?96515118') format('truetype'),
url('../font/zwiico.svg?96515118#zwiico') format('svg');
src: url('../font/zwiico.eot?44489499');
src: url('../font/zwiico.eot?44489499#iefix') format('embedded-opentype'),
url('../font/zwiico.woff2?44489499') format('woff2'),
url('../font/zwiico.woff?44489499') format('woff'),
url('../font/zwiico.ttf?44489499') format('truetype'),
url('../font/zwiico.svg?44489499#zwiico') format('svg');
font-weight: normal;
font-style: normal;
}
@ -15,7 +15,7 @@
@media screen and (-webkit-min-device-pixel-ratio:0) {
@font-face {
font-family: 'zwiico';
src: url('../font/zwiico.svg?96515118#zwiico') format('svg');
src: url('../font/zwiico.svg?44489499#zwiico') format('svg');
}
}
*/
@ -56,9 +56,6 @@
}
.zwiico-plus-circled:before { content: '\2191'; } /* '↑' */
.zwiico-flag:before { content: '\2691'; } /* '⚑' */
.zwiico-mail:before { content: '\2709'; } /* '✉' */
.zwiico-divide:before { content: '\e05b'; } /* '' */
.zwiico-logout:before { content: '\e800'; } /* '' */
.zwiico-plus:before { content: '\e801'; } /* '' */
.zwiico-cancel:before { content: '\e802'; } /* '' */
@ -72,6 +69,7 @@
.zwiico-folder:before { content: '\e80a'; } /* '' */
.zwiico-users:before { content: '\e80b'; } /* '' */
.zwiico-left:before { content: '\e80c'; } /* '' */
.zwiico-mail:before { content: '\e80d'; } /* '' */
.zwiico-user:before { content: '\e80e'; } /* '' */
.zwiico-update:before { content: '\e80f'; } /* '' */
.zwiico-home:before { content: '\e810'; } /* '' */
@ -94,6 +92,8 @@
.zwiico-login:before { content: '\e821'; } /* '' */
.zwiico-lock:before { content: '\e822'; } /* '' */
.zwiico-mimi:before { content: '\e823'; } /* '' */
.zwiico-divide:before { content: '\e824'; } /* '' */
.zwiico-flag:before { content: '\e825'; } /* '' */
.zwiico-spin:before { content: '\e831'; } /* '' */
.zwiico-twitter:before { content: '\f099'; } /* '' */
.zwiico-facebook:before { content: '\f09a'; } /* '' */
@ -104,6 +104,7 @@
.zwiico-download-cloud:before { content: '\f0ed'; } /* '' */
.zwiico-upload-cloud:before { content: '\f0ee'; } /* '' */
.zwiico-code:before { content: '\f121'; } /* '' */
.zwiico-puzzle:before { content: '\f12e'; } /* '' */
.zwiico-youtube:before { content: '\f167'; } /* '' */
.zwiico-instagram:before { content: '\f16d'; } /* '' */
.zwiico-brush:before { content: '\f1fc'; } /* '' */

Binary file not shown.

View File

@ -1,19 +1,13 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>Copyright (C) 2020 by original authors @ fontello.com</metadata>
<metadata>Copyright (C) 2021 by original authors @ fontello.com</metadata>
<defs>
<font id="zwiico" horiz-adv-x="1000" >
<font-face font-family="zwiico" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
<missing-glyph horiz-adv-x="1000" />
<glyph glyph-name="plus-circled" unicode="&#x2191;" d="M420 770q174 0 297-123t123-297-123-297-297-123-297 123-123 297 123 297 297 123z m52-470l200 0 0 102-200 0 0 202-102 0 0-202-202 0 0-102 202 0 0-202 102 0 0 202z" horiz-adv-x="840" />
<glyph glyph-name="flag" unicode="&#x2691;" d="M179 707q0-40-36-61v-707q0-7-5-12t-13-6h-36q-7 0-12 6t-6 12v707q-35 21-35 61 0 30 21 51t50 21 51-21 21-51z m821-36v-425q0-14-7-22t-22-15q-120-65-206-65-34 0-69 12t-60 27-65 27-79 12q-107 0-259-81-10-5-19-5-14 0-25 10t-10 25v415q0 17 17 30 12 8 44 24 132 67 235 67 60 0 112-16t122-49q21-11 49-11 30 0 65 12t62 26 49 26 30 12q15 0 25-10t11-26z" horiz-adv-x="1000" />
<glyph glyph-name="mail" unicode="&#x2709;" d="M929 11v428q-18-20-39-36-149-115-238-189-28-24-46-37t-48-28-57-13h-2q-26 0-57 13t-48 28-46 37q-88 74-238 189-21 16-39 36v-428q0-7 6-13t12-5h822q7 0 12 5t6 13z m0 586v14t-1 7-1 7-3 5-5 4-8 2h-822q-7 0-12-6t-6-12q0-94 83-159 107-84 223-176 4-3 20-17t25-21 25-17 28-16 24-5h2q11 0 24 5t28 16 25 17 25 21 20 17q116 92 224 176 30 24 56 65t26 73z m71 21v-607q0-37-26-63t-63-27h-822q-36 0-63 27t-26 63v607q0 37 26 63t63 26h822q37 0 63-26t26-63z" horiz-adv-x="1000" />
<glyph glyph-name="divide" unicode="&#xe05b;" d="M300 663q0 117 116 117 118 0 118-117t-118-118q-116 0-116 118z m0-625q0 117 116 117 118 0 118-117t-118-118q-116 0-116 118z m-300 312q0 43 30 73t74 31l625 0q44 0 74-31t31-73-31-73-74-31l-625 0q-44 0-74 31t-30 73z" horiz-adv-x="834" />
<glyph glyph-name="logout" unicode="&#xe800;" d="M357 46q0-2 1-11t0-14-2-14-5-11-12-3h-178q-67 0-114 47t-47 114v392q0 67 47 114t114 47h178q8 0 13-5t5-13q0-2 1-11t0-15-2-13-5-11-12-3h-178q-37 0-63-26t-27-64v-392q0-37 27-63t63-27h174t6 0 7-2 4-3 4-5 1-8z m518 304q0-14-11-25l-303-304q-11-10-25-10t-25 10-11 25v161h-250q-14 0-25 11t-11 25v214q0 15 11 25t25 11h250v161q0 14 11 25t25 10 25-10l303-304q11-10 11-25z" horiz-adv-x="928.6" />
<glyph glyph-name="plus" unicode="&#xe801;" d="M786 439v-107q0-22-16-38t-38-15h-232v-233q0-22-16-37t-38-16h-107q-22 0-38 16t-15 37v233h-232q-23 0-38 15t-16 38v107q0 23 16 38t38 16h232v232q0 22 15 38t38 16h107q23 0 38-16t16-38v-232h232q23 0 38-16t16-38z" horiz-adv-x="785.7" />
@ -40,6 +34,8 @@
<glyph glyph-name="left" unicode="&#xe80c;" d="M357 600v-500q0-14-10-25t-26-11-25 11l-250 250q-10 11-10 25t10 25l250 250q11 11 25 11t26-11 10-25z" horiz-adv-x="357.1" />
<glyph glyph-name="mail" unicode="&#xe80d;" d="M929 11v428q-18-20-39-36-149-115-238-189-28-24-46-37t-48-28-57-13h-2q-26 0-57 13t-48 28-46 37q-88 74-238 189-21 16-39 36v-428q0-7 6-13t12-5h822q7 0 12 5t6 13z m0 586v14t-1 7-1 7-3 5-5 4-8 2h-822q-7 0-12-6t-6-12q0-94 83-159 107-84 223-176 4-3 20-17t25-21 25-17 28-16 24-5h2q11 0 24 5t28 16 25 17 25 21 20 17q116 92 224 176 30 24 56 65t26 73z m71 21v-607q0-37-26-63t-63-27h-822q-36 0-63 27t-26 63v607q0 37 26 63t63 26h822q37 0 63-26t26-63z" horiz-adv-x="1000" />
<glyph glyph-name="user" unicode="&#xe80e;" d="M714 69q0-60-35-104t-84-44h-476q-49 0-84 44t-35 104q0 48 5 90t17 85 33 73 52 50 76 19q73-72 174-72t175 72q42 0 75-19t52-50 33-73 18-85 4-90z m-143 495q0-88-62-151t-152-63-151 63-63 151 63 152 151 63 152-63 62-152z" horiz-adv-x="714.3" />
<glyph glyph-name="update" unicode="&#xe80f;" d="M843 261q0-3 0-4-36-150-150-243t-267-93q-81 0-157 31t-136 88l-72-72q-11-11-25-11t-25 11-11 25v250q0 14 11 25t25 11h250q14 0 25-11t10-25-10-25l-77-77q40-36 90-57t105-20q74 0 139 37t104 99q6 10 30 66 4 13 16 13h107q8 0 13-6t5-12z m14 446v-250q0-14-10-25t-26-11h-250q-14 0-25 11t-10 25 10 25l77 77q-82 77-194 77-75 0-140-37t-104-99q-6-10-29-66-5-13-17-13h-111q-7 0-13 6t-5 12v4q36 150 151 243t268 93q81 0 158-31t137-88l72 72q11 11 25 11t26-11 10-25z" horiz-adv-x="857.1" />
@ -84,6 +80,10 @@
<glyph glyph-name="mimi" unicode="&#xe823;" d="M909 286c0-241-203-436-454-436s-455 195-455 436 204 564 455 564 454-324 454-564z m-454 396c-141 0-255-114-255-254s114-255 255-255 254 114 254 255-114 254-254 254z m91-254c0-51-41-91-91-91s-91 40-91 91 40 90 91 90 91-40 91-90z" horiz-adv-x="909" />
<glyph glyph-name="divide" unicode="&#xe824;" d="M300 663q0 117 116 117 118 0 118-117t-118-118q-116 0-116 118z m0-625q0 117 116 117 118 0 118-117t-118-118q-116 0-116 118z m-300 312q0 43 30 73t74 31l625 0q44 0 74-31t31-73-31-73-74-31l-625 0q-44 0-74 31t-30 73z" horiz-adv-x="834" />
<glyph glyph-name="flag" unicode="&#xe825;" d="M179 707q0-40-36-61v-707q0-7-5-12t-13-6h-36q-7 0-12 6t-6 12v707q-35 21-35 61 0 30 21 51t50 21 51-21 21-51z m821-36v-425q0-14-7-22t-22-15q-120-65-206-65-34 0-69 12t-60 27-65 27-79 12q-107 0-259-81-10-5-19-5-14 0-25 10t-10 25v415q0 17 17 30 12 8 44 24 132 67 235 67 60 0 112-16t122-49q21-11 49-11 30 0 65 12t62 26 49 26 30 12q15 0 25-10t11-26z" horiz-adv-x="1000" />
<glyph glyph-name="spin" unicode="&#xe831;" d="M46 144l0 0c0 0-1 0-1 0-8 18-15 37-21 55-6 19-11 38-15 58-19 99-8 203 35 298 3 6 10 8 15 5 1 0 2 0 2-1l0 0 80-59c5-3 6-9 4-14-5-12-9-25-12-37-4-13-7-26-9-40-11-67-3-137 23-201 2-5 0-10-4-13l0 0-80-56c-5-4-12-2-16 3-1 0-1 1-1 2l0 0z m120 574l0 0c0 1 0 1 0 1 15 13 30 25 46 37 16 11 33 22 51 31 89 50 192 72 297 60 6-1 10-6 10-13 0-1-1-1-1-2l0 0-31-94c-2-5-8-8-13-7-13 0-27 0-40 0-14-1-27-2-40-4-68-11-133-40-186-84-4-3-10-3-14 0l0 0-79 58c-5 3-6 11-2 16 0 0 1 1 2 1l0 0z m588 65l0 0c0 0 1 0 1 0 17-10 34-21 50-32 16-12 31-25 46-38 74-69 127-160 148-262 2-6-2-12-9-13-1 0-1 0-2 0l0 0-100 1c-5 0-10 4-11 9-3 13-8 26-12 38-5 12-10 25-17 36-31 61-78 113-137 150-5 3-6 8-5 13l0 0 31 92c2 6 9 9 15 7 1 0 2-1 2-1l0 0z m244-535l0 0c0 0 0 0 0 0-4-20-9-39-15-57-7-19-14-37-22-55-44-92-114-170-205-221-6-3-13-1-16 4 0 1-1 2-1 2l0 0-30 94c-2 6 1 12 6 14 11 7 22 15 32 23 11 9 21 18 30 27 49 48 84 109 101 176 2 5 6 8 11 8l0 0 98-1c6 0 11-5 11-11 0-1 0-2 0-3l0 0z m-438-395l0 0c0 0 0 0 0 0-20-2-40-3-60-3-20 0-40 1-59 4-102 12-198 54-276 125-5 4-5 11 0 16 0 0 1 1 1 1l0 0 81 58c5 3 12 2 16-2 10-8 20-16 32-23 11-7 22-14 34-20 62-31 131-45 200-41 6 0 10-3 12-8l0 0 29-92c2-6-1-12-7-14-1-1-2-1-3-1l0 0z" horiz-adv-x="1000" />
<glyph glyph-name="twitter" unicode="&#xf099;" d="M904 622q-37-54-90-93 0-8 0-23 0-73-21-145t-64-139-103-117-144-82-181-30q-151 0-276 81 19-2 43-2 126 0 224 77-59 1-105 36t-64 89q19-3 34-3 24 0 48 6-63 13-104 62t-41 115v2q38-21 82-23-37 25-59 64t-22 86q0 49 25 91 68-83 164-133t208-55q-5 21-5 41 0 75 53 127t127 53q79 0 132-57 61 12 115 44-21-64-80-100 52 6 104 28z" horiz-adv-x="928.6" />
@ -104,6 +104,8 @@
<glyph glyph-name="code" unicode="&#xf121;" d="M344 69l-28-28q-5-5-12-5t-13 5l-260 261q-6 5-6 12t6 13l260 260q5 6 13 6t12-6l28-28q6-5 6-13t-6-12l-219-220 219-219q6-6 6-13t-6-13z m330 596l-208-721q-2-7-9-11t-13-1l-34 9q-8 3-11 9t-2 14l209 720q2 8 8 11t13 2l35-10q7-2 11-9t1-13z m367-363l-260-261q-6-5-13-5t-13 5l-28 28q-5 6-5 13t5 13l219 219-219 220q-5 5-5 12t5 13l28 28q6 6 13 6t13-6l260-260q5-5 5-13t-5-12z" horiz-adv-x="1071.4" />
<glyph glyph-name="puzzle" unicode="&#xf12e;" d="M929 237q0-45-25-75t-69-30q-23 0-43 10t-33 21-32 21-39 10q-62 0-62-69 0-22 9-65t8-64v-3q-12 0-18 0-19-2-54-7t-65-7-54-3q-35 0-58 15t-23 47q0 20 9 39t22 32 21 33 10 43q0 44-31 69t-75 25q-47 0-80-26t-33-71q0-24 9-46t18-36 19-30 8-28q0-25-25-50-21-19-65-19-54 0-137 13-5 1-16 2t-15 3l-7 1q-1 0-2 0-1 0-1 1v571q1 0 10-2t19-2 12-2q83-14 137-14 44 0 65 20 25 24 25 49 0 13-8 29t-19 29-18 36-9 47q0 45 33 71t81 25q44 0 74-25t31-69q0-23-10-43t-21-33-22-31-9-40q0-32 23-47t58-14q35 0 100 8t91 9v-1q-1-1-2-9t-3-19-2-12q-13-84-13-137 0-45 19-65 25-26 50-26 12 0 28 8t30 19 36 19 46 8q46 0 71-33t26-80z" horiz-adv-x="928.6" />
<glyph glyph-name="youtube" unicode="&#xf167;" d="M542 156v-118q0-37-22-37-13 0-25 12v168q12 12 25 12 22 0 22-37z m189-1v-25h-51v25q0 38 25 38t26-38z m-540 122h60v52h-174v-52h59v-318h55v318z m161-318h50v276h-50v-211q-17-23-32-23-10 0-11 11-1 2-1 20v203h-50v-218q0-28 5-41 7-21 32-21 27 0 57 34v-30z m240 83v110q0 41-5 55-10 31-40 31-28 0-52-30v121h-50v-370h50v27q25-31 52-31 30 0 40 31 5 15 5 56z m188 6v7h-51q0-29-1-34-4-20-22-20-26 0-26 38v49h100v57q0 44-15 65-22 28-59 28-38 0-60-28-15-21-15-65v-96q0-44 16-65 22-29 60-29 40 0 60 30 10 15 12 30 1 5 1 33z m-339 509v117q0 39-24 39t-24-39v-117q0-39 24-39t24 39z m401-419q0-131-14-195-8-33-33-56t-57-25q-102-12-309-12t-310 12q-32 3-57 25t-32 56q-15 62-15 195 0 131 15 195 7 33 32 56t57 26q103 11 310 11t309-11q33-4 58-26t32-56q14-62 14-195z m-557 712h57l-67-223v-151h-56v151q-8 42-34 119-21 57-37 104h60l39-147z m207-186v-97q0-46-16-66-21-29-59-29-37 0-59 29-15 21-15 66v97q0 45 15 66 22 28 59 28 38 0 59-28 16-21 16-66z m187 91v-279h-51v31q-30-35-58-35-25 0-33 21-4 13-4 42v220h51v-205q0-19 0-20 2-12 12-12 15 0 32 24v213h51z" horiz-adv-x="857.1" />
<glyph glyph-name="instagram" unicode="&#xf16d;" d="M571 350q0 59-41 101t-101 42-101-42-42-101 42-101 101-42 101 42 41 101z m77 0q0-91-64-156t-155-64-156 64-64 156 64 156 156 64 155-64 64-156z m61 229q0-21-15-36t-37-15-36 15-15 36 15 36 36 15 37-15 15-36z m-280 123q-4 0-43 0t-59 0-54-2-57-5-40-11q-28-11-49-32t-33-49q-6-16-10-40t-6-58-1-53 0-59 0-43 0-43 0-59 1-53 6-58 10-40q12-28 33-49t49-32q16-6 40-11t57-5 54-2 59 0 43 0 42 0 59 0 54 2 58 5 39 11q28 11 50 32t32 49q6 16 10 40t6 58 1 53 0 59 0 43 0 43 0 59-1 53-6 58-10 40q-11 28-32 49t-50 32q-16 6-39 11t-58 5-54 2-59 0-42 0z m428-352q0-128-3-177-5-116-69-180t-179-69q-50-3-177-3t-177 3q-116 6-180 69t-69 180q-3 49-3 177t3 177q5 116 69 180t180 69q49 3 177 3t177-3q116-6 179-69t69-180q3-49 3-177z" horiz-adv-x="857.1" />

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -9,7 +9,7 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -2,18 +2,25 @@
/**
* 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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/
class blog extends common {
const VERSION = '4.4';
const REALNAME = 'Blog';
const DELETE = true;
const UPDATE = '0.0';
const DATADIRECTORY = []; // Contenu localisé inclus par défaut (page.json et module.json)
const EDIT_OWNER = 'owner';
const EDIT_GROUP = 'group';
const EDIT_ALL = 'all';
@ -87,8 +94,6 @@ class blog extends common {
public static $users = [];
const BLOG_VERSION = '4.2';
/**
* Flux RSS
*/
@ -758,4 +763,3 @@ class blog extends common {
}
}
}

View File

@ -7,7 +7,7 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -1,11 +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 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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -1,11 +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 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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -1,154 +1,153 @@
<article>
<div class="row">
<div class="col10">
<div class="blogDate">
<i class="far fa-calendar-alt"></i>
<?php $date = mb_detect_encoding(strftime('%d %B %Y', $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn'])), 'UTF-8', true)
? strftime('%d %B %Y', $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn']))
: utf8_encode(strftime('%d %B %Y', $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn'])));
$heure = mb_detect_encoding(strftime('%H:%M', $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn'])), 'UTF-8', true)
? strftime('%H:%M', $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn']))
: utf8_encode(strftime('%H:%M', $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn'])));
echo $date . ' à ' . $heure;
?>
</div>
</div>
<div class="col2">
<?php if (
$this->getUser('password') === $this->getInput('ZWII_USER_PASSWORD')
AND
( // Propriétaire
(
$this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1),'editConsent']) === $module::EDIT_OWNER
AND ( $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1),'userId']) === $this->getUser('id')
OR $this->getUser('group') === self::GROUP_ADMIN )
)
OR (
// Groupe
( $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1),'editConsent']) === self::GROUP_ADMIN
OR $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1),'editConsent']) === self::GROUP_MODERATOR)
AND $this->getUser('group') >= $this->getData(['module',$this->getUrl(0), 'posts', $this->getUrl(1),'editConsent'])
)
OR (
// Tout le monde
$this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1),'editConsent']) === $module::EDIT_ALL
AND $this->getUser('group') >= $module::$actions['config']
)
)
): ?>
<?php echo template::button('blogEdit', [
'href' => helper::baseUrl() . $this->getUrl(0) . '/edit/' . $this->getUrl(1) . '/' . $_SESSION['csrf'],
'value' => 'Editer'
]); ?>
<?php endif; ?>
<div class="row">
<div class="col10">
<div class="blogDate">
<i class="far fa-calendar-alt"></i>
<?php $date = mb_detect_encoding(strftime('%d %B %Y', $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn'])), 'UTF-8', true)
? strftime('%d %B %Y', $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn']))
: utf8_encode(strftime('%d %B %Y', $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn'])));
$heure = mb_detect_encoding(strftime('%H:%M', $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn'])), 'UTF-8', true)
? strftime('%H:%M', $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn']))
: utf8_encode(strftime('%H:%M', $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn'])));
echo $date . ' à ' . $heure;
?>
</div>
</div>
<?php $pictureSize = $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'pictureSize']) === null ? '100' : $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'pictureSize']); ?>
<?php if ($this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'hidePicture']) == false) {
echo '<img class="blogArticlePicture blogArticlePicture' . $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'picturePosition']) .
' pict' . $pictureSize . '" src="' . helper::baseUrl(false) . self::FILE_DIR.'source/' . $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'picture']) .
'" alt="' . $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'picture']) . '">';
} ?>
<?php echo $this->getData(['module', $this->getUrl(0),'posts', $this->getUrl(1), 'content']); ?>
<p class="clearBoth signature"><?php echo $module::$articleSignature;?></p>
<!-- Bloc RSS-->
<?php if ($this->getData(['module',$this->getUrl(0), 'config', 'feeds'])): ?>
<div id="rssFeed">
<a type="application/rss+xml" href="<?php echo helper::baseUrl() . $this->getUrl(0) . '/rss'; ?> ">
<img src='module/news/ressource/feed-icon-16.gif' />
<?php
echo '<p>' . $this->getData(['module',$this->getUrl(0), 'config', 'feedsLabel']) . '</p>' ;
?>
</a>
</div>
<?php endif; ?>
<?php if($this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'commentClose'])): ?>
<p>Cet article ne reçoit pas de commentaire.</p>
<?php else: ?>
<h3 id="comment">
<?php //$commentsNb = count($module::$comments); ?>
<?php $commentsNb = $module::$nbCommentsApproved; ?>
<?php $s = $commentsNb === 1 ? '': 's' ?>
<?php echo $commentsNb > 0 ? $commentsNb . ' ' . 'commentaire' . $s : 'Pas encore de commentaire'; ?>
</h3>
<?php echo template::formOpen('blogArticleForm'); ?>
<?php echo template::text('blogArticleCommentShow', [
'placeholder' => 'Rédiger un commentaire...',
'readonly' => true
]); ?>
<div id="blogArticleCommentWrapper" class="displayNone">
<?php if($this->getUser('password') === $this->getInput('ZWII_USER_PASSWORD')): ?>
<?php echo template::text('blogArticleUserName', [
'label' => 'Nom',
'readonly' => true,
'value' => $module::$editCommentSignature
]); ?>
<?php echo template::hidden('blogArticleUserId', [
'value' => $this->getUser('id')
]); ?>
<?php else: ?>
<div class="row">
<div class="col9">
<?php echo template::text('blogArticleAuthor', [
'label' => 'Nom'
]); ?>
</div>
<div class="col1 textAlignCenter verticalAlignBottom">
<div id="blogArticleOr">Ou</div>
</div>
<div class="col2 verticalAlignBottom">
<?php echo template::button('blogArticleLogin', [
'href' => helper::baseUrl() . 'user/login/' . str_replace('/', '_', $this->getUrl()) . '__comment',
'value' => 'Connexion'
]); ?>
</div>
</div>
<?php endif; ?>
<?php echo template::textarea('blogArticleContent', [
'label' => 'Commentaire avec maximum '.$this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'commentMaxlength']).' caractères',
'class' => 'editorWysiwygComment',
'noDirty' => true,
'maxlength' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'commentMaxlength'])
<div class="col2">
<?php if (
$this->getUser('password') === $this->getInput('ZWII_USER_PASSWORD')
AND
( // Propriétaire
(
$this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1),'editConsent']) === $module::EDIT_OWNER
AND ( $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1),'userId']) === $this->getUser('id')
OR $this->getUser('group') === self::GROUP_ADMIN )
)
OR (
// Groupe
( $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1),'editConsent']) === self::GROUP_ADMIN
OR $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1),'editConsent']) === self::GROUP_MODERATOR)
AND $this->getUser('group') >= $this->getData(['module',$this->getUrl(0), 'posts', $this->getUrl(1),'editConsent'])
)
OR (
// Tout le monde
$this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1),'editConsent']) === $module::EDIT_ALL
AND $this->getUser('group') >= $module::$actions['config']
)
)
): ?>
<?php echo template::button('blogEdit', [
'href' => helper::baseUrl() . $this->getUrl(0) . '/edit/' . $this->getUrl(1) . '/' . $_SESSION['csrf'],
'value' => 'Editer'
]); ?>
<div id="blogArticleContentAlarm"> </div>
<?php if($this->getUser('password') !== $this->getInput('ZWII_USER_PASSWORD')): ?>
<div class="row">
<div class="col12">
<?php echo template::captcha('blogArticleCaptcha', [
'limit' => $this->getData(['config','captchaStrong'])
]); ?>
</div>
</div>
<?php endif; ?>
<?php endif; ?>
</div>
</div>
<?php $pictureSize = $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'pictureSize']) === null ? '100' : $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'pictureSize']); ?>
<?php if ($this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'hidePicture']) == false) {
echo '<img class="blogArticlePicture blogArticlePicture' . $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'picturePosition']) .
' pict' . $pictureSize . '" src="' . helper::baseUrl(false) . self::FILE_DIR.'source/' . $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'picture']) .
'" alt="' . $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'picture']) . '">';
} ?>
<?php echo $this->getData(['module', $this->getUrl(0),'posts', $this->getUrl(1), 'content']); ?>
<p class="clearBoth signature"><?php echo $module::$articleSignature;?></p>
<!-- Bloc RSS-->
<?php if ($this->getData(['module',$this->getUrl(0), 'config', 'feeds'])): ?>
<div id="rssFeed">
<a type="application/rss+xml" href="<?php echo helper::baseUrl() . $this->getUrl(0) . '/rss'; ?> ">
<img src='module/news/ressource/feed-icon-16.gif' />
<?php
echo '<p>' . $this->getData(['module',$this->getUrl(0), 'config', 'feedsLabel']) . '</p>' ;
?>
</a>
</div>
<?php endif; ?>
<?php if($this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'commentClose'])): ?>
<p>Cet article ne reçoit pas de commentaire.</p>
<?php else: ?>
<h3 id="comment">
<?php //$commentsNb = count($module::$comments); ?>
<?php $commentsNb = $module::$nbCommentsApproved; ?>
<?php $s = $commentsNb === 1 ? '': 's' ?>
<?php echo $commentsNb > 0 ? $commentsNb . ' ' . 'commentaire' . $s : 'Pas encore de commentaire'; ?>
</h3>
<?php echo template::formOpen('blogArticleForm'); ?>
<?php echo template::text('blogArticleCommentShow', [
'placeholder' => 'Rédiger un commentaire...',
'readonly' => true
]); ?>
<div id="blogArticleCommentWrapper" class="displayNone">
<?php if($this->getUser('password') === $this->getInput('ZWII_USER_PASSWORD')): ?>
<?php echo template::text('blogArticleUserName', [
'label' => 'Nom',
'readonly' => true,
'value' => $module::$editCommentSignature
]); ?>
<?php echo template::hidden('blogArticleUserId', [
'value' => $this->getUser('id')
]); ?>
<?php else: ?>
<div class="row">
<div class="col2 offset8">
<?php echo template::button('blogArticleCommentHide', [
'class' => 'buttonGrey',
'value' => 'Annuler'
<div class="col9">
<?php echo template::text('blogArticleAuthor', [
'label' => 'Nom'
]); ?>
</div>
<div class="col2">
<?php echo template::submit('blogArticleSubmit', [
'value' => 'Envoyer',
'ico' => ''
<div class="col1 textAlignCenter verticalAlignBottom">
<div id="blogArticleOr">Ou</div>
</div>
<div class="col2 verticalAlignBottom">
<?php echo template::button('blogArticleLogin', [
'href' => helper::baseUrl() . 'user/login/' . str_replace('/', '_', $this->getUrl()) . '__comment',
'value' => 'Connexion'
]); ?>
</div>
</div>
<?php endif; ?>
<?php echo template::textarea('blogArticleContent', [
'label' => 'Commentaire avec maximum '.$this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'commentMaxlength']).' caractères',
'class' => 'editorWysiwygComment',
'noDirty' => true,
'maxlength' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'commentMaxlength'])
]); ?>
<div id="blogArticleContentAlarm"> </div>
<?php if($this->getUser('password') !== $this->getInput('ZWII_USER_PASSWORD')): ?>
<div class="row">
<div class="col12">
<?php echo template::captcha('blogArticleCaptcha', [
'limit' => $this->getData(['config','captchaStrong'])
]); ?>
</div>
</div>
<?php endif; ?>
<div class="row">
<div class="col2 offset8">
<?php echo template::button('blogArticleCommentHide', [
'class' => 'buttonGrey',
'value' => 'Annuler'
]); ?>
</div>
<div class="col2">
<?php echo template::submit('blogArticleSubmit', [
'value' => 'Envoyer',
'ico' => ''
]); ?>
</div>
</div>
<?php endif;?>
<div class="row">
<div class="col12">
<?php foreach($module::$comments as $commentId => $comment): ?>
<div class="block">
<h4><?php echo $module::$commentsSignature[$commentId]; ?>
le <?php echo mb_detect_encoding(strftime('%d %B %Y - %H:%M', $comment['createdOn']), 'UTF-8', true)
? strftime('%d %B %Y - %H:%M', $comment['createdOn'])
: utf8_encode(strftime('%d %B %Y - %H:%M', $comment['createdOn']));
?>
<?php echo $comment['content']; ?>
</div>
<?php endforeach; ?>
</div>
<?php endif;?>
<div class="row">
<div class="col12">
<?php foreach($module::$comments as $commentId => $comment): ?>
<div class="block">
<h4><?php echo $module::$commentsSignature[$commentId]; ?>
le <?php echo mb_detect_encoding(strftime('%d %B %Y - %H:%M', $comment['createdOn']), 'UTF-8', true)
? strftime('%d %B %Y - %H:%M', $comment['createdOn'])
: utf8_encode(strftime('%d %B %Y - %H:%M', $comment['createdOn']));
?>
</h4>
<?php echo $comment['content']; ?>
</div>
<?php endforeach; ?>
</div>
<?php echo $module::$pages; ?>
</article>
</div>
<?php echo $module::$pages; ?>

View File

@ -7,7 +7,7 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -1,11 +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 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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -7,7 +7,7 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -1,11 +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 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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -47,6 +47,6 @@
<?php echo template::speech('Aucun article.'); ?>
<?php endif; ?>
<div class="moduleVersion">Version
<?php echo $module::BLOG_VERSION; ?>
<?php echo $module::VERSION; ?>
</div>

View File

@ -7,7 +7,7 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -1,11 +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 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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -21,7 +21,6 @@
</a>
</div>
<div class="col9">
<article>
<h1 class="blogTitle">
<a href="<?php echo helper::baseUrl() . $this->getUrl(0) . '/' . $articleId; ?>">
<?php echo $article['title']; ?>
@ -45,7 +44,6 @@
<?php echo helper::subword(strip_tags($article['content']), 0, 400); ?>...
<a href="<?php echo helper::baseUrl() . $this->getUrl(0) . '/' . $articleId; ?>">Lire la suite</a>
</p>
</article>
</div>
</div>
<?php endforeach; ?>

View File

@ -9,13 +9,19 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/
class form extends common {
const VERSION = '2.8';
const REALNAME = 'Formulaire';
const DELETE = true;
const UPDATE = '0.0';
const DATADIRECTORY = []; // Contenu localisé inclus par défaut (page.json et module.json)
public static $actions = [
'config' => self::GROUP_MODERATOR,
'data' => self::GROUP_MODERATOR,
@ -32,7 +38,6 @@ class form extends common {
public static $pagination;
const FORM_VERSION = '2.7';
// Objets
const TYPE_MAIL = 'mail';
@ -166,7 +171,7 @@ class form extends common {
/**
* Export CSV
* @author Frédéric Tempez <frederic.tempez@outlook.com>
* @copyright Copyright (C) 2018-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
*/
public function export2csv() {
// Jeton incorrect
@ -285,7 +290,7 @@ class form extends common {
if(
$this->getData(['module', $this->getUrl(0), 'config', 'captcha'])
// AND $this->getInput('formcaptcha', helper::FILTER_INT) !== $this->getInput('formcaptchaFirstNumber', helper::FILTER_INT) + $this->getInput('formcaptchaSecondNumber', helper::FILTER_INT))
AND password_verify($this->getInput('formCaptcha', helper::FILTER_INT), $this->getInput('formCaptchaResult') ) === false )
AND password_verify($this->getInput('formCaptcha', helper::FILTER_INT), $this->getInput('formCaptchaResult') ) === false )
{
self::$inputNotices['formCaptcha'] = 'Incorrect';

View File

@ -8,7 +8,7 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -1,11 +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 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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -164,5 +164,5 @@
</div>
<?php echo template::formClose(); ?>
<div class="moduleVersion">Version
<?php echo $module::FORM_VERSION; ?>
<?php echo $module::VERSION; ?>
</div>

View File

@ -7,7 +7,7 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -1,11 +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 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-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/

View File

@ -26,5 +26,5 @@
<?php echo template::table([11, 1], $module::$data, ['Données', '']); ?>
<?php echo $module::$pagination; ?>
<div class="moduleVersion">Version
<?php echo $module::FORM_VERSION; ?>
<?php echo $module::VERSION; ?>
</div>

View File

@ -9,17 +9,24 @@
* @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-2020, Frédéric Tempez
* @copyright Copyright (C) 2018-2021, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/
class gallery extends common {
const VERSION = '2.6';
const REALNAME = 'Galerie';
const DELETE = true;
const UPDATE = '0.0';
const DATADIRECTORY = []; // Contenu localisé inclus par défaut (page.json et module.json)
const SORT_ASC = 'SORT_ASC';
const SORT_DSC = 'SORT_DSC';
const SORT_HAND = 'SORT_HAND';
const GALLERY_VERSION = '2.5';
public static $directories = [];
@ -691,4 +698,4 @@ class galleriesHelper extends helper {
}
return $dirContent;
}
}
}

Some files were not shown because too many files have changed in this diff Show More