diff --git a/core/vendor/phpmailer/.htaccess b/core/class/.htaccess
old mode 100755
new mode 100644
similarity index 100%
rename from core/vendor/phpmailer/.htaccess
rename to core/class/.htaccess
diff --git a/core/vendor/sitemap/SitemapGenerator.php b/core/class/SitemapGenerator.class.php
similarity index 100%
rename from core/vendor/sitemap/SitemapGenerator.php
rename to core/class/SitemapGenerator.class.php
diff --git a/core/class/autoload.php b/core/class/autoload.php
new file mode 100644
index 00000000..53eac21b
--- /dev/null
+++ b/core/class/autoload.php
@@ -0,0 +1,13 @@
+ 'rgba(' . $rgba[0] . ',' . $rgba[1] . ',' . $rgba[2] . ',' . $rgba[3] . ')',
+ 'darken' => 'rgba(' . max(0, $rgba[0] - 15) . ',' . max(0, $rgba[1] - 15) . ',' . max(0, $rgba[2] - 15) . ',' . $rgba[3] . ')',
+ 'veryDarken' => 'rgba(' . max(0, $rgba[0] - 20) . ',' . max(0, $rgba[1] - 20) . ',' . max(0, $rgba[2] - 20) . ',' . $rgba[3] . ')',
+ 'text' => self::relativeLuminanceW3C($rgba) > .22 ? "inherit" : "white"
+ ];
+ }
+
+ /**
+ * Supprime un cookie
+ * @param string $cookieKey Clé du cookie à supprimer
+ */
+ public static function deleteCookie($cookieKey) {
+ unset($_COOKIE[$cookieKey]);
+ setcookie($cookieKey, '', time() - 3600, helper::baseUrl(false, false));
+ }
+
+ /**
+ * Filtre une chaîne en fonction d'un tableau de données
+ * @param string $text Chaîne à filtrer
+ * @param int $filter Type de filtre à appliquer
+ * @return string
+ */
+ public static function filter($text, $filter) {
+ $text = trim($text);
+ switch($filter) {
+ case self::FILTER_BOOLEAN:
+ $text = (bool) $text;
+ break;
+ case self::FILTER_DATETIME:
+ $timezone = new DateTimeZone(core::$timezone);
+ $date = new DateTime($text);
+ $date->setTimezone($timezone);
+ $text = (int) $date->format('U');
+ break;
+ case self::FILTER_FLOAT:
+ $text = filter_var($text, FILTER_SANITIZE_NUMBER_FLOAT);
+ $text = (float) $text;
+ break;
+ case self::FILTER_ID:
+ $text = mb_strtolower($text, 'UTF-8');
+ $text = strip_tags(str_replace(
+ explode(',', 'á,à,â,ä,ã,å,ç,é,è,ê,ë,í,ì,î,ï,ñ,ó,ò,ô,ö,õ,ú,ù,û,ü,ý,ÿ,\',", '),
+ explode(',', 'a,a,a,a,a,a,c,e,e,e,e,i,i,i,i,n,o,o,o,o,o,u,u,u,u,y,y,-,-,-'),
+ $text
+ ));
+ $text = preg_replace('/([^a-z0-9-])/', '', $text);
+ // Cas où un identifiant est vide
+ if (empty($text)) {
+ $text = uniqid('');
+ }
+ // Un ID ne peut pas être un entier, pour éviter les conflits avec le système de pagination
+ if(intval($text) !== 0) {
+ $text = 'i' . $text;
+ }
+ break;
+ case self::FILTER_INT:
+ $text = (int) filter_var($text, FILTER_SANITIZE_NUMBER_INT);
+ break;
+ case self::FILTER_MAIL:
+ $text = filter_var($text, FILTER_SANITIZE_EMAIL);
+ break;
+ case self::FILTER_PASSWORD:
+ $text = password_hash($text, PASSWORD_BCRYPT);
+ break;
+ case self::FILTER_STRING_LONG:
+ $text = mb_substr(filter_var($text, FILTER_SANITIZE_STRING), 0, 500000);
+ break;
+ case self::FILTER_STRING_SHORT:
+ $text = mb_substr(filter_var($text, FILTER_SANITIZE_STRING), 0, 500);
+ break;
+ case self::FILTER_TIMESTAMP:
+ $text = date('Y-m-d H:i:s', $text);
+ break;
+ case self::FILTER_URL:
+ $text = filter_var($text, FILTER_SANITIZE_URL);
+ break;
+ }
+ return get_magic_quotes_gpc() ? stripslashes($text) : $text;
+ }
+
+ /**
+ * Incrémente une clé en fonction des clés ou des valeurs d'un tableau
+ * @param mixed $key Clé à incrémenter
+ * @param array $array Tableau à vérifier
+ * @return string
+ */
+ public static function increment($key, $array = []) {
+ // Pas besoin d'incrémenter si la clef n'existe pas
+ if($array === []) {
+ return $key;
+ }
+ // Incrémente la clef
+ else {
+ // Si la clef est numérique elle est incrémentée
+ if(is_numeric($key)) {
+ $newKey = $key;
+ while(array_key_exists($newKey, $array) OR in_array($newKey, $array)) {
+ $newKey++;
+ }
+ }
+ // Sinon l'incrémentation est ajoutée après la clef
+ else {
+ $i = 2;
+ $newKey = $key;
+ while(array_key_exists($newKey, $array) OR in_array($newKey, $array)) {
+ $newKey = $key . '-' . $i;
+ $i++;
+ }
+ }
+ return $newKey;
+ }
+ }
+
+ /**
+ * Minimise du css
+ * @param string $css Css à minimiser
+ * @return string
+ */
+ public static function minifyCss($css) {
+ // Supprime les commentaires
+ $css = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $css);
+ // Supprime les tabulations, espaces, nouvelles lignes, etc...
+ $css = str_replace(["\r\n", "\r", "\n" ,"\t", ' ', ' ', ' '], '', $css);
+ $css = preg_replace(['(( )+{)', '({( )+)'], '{', $css);
+ $css = preg_replace(['(( )+})', '(}( )+)', '(;( )*})'], '}', $css);
+ $css = preg_replace(['(;( )+)', '(( )+;)'], ';', $css);
+ // Retourne le css minifié
+ return $css;
+ }
+
+ /**
+ * Minimise du js
+ * @param string $js Js à minimiser
+ * @return string
+ */
+ public static function minifyJs($js) {
+ // Supprime les commentaires
+ $js = preg_replace('/\\/\\*[^*]*\\*+([^\\/][^*]*\\*+)*\\/|\s*(?getUrl()
+ * @param string $item pagination nombre d'éléments par page
+ * @param null|int $sufix Suffixe de l'url
+ * @return array
+ */
+ public static function pagination($array, $url, $item, $sufix = null) {
+ // Scinde l'url
+ $url = explode('/', $url);
+ // Url de pagination
+ $urlPagination = is_numeric($url[count($url) - 1]) ? array_pop($url) : 1;
+ // Url de la page courante
+ $urlCurrent = implode('/', $url);
+ // Nombre d'éléments à afficher
+ $nbElements = count($array);
+ // Nombre de page
+ $nbPage = ceil($nbElements / $item);
+ // Page courante
+ $currentPage = is_numeric($urlPagination) ? self::filter($urlPagination, self::FILTER_INT) : 1;
+ // Premier élément de la page
+ $firstElement = ($currentPage - 1) * $item;
+ // Dernier élément de la page
+ $lastElement = $firstElement + $item;
+ $lastElement = ($lastElement > $nbElements) ? $nbElements : $lastElement;
+ // Mise en forme de la liste des pages
+ $pages = '';
+ if($nbPage > 1) {
+ for($i = 1; $i <= $nbPage; $i++) {
+ $disabled = ($i === $currentPage) ? ' class="disabled"' : false;
+ $pages .= '' . $i . '';
+ }
+ $pages = '
';
+ }
+ // Retourne un tableau contenant les informations sur la pagination
+ return [
+ 'first' => $firstElement,
+ 'last' => $lastElement,
+ 'pages' => $pages
+ ];
+ }
+
+ /**
+ * Calcul de la luminance relative d'une couleur
+ */
+ public static function relativeLuminanceW3C($rgba) {
+ // Conversion en sRGB
+ $RsRGB = $rgba[0] / 255;
+ $GsRGB = $rgba[1] / 255;
+ $BsRGB = $rgba[2] / 255;
+ // Ajout de la transparence
+ $RsRGBA = $rgba[3] * $RsRGB + (1 - $rgba[3]);
+ $GsRGBA = $rgba[3] * $GsRGB + (1 - $rgba[3]);
+ $BsRGBA = $rgba[3] * $BsRGB + (1 - $rgba[3]);
+ // Calcul de la luminance
+ $R = ($RsRGBA <= .03928) ? $RsRGBA / 12.92 : pow(($RsRGBA + .055) / 1.055, 2.4);
+ $G = ($GsRGBA <= .03928) ? $GsRGBA / 12.92 : pow(($GsRGBA + .055) / 1.055, 2.4);
+ $B = ($BsRGBA <= .03928) ? $BsRGBA / 12.92 : pow(($BsRGBA + .055) / 1.055, 2.4);
+ return .2126 * $R + .7152 * $G + .0722 * $B;
+ }
+
+ /**
+ * Retourne les attributs d'une balise au bon format
+ * @param array $array Liste des attributs ($key => $value)
+ * @param array $exclude Clés à ignorer ($key)
+ * @return string
+ */
+ public static function sprintAttributes(array $array = [], array $exclude = []) {
+ $exclude = array_merge(
+ [
+ 'before',
+ 'classWrapper',
+ 'help',
+ 'label'
+ ],
+ $exclude
+ );
+ $attributes = [];
+ foreach($array as $key => $value) {
+ if(($value OR $value === 0) AND in_array($key, $exclude) === false) {
+ // Désactive le message de modifications non enregistrées pour le champ
+ if($key === 'noDirty') {
+ $attributes[] = 'data-no-dirty';
+ }
+ // Disabled
+ // Readonly
+ elseif(in_array($key, ['disabled', 'readonly'])) {
+ $attributes[] = sprintf('%s', $key);
+ }
+ // Autres
+ else {
+ $attributes[] = sprintf('%s="%s"', $key, $value);
+ }
+ }
+ }
+ return implode(' ', $attributes);
+ }
+
+ /**
+ * Retourne un segment de chaîne sans couper de mot
+ * @param string $text Texte à scinder
+ * @param int $start (voir substr de PHP pour fonctionnement)
+ * @param int $length (voir substr de PHP pour fonctionnement)
+ * @return string
+ */
+ public static function subword($text, $start, $length) {
+ $text = trim($text);
+ if(strlen($text) > $length) {
+ $text = mb_substr($text, $start, $length);
+ $text = mb_substr($text, 0, min(mb_strlen($text), mb_strrpos($text, ' ')));
+ }
+ return $text;
+ }
+
+}
\ No newline at end of file
diff --git a/core/class/phpmailer/.htaccess b/core/class/phpmailer/.htaccess
new file mode 100644
index 00000000..3b355e3e
--- /dev/null
+++ b/core/class/phpmailer/.htaccess
@@ -0,0 +1,3 @@
+# Bloque l'accès à la librairie
+Order deny,allow
+Deny from all
\ No newline at end of file
diff --git a/core/vendor/phpmailer/exception.php b/core/class/phpmailer/exception.class.php
similarity index 100%
rename from core/vendor/phpmailer/exception.php
rename to core/class/phpmailer/exception.class.php
diff --git a/core/vendor/phpmailer/phpmailer.php b/core/class/phpmailer/phpmailer.class.php
similarity index 100%
rename from core/vendor/phpmailer/phpmailer.php
rename to core/class/phpmailer/phpmailer.class.php
diff --git a/core/class/template.class.php b/core/class/template.class.php
new file mode 100644
index 00000000..8c68199f
--- /dev/null
+++ b/core/class/template.class.php
@@ -0,0 +1,745 @@
+ $value)
+ * @return string
+ */
+ public static function button($nameId, array $attributes = []) {
+ // Attributs par défaut
+ $attributes = array_merge([
+ 'class' => '',
+ 'disabled' => false,
+ 'href' => 'javascript:void(0);',
+ 'ico' => '',
+ 'id' => $nameId,
+ 'name' => $nameId,
+ 'target' => '',
+ 'uniqueSubmission' => false,
+ 'value' => 'Bouton'
+ ], $attributes);
+ // Retourne le html
+ return sprintf(
+ '%s',
+ helper::sprintAttributes($attributes, ['class', 'disabled', 'ico', 'value']),
+ $attributes['disabled'] ? 'disabled' : '',
+ $attributes['class'],
+ $attributes['uniqueSubmission'] ? 'uniqueSubmission' : '',
+ ($attributes['ico'] ? template::ico($attributes['ico'], 'right') : '') . $attributes['value']
+ );
+ }
+
+ /**
+ * Crée un champ capcha
+ * @param string $nameId Nom et id du champ
+ * @param array $attributes Attributs ($key => $value)
+ * @return string
+ */
+ public static function capcha($nameId, array $attributes = []) {
+ // Attributs par défaut
+ $attributes = array_merge([
+ 'class' => '',
+ 'classWrapper' => '',
+ 'help' => '',
+ 'id' => $nameId,
+ 'name' => $nameId,
+ 'value' => ''
+ ], $attributes);
+ // Génère deux nombres pour le capcha
+ $firstNumber = mt_rand(1, 15);
+ $secondNumber = mt_rand(1, 15);
+ // Début du wrapper
+ $html = '';
+ // Label
+ $html .= self::label($attributes['id'], $firstNumber . ' + ' . $secondNumber . ' = ?', [
+ 'help' => $attributes['help']
+ ]);
+ // Notice
+ $notice = '';
+ if(array_key_exists($attributes['id'], common::$inputNotices)) {
+ $notice = common::$inputNotices[$attributes['id']];
+ $attributes['class'] .= ' notice';
+ }
+ $html .= self::notice($attributes['id'], $notice);
+ // Capcha
+ $html .= sprintf(
+ '',
+ helper::sprintAttributes($attributes)
+ );
+ // Champs cachés contenant les nombres
+ $html .= self::hidden($attributes['id'] . 'FirstNumber', [
+ 'value' => $firstNumber,
+ 'before' => false
+ ]);
+ $html .= self::hidden($attributes['id'] . 'SecondNumber', [
+ 'value' => $secondNumber,
+ 'before' => false
+ ]);
+ // Fin du wrapper
+ $html .= '
';
+ // Retourne le html
+ return $html;
+ }
+
+ /**
+ * Crée une case à cocher à sélection multiple
+ * @param string $nameId Nom et id du champ
+ * @param string $value Valeur de la case à cocher
+ * @param string $label Label de la case à cocher
+ * @param array $attributes Attributs ($key => $value)
+ * @return string
+ */
+ public static function checkbox($nameId, $value, $label, array $attributes = []) {
+ // Attributs par défaut
+ $attributes = array_merge([
+ 'before' => true,
+ 'checked' => '',
+ 'class' => '',
+ 'classWrapper' => '',
+ 'disabled' => false,
+ 'help' => '',
+ 'id' => $nameId,
+ 'name' => $nameId
+ ], $attributes);
+ // Sauvegarde des données en cas d'erreur
+ if($attributes['before'] AND array_key_exists($attributes['id'], common::$inputBefore)) {
+ $attributes['checked'] = (bool) common::$inputBefore[$attributes['id']];
+ }
+ // Début du wrapper
+ $html = '';
+ // Notice
+ $notice = '';
+ if(array_key_exists($attributes['id'], common::$inputNotices)) {
+ $notice = common::$inputNotices[$attributes['id']];
+ $attributes['class'] .= ' notice';
+ }
+ $html .= self::notice($attributes['id'], $notice);
+ // Case à cocher
+ $html .= sprintf(
+ '',
+ $value,
+ helper::sprintAttributes($attributes)
+ );
+ // Label
+ $html .= self::label($attributes['id'], '' . $label . '', [
+ 'help' => $attributes['help']
+ ]);
+ // Fin du wrapper
+ $html .= '
';
+ // Retourne le html
+ return $html;
+ }
+
+ /**
+ * Crée un champ date
+ * @param string $nameId Nom et id du champ
+ * @param array $attributes Attributs ($key => $value)
+ * @return string
+ */
+ public static function date($nameId, array $attributes = []) {
+ // Attributs par défaut
+ $attributes = array_merge([
+ 'autocomplete' => 'on',
+ 'before' => true,
+ 'class' => '',
+ 'classWrapper' => '',
+ 'noDirty' => false,
+ 'disabled' => false,
+ 'help' => '',
+ 'id' => $nameId,
+ 'label' => '',
+ 'name' => $nameId,
+ 'placeholder' => '',
+ 'readonly' => true,
+ 'value' => ''
+ ], $attributes);
+ // Sauvegarde des données en cas d'erreur
+ if($attributes['before'] AND array_key_exists($attributes['id'], common::$inputBefore)) {
+ $attributes['value'] = common::$inputBefore[$attributes['id']];
+ }
+ else {
+ $attributes['value'] = ($attributes['value'] ? helper::filter($attributes['value'], helper::FILTER_TIMESTAMP) : '');
+ }
+ // Début du wrapper
+ $html = '';
+ // Label
+ if($attributes['label']) {
+ $html .= self::label($attributes['id'], $attributes['label'], [
+ 'help' => $attributes['help']
+ ]);
+ }
+ // Notice
+ $notice = '';
+ if(array_key_exists($attributes['id'], common::$inputNotices)) {
+ $notice = common::$inputNotices[$attributes['id']];
+ $attributes['class'] .= ' notice';
+ }
+ $html .= self::notice($attributes['id'], $notice);
+ // Date visible
+ $html .= sprintf(
+ '',
+ $attributes['class'],
+ $attributes['value'],
+ helper::sprintAttributes($attributes, ['class', 'value'])
+ );
+ // Fin du wrapper
+ $html .= '
';
+ // Retourne le html
+ return $html;
+ }
+
+ /**
+ * Crée un champ d'upload de fichier
+ * @param string $nameId Nom et id du champ
+ * @param array $attributes Attributs ($key => $value)
+ * @return string
+ */
+ public static function file($nameId, array $attributes = []) {
+ // Attributs par défaut
+ $attributes = array_merge([
+ 'before' => true,
+ 'class' => '',
+ 'classWrapper' => '',
+ 'noDirty' => false,
+ 'disabled' => false,
+ 'extensions' => '',
+ 'help' => '',
+ 'id' => $nameId,
+ 'label' => '',
+ 'maxlength' => '500',
+ 'name' => $nameId,
+ 'type' => 2,
+ 'value' => ''
+ ], $attributes);
+ // Sauvegarde des données en cas d'erreur
+ if($attributes['before'] AND array_key_exists($attributes['id'], common::$inputBefore)) {
+ $attributes['value'] = common::$inputBefore[$attributes['id']];
+ }
+ // Début du wrapper
+ $html = '';
+ // Retourne le html
+ return $html;
+ }
+
+ /**
+ * Ferme un formulaire
+ * @return string
+ */
+ public static function formClose() {
+ return '';
+ }
+
+ /**
+ * Ouvre un formulaire protégé par CSRF
+ * @param string $id Id du formulaire
+ * @return string
+ */
+ public static function formOpen($id) {
+ // Ouverture formulaire
+ $html = '';
- }
-
- /**
- * Ouvre un formulaire protégé par CSRF
- * @param string $id Id du formulaire
- * @return string
- */
- public static function formOpen($id) {
- // Ouverture formulaire
- $html = '