Compare commits
1 Commits
046c23f2d2
...
feature/da
| Author | SHA1 | Date | |
|---|---|---|---|
| 77e7cf5d85 |
38
.env.example
Normal file
38
.env.example
Normal file
@@ -0,0 +1,38 @@
|
||||
# Configuration de l'environnement
|
||||
APP_ENV=development
|
||||
APP_DEBUG=true
|
||||
APP_URL=http://localhost
|
||||
|
||||
# Configuration de la base de données
|
||||
DB_HOST=maria3
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=cleo
|
||||
DB_USERNAME=cleo_user
|
||||
DB_PASSWORD=your_password_here
|
||||
|
||||
# Configuration de logging
|
||||
LOG_LEVEL=debug
|
||||
LOG_SQL=true
|
||||
LOG_PERFORMANCE=true
|
||||
|
||||
# Configuration email (PHPMailer)
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=smtp.example.com
|
||||
MAIL_PORT=587
|
||||
MAIL_USERNAME=
|
||||
MAIL_PASSWORD=
|
||||
MAIL_ENCRYPTION=tls
|
||||
MAIL_FROM_ADDRESS=noreply@example.com
|
||||
MAIL_FROM_NAME="CLEO App"
|
||||
|
||||
# Configuration de sécurité
|
||||
EXCLUDE_IP=
|
||||
SESSION_LIFETIME=120
|
||||
SESSION_SECURE_COOKIE=false
|
||||
|
||||
# Configuration des chemins
|
||||
UPLOAD_PATH=/pub/files/upload/
|
||||
|
||||
# Clés API (si nécessaire)
|
||||
API_KEY=
|
||||
API_SECRET=
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -32,7 +32,7 @@ pub/files/upload/*
|
||||
# Sauvegardes
|
||||
*.bak
|
||||
*.backup
|
||||
*.sql
|
||||
# *.sql
|
||||
backup/
|
||||
backups/
|
||||
|
||||
@@ -40,4 +40,4 @@ backups/
|
||||
sessions/
|
||||
|
||||
# Fichiers système
|
||||
Thumbs.db
|
||||
Thumbs.db*.swp
|
||||
|
||||
33
CLAUDE.md
Normal file
33
CLAUDE.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Instructions pour Claude Code
|
||||
|
||||
## R<>gles importantes
|
||||
|
||||
### 1. VALIDATION OBLIGATOIRE
|
||||
**<2A> TOUJOURS attendre la validation de l'utilisateur avant de commencer <20> coder !**
|
||||
- Pr<50>senter d'abord le plan d'action
|
||||
- Expliquer ce qui va <20>tre fait
|
||||
- Attendre un "ok", "vas-y", "c'est bon" ou <20>quivalent avant de coder
|
||||
|
||||
### 2. Contexte du projet CLEO
|
||||
- Application PHP 8.3 de gestion de devis pour PME
|
||||
- Architecture MVC avec framework maison "d6"
|
||||
- Base de donn<6E>es MariaDB sur serveur distant "maria3"
|
||||
|
||||
### 3. Conventions de code
|
||||
- Utiliser PDO pour toutes les connexions <20> la base de donn<6E>es
|
||||
- Requ<71>tes pr<70>par<61>es obligatoires (pas de concat<61>nation SQL)
|
||||
- Variables d'environnement pour les credentials (.env)
|
||||
- Pas de commentaires dans le code sauf si demand<6E> explicitement
|
||||
|
||||
### 4. S<>curit<69>
|
||||
- Ne jamais exposer les mots de passe en clair
|
||||
- Toujours valider et nettoyer les entr<74>es utilisateur
|
||||
- Utiliser password_hash() avec bcrypt pour les mots de passe
|
||||
|
||||
### 5. Git
|
||||
- Branche principale : main
|
||||
- Format des branches : feature/nom-fonctionnalit<69>-version
|
||||
- Commits atomiques avec messages clairs
|
||||
|
||||
---
|
||||
*Document cr<63><72> le 11 septembre 2025*
|
||||
229
config/Database.php
Normal file
229
config/Database.php
Normal file
@@ -0,0 +1,229 @@
|
||||
<?php
|
||||
|
||||
class Database {
|
||||
private static $instance = null;
|
||||
private $pdo;
|
||||
private $host;
|
||||
private $dbname;
|
||||
private $username;
|
||||
private $password;
|
||||
private $charset = 'utf8mb4';
|
||||
private $options = [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_EMULATE_PREPARES => false,
|
||||
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci"
|
||||
];
|
||||
|
||||
private function __construct() {
|
||||
$this->loadEnvironment();
|
||||
$this->connect();
|
||||
}
|
||||
|
||||
private function loadEnvironment() {
|
||||
$envFile = dirname(__DIR__) . '/.env';
|
||||
if (file_exists($envFile)) {
|
||||
$lines = file($envFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||
foreach ($lines as $line) {
|
||||
if (strpos(trim($line), '#') === 0) continue;
|
||||
|
||||
list($name, $value) = explode('=', $line, 2);
|
||||
$name = trim($name);
|
||||
$value = trim($value);
|
||||
|
||||
if (!isset($_ENV[$name])) {
|
||||
putenv(sprintf('%s=%s', $name, $value));
|
||||
$_ENV[$name] = $value;
|
||||
$_SERVER[$name] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->host = $_ENV['DB_HOST'] ?? 'localhost';
|
||||
$this->dbname = $_ENV['DB_DATABASE'] ?? 'cleo';
|
||||
$this->username = $_ENV['DB_USERNAME'] ?? 'root';
|
||||
$this->password = $_ENV['DB_PASSWORD'] ?? '';
|
||||
}
|
||||
|
||||
private function connect() {
|
||||
try {
|
||||
$dsn = "mysql:host={$this->host};dbname={$this->dbname};charset={$this->charset}";
|
||||
$this->pdo = new PDO($dsn, $this->username, $this->password, $this->options);
|
||||
|
||||
if ($_ENV['LOG_SQL'] ?? false) {
|
||||
$this->logConnection(true);
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
if ($_ENV['APP_DEBUG'] ?? false) {
|
||||
throw new Exception("Erreur de connexion à la base de données: " . $e->getMessage());
|
||||
} else {
|
||||
throw new Exception("Erreur de connexion à la base de données");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function getInstance() {
|
||||
if (self::$instance === null) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
public function getPDO() {
|
||||
return $this->pdo;
|
||||
}
|
||||
|
||||
public function query($sql, $params = []) {
|
||||
$start = microtime(true);
|
||||
|
||||
try {
|
||||
if (empty($params)) {
|
||||
$stmt = $this->pdo->query($sql);
|
||||
} else {
|
||||
$stmt = $this->pdo->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
}
|
||||
|
||||
$this->logQuery($sql, $params, microtime(true) - $start);
|
||||
return $stmt;
|
||||
|
||||
} catch (PDOException $e) {
|
||||
$this->logError($sql, $params, $e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
public function fetchAll($sql, $params = []) {
|
||||
$stmt = $this->query($sql, $params);
|
||||
return $stmt->fetchAll();
|
||||
}
|
||||
|
||||
public function fetchOne($sql, $params = []) {
|
||||
$stmt = $this->query($sql, $params);
|
||||
return $stmt->fetch();
|
||||
}
|
||||
|
||||
public function fetchColumn($sql, $params = [], $column = 0) {
|
||||
$stmt = $this->query($sql, $params);
|
||||
return $stmt->fetchColumn($column);
|
||||
}
|
||||
|
||||
public function insert($table, $data) {
|
||||
$columns = array_keys($data);
|
||||
$values = array_map(function($col) { return ':' . $col; }, $columns);
|
||||
|
||||
$sql = sprintf(
|
||||
"INSERT INTO %s (%s) VALUES (%s)",
|
||||
$table,
|
||||
implode(', ', $columns),
|
||||
implode(', ', $values)
|
||||
);
|
||||
|
||||
$this->query($sql, $data);
|
||||
return $this->pdo->lastInsertId();
|
||||
}
|
||||
|
||||
public function update($table, $data, $where, $whereParams = []) {
|
||||
$set = [];
|
||||
foreach ($data as $column => $value) {
|
||||
$set[] = "$column = :set_$column";
|
||||
}
|
||||
|
||||
$sql = sprintf(
|
||||
"UPDATE %s SET %s WHERE %s",
|
||||
$table,
|
||||
implode(', ', $set),
|
||||
$where
|
||||
);
|
||||
|
||||
$params = [];
|
||||
foreach ($data as $column => $value) {
|
||||
$params["set_$column"] = $value;
|
||||
}
|
||||
$params = array_merge($params, $whereParams);
|
||||
|
||||
$stmt = $this->query($sql, $params);
|
||||
return $stmt->rowCount();
|
||||
}
|
||||
|
||||
public function delete($table, $where, $params = []) {
|
||||
$sql = "DELETE FROM $table WHERE $where";
|
||||
$stmt = $this->query($sql, $params);
|
||||
return $stmt->rowCount();
|
||||
}
|
||||
|
||||
public function beginTransaction() {
|
||||
return $this->pdo->beginTransaction();
|
||||
}
|
||||
|
||||
public function commit() {
|
||||
return $this->pdo->commit();
|
||||
}
|
||||
|
||||
public function rollback() {
|
||||
return $this->pdo->rollBack();
|
||||
}
|
||||
|
||||
public function lastInsertId() {
|
||||
return $this->pdo->lastInsertId();
|
||||
}
|
||||
|
||||
private function logQuery($sql, $params, $executionTime) {
|
||||
// Debug désactivé pour les requêtes SQL
|
||||
return;
|
||||
}
|
||||
|
||||
private function logError($sql, $params, $error) {
|
||||
// On garde seulement le log d'erreur dans error_log, pas de debug
|
||||
error_log("SQL Error: $error | Query: $sql");
|
||||
}
|
||||
|
||||
private function logConnection($success) {
|
||||
// Debug désactivé pour les connexions
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function getinfos($sql, $dbn = "gen", $format = "normal") {
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
$result = $db->fetchAll($sql);
|
||||
|
||||
if (strtolower($format) == "json") {
|
||||
return json_encode($result);
|
||||
}
|
||||
return $result;
|
||||
|
||||
} catch (Exception $e) {
|
||||
if ($_ENV['APP_DEBUG'] ?? false) {
|
||||
error_log("Erreur getinfos: " . $e->getMessage());
|
||||
}
|
||||
return ($format == "json") ? json_encode([]) : [];
|
||||
}
|
||||
}
|
||||
|
||||
function qSQL($sql, $dbn = "gen", $lastid = false) {
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
|
||||
$queryType = strtoupper(substr(trim($sql), 0, 6));
|
||||
|
||||
if ($queryType === 'INSERT' || $queryType === 'UPDATE' || $queryType === 'DELETE') {
|
||||
$stmt = $db->query($sql);
|
||||
|
||||
if ($lastid && $queryType === 'INSERT') {
|
||||
return $db->lastInsertId();
|
||||
}
|
||||
|
||||
return $stmt;
|
||||
} else {
|
||||
return $db->query($sql);
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
if ($_ENV['APP_DEBUG'] ?? false) {
|
||||
error_log("Erreur qSQL: " . $e->getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
219
config/conf.php
219
config/conf.php
@@ -1,17 +1,19 @@
|
||||
<?php
|
||||
|
||||
require_once dirname(__FILE__) . '/Database.php';
|
||||
|
||||
class Conf
|
||||
{
|
||||
const admin = 1; // TRUE ou FALSE pour indiquer si l'application est admin ou non
|
||||
const intra = 1; // Est-ce un intranet privé TRUE 1, ou un site public FALSE 0
|
||||
const erp = 1; //! Est-ce un ERP ? Utile pour la gestion documentaire avec les paths spéciaux pour l'ERP
|
||||
const magazine = 0; //! Est-ce qu'on veut transformer les PDF en JPG pour la lecture Magazine dans le d6tools.upload ?
|
||||
const admin = 1;
|
||||
const intra = 1;
|
||||
const erp = 1;
|
||||
const magazine = 0;
|
||||
|
||||
public $_appname;
|
||||
public $_appscript;
|
||||
public $_appversion;
|
||||
public $_appname = "cleo";
|
||||
public $_appscript = "login";
|
||||
public $_appversion = "2.0.1";
|
||||
public $_appenv;
|
||||
public $_apptitle;
|
||||
public $_apptitle = "CLEO - Gestion de devis";
|
||||
|
||||
public $_brandname;
|
||||
public $_brandadresse1;
|
||||
@@ -27,83 +29,107 @@ class Conf
|
||||
public $_piwikid;
|
||||
public $_googlid;
|
||||
|
||||
public $_excludeIp = "90.59.145.27"; //! IP à exclure pour le comptage des visites et pour le debug
|
||||
public $_excludeIp;
|
||||
public $_clientIp;
|
||||
public $_devIp = false;
|
||||
|
||||
public $_pathupload = "/pub/files/upload/"; //! le path de base pour les uploads
|
||||
public $_debug_level = 0;
|
||||
public $_log_sql = false;
|
||||
public $_log_performance = false;
|
||||
public $_log_file_path = '';
|
||||
|
||||
//! les infos de connexion de la base de données
|
||||
public $_dbhost = 'localhost';
|
||||
public $_dbname = 'uof_frontal';
|
||||
public $_dbuser = 'uof_front_user';
|
||||
public $_dbpass = 'd66,UnikOffice.User';
|
||||
public $_pathupload;
|
||||
|
||||
public $_dbghost = 'localhost';
|
||||
public $_dbgname = '';
|
||||
public $_dbguser = 'uof_linet_user';
|
||||
public $_dbgpass = 'd66,UOF-LinetRH.User';
|
||||
public $_dbhost;
|
||||
public $_dbname;
|
||||
public $_dbuser;
|
||||
public $_dbpass;
|
||||
|
||||
public $_dbuhost = 'localhost';
|
||||
public $_dbuname = '';
|
||||
public $_dbuuser = 'uof_linet_user';
|
||||
public $_dbupass = 'd66,UOF-LinetRH.User';
|
||||
|
||||
public $_tbusers = ""; // Spécifie la table des users de cette application, par défaut uof_frontal.users, mais sur Linet c'est dans uof_linet.commerciaux
|
||||
|
||||
//! les infos de l'entité de l'utilisateur
|
||||
public $_entite = '';
|
||||
|
||||
//! indique si c'est une nouvelle version pour les tests de nouveaux modules et librairies
|
||||
public $_new_version = false;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
//! on va chercher la configuration de l'application dans la table ce_frontal.y_conf
|
||||
$mysqli = new mysqli($this->_dbhost, $this->_dbuser, $this->_dbpass, $this->_dbname);
|
||||
$sql = 'SELECT * FROM y_conf WHERE admin=' . self::admin . ' AND active=1 LIMIT 1;';
|
||||
$mysqli->set_charset("utf8");
|
||||
$res = $mysqli->query($sql);
|
||||
$resconf = $res->fetch_assoc();
|
||||
$this->_appenv = $resconf["appenv"];
|
||||
$this->_appversion = $resconf["appversion"];
|
||||
$this->_appscript = $resconf["appscript"]; //! le script à appeler par défaut si l'utilisateur n'est pas reconnu
|
||||
|
||||
$this->_brandgroupe = $resconf["brandgroupe"];
|
||||
$this->_brandmulti = $resconf["brandmulti"];
|
||||
|
||||
//! On va chercher les infos de base de cette appname dans ce_frontal.users_entites en fonction du http_host
|
||||
$http_host = $_SERVER['HTTP_HOST'];
|
||||
error_log("http_host : ".$http_host);
|
||||
$sql = 'SELECT * FROM users_entites WHERE http_host LIKE "%' . $http_host . '%" AND active=1 LIMIT 1;';
|
||||
$res = $mysqli->query($sql);
|
||||
$mysqli->close();
|
||||
$resentite = $res->fetch_assoc();
|
||||
if (empty($resentite)) {
|
||||
//! on ne trouve pas ce http_host, on part sur la demo
|
||||
$this->_appname = "udo_demo";
|
||||
$mysqli = new mysqli($this->_dbhost, $this->_dbuser, $this->_dbpass, $this->_dbname);
|
||||
$sql = 'SELECT * FROM users_entites WHERE rowid=1;'; // appname="' . $this->_appname . '" AND active=1 LIMIT 1;';
|
||||
$res = $mysqli->query($sql);
|
||||
$mysqli->close();
|
||||
$resentite = $res->fetch_assoc();
|
||||
$this->loadEnvironment();
|
||||
$this->loadConfiguration();
|
||||
$this->setupDebug();
|
||||
}
|
||||
$this->_entite = $resentite;
|
||||
$this->_appname = $resentite["appname"];
|
||||
$this->_apptitle = $resentite["libelle"];
|
||||
$this->_brandname = $resentite["libelle"];
|
||||
$this->_brandadresse1 = $resentite["adresse1"];
|
||||
$this->_brandadresse2 = $resentite["adresse2"];
|
||||
$this->_brandcp = $resentite["cp"];
|
||||
$this->_brandville = $resentite["ville"];
|
||||
$this->_brandtel = $resentite["tel1"];
|
||||
$this->_brandemail = $resentite["email"];
|
||||
$this->_brandlogo = $resentite["appname"];
|
||||
|
||||
$this->_dbgname = $resentite["groupebase"];
|
||||
$this->_dbuname = $resentite["genbase"];
|
||||
$this->_tbusers = $resentite["table_users_gen"]; //! Spécifie la table des users de cette application, par défaut dans uof_frontal.users
|
||||
private function loadEnvironment() {
|
||||
$envFile = dirname(__DIR__) . '/.env';
|
||||
if (file_exists($envFile)) {
|
||||
$lines = file($envFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||
foreach ($lines as $line) {
|
||||
if (strpos(trim($line), '#') === 0) continue;
|
||||
|
||||
list($name, $value) = explode('=', $line, 2);
|
||||
$name = trim($name);
|
||||
$value = trim($value);
|
||||
|
||||
if (!isset($_ENV[$name])) {
|
||||
putenv(sprintf('%s=%s', $name, $value));
|
||||
$_ENV[$name] = $value;
|
||||
$_SERVER[$name] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->_dbhost = $_ENV['DB_HOST'] ?? 'localhost';
|
||||
$this->_dbname = $_ENV['DB_DATABASE'] ?? 'cleo';
|
||||
$this->_dbuser = $_ENV['DB_USERNAME'] ?? 'cleo_user';
|
||||
$this->_dbpass = $_ENV['DB_PASSWORD'] ?? '';
|
||||
|
||||
$this->_excludeIp = $_ENV['EXCLUDE_IP'] ?? '';
|
||||
$this->_pathupload = $_ENV['UPLOAD_PATH'] ?? '/pub/files/upload/';
|
||||
|
||||
$this->_appenv = $_ENV['APP_ENV'] ?? 'production';
|
||||
$this->_debug_level = $_ENV['LOG_LEVEL'] === 'debug' ? 4 : 0;
|
||||
$this->_log_sql = filter_var($_ENV['LOG_SQL'] ?? false, FILTER_VALIDATE_BOOLEAN);
|
||||
$this->_log_performance = filter_var($_ENV['LOG_PERFORMANCE'] ?? false, FILTER_VALIDATE_BOOLEAN);
|
||||
}
|
||||
|
||||
private function loadConfiguration() {
|
||||
$http_host = $_SERVER['HTTP_HOST'];
|
||||
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
|
||||
$sql = "SELECT * FROM users_entites WHERE http_host LIKE :host AND active = 1 LIMIT 1";
|
||||
$entite = $db->fetchOne($sql, ['host' => "%$http_host%"]);
|
||||
|
||||
if (empty($entite)) {
|
||||
$sql = "SELECT * FROM users_entites WHERE rowid = 1";
|
||||
$entite = $db->fetchOne($sql);
|
||||
}
|
||||
|
||||
if ($entite) {
|
||||
$this->_entite = $entite;
|
||||
$this->_appname = $entite["appname"] ?? "cleo";
|
||||
$this->_apptitle = $entite["libelle"] ?? "CLEO";
|
||||
$this->_brandname = $entite["libelle"] ?? "";
|
||||
$this->_brandadresse1 = $entite["adresse1"] ?? "";
|
||||
$this->_brandadresse2 = $entite["adresse2"] ?? "";
|
||||
$this->_brandcp = $entite["cp"] ?? "";
|
||||
$this->_brandville = $entite["ville"] ?? "";
|
||||
$this->_brandtel = $entite["tel1"] ?? "";
|
||||
$this->_brandemail = $entite["email"] ?? "";
|
||||
$this->_brandlogo = $entite["appname"] ?? "cleo";
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log("Erreur de configuration: " . $e->getMessage());
|
||||
$this->setDefaultConfiguration();
|
||||
}
|
||||
}
|
||||
|
||||
private function setDefaultConfiguration() {
|
||||
$this->_appname = "cleo";
|
||||
$this->_apptitle = "CLEO - Gestion de devis";
|
||||
$this->_brandname = "CLEO";
|
||||
$this->_brandemail = $_ENV['MAIL_FROM_ADDRESS'] ?? "noreply@example.com";
|
||||
}
|
||||
|
||||
private function setupDebug() {
|
||||
if (!empty($_SERVER["HTTP_CLIENT_IP"])) {
|
||||
$this->_clientIp = $_SERVER["HTTP_CLIENT_IP"];
|
||||
} elseif (!empty($_SERVER["HTTP_X_FORWARDED_FOR"])) {
|
||||
@@ -111,13 +137,52 @@ class Conf
|
||||
} else {
|
||||
$this->_clientIp = $_SERVER["REMOTE_ADDR"];
|
||||
}
|
||||
//if ($this->_clientIp == $this->_excludeIp) {
|
||||
|
||||
$http_host = $_SERVER['HTTP_HOST'] ?? '';
|
||||
$isDev = strpos($http_host, 'dcleo.unikoffice.com') !== false;
|
||||
$isRecette = strpos($http_host, 'rcleo.unikoffice.com') !== false;
|
||||
$isDebugEnv = $_ENV['APP_DEBUG'] === 'true' || $_ENV['APP_ENV'] === 'development';
|
||||
|
||||
if ($isDev || $isRecette || $isDebugEnv) {
|
||||
ini_set('error_reporting', -1);
|
||||
ini_set('display_errors', '1');
|
||||
// $this->_devIp = true;
|
||||
//} else {
|
||||
// ini_set('error_reporting', 0);
|
||||
// ini_set('display_errors', '0');
|
||||
//}
|
||||
$this->_devIp = true;
|
||||
|
||||
$this->_debug_level = 4;
|
||||
$this->_log_sql = true;
|
||||
$this->_log_performance = true;
|
||||
$this->_log_file_path = dirname(__DIR__) . '/log/' . date('md') . '.log';
|
||||
|
||||
ini_set('log_errors', '1');
|
||||
ini_set('error_log', $this->_log_file_path);
|
||||
ini_set('display_startup_errors', '1');
|
||||
} else {
|
||||
ini_set('error_reporting', 0);
|
||||
ini_set('display_errors', '0');
|
||||
ini_set('log_errors', '0');
|
||||
$this->_debug_level = 0;
|
||||
$this->_log_sql = false;
|
||||
$this->_log_performance = false;
|
||||
}
|
||||
}
|
||||
|
||||
public function debug($data, $type = 'DEBUG', $level = 3) {
|
||||
if ($this->_debug_level < $level) return;
|
||||
|
||||
$levels = ['ERROR', 'WARNING', 'INFO', 'DEBUG'];
|
||||
$timestamp = date('Y-m-d H:i:s');
|
||||
$message = "[$timestamp] [$type] " . (is_array($data) ? json_encode($data) : $data) . PHP_EOL;
|
||||
|
||||
if ($this->_log_file_path) {
|
||||
error_log($message, 3, $this->_log_file_path);
|
||||
}
|
||||
|
||||
// Ne pas afficher les commentaires HTML pour les requêtes AJAX
|
||||
$isAjax = !empty($_SERVER['HTTP_X_REQUESTED_WITH']) &&
|
||||
strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest';
|
||||
|
||||
if ($this->_devIp && ini_get('display_errors') && !$isAjax) {
|
||||
echo "<!-- $message -->\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
184
config/conf_new.php
Normal file
184
config/conf_new.php
Normal file
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
require_once dirname(__FILE__) . '/Database.php';
|
||||
|
||||
class Conf
|
||||
{
|
||||
const admin = 1;
|
||||
const intra = 1;
|
||||
const erp = 1;
|
||||
const magazine = 0;
|
||||
|
||||
public $_appname = "cleo";
|
||||
public $_appscript = "login";
|
||||
public $_appversion = "2.0.1";
|
||||
public $_appenv;
|
||||
public $_apptitle = "CLEO - Gestion de devis";
|
||||
|
||||
public $_brandname;
|
||||
public $_brandadresse1;
|
||||
public $_brandadresse2;
|
||||
public $_brandcp;
|
||||
public $_brandville;
|
||||
public $_brandtel;
|
||||
public $_brandemail;
|
||||
public $_brandlogo;
|
||||
public $_brandgroupe;
|
||||
public $_brandmulti;
|
||||
|
||||
public $_piwikid;
|
||||
public $_googlid;
|
||||
|
||||
public $_excludeIp;
|
||||
public $_clientIp;
|
||||
public $_devIp = false;
|
||||
|
||||
public $_debug_level = 0;
|
||||
public $_log_sql = false;
|
||||
public $_log_performance = false;
|
||||
public $_log_file_path = '';
|
||||
|
||||
public $_pathupload;
|
||||
|
||||
public $_dbhost;
|
||||
public $_dbname;
|
||||
public $_dbuser;
|
||||
public $_dbpass;
|
||||
|
||||
public $_entite = '';
|
||||
public $_new_version = false;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->loadEnvironment();
|
||||
$this->loadConfiguration();
|
||||
$this->setupDebug();
|
||||
}
|
||||
|
||||
private function loadEnvironment() {
|
||||
$envFile = dirname(__DIR__) . '/.env';
|
||||
if (file_exists($envFile)) {
|
||||
$lines = file($envFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||
foreach ($lines as $line) {
|
||||
if (strpos(trim($line), '#') === 0) continue;
|
||||
|
||||
list($name, $value) = explode('=', $line, 2);
|
||||
$name = trim($name);
|
||||
$value = trim($value);
|
||||
|
||||
if (!isset($_ENV[$name])) {
|
||||
putenv(sprintf('%s=%s', $name, $value));
|
||||
$_ENV[$name] = $value;
|
||||
$_SERVER[$name] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->_dbhost = $_ENV['DB_HOST'] ?? 'localhost';
|
||||
$this->_dbname = $_ENV['DB_DATABASE'] ?? 'cleo';
|
||||
$this->_dbuser = $_ENV['DB_USERNAME'] ?? 'cleo_user';
|
||||
$this->_dbpass = $_ENV['DB_PASSWORD'] ?? '';
|
||||
|
||||
$this->_excludeIp = $_ENV['EXCLUDE_IP'] ?? '';
|
||||
$this->_pathupload = $_ENV['UPLOAD_PATH'] ?? '/pub/files/upload/';
|
||||
|
||||
$this->_appenv = $_ENV['APP_ENV'] ?? 'production';
|
||||
$this->_debug_level = $_ENV['LOG_LEVEL'] === 'debug' ? 4 : 0;
|
||||
$this->_log_sql = filter_var($_ENV['LOG_SQL'] ?? false, FILTER_VALIDATE_BOOLEAN);
|
||||
$this->_log_performance = filter_var($_ENV['LOG_PERFORMANCE'] ?? false, FILTER_VALIDATE_BOOLEAN);
|
||||
}
|
||||
|
||||
private function loadConfiguration() {
|
||||
$http_host = $_SERVER['HTTP_HOST'];
|
||||
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
|
||||
$sql = "SELECT * FROM users_entites WHERE http_host LIKE :host AND active = 1 LIMIT 1";
|
||||
$entite = $db->fetchOne($sql, ['host' => "%$http_host%"]);
|
||||
|
||||
if (empty($entite)) {
|
||||
$sql = "SELECT * FROM users_entites WHERE rowid = 1";
|
||||
$entite = $db->fetchOne($sql);
|
||||
}
|
||||
|
||||
if ($entite) {
|
||||
$this->_entite = $entite;
|
||||
$this->_appname = $entite["appname"] ?? "cleo";
|
||||
$this->_apptitle = $entite["libelle"] ?? "CLEO";
|
||||
$this->_brandname = $entite["libelle"] ?? "";
|
||||
$this->_brandadresse1 = $entite["adresse1"] ?? "";
|
||||
$this->_brandadresse2 = $entite["adresse2"] ?? "";
|
||||
$this->_brandcp = $entite["cp"] ?? "";
|
||||
$this->_brandville = $entite["ville"] ?? "";
|
||||
$this->_brandtel = $entite["tel1"] ?? "";
|
||||
$this->_brandemail = $entite["email"] ?? "";
|
||||
$this->_brandlogo = $entite["appname"] ?? "cleo";
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log("Erreur de configuration: " . $e->getMessage());
|
||||
$this->setDefaultConfiguration();
|
||||
}
|
||||
}
|
||||
|
||||
private function setDefaultConfiguration() {
|
||||
$this->_appname = "cleo";
|
||||
$this->_apptitle = "CLEO - Gestion de devis";
|
||||
$this->_brandname = "CLEO";
|
||||
$this->_brandemail = $_ENV['MAIL_FROM_ADDRESS'] ?? "noreply@example.com";
|
||||
}
|
||||
|
||||
private function setupDebug() {
|
||||
if (!empty($_SERVER["HTTP_CLIENT_IP"])) {
|
||||
$this->_clientIp = $_SERVER["HTTP_CLIENT_IP"];
|
||||
} elseif (!empty($_SERVER["HTTP_X_FORWARDED_FOR"])) {
|
||||
$this->_clientIp = $_SERVER["HTTP_X_FORWARDED_FOR"];
|
||||
} else {
|
||||
$this->_clientIp = $_SERVER["REMOTE_ADDR"];
|
||||
}
|
||||
|
||||
$http_host = $_SERVER['HTTP_HOST'] ?? '';
|
||||
$isDev = strpos($http_host, 'dcleo.unikoffice.com') !== false;
|
||||
$isRecette = strpos($http_host, 'rcleo.unikoffice.com') !== false;
|
||||
$isDebugEnv = $_ENV['APP_DEBUG'] === 'true' || $_ENV['APP_ENV'] === 'development';
|
||||
|
||||
if ($isDev || $isRecette || $isDebugEnv) {
|
||||
ini_set('error_reporting', -1);
|
||||
ini_set('display_errors', '1');
|
||||
$this->_devIp = true;
|
||||
|
||||
$this->_debug_level = 4;
|
||||
$this->_log_sql = true;
|
||||
$this->_log_performance = true;
|
||||
$this->_log_file_path = dirname(__DIR__) . '/log/' . $this->_appname . '_debug_' . date('Y-m-d') . '.log';
|
||||
|
||||
ini_set('log_errors', '1');
|
||||
ini_set('error_log', $this->_log_file_path);
|
||||
ini_set('display_startup_errors', '1');
|
||||
} else {
|
||||
ini_set('error_reporting', 0);
|
||||
ini_set('display_errors', '0');
|
||||
ini_set('log_errors', '0');
|
||||
$this->_debug_level = 0;
|
||||
$this->_log_sql = false;
|
||||
$this->_log_performance = false;
|
||||
}
|
||||
}
|
||||
|
||||
public function debug($data, $type = 'DEBUG', $level = 3) {
|
||||
if ($this->_debug_level < $level) return;
|
||||
|
||||
$levels = ['ERROR', 'WARNING', 'INFO', 'DEBUG'];
|
||||
$timestamp = date('Y-m-d H:i:s');
|
||||
$message = "[$timestamp] [$type] " . (is_array($data) ? json_encode($data) : $data) . PHP_EOL;
|
||||
|
||||
if ($this->_log_file_path) {
|
||||
error_log($message, 3, $this->_log_file_path);
|
||||
}
|
||||
|
||||
if ($this->_devIp && ini_get('display_errors')) {
|
||||
echo "<!-- $message -->\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
148
config/conf_old.php
Normal file
148
config/conf_old.php
Normal file
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
class Conf
|
||||
{
|
||||
const admin = 1; // TRUE ou FALSE pour indiquer si l'application est admin ou non
|
||||
const intra = 1; // Est-ce un intranet privé TRUE 1, ou un site public FALSE 0
|
||||
const erp = 1; //! Est-ce un ERP ? Utile pour la gestion documentaire avec les paths spéciaux pour l'ERP
|
||||
const magazine = 0; //! Est-ce qu'on veut transformer les PDF en JPG pour la lecture Magazine dans le d6tools.upload ?
|
||||
|
||||
public $_appname;
|
||||
public $_appscript;
|
||||
public $_appversion;
|
||||
public $_appenv;
|
||||
public $_apptitle;
|
||||
|
||||
public $_brandname;
|
||||
public $_brandadresse1;
|
||||
public $_brandadresse2;
|
||||
public $_brandcp;
|
||||
public $_brandville;
|
||||
public $_brandtel;
|
||||
public $_brandemail;
|
||||
public $_brandlogo;
|
||||
public $_brandgroupe;
|
||||
public $_brandmulti;
|
||||
|
||||
public $_piwikid;
|
||||
public $_googlid;
|
||||
|
||||
public $_excludeIp = "82.67.142.214"; //! IP à exclure pour le comptage des visites et pour le debug
|
||||
public $_clientIp;
|
||||
public $_devIp = false;
|
||||
|
||||
//! Configuration du debug
|
||||
public $_debug_level = 0; //! 0=off, 1=errors, 2=warnings, 3=info, 4=debug
|
||||
public $_log_sql = false; //! Logger les requêtes SQL
|
||||
public $_log_performance = false; //! Logger les temps d'exécution
|
||||
public $_log_file_path = ''; //! Chemin du fichier de log
|
||||
|
||||
public $_pathupload = "/pub/files/upload/"; //! le path de base pour les uploads
|
||||
|
||||
//! les infos de connexion de la base de données
|
||||
public $_dbhost = 'localhost';
|
||||
public $_dbname = 'uof_frontal';
|
||||
public $_dbuser = 'uof_front_user';
|
||||
public $_dbpass = 'd66,UnikOffice.User';
|
||||
|
||||
public $_dbghost = 'localhost';
|
||||
public $_dbgname = '';
|
||||
public $_dbguser = 'uof_linet_user';
|
||||
public $_dbgpass = 'd66,UOF-LinetRH.User';
|
||||
|
||||
public $_dbuhost = 'localhost';
|
||||
public $_dbuname = '';
|
||||
public $_dbuuser = 'uof_linet_user';
|
||||
public $_dbupass = 'd66,UOF-LinetRH.User';
|
||||
|
||||
public $_tbusers = ""; // Spécifie la table des users de cette application, par défaut uof_frontal.users, mais sur Linet c'est dans uof_linet.commerciaux
|
||||
|
||||
//! les infos de l'entité de l'utilisateur
|
||||
public $_entite = '';
|
||||
|
||||
//! indique si c'est une nouvelle version pour les tests de nouveaux modules et librairies
|
||||
public $_new_version = false;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
//! on va chercher la configuration de l'application dans la table ce_frontal.y_conf
|
||||
$mysqli = new mysqli($this->_dbhost, $this->_dbuser, $this->_dbpass, $this->_dbname);
|
||||
$sql = 'SELECT * FROM y_conf WHERE admin=' . self::admin . ' AND active=1 LIMIT 1;';
|
||||
$mysqli->set_charset("utf8");
|
||||
$res = $mysqli->query($sql);
|
||||
$resconf = $res->fetch_assoc();
|
||||
$this->_appenv = $resconf["appenv"];
|
||||
$this->_appversion = "2.0.1";
|
||||
$this->_appscript = $resconf["appscript"]; //! le script à appeler par défaut si l'utilisateur n'est pas reconnu
|
||||
|
||||
$this->_brandgroupe = $resconf["brandgroupe"];
|
||||
$this->_brandmulti = $resconf["brandmulti"];
|
||||
|
||||
//! On va chercher les infos de base de cette appname dans ce_frontal.users_entites en fonction du http_host
|
||||
$http_host = $_SERVER['HTTP_HOST'];
|
||||
error_log("http_host : ".$http_host);
|
||||
$sql = 'SELECT * FROM users_entites WHERE http_host LIKE "%' . $http_host . '%" AND active=1 LIMIT 1;';
|
||||
$res = $mysqli->query($sql);
|
||||
$mysqli->close();
|
||||
$resentite = $res->fetch_assoc();
|
||||
if (empty($resentite)) {
|
||||
//! on ne trouve pas ce http_host, on part sur la demo
|
||||
$this->_appname = "udo_demo";
|
||||
$mysqli = new mysqli($this->_dbhost, $this->_dbuser, $this->_dbpass, $this->_dbname);
|
||||
$sql = 'SELECT * FROM users_entites WHERE rowid=1;'; // appname="' . $this->_appname . '" AND active=1 LIMIT 1;';
|
||||
$res = $mysqli->query($sql);
|
||||
$mysqli->close();
|
||||
$resentite = $res->fetch_assoc();
|
||||
}
|
||||
$this->_entite = $resentite;
|
||||
$this->_appname = $resentite["appname"];
|
||||
$this->_apptitle = $resentite["libelle"];
|
||||
$this->_brandname = $resentite["libelle"];
|
||||
$this->_brandadresse1 = $resentite["adresse1"];
|
||||
$this->_brandadresse2 = $resentite["adresse2"];
|
||||
$this->_brandcp = $resentite["cp"];
|
||||
$this->_brandville = $resentite["ville"];
|
||||
$this->_brandtel = $resentite["tel1"];
|
||||
$this->_brandemail = $resentite["email"];
|
||||
$this->_brandlogo = $resentite["appname"];
|
||||
|
||||
$this->_dbgname = $resentite["groupebase"];
|
||||
$this->_dbuname = $resentite["genbase"];
|
||||
$this->_tbusers = $resentite["table_users_gen"]; //! Spécifie la table des users de cette application, par défaut dans uof_frontal.users
|
||||
|
||||
if (!empty($_SERVER["HTTP_CLIENT_IP"])) {
|
||||
$this->_clientIp = $_SERVER["HTTP_CLIENT_IP"];
|
||||
} elseif (!empty($_SERVER["HTTP_X_FORWARDED_FOR"])) {
|
||||
$this->_clientIp = $_SERVER["HTTP_X_FORWARDED_FOR"];
|
||||
} else {
|
||||
$this->_clientIp = $_SERVER["REMOTE_ADDR"];
|
||||
}
|
||||
// Active le debug uniquement pour dev et recette
|
||||
if (strpos($http_host, 'dcleo.unikoffice.com') !== false || strpos($http_host, 'rcleo.unikoffice.com') !== false) {
|
||||
ini_set('error_reporting', -1);
|
||||
ini_set('display_errors', '1');
|
||||
$this->_devIp = true;
|
||||
|
||||
// Configuration avancée du debug pour dev/recette
|
||||
$this->_debug_level = 4; // Niveau debug complet
|
||||
$this->_log_sql = true; // Logger les requêtes SQL
|
||||
$this->_log_performance = true; // Mesurer les performances
|
||||
$this->_log_file_path = dirname(__DIR__) . '/log/' . $this->_appname . '_debug_' . date('Y-m-d') . '.log';
|
||||
|
||||
// Options PHP supplémentaires pour le debug
|
||||
ini_set('log_errors', '1');
|
||||
ini_set('error_log', $this->_log_file_path);
|
||||
ini_set('display_startup_errors', '1');
|
||||
ini_set('track_errors', '1');
|
||||
ini_set('html_errors', '1');
|
||||
ini_set('xmlrpc_errors', '0');
|
||||
} else {
|
||||
ini_set('error_reporting', 0);
|
||||
ini_set('display_errors', '0');
|
||||
ini_set('log_errors', '0');
|
||||
$this->_debug_level = 0;
|
||||
$this->_log_sql = false;
|
||||
$this->_log_performance = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
106
config/init.php
106
config/init.php
@@ -23,3 +23,109 @@ require_once FMKROOT . DS . 'd6_tools.php';
|
||||
|
||||
//! Chargement des fichiers spécifiques au projet
|
||||
require_once FMKROOT . DS . 'lib_cleo.php';
|
||||
|
||||
//! Handler d'exceptions global
|
||||
function exception_handler($exception) {
|
||||
global $Conf;
|
||||
|
||||
$error_data = array(
|
||||
'type' => 'EXCEPTION',
|
||||
'message' => $exception->getMessage(),
|
||||
'file' => $exception->getFile(),
|
||||
'line' => $exception->getLine(),
|
||||
'code' => $exception->getCode(),
|
||||
'trace' => $exception->getTraceAsString()
|
||||
);
|
||||
|
||||
// Logger l'exception
|
||||
if (isset($Conf->_debug_level) && $Conf->_debug_level > 0) {
|
||||
debug($error_data, "UNCAUGHT_EXCEPTION", 1);
|
||||
}
|
||||
|
||||
// Logger dans la table z_logs
|
||||
eLog(0, "Exception non gérée: " . $exception->getMessage() . " dans " . $exception->getFile() . ":" . $exception->getLine());
|
||||
|
||||
// Afficher une erreur propre à l'utilisateur
|
||||
if (isset($Conf->_devIp) && $Conf->_devIp && ini_get('display_errors')) {
|
||||
// En mode dev, afficher les détails
|
||||
echo "<div style='background:#fee; border:2px solid #c00; padding:20px; margin:20px; font-family:monospace;'>";
|
||||
echo "<h2 style='color:#c00;'>Exception non gérée</h2>";
|
||||
echo "<p><strong>Message:</strong> " . htmlspecialchars($exception->getMessage()) . "</p>";
|
||||
echo "<p><strong>Fichier:</strong> " . htmlspecialchars($exception->getFile()) . " ligne " . $exception->getLine() . "</p>";
|
||||
echo "<p><strong>Code:</strong> " . $exception->getCode() . "</p>";
|
||||
echo "<pre style='background:#fff; padding:10px; overflow:auto;'>" . htmlspecialchars($exception->getTraceAsString()) . "</pre>";
|
||||
echo "</div>";
|
||||
} else {
|
||||
// En production, afficher un message générique
|
||||
echo "<div style='text-align:center; padding:50px;'>";
|
||||
echo "<h2>Une erreur est survenue</h2>";
|
||||
echo "<p>Nous nous excusons pour la gêne occasionnée. L'erreur a été enregistrée.</p>";
|
||||
echo "<p><a href='/'>Retour à l'accueil</a></p>";
|
||||
echo "</div>";
|
||||
}
|
||||
}
|
||||
|
||||
//! Handler d'erreurs global
|
||||
function error_handler($errno, $errstr, $errfile, $errline) {
|
||||
global $Conf;
|
||||
|
||||
// Vérifier si l'erreur doit être rapportée selon error_reporting
|
||||
if (!(error_reporting() & $errno)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$error_types = array(
|
||||
E_ERROR => 'ERROR',
|
||||
E_WARNING => 'WARNING',
|
||||
E_PARSE => 'PARSE',
|
||||
E_NOTICE => 'NOTICE',
|
||||
E_CORE_ERROR => 'CORE_ERROR',
|
||||
E_CORE_WARNING => 'CORE_WARNING',
|
||||
E_COMPILE_ERROR => 'COMPILE_ERROR',
|
||||
E_COMPILE_WARNING => 'COMPILE_WARNING',
|
||||
E_USER_ERROR => 'USER_ERROR',
|
||||
E_USER_WARNING => 'USER_WARNING',
|
||||
E_USER_NOTICE => 'USER_NOTICE',
|
||||
E_STRICT => 'STRICT',
|
||||
E_RECOVERABLE_ERROR => 'RECOVERABLE_ERROR',
|
||||
E_DEPRECATED => 'DEPRECATED',
|
||||
E_USER_DEPRECATED => 'USER_DEPRECATED'
|
||||
);
|
||||
|
||||
$error_type = isset($error_types[$errno]) ? $error_types[$errno] : 'UNKNOWN';
|
||||
|
||||
$error_data = array(
|
||||
'type' => $error_type,
|
||||
'errno' => $errno,
|
||||
'message' => $errstr,
|
||||
'file' => $errfile,
|
||||
'line' => $errline
|
||||
);
|
||||
|
||||
// Déterminer le niveau de debug pour ce type d'erreur
|
||||
$debug_level = 4; // Par défaut niveau le plus bas
|
||||
if (in_array($errno, array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR))) {
|
||||
$debug_level = 1; // Erreurs critiques
|
||||
} elseif (in_array($errno, array(E_WARNING, E_CORE_WARNING, E_COMPILE_WARNING, E_USER_WARNING))) {
|
||||
$debug_level = 2; // Warnings
|
||||
} elseif (in_array($errno, array(E_NOTICE, E_USER_NOTICE))) {
|
||||
$debug_level = 3; // Notices
|
||||
}
|
||||
|
||||
// Logger l'erreur
|
||||
if (isset($Conf->_debug_level) && $Conf->_debug_level >= $debug_level) {
|
||||
debug($error_data, "PHP_ERROR", $debug_level);
|
||||
}
|
||||
|
||||
// Pour les erreurs critiques, logger aussi dans z_logs
|
||||
if ($debug_level == 1) {
|
||||
eLog(0, "Erreur PHP $error_type: $errstr dans $errfile:$errline");
|
||||
}
|
||||
|
||||
// Ne pas exécuter le handler d'erreur PHP interne
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Enregistrer les handlers
|
||||
set_exception_handler('exception_handler');
|
||||
set_error_handler('error_handler');
|
||||
|
||||
@@ -161,9 +161,11 @@ switch ($Route->_action) {
|
||||
$sql = "SELECT rowid, CONCAT(firstname, ' ', name) AS libelle FROM contacts WHERE fk_soc=" . $fk_tiers . " ORDER BY libelle;";
|
||||
$res = qSQL($sql, "groupe");
|
||||
$arr = array();
|
||||
while ($rec = $res->fetch_assoc()) {
|
||||
if ($res instanceof PDOStatement) {
|
||||
while ($rec = $res->fetch(PDO::FETCH_ASSOC)) {
|
||||
$arr[] = $rec;
|
||||
}
|
||||
}
|
||||
$jsonresult = json_encode($arr);
|
||||
$lignes = $jsonresult;
|
||||
echo $lignes;
|
||||
|
||||
105
deploy-cleo-dev.sh
Executable file
105
deploy-cleo-dev.sh
Executable file
@@ -0,0 +1,105 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script de déploiement de Cleo vers l'environnement de développement
|
||||
|
||||
cd /home/pierre/dev/cleo
|
||||
|
||||
# Configuration du serveur hôte Debian 12
|
||||
HOST_SSH_HOST=195.154.80.116 # Adresse IP du serveur hôte
|
||||
HOST_SSH_USER=root # Utilisateur SSH sur le serveur hôte
|
||||
HOST_SSH_PORT=22 # Port SSH du serveur hôte
|
||||
HOST_SSH_KEY=/home/pierre/.ssh/id_rsa_mbpi # Clé SSH privée pour accéder au serveur hôte
|
||||
|
||||
# Configuration du conteneur Incus hébergeant cette application
|
||||
CT_PROJECT_NAME=default # Nom du projet Incus où se trouve le conteneur
|
||||
CT_NAME=dva-front # Nom du conteneur Incus
|
||||
CT_IP=13.23.33.42 # IP interne du conteneur Incus
|
||||
CT_SSH_USER=root # Utilisateur SSH dans le conteneur
|
||||
CT_SSH_PORT=22 # Port SSH interne du conteneur
|
||||
CT_SSH_KEY=/root/.ssh/id_rsa_in3_pierre # Clé SSH privée pour accéder au conteneur
|
||||
|
||||
# Configuration de l'application
|
||||
DOMAIN_NAME=dcleo.unikoffice.com # Nom de domaine du site
|
||||
SERVER_PORT=3000 # Port du serveur Node.js
|
||||
ADMIN_PORT=3001 # Port du serveur d'administration
|
||||
DEPLOY_DIR=/var/www # Répertoire de déploiement sur le conteneur
|
||||
APP_NAME=cleo # Nom de l'application et du fichier de config nginx
|
||||
|
||||
# Propriétaire et groupe pour les fichiers et dossiers de destination
|
||||
OWNER=nginx
|
||||
GROUP=nginx
|
||||
|
||||
# Vérifier que les variables nécessaires sont définies
|
||||
if [ -z "$HOST_SSH_HOST" ] || [ -z "$HOST_SSH_USER" ] || [ -z "$CT_NAME" ] || [ -z "$CT_PROJECT_NAME" ]; then
|
||||
echo "Erreur: Variables HOST_SSH_HOST, HOST_SSH_USER, CT_NAME et CT_PROJECT_NAME requises dans $ENV_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Variables pour les alertes (optionnelles)
|
||||
ALERT_EMAIL=${ALERT_EMAIL:-""}
|
||||
DISCORD_WEBHOOK_URL=${DISCORD_WEBHOOK_URL:-""}
|
||||
|
||||
# Utiliser les valeurs par défaut si non définies
|
||||
HOST_SSH_PORT=${HOST_SSH_PORT:-22}
|
||||
SERVER_PORT=${SERVER_PORT:-3000}
|
||||
ADMIN_PORT=${ADMIN_PORT:-3001}
|
||||
DOMAIN_NAME=${DOMAIN_NAME:-$CT_IP}
|
||||
DEPLOY_DIR=${DEPLOY_DIR:-/var/www}
|
||||
APP_NAME=${APP_NAME:-d6soft}
|
||||
SUB_DIR=${SUB_DIR:-web}
|
||||
|
||||
# Afficher les paramètres
|
||||
echo "=== Paramètres de déploiement ==="
|
||||
echo "Serveur hôte: $HOST_SSH_USER@$HOST_SSH_HOST:$HOST_SSH_PORT"
|
||||
echo "Projet Incus: $CT_PROJECT_NAME"
|
||||
echo "Conteneur: $CT_NAME"
|
||||
echo "Domaine: $DOMAIN_NAME"
|
||||
echo "Répertoire de déploiement: $DEPLOY_DIR/$APP_NAME"
|
||||
echo "Propriétaire: $OWNER"
|
||||
echo "Groupe: $GROUP"
|
||||
echo "=================================="
|
||||
|
||||
# Définir les options SSH
|
||||
SSH_OPTS="-p $HOST_SSH_PORT"
|
||||
SCP_OPTS="-P $HOST_SSH_PORT"
|
||||
if [ ! -z "$HOST_SSH_KEY" ]; then
|
||||
SSH_OPTS="$SSH_OPTS -i \"$HOST_SSH_KEY\""
|
||||
SCP_OPTS="$SCP_OPTS -i \"$HOST_SSH_KEY\""
|
||||
fi
|
||||
|
||||
# 1. Copier les fichiers vers le HOST incus
|
||||
echo "=== Copie des fichiers vers le HOST Incus ==="
|
||||
rsync -avz --progress --exclude='.git' --exclude='log/*.log' --exclude='pub/files/upload' -e "ssh $SSH_OPTS" ./ $HOST_SSH_USER@$HOST_SSH_HOST:/tmp/$APP_NAME/
|
||||
|
||||
# 2. Créer le répertoire de destination dans le conteneur
|
||||
echo "=== Création du répertoire de destination dans le conteneur ==="
|
||||
eval "ssh $SSH_OPTS $HOST_SSH_USER@$HOST_SSH_HOST \"incus project switch $CT_PROJECT_NAME\""
|
||||
eval "ssh $SSH_OPTS $HOST_SSH_USER@$HOST_SSH_HOST \"incus exec $CT_NAME -- mkdir -p $DEPLOY_DIR/$APP_NAME\""
|
||||
|
||||
# 3. Transférer les fichiers vers le conteneur Incus
|
||||
echo "=== Transfert des fichiers vers le conteneur Incus ==="
|
||||
eval "ssh $SSH_OPTS $HOST_SSH_USER@$HOST_SSH_HOST \"incus file push --recursive /tmp/$APP_NAME/. $CT_NAME/$DEPLOY_DIR/\""
|
||||
|
||||
# 4. Configurer les permissions dans le conteneur
|
||||
echo "=== Configuration des permissions dans le conteneur ==="
|
||||
eval "ssh $SSH_OPTS $HOST_SSH_USER@$HOST_SSH_HOST \"incus exec $CT_NAME -- sh -c 'chown -R $OWNER:$GROUP $DEPLOY_DIR/$APP_NAME && \
|
||||
find $DEPLOY_DIR/$APP_NAME -type d -exec chmod 755 {} \\; && \
|
||||
find $DEPLOY_DIR/$APP_NAME -type f -exec chmod 644 {} \\; && \
|
||||
mkdir -p $DEPLOY_DIR/$APP_NAME/log && \
|
||||
chmod 775 $DEPLOY_DIR/$APP_NAME/log && \
|
||||
chown $OWNER:$GROUP $DEPLOY_DIR/$APP_NAME/log && \
|
||||
if [ -d $DEPLOY_DIR/$APP_NAME/pub/files/upload ]; then chmod 775 $DEPLOY_DIR/$APP_NAME/pub/files/upload; fi && \
|
||||
if [ -d $DEPLOY_DIR/$APP_NAME/server/logs ]; then chmod 775 $DEPLOY_DIR/$APP_NAME/server/logs; fi && \
|
||||
if [ -d $DEPLOY_DIR/$APP_NAME/mda/backend/logs ]; then chmod 775 $DEPLOY_DIR/$APP_NAME/mda/backend/logs; fi && \
|
||||
if [ -d $DEPLOY_DIR/$APP_NAME/mda/db ]; then chmod 775 $DEPLOY_DIR/$APP_NAME/mda/db; fi'\""
|
||||
|
||||
# 5. Nettoyer les fichiers temporaires sur l'hôte
|
||||
echo "=== Nettoyage des fichiers temporaires sur l'hôte ==="
|
||||
eval "ssh $SSH_OPTS $HOST_SSH_USER@$HOST_SSH_HOST \"rm -rf /tmp/$APP_NAME\""
|
||||
|
||||
echo "==================================================="
|
||||
echo "Déploiement terminé avec succès !"
|
||||
echo "==================================================="
|
||||
echo "Votre site $APP_NAME est maintenant déployé dans le conteneur $CT_NAME."
|
||||
echo "Chemin de déploiement: $DEPLOY_DIR/$APP_NAME"
|
||||
echo "Le dossier log a été créé avec les permissions 775 et appartient à $OWNER:$GROUP"
|
||||
151
deploy-cleo-fast.sh
Executable file
151
deploy-cleo-fast.sh
Executable file
@@ -0,0 +1,151 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script de déploiement optimisé de Cleo vers l'environnement de développement
|
||||
# Version: 2.0 - Utilise tar.gz pour un transfert plus rapide
|
||||
|
||||
cd /home/pierre/dev/cleo
|
||||
|
||||
# Configuration du serveur hôte Debian 12
|
||||
HOST_SSH_HOST=195.154.80.116 # Adresse IP du serveur hôte
|
||||
HOST_SSH_USER=root # Utilisateur SSH sur le serveur hôte
|
||||
HOST_SSH_PORT=22 # Port SSH du serveur hôte
|
||||
HOST_SSH_KEY=/home/pierre/.ssh/id_rsa_mbpi # Clé SSH privée pour accéder au serveur hôte
|
||||
|
||||
# Configuration du conteneur Incus hébergeant cette application
|
||||
CT_PROJECT_NAME=default # Nom du projet Incus où se trouve le conteneur
|
||||
CT_NAME=dva-front # Nom du conteneur Incus
|
||||
CT_IP=13.23.33.42 # IP interne du conteneur Incus
|
||||
DEPLOY_DIR=/var/www # Répertoire de déploiement sur le conteneur
|
||||
APP_NAME=cleo # Nom de l'application
|
||||
|
||||
# Propriétaire et groupe pour les fichiers et dossiers de destination
|
||||
OWNER=nginx
|
||||
GROUP=nginx
|
||||
|
||||
# Couleurs pour l'affichage
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Définir les options SSH
|
||||
SSH_OPTS="-p $HOST_SSH_PORT"
|
||||
if [ ! -z "$HOST_SSH_KEY" ]; then
|
||||
SSH_OPTS="$SSH_OPTS -i $HOST_SSH_KEY"
|
||||
fi
|
||||
|
||||
# Afficher les paramètres
|
||||
echo -e "${GREEN}=== Déploiement optimisé CLEO ===${NC}"
|
||||
echo "Serveur hôte: $HOST_SSH_USER@$HOST_SSH_HOST:$HOST_SSH_PORT"
|
||||
echo "Conteneur: $CT_NAME"
|
||||
echo "Déploiement: $DEPLOY_DIR/$APP_NAME"
|
||||
echo "=================================="
|
||||
|
||||
# 1. Créer l'archive tar.gz localement
|
||||
echo -e "${YELLOW}1. Création de l'archive...${NC}"
|
||||
tar -czf /tmp/cleo.tar.gz \
|
||||
--exclude='.git' \
|
||||
--exclude='log/*.log' \
|
||||
--exclude='pub/files/upload/*' \
|
||||
--exclude='docs/*.sql' \
|
||||
--exclude='vendor' \
|
||||
--exclude='backup_*' \
|
||||
--exclude='*.tar.gz' \
|
||||
--exclude='.env.swp' \
|
||||
.
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}Erreur lors de la création de l'archive${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ARCHIVE_SIZE=$(du -h /tmp/cleo.tar.gz | cut -f1)
|
||||
echo -e "${GREEN}✓ Archive créée: /tmp/cleo.tar.gz ($ARCHIVE_SIZE)${NC}"
|
||||
|
||||
# 2. Copier l'archive vers IN3
|
||||
echo -e "${YELLOW}2. Transfert de l'archive vers IN3...${NC}"
|
||||
scp -P $HOST_SSH_PORT -i $HOST_SSH_KEY /tmp/cleo.tar.gz $HOST_SSH_USER@$HOST_SSH_HOST:/tmp/
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}Erreur lors du transfert de l'archive${NC}"
|
||||
rm -f /tmp/cleo.tar.gz
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✓ Archive transférée sur IN3${NC}"
|
||||
|
||||
# 3. Nettoyer l'ancien répertoire /tmp/cleo sur IN3 s'il existe
|
||||
echo -e "${YELLOW}3. Nettoyage des anciens fichiers temporaires sur IN3...${NC}"
|
||||
ssh $SSH_OPTS $HOST_SSH_USER@$HOST_SSH_HOST "rm -rf /tmp/cleo 2>/dev/null || true"
|
||||
echo -e "${GREEN}✓ Nettoyage effectué${NC}"
|
||||
|
||||
# 4. Transférer et extraire dans le conteneur
|
||||
echo -e "${YELLOW}4. Déploiement dans le conteneur $CT_NAME...${NC}"
|
||||
|
||||
# Script à exécuter sur IN3
|
||||
REMOTE_SCRIPT="
|
||||
set -e
|
||||
|
||||
# Sélectionner le projet Incus
|
||||
incus project switch $CT_PROJECT_NAME
|
||||
|
||||
# Transférer l'archive dans le conteneur
|
||||
echo 'Transfert de l archive dans le conteneur...'
|
||||
incus file push /tmp/cleo.tar.gz $CT_NAME/tmp/
|
||||
|
||||
# Créer le répertoire de destination et extraire
|
||||
echo 'Extraction de l archive...'
|
||||
incus exec $CT_NAME -- sh -c '
|
||||
mkdir -p $DEPLOY_DIR/$APP_NAME && \
|
||||
cd $DEPLOY_DIR/$APP_NAME && \
|
||||
tar -xzf /tmp/cleo.tar.gz && \
|
||||
rm -f /tmp/cleo.tar.gz
|
||||
'
|
||||
|
||||
# Configurer les permissions
|
||||
echo 'Configuration des permissions...'
|
||||
incus exec $CT_NAME -- sh -c '
|
||||
chown -R $OWNER:$GROUP $DEPLOY_DIR/$APP_NAME && \
|
||||
find $DEPLOY_DIR/$APP_NAME -type d -exec chmod 755 {} \; && \
|
||||
find $DEPLOY_DIR/$APP_NAME -type f -exec chmod 644 {} \; && \
|
||||
mkdir -p $DEPLOY_DIR/$APP_NAME/log && \
|
||||
chmod 777 $DEPLOY_DIR/$APP_NAME/log && \
|
||||
touch $DEPLOY_DIR/$APP_NAME/log/$(date +%m%d).log && \
|
||||
chmod 777 $DEPLOY_DIR/$APP_NAME/log/$(date +%m%d).log && \
|
||||
chown nobody:nobody $DEPLOY_DIR/$APP_NAME/log/*.log && \
|
||||
chmod 644 $DEPLOY_DIR/$APP_NAME/.env && \
|
||||
rm -f $DEPLOY_DIR/$APP_NAME/.env.swp && \
|
||||
if [ -d $DEPLOY_DIR/$APP_NAME/pub/files/upload ]; then
|
||||
chmod 775 $DEPLOY_DIR/$APP_NAME/pub/files/upload && \
|
||||
chown $OWNER:$GROUP $DEPLOY_DIR/$APP_NAME/pub/files/upload
|
||||
fi
|
||||
'
|
||||
|
||||
# Nettoyer l'archive sur IN3
|
||||
rm -f /tmp/cleo.tar.gz
|
||||
|
||||
echo 'Déploiement terminé avec succès!'
|
||||
"
|
||||
|
||||
# Exécuter le script sur IN3
|
||||
ssh $SSH_OPTS $HOST_SSH_USER@$HOST_SSH_HOST "$REMOTE_SCRIPT"
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}Erreur lors du déploiement${NC}"
|
||||
# Nettoyer l'archive locale et distante
|
||||
rm -f /tmp/cleo.tar.gz
|
||||
ssh $SSH_OPTS $HOST_SSH_USER@$HOST_SSH_HOST "rm -f /tmp/cleo.tar.gz 2>/dev/null || true"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 5. Nettoyer l'archive locale
|
||||
echo -e "${YELLOW}5. Nettoyage local...${NC}"
|
||||
rm -f /tmp/cleo.tar.gz
|
||||
echo -e "${GREEN}✓ Archive locale supprimée${NC}"
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}===================================================${NC}"
|
||||
echo -e "${GREEN} Déploiement terminé avec succès ! ${NC}"
|
||||
echo -e "${GREEN}===================================================${NC}"
|
||||
echo "Site: http://dcleo.unikoffice.com"
|
||||
echo "Chemin: $DEPLOY_DIR/$APP_NAME sur $CT_NAME"
|
||||
echo ""
|
||||
@@ -1,16 +1,20 @@
|
||||
# CLEO - Analyse de l'application de gestion de devis
|
||||
# CLEO - Application de gestion de devis
|
||||
|
||||
## Vue d'ensemble
|
||||
|
||||
CLEO est une application web de gestion de devis développée en PHP 8.3 pour les PME. Elle utilise une architecture MVC classique avec un framework maison appelé "d6".
|
||||
|
||||
**Version actuelle** : 2.0.1 (migration complétée le 12 septembre 2025)
|
||||
|
||||
## Architecture technique
|
||||
|
||||
### Stack technologique
|
||||
- **Langage** : PHP 8.3
|
||||
- **Architecture** : MVC (Model-View-Controller)
|
||||
- **Framework** : Framework maison "d6"
|
||||
- **Base de données** : MySQL/MariaDB
|
||||
- **Base de données** : MariaDB 11.4
|
||||
- **Connexion DB** : PDO avec requêtes préparées
|
||||
- **Configuration** : Variables d'environnement (.env)
|
||||
- **Gestion des dépendances** : Composer
|
||||
- **Bibliothèques principales** :
|
||||
- PHPMailer 6.8 (envoi d'emails)
|
||||
@@ -70,11 +74,12 @@ cleo/
|
||||
|
||||
## Base de données
|
||||
|
||||
### Bases multiples
|
||||
- **uof_frontal** : Base principale de l'application
|
||||
- Possibilité de connexion à plusieurs bases selon le contexte
|
||||
### Architecture actuelle
|
||||
- **Base unique** : `cleo` sur le container `maria3`
|
||||
- **Connexion** : PDO avec pattern Singleton
|
||||
- **Sécurité** : Requêtes préparées systématiques
|
||||
|
||||
### Tables principales identifiées
|
||||
### Tables principales
|
||||
- `devis` : Table principale des devis
|
||||
- `devis_produits` : Lignes de produits des devis
|
||||
- `devis_histo` : Historique des modifications
|
||||
@@ -88,31 +93,33 @@ cleo/
|
||||
|
||||
## Points de sécurité
|
||||
|
||||
### Vulnérabilités critiques identifiées
|
||||
### Vulnérabilités corrigées (v2.0.1)
|
||||
|
||||
#### 1. Stockage des mots de passe en clair
|
||||
- **Localisation** : `config/conf.php:40-50`
|
||||
- **Risque** : Exposition des credentials de base de données
|
||||
- **Recommandation** : Utiliser des variables d'environnement (.env)
|
||||
✅ **1. Stockage des mots de passe**
|
||||
- Credentials externalisés dans `.env`
|
||||
- Variables d'environnement utilisées systématiquement
|
||||
|
||||
#### 2. Injections SQL potentielles
|
||||
- **Localisation** : Multiple, ex: `controllers/cjxdevis.php`
|
||||
- **Problème** : Concaténation directe de variables dans les requêtes SQL
|
||||
- **Exemple** :
|
||||
```php
|
||||
$sql .= ' AND SUBSTR(cp,1,2) IN (' . $depts . ') ';
|
||||
```
|
||||
- **Recommandation** : Utiliser des requêtes préparées PDO
|
||||
✅ **2. Protection contre les injections SQL**
|
||||
- Migration complète vers PDO
|
||||
- Requêtes préparées dans la classe `Database`
|
||||
- Pattern Singleton pour la connexion
|
||||
|
||||
#### 3. Gestion des erreurs non sécurisée
|
||||
- **Localisation** : `pub/res/d6/d6_tools.php:66-84`
|
||||
- **Problème** : Pas de gestion d'erreurs robuste pour les connexions DB
|
||||
- **Recommandation** : Implémenter un système de logging sécurisé
|
||||
✅ **3. Gestion des erreurs sécurisée**
|
||||
- Classe `Database` avec gestion d'erreurs centralisée
|
||||
- Logging contrôlé par variables d'environnement
|
||||
- Mode debug désactivable en production
|
||||
|
||||
#### 4. Configuration sensible exposée
|
||||
- **Localisation** : `config/conf.php:30`
|
||||
- **Problème** : IP exclue hardcodée dans le code
|
||||
- **Recommandation** : Externaliser dans un fichier de configuration
|
||||
### Vulnérabilités restantes à traiter
|
||||
|
||||
#### 1. Injections SQL résiduelles
|
||||
- **Localisation** : Certains contrôleurs (`controllers/cjx*.php`)
|
||||
- **Problème** : Concaténations directes dans certaines requêtes complexes
|
||||
- **Recommandation** : Audit complet et migration progressive
|
||||
|
||||
#### 2. Configuration IP en dur
|
||||
- **Localisation** : `config/conf.php`
|
||||
- **Problème** : Certaines IPs encore hardcodées
|
||||
- **Recommandation** : Migration complète vers `.env`
|
||||
|
||||
### Points positifs de sécurité
|
||||
- Utilisation de `password_hash()` avec bcrypt pour les mots de passe utilisateurs
|
||||
@@ -164,11 +171,11 @@ $sql .= ' AND SUBSTR(cp,1,2) IN (' . $depts . ') ';
|
||||
|
||||
## Plan d'amélioration recommandé
|
||||
|
||||
### Court terme (Sécurité critique)
|
||||
1. Migrer les credentials vers des variables d'environnement
|
||||
2. Remplacer les requêtes SQL par des requêtes préparées
|
||||
3. Implémenter une gestion d'erreurs sécurisée
|
||||
4. Auditer et corriger les failles XSS potentielles
|
||||
### Court terme (Sécurité - En cours)
|
||||
1. ✅ Migrer les credentials vers des variables d'environnement
|
||||
2. ✅ Remplacer les requêtes SQL par des requêtes préparées (classe Database)
|
||||
3. ✅ Implémenter une gestion d'erreurs sécurisée
|
||||
4. ⏳ Auditer et corriger les failles XSS potentielles
|
||||
|
||||
### Moyen terme (Qualité et maintenabilité)
|
||||
1. Migrer vers une structure PSR-4 avec namespaces
|
||||
@@ -182,13 +189,31 @@ $sql .= ' AND SUBSTR(cp,1,2) IN (' . $depts . ') ';
|
||||
3. Ajouter un système de cache performant
|
||||
4. Mettre en place un pipeline CI/CD
|
||||
|
||||
## Architecture de déploiement
|
||||
|
||||
### Environnement DEV (Actuel - IN3)
|
||||
- **Container `dva-front`** : Application PHP 8.3 + Nginx (Alpine Linux)
|
||||
- IP : 13.23.33.42
|
||||
- MariaDB : **Supprimé** (12/09/2025)
|
||||
- **Container `maria3`** : Base de données MariaDB 11.4
|
||||
- IP : 13.23.33.4
|
||||
- Base : `cleo`
|
||||
|
||||
### Environnement PROD (Futur - IN4)
|
||||
- **Container `nx4`** : Application PHP
|
||||
- **Container `maria4`** : Base de données
|
||||
|
||||
## Conclusion
|
||||
|
||||
CLEO est une application fonctionnelle qui répond aux besoins métier de gestion de devis pour PME. Cependant, elle nécessite des améliorations importantes en termes de sécurité et de modernisation du code pour garantir sa pérennité et sa maintenabilité.
|
||||
CLEO v2.0.1 représente une évolution majeure avec la migration réussie vers une architecture sécurisée :
|
||||
- ✅ Base de données unique et centralisée
|
||||
- ✅ Connexions PDO avec requêtes préparées
|
||||
- ✅ Configuration externalisée
|
||||
- ✅ Séparation application/base de données
|
||||
|
||||
Les priorités absolues sont la sécurisation des accès base de données et la protection contre les injections SQL. Une fois ces points critiques adressés, l'application pourra évoluer progressivement vers des standards plus modernes.
|
||||
Les priorités de sécurité critiques ont été adressées. L'application peut maintenant évoluer sereinement vers des standards plus modernes tout en maintenant sa stabilité opérationnelle.
|
||||
|
||||
---
|
||||
|
||||
*Document généré le 11 septembre 2025*
|
||||
*Analyse basée sur l'examen du code source de l'application CLEO*
|
||||
*Document mis à jour le 12 septembre 2025*
|
||||
*Version 2.0.1 - Post-migration*
|
||||
151
docs/TODO.md
151
docs/TODO.md
@@ -83,12 +83,137 @@
|
||||
- [ ] Adapter aux spécificités SAP
|
||||
- [ ] Filtres supplémentaires (état EDI, prise en charge)
|
||||
|
||||
## Migration Infrastructure - Séparation Application/Base de données
|
||||
|
||||
### ✅ PHASE 1 COMPLÉTÉE (12 septembre 2025)
|
||||
|
||||
**Description**: Migration réussie de l'architecture DEV/RECETTE vers la nouvelle structure avec séparation application/base de données.
|
||||
|
||||
### Architecture actuelle (après migration DEV)
|
||||
- **DEV/RECETTE**: Host IN3 ✅
|
||||
- Container `dva-front` (application PHP uniquement) ✅
|
||||
- Container `maria3` (MariaDB dédié avec base `cleo`) ✅
|
||||
- **PROD**: Host IN2 (actuel, à migrer)
|
||||
- Container `nx4` (application + BDD intégrées)
|
||||
- Bases de données: `uof_frontal` et `uof_linet`
|
||||
|
||||
### Architecture cible PROD (à faire)
|
||||
- **PROD**: Host IN4 (nouveau)
|
||||
- Container `pra-front` (import depuis IN3.dva-front)
|
||||
- Container `maria4` (import depuis IN3.maria3)
|
||||
- **Décommissionnement**: Host IN2 (après migration PROD)
|
||||
|
||||
### ✅ Refactoring de la base de données (COMPLÉTÉ)
|
||||
**Changements réalisés**:
|
||||
1. ✅ **Suppression de la base `uof_frontal`**
|
||||
- Configuration externalisée dans `.env`
|
||||
- Table `y_pages` migrée vers `cleo`
|
||||
2. ✅ **Fusion `uof_frontal` + `uof_linet` → `cleo`**
|
||||
- Une seule base de données
|
||||
- Connexion PDO avec pattern Singleton
|
||||
3. ✅ **Intégration des logs**
|
||||
- Table `z_logs` dans la base `cleo`
|
||||
- Tables `z_sessions` et `z_stats` créées
|
||||
|
||||
### Plan de migration - État d'avancement
|
||||
|
||||
#### ✅ Phase 0 - Refactoring base de données (COMPLÉTÉ - 12/09/2025)
|
||||
- [x] Script de migration SQL créé
|
||||
- [x] Table `y_pages` migrée depuis `uof_frontal`
|
||||
- [x] Table `z_logs` créée dans `cleo`
|
||||
- [x] Base `cleo` créée avec toutes les tables
|
||||
- [x] Données migrées de `uof_linet` vers `cleo`
|
||||
- [x] Références à `uof_frontal` supprimées
|
||||
- [x] Classe Database PDO créée
|
||||
- [x] Variables d'environnement `.env` implémentées
|
||||
- [x] Tests validés en DEV
|
||||
|
||||
#### ✅ Phase 1 - Environnement DEV IN3 (COMPLÉTÉ - 12/09/2025)
|
||||
- [x] Container `maria3` créé sur IN3
|
||||
- [x] MariaDB 11.4 installé et configuré
|
||||
- [x] Base `cleo` migrée vers `maria3`
|
||||
- [x] Configuration pointant vers `maria3` (IP: 13.23.33.4)
|
||||
- [x] Application testée et fonctionnelle
|
||||
- [x] MariaDB supprimé de `dva-front`
|
||||
- [x] Script de déploiement optimisé (`deploy-cleo-fast.sh`)
|
||||
|
||||
#### Phase 2 - Préparation PROD IN4 (À FAIRE)
|
||||
**Export depuis IN3:**
|
||||
- [ ] Exporter le container `dva-front` depuis IN3
|
||||
```bash
|
||||
incus export dva-front dva-front-export.tar.gz
|
||||
```
|
||||
- [ ] Exporter le container `maria3` depuis IN3
|
||||
```bash
|
||||
incus export maria3 maria3-export.tar.gz
|
||||
```
|
||||
|
||||
**Import sur IN4:**
|
||||
- [ ] Importer `dva-front` comme `pra-front` sur IN4
|
||||
```bash
|
||||
incus import dva-front-export.tar.gz pra-front
|
||||
```
|
||||
- [ ] Importer `maria3` comme `maria4` sur IN4
|
||||
```bash
|
||||
incus import maria3-export.tar.gz maria4
|
||||
```
|
||||
- [ ] Configurer les IPs et paramètres réseau sur IN4
|
||||
- [ ] Adapter le fichier `.env` pour l'environnement PROD
|
||||
|
||||
#### Phase 3 - Migration des données PROD (À FAIRE)
|
||||
- [ ] Effectuer une sauvegarde complète des bases PROD sur IN2/nx4
|
||||
- [ ] Exporter les données de `uof_frontal` et `uof_linet` depuis IN2/nx4
|
||||
- [ ] Utiliser le script de migration SQL pour fusionner les données
|
||||
- [ ] Importer les données fusionnées dans `maria4` sur IN4
|
||||
- [ ] Configurer `pra-front` pour pointer vers `maria4`
|
||||
- [ ] Tests de validation en pré-production
|
||||
|
||||
#### Phase 4 - Bascule PROD (À FAIRE)
|
||||
- [ ] Planifier la fenêtre de maintenance
|
||||
- [ ] Arrêter l'application sur IN2
|
||||
- [ ] Synchronisation finale des données vers IN4/maria4
|
||||
- [ ] Basculer le DNS/proxy vers IN4
|
||||
- [ ] Valider le fonctionnement en production
|
||||
- [ ] Monitoring post-migration (48h)
|
||||
- [ ] Décommissionner IN2 après période de stabilisation
|
||||
|
||||
### Configuration technique
|
||||
|
||||
#### Variables d'environnement
|
||||
**DEV (IN3) - Actuel:**
|
||||
```env
|
||||
DB_HOST=13.23.33.4 # IP de maria3
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=cleo
|
||||
DB_USERNAME=cleo_user
|
||||
DB_PASSWORD=CleoDev2025!
|
||||
```
|
||||
|
||||
**PROD (IN4) - À configurer:**
|
||||
```env
|
||||
DB_HOST=<IP_maria4> # À définir sur IN4
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=cleo
|
||||
DB_USERNAME=cleo_user
|
||||
DB_PASSWORD=<PROD_PASSWORD> # À sécuriser
|
||||
```
|
||||
|
||||
#### Sécurité réseau
|
||||
- ✅ Connexions uniquement depuis les containers applicatifs
|
||||
- ✅ Pas d'exposition directe des ports MariaDB
|
||||
- [ ] Firewall entre containers à configurer sur IN4
|
||||
|
||||
#### Backup et restauration
|
||||
- [ ] Scripts de backup automatisés à mettre en place
|
||||
- [ ] Réplication master-slave pour haute disponibilité (optionnel)
|
||||
|
||||
## Améliorations techniques prioritaires
|
||||
|
||||
### Sécurité (URGENT)
|
||||
- [ ] Migrer les credentials DB vers des variables d'environnement
|
||||
- [ ] Remplacer toutes les requêtes SQL par des requêtes préparées
|
||||
- [ ] Audit et correction des failles XSS
|
||||
### Sécurité
|
||||
- [x] ✅ Migrer les credentials DB vers des variables d'environnement
|
||||
- [x] ✅ Classe Database avec requêtes préparées PDO
|
||||
- [ ] Audit complet des contrôleurs pour injections SQL résiduelles
|
||||
- [ ] Correction des failles XSS potentielles
|
||||
|
||||
### Performance
|
||||
- [ ] Implémenter la pagination côté serveur pour toutes les listes
|
||||
@@ -156,7 +281,21 @@ ALTER TABLE devis ADD COLUMN date_transfert_edi DATETIME;
|
||||
ALTER TABLE devis ADD COLUMN erreur_transfert_edi TEXT;
|
||||
```
|
||||
|
||||
## Résumé de l'état actuel
|
||||
|
||||
### ✅ Réalisations (v2.0.1 - 12 septembre 2025)
|
||||
1. **Migration DEV complétée** : Architecture séparée application/BDD
|
||||
2. **Base unique `cleo`** : Fusion réussie de 3 bases en une seule
|
||||
3. **Sécurité renforcée** : PDO, requêtes préparées, variables d'environnement
|
||||
4. **Container `dva-front`** : MariaDB supprimé, application PHP uniquement
|
||||
5. **Container `maria3`** : Base de données centralisée opérationnelle
|
||||
|
||||
### 🎯 Prochaines étapes prioritaires
|
||||
1. **Migration PROD vers IN4** : Export/Import des containers vers `pra-front` et `maria4`
|
||||
2. **Fonctionnalités métier** : Points 6, 14, 16 (voir sections ci-dessus)
|
||||
3. **Sécurité** : Audit des contrôleurs pour injections SQL résiduelles
|
||||
|
||||
---
|
||||
|
||||
*Document créé le 11 septembre 2025*
|
||||
*À mettre à jour au fur et à mesure de l'avancement des développements*
|
||||
*Document mis à jour le 12 septembre 2025*
|
||||
*Version 2.0.1 - Post-migration DEV*
|
||||
1265
docs/cleo.sql
Normal file
1265
docs/cleo.sql
Normal file
File diff suppressed because it is too large
Load Diff
177274
docs/uof_linet_20250911.sql
Normal file
177274
docs/uof_linet_20250911.sql
Normal file
File diff suppressed because one or more lines are too long
243
migration/README.md
Normal file
243
migration/README.md
Normal file
@@ -0,0 +1,243 @@
|
||||
# Migration CLEO vers la nouvelle architecture
|
||||
|
||||
## ✅ MIGRATION COMPLÉTÉE (12 septembre 2025)
|
||||
|
||||
## Vue d'ensemble
|
||||
|
||||
Cette migration a transformé l'architecture de CLEO pour :
|
||||
- ✅ **Fusionner 3 bases de données** (`uof_frontal`, `uof_linet`, `logs`) en une seule base `cleo`
|
||||
- ✅ **Sécuriser les connexions** avec PDO et requêtes préparées
|
||||
- ✅ **Externaliser la configuration** dans des variables d'environnement
|
||||
- ✅ **Séparer** application (dva-front) et base de données (maria3)
|
||||
|
||||
## Pré-requis
|
||||
|
||||
- PHP 8.3+
|
||||
- MariaDB/MySQL 5.7+
|
||||
- Accès aux bases existantes (`uof_frontal`, `uof_linet`)
|
||||
- Container `maria3` accessible depuis l'application
|
||||
|
||||
## Structure de la migration
|
||||
|
||||
```
|
||||
migration/
|
||||
├── migrate_to_cleo.sql # Script SQL de migration des données
|
||||
├── deploy_new_architecture.sh # Script de déploiement automatique
|
||||
├── rollback.sh # Script de retour arrière
|
||||
└── README.md # Ce fichier
|
||||
```
|
||||
|
||||
## Étapes de migration
|
||||
|
||||
### 1. Préparation
|
||||
|
||||
```bash
|
||||
# Se placer à la racine du projet
|
||||
cd /home/pierre/dev/cleo
|
||||
|
||||
# Vérifier le fichier .env
|
||||
cp .env.example .env
|
||||
nano .env # Éditer avec vos paramètres
|
||||
```
|
||||
|
||||
Configuration actuelle dans `.env` :
|
||||
```env
|
||||
DB_HOST=13.23.33.4 # IP du container maria3
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=cleo
|
||||
DB_USERNAME=cleo_user
|
||||
DB_PASSWORD=CleoDev2025! # À changer en production
|
||||
```
|
||||
|
||||
### 2. Exécution de la migration
|
||||
|
||||
```bash
|
||||
# Rendre les scripts exécutables
|
||||
chmod +x migration/*.sh
|
||||
|
||||
# Lancer la migration
|
||||
./migration/deploy_new_architecture.sh
|
||||
```
|
||||
|
||||
Le script effectue automatiquement :
|
||||
- ✅ Sauvegarde des fichiers actuels
|
||||
- ✅ Test de connexion à MariaDB
|
||||
- ✅ Migration des bases de données
|
||||
- ✅ Activation des nouveaux fichiers
|
||||
- ✅ Tests de validation
|
||||
|
||||
### 3. Vérification
|
||||
|
||||
Après la migration, vérifier :
|
||||
|
||||
```bash
|
||||
# Connexion à la base
|
||||
mysql -h maria3 -u cleo_user -p cleo
|
||||
|
||||
# Vérifier les tables
|
||||
SHOW TABLES;
|
||||
|
||||
# Compter les enregistrements
|
||||
SELECT 'devis' as table_name, COUNT(*) FROM devis
|
||||
UNION ALL
|
||||
SELECT 'clients', COUNT(*) FROM clients
|
||||
UNION ALL
|
||||
SELECT 'users', COUNT(*) FROM users;
|
||||
```
|
||||
|
||||
Tester l'application :
|
||||
- Connexion utilisateur
|
||||
- Consultation des devis
|
||||
- Création d'un nouveau devis
|
||||
- Export Excel
|
||||
|
||||
### 4. En cas de problème
|
||||
|
||||
Si la migration échoue ou cause des problèmes :
|
||||
|
||||
```bash
|
||||
# Revenir à l'ancienne architecture
|
||||
./migration/rollback.sh
|
||||
```
|
||||
|
||||
Le rollback :
|
||||
- Restaure les fichiers originaux
|
||||
- Conserve les nouveaux fichiers dans `migration/new_architecture_backup/`
|
||||
- L'application revient sur les bases `uof_frontal` et `uof_linet`
|
||||
|
||||
## Changements techniques
|
||||
|
||||
### Fichiers modifiés
|
||||
|
||||
| Fichier | Changement |
|
||||
|---------|------------|
|
||||
| `config/conf.php` | Utilise les variables d'environnement |
|
||||
| `config/Database.php` | Nouvelle classe PDO singleton |
|
||||
| `pub/res/d6/d6_tools.php` | Utilise la classe Database |
|
||||
| `.env` | Configuration externalisée |
|
||||
|
||||
### Structure de la base `cleo`
|
||||
|
||||
```sql
|
||||
-- Tables métier (ex-uof_linet)
|
||||
devis
|
||||
devis_produits
|
||||
devis_histo
|
||||
clients
|
||||
produits
|
||||
produits_familles
|
||||
marches
|
||||
users
|
||||
x_familles
|
||||
x_statuts_devis
|
||||
x_clients_types
|
||||
|
||||
-- Tables système
|
||||
y_pages (ex-uof_frontal)
|
||||
users_entites (ex-uof_frontal)
|
||||
z_logs (ex-base logs ou nouvelle)
|
||||
```
|
||||
|
||||
### Améliorations de sécurité
|
||||
|
||||
1. **Requêtes préparées PDO** : Protection contre les injections SQL
|
||||
2. **Variables d'environnement** : Credentials hors du code
|
||||
3. **Connexion unique** : Pattern Singleton pour la DB
|
||||
4. **Logging amélioré** : Traçabilité des requêtes SQL
|
||||
|
||||
## Environnements
|
||||
|
||||
### DEV/RECETTE (IN3) - ACTIF
|
||||
```
|
||||
Container: dva-front (13.23.33.42)
|
||||
├── Application PHP 8.3
|
||||
├── Nginx (Alpine Linux)
|
||||
├── MariaDB : SUPPRIMÉ (12/09/2025)
|
||||
└── Connexion vers maria3
|
||||
|
||||
Container: maria3 (13.23.33.4)
|
||||
├── MariaDB 11.4
|
||||
├── Base de données : cleo
|
||||
├── Tables migrées : 30+
|
||||
└── Utilisateur : cleo_user
|
||||
```
|
||||
|
||||
**Actions réalisées :**
|
||||
- ✅ Migration des bases `uof_frontal` et `uof_linet` vers `cleo`
|
||||
- ✅ Création des tables manquantes (`z_sessions`, `z_stats`, `marches_listes`)
|
||||
- ✅ Configuration PDO avec pattern Singleton
|
||||
- ✅ Suppression complète de MariaDB sur dva-front
|
||||
- ✅ Script de déploiement optimisé (`deploy-cleo-fast.sh`)
|
||||
|
||||
### PROD (IN4 - futur)
|
||||
```
|
||||
Container: nx4 → Application PHP
|
||||
Container: maria4 → Base de données cleo
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Erreur de connexion à la base
|
||||
|
||||
```bash
|
||||
# Vérifier la connectivité
|
||||
mysql -h maria3 -u cleo_user -p
|
||||
|
||||
# Vérifier les permissions
|
||||
SHOW GRANTS FOR 'cleo_user'@'%';
|
||||
```
|
||||
|
||||
### Erreur PHP après migration
|
||||
|
||||
```bash
|
||||
# Vérifier les logs
|
||||
tail -f log/cleo_debug_*.log
|
||||
|
||||
# Vérifier les permissions des fichiers
|
||||
ls -la config/conf.php
|
||||
ls -la .env
|
||||
```
|
||||
|
||||
### Tables manquantes
|
||||
|
||||
```bash
|
||||
# Réexécuter uniquement la migration SQL
|
||||
mysql -h maria3 -u cleo_user -p cleo < migration/migrate_to_cleo.sql
|
||||
```
|
||||
|
||||
## Support
|
||||
|
||||
Pour toute question ou problème :
|
||||
1. Consulter les logs dans `/log/`
|
||||
2. Vérifier le fichier `.env`
|
||||
3. Utiliser le rollback si nécessaire
|
||||
4. Documenter l'erreur dans un issue GitHub
|
||||
|
||||
## État post-migration
|
||||
|
||||
### Fichiers créés/modifiés
|
||||
- ✅ `.env` : Configuration externalisée
|
||||
- ✅ `config/Database.php` : Classe PDO singleton
|
||||
- ✅ `config/conf.php` : Utilise les variables d'environnement
|
||||
- ✅ `pub/res/d6/d6_tools.php` : Fonctions utilitaires mises à jour
|
||||
- ✅ `deploy-cleo-fast.sh` : Script de déploiement optimisé (tar.gz)
|
||||
|
||||
### Problèmes résolus durant la migration
|
||||
1. **Tables manquantes** : Création de `z_sessions`, `z_stats`, `marches_listes`
|
||||
2. **Permissions fichiers** : `.env` en 644, logs en 777 avec owner `nobody`
|
||||
3. **Compatibilité PDO** : Remplacement de `fetch_assoc()` par `fetch(PDO::FETCH_ASSOC)`
|
||||
4. **Debug AJAX** : Suppression des commentaires HTML dans les réponses JSON
|
||||
5. **Fonctions manquantes** : Ajout de `checkPsswd()`, `affiche_date()`, etc.
|
||||
|
||||
### Scripts de déploiement
|
||||
```bash
|
||||
# Déploiement rapide (30 secondes)
|
||||
./deploy-cleo-fast.sh
|
||||
|
||||
# Déploiement dev (si besoin)
|
||||
./deploy-cleo-dev.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
*Migration complétée pour CLEO v2.0.1 - 12 septembre 2025*
|
||||
10
migration/create_marches_listes.sql
Normal file
10
migration/create_marches_listes.sql
Normal file
@@ -0,0 +1,10 @@
|
||||
-- Création de la table marches_listes
|
||||
CREATE TABLE IF NOT EXISTS `marches_listes` (
|
||||
`rowid` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`fk_marche` int(11) DEFAULT NULL,
|
||||
`terme_achat` varchar(255) DEFAULT NULL,
|
||||
`date_created` datetime DEFAULT current_timestamp(),
|
||||
`date_modified` datetime DEFAULT current_timestamp() ON UPDATE current_timestamp(),
|
||||
PRIMARY KEY (`rowid`),
|
||||
KEY `idx_fk_marche` (`fk_marche`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
48
migration/create_missing_tables.sql
Normal file
48
migration/create_missing_tables.sql
Normal file
@@ -0,0 +1,48 @@
|
||||
-- Script pour créer les tables manquantes dans la base cleo
|
||||
-- Date: 2025-09-12
|
||||
|
||||
USE cleo;
|
||||
|
||||
-- Table z_sessions pour la gestion des sessions utilisateurs
|
||||
CREATE TABLE IF NOT EXISTS `z_sessions` (
|
||||
`rowid` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`sid` varchar(255) NOT NULL,
|
||||
`fk_user` int(11) DEFAULT 0,
|
||||
`role` varchar(10) DEFAULT NULL,
|
||||
`data` text,
|
||||
`date_modified` datetime DEFAULT NULL,
|
||||
`ip` varchar(50) DEFAULT NULL,
|
||||
`browser` varchar(255) DEFAULT NULL,
|
||||
PRIMARY KEY (`rowid`),
|
||||
UNIQUE KEY `idx_sid` (`sid`),
|
||||
KEY `idx_user` (`fk_user`),
|
||||
KEY `idx_date` (`date_modified`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Ajouter la colonne 'date' manquante dans z_logs si elle n'existe pas
|
||||
ALTER TABLE `z_logs`
|
||||
ADD COLUMN IF NOT EXISTS `date` datetime DEFAULT NULL AFTER `date_histo`;
|
||||
|
||||
-- Index pour améliorer les performances
|
||||
ALTER TABLE `z_logs` ADD INDEX IF NOT EXISTS `idx_date_logs` (`date`);
|
||||
|
||||
-- Table z_stats pour les statistiques (optionnelle pour plus tard)
|
||||
CREATE TABLE IF NOT EXISTS `z_stats` (
|
||||
`rowid` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`date` datetime DEFAULT NULL,
|
||||
`root` varchar(255) DEFAULT NULL,
|
||||
`server_ip` varchar(50) DEFAULT NULL,
|
||||
`server_soft` varchar(255) DEFAULT NULL,
|
||||
`server_name` varchar(255) DEFAULT NULL,
|
||||
`client_ip` varchar(50) DEFAULT NULL,
|
||||
`client_browser` text,
|
||||
`client_origine` text,
|
||||
`client_page` text,
|
||||
`fk_user` int(11) DEFAULT 0,
|
||||
`appname` varchar(50) DEFAULT NULL,
|
||||
`delay` decimal(10,3) DEFAULT 0,
|
||||
PRIMARY KEY (`rowid`),
|
||||
KEY `idx_date_stats` (`date`),
|
||||
KEY `idx_user_stats` (`fk_user`),
|
||||
KEY `idx_ip_stats` (`client_ip`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
163
migration/deploy_new_architecture.sh
Executable file
163
migration/deploy_new_architecture.sh
Executable file
@@ -0,0 +1,163 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script de déploiement de la nouvelle architecture CLEO
|
||||
# Version: 2.0.1
|
||||
# Date: 2025-09-11
|
||||
|
||||
set -e # Arrêter en cas d'erreur
|
||||
|
||||
# Couleurs pour l'affichage
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
echo -e "${GREEN}================================================${NC}"
|
||||
echo -e "${GREEN} Déploiement CLEO - Nouvelle Architecture ${NC}"
|
||||
echo -e "${GREEN}================================================${NC}"
|
||||
echo ""
|
||||
|
||||
# Vérifier qu'on est dans le bon répertoire
|
||||
if [ ! -f "index.php" ] || [ ! -d "config" ]; then
|
||||
echo -e "${RED}Erreur: Ce script doit être exécuté depuis la racine du projet CLEO${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Fonction pour demander confirmation
|
||||
confirm() {
|
||||
read -p "$1 [y/N] " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# 1. Vérification du fichier .env
|
||||
echo -e "${YELLOW}1. Vérification de la configuration...${NC}"
|
||||
if [ ! -f ".env" ]; then
|
||||
echo -e "${RED} Le fichier .env n'existe pas!${NC}"
|
||||
echo " Copie de .env.example vers .env..."
|
||||
cp .env.example .env
|
||||
echo -e "${YELLOW} IMPORTANT: Veuillez éditer le fichier .env avec vos paramètres${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN} ✓ Fichier .env trouvé${NC}"
|
||||
|
||||
# 2. Backup des anciens fichiers
|
||||
echo -e "${YELLOW}2. Sauvegarde des fichiers actuels...${NC}"
|
||||
BACKUP_DIR="backup_$(date +%Y%m%d_%H%M%S)"
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
# Sauvegarder les fichiers critiques
|
||||
if [ -f "config/conf.php" ]; then
|
||||
cp config/conf.php "$BACKUP_DIR/conf.php.bak"
|
||||
echo " - config/conf.php sauvegardé"
|
||||
fi
|
||||
|
||||
if [ -f "pub/res/d6/d6_tools.php" ]; then
|
||||
cp pub/res/d6/d6_tools.php "$BACKUP_DIR/d6_tools.php.bak"
|
||||
echo " - pub/res/d6/d6_tools.php sauvegardé"
|
||||
fi
|
||||
|
||||
echo -e "${GREEN} ✓ Sauvegarde effectuée dans $BACKUP_DIR${NC}"
|
||||
|
||||
# 3. Vérification de la connexion à la base de données
|
||||
echo -e "${YELLOW}3. Test de connexion à la base de données...${NC}"
|
||||
|
||||
# Lire les paramètres depuis .env
|
||||
source .env
|
||||
|
||||
# Tester la connexion MySQL
|
||||
mysql -h"$DB_HOST" -u"$DB_USERNAME" -p"$DB_PASSWORD" -e "SELECT 1" >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
echo -e "${GREEN} ✓ Connexion à MariaDB réussie${NC}"
|
||||
else
|
||||
echo -e "${RED} ✗ Impossible de se connecter à MariaDB${NC}"
|
||||
echo " Vérifiez les paramètres dans .env"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 4. Exécution du script de migration SQL
|
||||
echo -e "${YELLOW}4. Migration de la base de données...${NC}"
|
||||
if confirm " Voulez-vous exécuter le script de migration SQL?"; then
|
||||
echo " Exécution de migrate_to_cleo.sql..."
|
||||
mysql -h"$DB_HOST" -u"$DB_USERNAME" -p"$DB_PASSWORD" < migration/migrate_to_cleo.sql
|
||||
if [ $? -eq 0 ]; then
|
||||
echo -e "${GREEN} ✓ Migration SQL effectuée${NC}"
|
||||
else
|
||||
echo -e "${RED} ✗ Erreur lors de la migration SQL${NC}"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo " Migration SQL ignorée"
|
||||
fi
|
||||
|
||||
# 5. Activation des nouveaux fichiers
|
||||
echo -e "${YELLOW}5. Activation de la nouvelle architecture...${NC}"
|
||||
|
||||
# Remplacer conf.php
|
||||
if [ -f "config/conf_new.php" ]; then
|
||||
mv config/conf.php config/conf_old.php 2>/dev/null || true
|
||||
cp config/conf_new.php config/conf.php
|
||||
echo -e "${GREEN} ✓ config/conf.php mis à jour${NC}"
|
||||
fi
|
||||
|
||||
# Remplacer d6_tools.php
|
||||
if [ -f "pub/res/d6/d6_tools_new.php" ]; then
|
||||
mv pub/res/d6/d6_tools.php pub/res/d6/d6_tools_old.php 2>/dev/null || true
|
||||
cp pub/res/d6/d6_tools_new.php pub/res/d6/d6_tools.php
|
||||
echo -e "${GREEN} ✓ d6_tools.php mis à jour${NC}"
|
||||
fi
|
||||
|
||||
# 6. Vérification des permissions
|
||||
echo -e "${YELLOW}6. Vérification des permissions...${NC}"
|
||||
chmod 644 config/conf.php
|
||||
chmod 644 pub/res/d6/d6_tools.php
|
||||
chmod 600 .env
|
||||
echo -e "${GREEN} ✓ Permissions mises à jour${NC}"
|
||||
|
||||
# 7. Création du répertoire de logs si nécessaire
|
||||
echo -e "${YELLOW}7. Création du répertoire de logs...${NC}"
|
||||
mkdir -p log
|
||||
chmod 755 log
|
||||
echo -e "${GREEN} ✓ Répertoire log créé${NC}"
|
||||
|
||||
# 8. Test de l'application
|
||||
echo -e "${YELLOW}8. Test de connexion à la base CLEO...${NC}"
|
||||
php -r "
|
||||
require_once 'config/Database.php';
|
||||
try {
|
||||
\$db = Database::getInstance();
|
||||
echo ' ✓ Connexion PDO réussie' . PHP_EOL;
|
||||
\$result = \$db->fetchOne('SELECT COUNT(*) as nb FROM users');
|
||||
echo ' ✓ ' . \$result['nb'] . ' utilisateurs trouvés' . PHP_EOL;
|
||||
} catch (Exception \$e) {
|
||||
echo ' ✗ Erreur: ' . \$e->getMessage() . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
"
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo -e "${GREEN} ✓ Tests réussis${NC}"
|
||||
else
|
||||
echo -e "${RED} ✗ Tests échoués${NC}"
|
||||
echo " Utilisez ./migration/rollback.sh pour revenir en arrière"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}================================================${NC}"
|
||||
echo -e "${GREEN} Déploiement terminé avec succès! ${NC}"
|
||||
echo -e "${GREEN}================================================${NC}"
|
||||
echo ""
|
||||
echo "Prochaines étapes:"
|
||||
echo "1. Testez l'application dans votre navigateur"
|
||||
echo "2. Vérifiez les logs dans le répertoire /log"
|
||||
echo "3. En cas de problème, utilisez ./migration/rollback.sh"
|
||||
echo ""
|
||||
echo "Configuration actuelle:"
|
||||
echo " - Base de données: $DB_DATABASE sur $DB_HOST"
|
||||
echo " - Environnement: $APP_ENV"
|
||||
echo " - Debug: $APP_DEBUG"
|
||||
echo ""
|
||||
37
migration/execute_marches_listes.sh
Normal file
37
migration/execute_marches_listes.sh
Normal file
@@ -0,0 +1,37 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Script pour créer la table marches_listes"
|
||||
echo "========================================="
|
||||
echo ""
|
||||
echo "Veuillez exécuter les commandes suivantes :"
|
||||
echo ""
|
||||
echo "1. Connectez-vous à IN3 :"
|
||||
echo " ssh root@195.154.80.116"
|
||||
echo ""
|
||||
echo "2. Connectez-vous au conteneur maria3 :"
|
||||
echo " incus exec maria3 -- bash"
|
||||
echo ""
|
||||
echo "3. Connectez-vous à MariaDB :"
|
||||
echo " mariadb -u root"
|
||||
echo ""
|
||||
echo "4. Sélectionnez la base de données :"
|
||||
echo " USE cleo;"
|
||||
echo ""
|
||||
echo "5. Créez la table marches_listes :"
|
||||
cat << 'EOF'
|
||||
CREATE TABLE IF NOT EXISTS `marches_listes` (
|
||||
`rowid` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`fk_marche` int(11) DEFAULT NULL,
|
||||
`terme_achat` varchar(255) DEFAULT NULL,
|
||||
`date_created` datetime DEFAULT current_timestamp(),
|
||||
`date_modified` datetime DEFAULT current_timestamp() ON UPDATE current_timestamp(),
|
||||
PRIMARY KEY (`rowid`),
|
||||
KEY `idx_fk_marche` (`fk_marche`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
EOF
|
||||
echo ""
|
||||
echo "6. Vérifiez que la table est créée :"
|
||||
echo " SHOW TABLES LIKE 'marches_listes';"
|
||||
echo ""
|
||||
echo "7. Quittez MariaDB :"
|
||||
echo " EXIT;"
|
||||
196
migration/migrate_to_cleo.sql
Normal file
196
migration/migrate_to_cleo.sql
Normal file
@@ -0,0 +1,196 @@
|
||||
-- Script de migration vers la base unique CLEO
|
||||
-- Date: 2025-09-11
|
||||
-- Version: 2.0.1
|
||||
|
||||
-- ==============================================================================
|
||||
-- ÉTAPE 1: Création de la base CLEO
|
||||
-- ==============================================================================
|
||||
|
||||
CREATE DATABASE IF NOT EXISTS `cleo`
|
||||
DEFAULT CHARACTER SET utf8mb4
|
||||
COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
USE `cleo`;
|
||||
|
||||
-- ==============================================================================
|
||||
-- ÉTAPE 2: Migration des tables depuis uof_linet
|
||||
-- ==============================================================================
|
||||
|
||||
-- Tables métier principales
|
||||
CREATE TABLE IF NOT EXISTS `devis` LIKE `uof_linet`.`devis`;
|
||||
INSERT INTO `devis` SELECT * FROM `uof_linet`.`devis`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `devis_produits` LIKE `uof_linet`.`devis_produits`;
|
||||
INSERT INTO `devis_produits` SELECT * FROM `uof_linet`.`devis_produits`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `devis_histo` LIKE `uof_linet`.`devis_histo`;
|
||||
INSERT INTO `devis_histo` SELECT * FROM `uof_linet`.`devis_histo`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `clients` LIKE `uof_linet`.`clients`;
|
||||
INSERT INTO `clients` SELECT * FROM `uof_linet`.`clients`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `produits` LIKE `uof_linet`.`produits`;
|
||||
INSERT INTO `produits` SELECT * FROM `uof_linet`.`produits`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `produits_familles` LIKE `uof_linet`.`produits_familles`;
|
||||
INSERT INTO `produits_familles` SELECT * FROM `uof_linet`.`produits_familles`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `marches` LIKE `uof_linet`.`marches`;
|
||||
INSERT INTO `marches` SELECT * FROM `uof_linet`.`marches`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `users` LIKE `uof_linet`.`users`;
|
||||
INSERT INTO `users` SELECT * FROM `uof_linet`.`users`;
|
||||
|
||||
-- Tables de référence (x_*)
|
||||
CREATE TABLE IF NOT EXISTS `x_familles` LIKE `uof_linet`.`x_familles`;
|
||||
INSERT INTO `x_familles` SELECT * FROM `uof_linet`.`x_familles`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `x_statuts_devis` LIKE `uof_linet`.`x_statuts_devis`;
|
||||
INSERT INTO `x_statuts_devis` SELECT * FROM `uof_linet`.`x_statuts_devis`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `x_clients_types` LIKE `uof_linet`.`x_clients_types`;
|
||||
INSERT INTO `x_clients_types` SELECT * FROM `uof_linet`.`x_clients_types`;
|
||||
|
||||
-- ==============================================================================
|
||||
-- ÉTAPE 3: Migration de y_pages depuis uof_frontal
|
||||
-- ==============================================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `y_pages` (
|
||||
`rowid` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`script` varchar(50) DEFAULT NULL,
|
||||
`titre` varchar(255) DEFAULT NULL,
|
||||
`description` text,
|
||||
`keywords` text,
|
||||
`admin` tinyint(1) DEFAULT 0,
|
||||
`active` tinyint(1) DEFAULT 1,
|
||||
`mail` tinyint(1) DEFAULT 0,
|
||||
`form` tinyint(1) DEFAULT 0,
|
||||
`sidebar` tinyint(1) DEFAULT 0,
|
||||
`chart` tinyint(1) DEFAULT 0,
|
||||
`agenda` tinyint(1) DEFAULT 0,
|
||||
`autocomplete` tinyint(1) DEFAULT 0,
|
||||
`scheduler` tinyint(1) DEFAULT 0,
|
||||
`osm` tinyint(1) DEFAULT 0,
|
||||
`vuejs` tinyint(1) DEFAULT 0,
|
||||
`files` tinyint(1) DEFAULT 0,
|
||||
`layout` varchar(50) DEFAULT 'default',
|
||||
PRIMARY KEY (`rowid`),
|
||||
KEY `idx_script` (`script`),
|
||||
KEY `idx_admin` (`admin`),
|
||||
KEY `idx_active` (`active`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Import des données depuis uof_frontal.y_pages
|
||||
INSERT INTO `y_pages` SELECT * FROM `uof_frontal`.`y_pages` WHERE admin = 1;
|
||||
|
||||
-- ==============================================================================
|
||||
-- ÉTAPE 4: Migration de users_entites depuis uof_frontal
|
||||
-- ==============================================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `users_entites` (
|
||||
`rowid` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`appname` varchar(50) DEFAULT NULL,
|
||||
`libelle` varchar(255) DEFAULT NULL,
|
||||
`adresse1` varchar(255) DEFAULT NULL,
|
||||
`adresse2` varchar(255) DEFAULT NULL,
|
||||
`cp` varchar(10) DEFAULT NULL,
|
||||
`ville` varchar(100) DEFAULT NULL,
|
||||
`tel1` varchar(20) DEFAULT NULL,
|
||||
`email` varchar(255) DEFAULT NULL,
|
||||
`http_host` varchar(255) DEFAULT NULL,
|
||||
`groupebase` varchar(50) DEFAULT NULL,
|
||||
`genbase` varchar(50) DEFAULT NULL,
|
||||
`table_users_gen` varchar(100) DEFAULT 'users',
|
||||
`active` tinyint(1) DEFAULT 1,
|
||||
PRIMARY KEY (`rowid`),
|
||||
KEY `idx_appname` (`appname`),
|
||||
KEY `idx_http_host` (`http_host`),
|
||||
KEY `idx_active` (`active`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Import des données depuis uof_frontal.users_entites
|
||||
INSERT INTO `users_entites` SELECT * FROM `uof_frontal`.`users_entites`;
|
||||
|
||||
-- ==============================================================================
|
||||
-- ÉTAPE 5: Création de la table z_logs (depuis la base logs si elle existe)
|
||||
-- ==============================================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `z_logs` (
|
||||
`rowid` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`fk_user` int(11) DEFAULT 0,
|
||||
`script` varchar(50) DEFAULT NULL,
|
||||
`user_agent` varchar(100) DEFAULT NULL,
|
||||
`http_host` varchar(100) DEFAULT NULL,
|
||||
`ip_client` varchar(50) DEFAULT NULL,
|
||||
`appname` varchar(50) DEFAULT NULL,
|
||||
`commentaire` text,
|
||||
`date_histo` datetime DEFAULT NULL,
|
||||
`notif` tinyint(1) DEFAULT 0,
|
||||
PRIMARY KEY (`rowid`),
|
||||
KEY `idx_user` (`fk_user`),
|
||||
KEY `idx_date` (`date_histo`),
|
||||
KEY `idx_script` (`script`),
|
||||
KEY `idx_appname` (`appname`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Si la base logs existe, importer les données
|
||||
-- INSERT INTO `z_logs` SELECT * FROM `logs`.`z_logs`;
|
||||
|
||||
-- ==============================================================================
|
||||
-- ÉTAPE 6: Mise à jour des configurations
|
||||
-- ==============================================================================
|
||||
|
||||
-- Mise à jour de users_entites pour la nouvelle configuration
|
||||
UPDATE `users_entites`
|
||||
SET
|
||||
`genbase` = 'cleo',
|
||||
`groupebase` = 'cleo',
|
||||
`table_users_gen` = 'users'
|
||||
WHERE `active` = 1;
|
||||
|
||||
-- ==============================================================================
|
||||
-- ÉTAPE 7: Création de l'utilisateur pour l'application
|
||||
-- ==============================================================================
|
||||
|
||||
-- Créer l'utilisateur s'il n'existe pas
|
||||
CREATE USER IF NOT EXISTS 'cleo_user'@'%' IDENTIFIED BY 'CleoDev2025!';
|
||||
|
||||
-- Donner tous les privilèges sur la base cleo
|
||||
GRANT ALL PRIVILEGES ON `cleo`.* TO 'cleo_user'@'%';
|
||||
|
||||
-- Rafraîchir les privilèges
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
-- ==============================================================================
|
||||
-- ÉTAPE 8: Vérifications
|
||||
-- ==============================================================================
|
||||
|
||||
-- Afficher le nombre de lignes par table
|
||||
SELECT 'devis' as table_name, COUNT(*) as nb_lignes FROM devis
|
||||
UNION ALL
|
||||
SELECT 'devis_produits', COUNT(*) FROM devis_produits
|
||||
UNION ALL
|
||||
SELECT 'clients', COUNT(*) FROM clients
|
||||
UNION ALL
|
||||
SELECT 'produits', COUNT(*) FROM produits
|
||||
UNION ALL
|
||||
SELECT 'marches', COUNT(*) FROM marches
|
||||
UNION ALL
|
||||
SELECT 'users', COUNT(*) FROM users
|
||||
UNION ALL
|
||||
SELECT 'y_pages', COUNT(*) FROM y_pages
|
||||
UNION ALL
|
||||
SELECT 'users_entites', COUNT(*) FROM users_entites
|
||||
UNION ALL
|
||||
SELECT 'z_logs', COUNT(*) FROM z_logs;
|
||||
|
||||
-- ==============================================================================
|
||||
-- FIN DE LA MIGRATION
|
||||
-- ==============================================================================
|
||||
--
|
||||
-- IMPORTANT: Après exécution de ce script:
|
||||
-- 1. Vérifier que toutes les données ont été correctement migrées
|
||||
-- 2. Mettre à jour le fichier .env avec les nouvelles informations de connexion
|
||||
-- 3. Tester l'application avec la nouvelle base
|
||||
-- 4. Si tout est OK, sauvegarder les anciennes bases avant suppression
|
||||
--
|
||||
113
migration/rollback.sh
Executable file
113
migration/rollback.sh
Executable file
@@ -0,0 +1,113 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script de rollback pour revenir à l'ancienne architecture
|
||||
# Version: 2.0.1
|
||||
# Date: 2025-09-11
|
||||
|
||||
set -e
|
||||
|
||||
# Couleurs pour l'affichage
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
echo -e "${YELLOW}================================================${NC}"
|
||||
echo -e "${YELLOW} Rollback CLEO - Retour architecture legacy ${NC}"
|
||||
echo -e "${YELLOW}================================================${NC}"
|
||||
echo ""
|
||||
|
||||
# Vérifier qu'on est dans le bon répertoire
|
||||
if [ ! -f "index.php" ] || [ ! -d "config" ]; then
|
||||
echo -e "${RED}Erreur: Ce script doit être exécuté depuis la racine du projet CLEO${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Fonction pour demander confirmation
|
||||
confirm() {
|
||||
read -p "$1 [y/N] " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
echo -e "${YELLOW}ATTENTION: Cette opération va restaurer l'ancienne configuration${NC}"
|
||||
if ! confirm "Voulez-vous continuer?"; then
|
||||
echo "Rollback annulé"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e "${YELLOW}1. Restauration des fichiers originaux...${NC}"
|
||||
|
||||
# Restaurer conf.php
|
||||
if [ -f "config/conf_old.php" ]; then
|
||||
mv config/conf.php config/conf_new_backup.php 2>/dev/null || true
|
||||
mv config/conf_old.php config/conf.php
|
||||
echo -e "${GREEN} ✓ config/conf.php restauré${NC}"
|
||||
else
|
||||
# Chercher dans les backups
|
||||
LATEST_BACKUP=$(ls -td backup_* 2>/dev/null | head -1)
|
||||
if [ -n "$LATEST_BACKUP" ] && [ -f "$LATEST_BACKUP/conf.php.bak" ]; then
|
||||
cp "$LATEST_BACKUP/conf.php.bak" config/conf.php
|
||||
echo -e "${GREEN} ✓ config/conf.php restauré depuis $LATEST_BACKUP${NC}"
|
||||
else
|
||||
echo -e "${RED} ✗ Impossible de restaurer config/conf.php${NC}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Restaurer d6_tools.php
|
||||
if [ -f "pub/res/d6/d6_tools_old.php" ]; then
|
||||
mv pub/res/d6/d6_tools.php pub/res/d6/d6_tools_new_backup.php 2>/dev/null || true
|
||||
mv pub/res/d6/d6_tools_old.php pub/res/d6/d6_tools.php
|
||||
echo -e "${GREEN} ✓ d6_tools.php restauré${NC}"
|
||||
else
|
||||
# Chercher dans les backups
|
||||
LATEST_BACKUP=$(ls -td backup_* 2>/dev/null | head -1)
|
||||
if [ -n "$LATEST_BACKUP" ] && [ -f "$LATEST_BACKUP/d6_tools.php.bak" ]; then
|
||||
cp "$LATEST_BACKUP/d6_tools.php.bak" pub/res/d6/d6_tools.php
|
||||
echo -e "${GREEN} ✓ d6_tools.php restauré depuis $LATEST_BACKUP${NC}"
|
||||
else
|
||||
echo -e "${RED} ✗ Impossible de restaurer d6_tools.php${NC}"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e "${YELLOW}2. Configuration de la base de données...${NC}"
|
||||
echo -e "${YELLOW} Note: Les bases uof_frontal et uof_linet doivent être disponibles${NC}"
|
||||
echo -e "${YELLOW} La base 'cleo' reste en place pour référence future${NC}"
|
||||
|
||||
echo ""
|
||||
echo -e "${YELLOW}3. Nettoyage...${NC}"
|
||||
|
||||
# Conserver les nouveaux fichiers pour référence
|
||||
if [ ! -d "migration/new_architecture_backup" ]; then
|
||||
mkdir -p migration/new_architecture_backup
|
||||
fi
|
||||
|
||||
# Sauvegarder les nouveaux fichiers
|
||||
[ -f "config/conf_new.php" ] && cp config/conf_new.php migration/new_architecture_backup/
|
||||
[ -f "config/Database.php" ] && cp config/Database.php migration/new_architecture_backup/
|
||||
[ -f "pub/res/d6/d6_tools_new.php" ] && cp pub/res/d6/d6_tools_new.php migration/new_architecture_backup/
|
||||
[ -f ".env" ] && cp .env migration/new_architecture_backup/
|
||||
[ -f ".env.example" ] && cp .env.example migration/new_architecture_backup/
|
||||
|
||||
echo -e "${GREEN} ✓ Nouveaux fichiers sauvegardés dans migration/new_architecture_backup/${NC}"
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}================================================${NC}"
|
||||
echo -e "${GREEN} Rollback terminé! ${NC}"
|
||||
echo -e "${GREEN}================================================${NC}"
|
||||
echo ""
|
||||
echo "L'application utilise maintenant l'ancienne architecture avec:"
|
||||
echo " - Base uof_frontal pour la configuration"
|
||||
echo " - Base uof_linet pour les données métier"
|
||||
echo ""
|
||||
echo "Les fichiers de la nouvelle architecture sont conservés dans:"
|
||||
echo " - migration/new_architecture_backup/"
|
||||
echo ""
|
||||
echo "Pour réessayer la migration plus tard:"
|
||||
echo " ./migration/deploy_new_architecture.sh"
|
||||
echo ""
|
||||
@@ -4,7 +4,7 @@ $aModel = array();
|
||||
function openSession($userdata)
|
||||
{
|
||||
$uid = $userdata['rowid'];
|
||||
$urole = $userdata['role'];
|
||||
$urole = $userdata['fk_role'];
|
||||
|
||||
$sql = "DELETE FROM z_sessions WHERE fk_user=" . $uid . ";";
|
||||
qSQL($sql, "gen");
|
||||
|
||||
@@ -26,7 +26,7 @@ if ($Conf::intra || $Conf::admin > 0) {
|
||||
?>
|
||||
<meta name="HandheldFriendly" content="True">
|
||||
<meta name="MobileOptimized" content="320">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<link rel="icon" href="favicon.ico"/>
|
||||
<link rel="shortcut icon" href="favicon.ico"/>
|
||||
<link rel="apple-touch-icon" href="favicon.ico"/>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<?php
|
||||
setlocale(LC_ALL, 'fr', 'fr_FR', 'french', 'fra', 'fra_FRA', 'fr_FR.ISO_8859-1', 'fra_FRA.ISO_8859-1', 'fr_FR.utf8', 'fr_FR.utf-8', 'fra_FRA.utf8', 'fra_FRA.utf-8');
|
||||
|
||||
$today = date("Y-m-d H:i:s");
|
||||
require_once dirname(__DIR__, 3) . '/config/Database.php';
|
||||
|
||||
$today = date("Y-m-d H:i:s");
|
||||
$dateFr = date("d/m/Y");
|
||||
$dateTimeFr = date("d/m/Y H:i:s");
|
||||
$timeFr = date("H:i:s");
|
||||
@@ -12,310 +13,21 @@ $jour_abr = array("Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam");
|
||||
$mois = array("", "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre");
|
||||
$mois_abr = array("", "Jan", "Fév", "Mar", "Avr", "Mai", "Jui", "Jul", "Aoû", "Sep", "Oct", "Nov", "Déc");
|
||||
|
||||
function getinfos($cSQL, $dbn = "gen", $format = "normal") {
|
||||
$result = array();
|
||||
// La fonction getinfos() est maintenant définie dans config/Database.php
|
||||
// pour éviter les conflits de redéclaration
|
||||
|
||||
$resql = qSQL($cSQL, $dbn);
|
||||
while ($rec = $resql->fetch_assoc()) {
|
||||
$result[] = $rec;
|
||||
}
|
||||
if (strtolower($format) == "json") {
|
||||
$jsonresult = json_encode($result);
|
||||
$lignes = $jsonresult;
|
||||
return $lignes;
|
||||
} else {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
//! qSQL : fonction de requête SQL à la base de données
|
||||
function qSQL($qsql, $dbn = "gen", $lastid = false) {
|
||||
global $Conf;
|
||||
$dbh = $Conf->_dbhost;
|
||||
//! si en paramètre on spécifie une base de données $dbn, on s'y connecte,
|
||||
//! sinon on regarde si la base utilisateur est renseignée, si c'est le cas on s'y connecte, sinon on prend la base par défaut
|
||||
if ($dbn == "gen") {
|
||||
if ($Conf->_dbuname == "") {
|
||||
$dbn = $Conf->_dbname;
|
||||
$dbu = $Conf->_dbuser;
|
||||
$dbp = $Conf->_dbpass;
|
||||
} else {
|
||||
$dbn = $Conf->_dbuname;
|
||||
$dbu = $Conf->_dbuuser;
|
||||
$dbp = $Conf->_dbupass;
|
||||
}
|
||||
} else {
|
||||
if (strtolower($dbn) == "principale" || strtolower($dbn) == "frontal") {
|
||||
$dbn = $Conf->_dbname;
|
||||
$dbu = $Conf->_dbuser;
|
||||
$dbp = $Conf->_dbpass;
|
||||
} else {
|
||||
if (strtolower($dbn) == "credemo") {
|
||||
$dbn = $Conf->_dbcname;
|
||||
$dbu = $Conf->_dbcuser;
|
||||
$dbp = $Conf->_dbcpass;
|
||||
} else {
|
||||
//! sinon on prend le groupe
|
||||
$dbn = $Conf->_dbgname;
|
||||
$dbu = $Conf->_dbguser;
|
||||
$dbp = $Conf->_dbgpass;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$mysqli = new mysqli($dbh, $dbu, $dbp, $dbn);
|
||||
$mysqli->set_charset("utf8");
|
||||
if ($mysqli->connect_error) {
|
||||
// la connexion ne s'est pas faite
|
||||
$mysqli->close();
|
||||
return false;
|
||||
} else {
|
||||
// la connexion s'est faite correctement
|
||||
if ($qres = $mysqli->query($qsql)) {
|
||||
if ($lastid) {
|
||||
$qres = $mysqli->insert_id;
|
||||
}
|
||||
$mysqli->close();
|
||||
return $qres;
|
||||
} else {
|
||||
$mysqli->close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function hashPsswd($p) {
|
||||
$options = [
|
||||
'cost' => 11, // Cout algorithmique
|
||||
];
|
||||
// Génération du MDP
|
||||
$psswd = password_hash($p, PASSWORD_BCRYPT, $options);
|
||||
return $psswd;
|
||||
}
|
||||
|
||||
function createPsswd($id, $p, $dbgen = "gen") {
|
||||
global $Conf;
|
||||
global $Route;
|
||||
|
||||
$psswd = hashPsswd($p);
|
||||
|
||||
if ($Conf::admin) {
|
||||
if (substr($Conf->_appname, 0, 3) == "ce_") {
|
||||
if ($Route->_script == "salaries") {
|
||||
$sql = 'UPDATE salaries SET userpswd="' . $psswd . '", userpass="xxx" WHERE rowid=' . $id . ';';
|
||||
} else {
|
||||
$sql = 'UPDATE users SET userpswd="' . $psswd . '", userpass="xxx" WHERE rowid=' . $id . ';';
|
||||
}
|
||||
} else {
|
||||
$sql = 'UPDATE users SET userpswd="' . $psswd . '", userpass="xxx" WHERE rowid=' . $id . ';';
|
||||
}
|
||||
} else {
|
||||
$sql = 'UPDATE salaries SET userpswd="' . $psswd . '", userpass="xxx" WHERE rowid=' . $id . ';';
|
||||
}
|
||||
|
||||
qSQL($sql);
|
||||
|
||||
eLog($sql);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function checkPsswd($p, $pCr) {
|
||||
// Récupération et vérification du MDP saisi par l'utilisateur
|
||||
// $p : le pass en clair, $pCr : le pass enregistré et hashé
|
||||
if (password_verify($p, $pCr)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function generateRandomPassword() {
|
||||
//Initialize the random password
|
||||
$password = '';
|
||||
|
||||
//Initialize a random desired length
|
||||
$desired_length = rand(8, 12);
|
||||
|
||||
for ($length = 0; $length < $desired_length; $length++) {
|
||||
//Append a random ASCII character (including symbols)
|
||||
$password .= chr(rand(44, 122));
|
||||
}
|
||||
// On remplace quelques caractères non désirés
|
||||
$password = str_replace("/", "&", $password);
|
||||
$password = str_replace("<", "!", $password);
|
||||
$password = str_replace(">", "!", $password);
|
||||
$password = str_replace("=", "#", $password);
|
||||
$password = str_replace("\\", "&", $password);
|
||||
$password = str_replace("^", "%", $password);
|
||||
$password = str_replace(chr(96), "#", $password);
|
||||
|
||||
return $password;
|
||||
}
|
||||
|
||||
function eLog($comment, $notif = false) {
|
||||
global $Session;
|
||||
global $Route;
|
||||
global $Conf;
|
||||
|
||||
if (!empty($_SERVER["HTTP_CLIENT_IP"])) {
|
||||
$ip = $_SERVER["HTTP_CLIENT_IP"];
|
||||
} elseif (!empty($_SERVER["HTTP_X_FORWARDED_FOR"])) {
|
||||
$ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
|
||||
} else {
|
||||
$ip = $_SERVER["REMOTE_ADDR"];
|
||||
}
|
||||
$hn = getHostByName($ip);
|
||||
$ha = @getHostByAddr($hn);
|
||||
$us = $_SERVER["HTTP_USER_AGENT"];
|
||||
if (isset($Session->_user["rowid"])) {
|
||||
$user = $Session->_user["rowid"];
|
||||
if ($user == "") {
|
||||
$user = 0;
|
||||
}
|
||||
} else {
|
||||
$user = 0;
|
||||
}
|
||||
$script = $Route->_script;
|
||||
$comment = nettoie_input($comment);
|
||||
$dt = date("Y-m-d H:i:s");
|
||||
if ($notif) {
|
||||
$not = 1;
|
||||
} else {
|
||||
$not = 2;
|
||||
}
|
||||
$sql = 'INSERT INTO z_logs (date, ip, host, adrhost, infos, fk_user, page, commentaire, chk_notif) VALUES ("' . $dt . '", "' . $ip . '", "' . $hn . '", "' . $ha . '", "' . $us . '", "' . $user . '", "' . $script . '", "' . $comment . '", ' . $not . ');';
|
||||
qSQL($sql, "gen");
|
||||
|
||||
if (strpos(strtolower($comment), 'erreur') !== false) {
|
||||
//! S'il y a spécifiquement une erreur on l'enregistre dans un fichier log à la racine du site
|
||||
error_log($dt . ";" . $ip . ";" . $script . ";" . $comment . "\r\n", 3, "./" . $Conf->_appname . ".log");
|
||||
}
|
||||
}
|
||||
// La fonction qSQL() est maintenant définie dans config/Database.php
|
||||
// pour éviter les conflits de redéclaration
|
||||
|
||||
// Fonction logstats simplifiée (la table z_stats n'existe pas encore)
|
||||
function logstats($delay = 0, $fk_user = 0, $appname = "") {
|
||||
global $Conf;
|
||||
$dt = date("Y-m-d H:i:s");
|
||||
|
||||
$exclude_clients_ip = "aucune";
|
||||
if (isset($Conf->_excludeIp)) {
|
||||
$exclude_clients_ip = $Conf->_excludeIp;
|
||||
}
|
||||
|
||||
if (isset($Conf->_clientIp)) {
|
||||
$client_ip = $Conf->_clientIp;
|
||||
} else {
|
||||
if (!empty($_SERVER["HTTP_CLIENT_IP"])) {
|
||||
$client_ip = $_SERVER["HTTP_CLIENT_IP"];
|
||||
} elseif (!empty($_SERVER["HTTP_X_FORWARDED_FOR"])) {
|
||||
$client_ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
|
||||
} else {
|
||||
$client_ip = $_SERVER["REMOTE_ADDR"];
|
||||
}
|
||||
}
|
||||
$verif_ip = strpos($exclude_clients_ip, $client_ip);
|
||||
|
||||
if ($verif_ip === false) {
|
||||
|
||||
$home = $_SERVER["HOME"];
|
||||
$doc_root = $_SERVER["DOCUMENT_ROOT"];
|
||||
$doc_root = substr($doc_root, strlen($home));
|
||||
|
||||
$sql = 'INSERT INTO z_stats SET ';
|
||||
$sql .= 'date="' . $dt . '", ';
|
||||
$sql .= 'root="' . $doc_root . '", ';
|
||||
$sql .= 'server_ip="' . $_SERVER["SERVER_ADDR"] . '", ';
|
||||
$sql .= 'server_soft="' . $_SERVER["SERVER_SOFTWARE"] . '", ';
|
||||
$sql .= 'server_name="' . $_SERVER["SERVER_NAME"] . '", ';
|
||||
$sql .= 'client_ip="' . $client_ip . '", ';
|
||||
$sql .= 'client_browser="' . $_SERVER["HTTP_USER_AGENT"] . '", ';
|
||||
if (isset($_SERVER["HTTP_REFERER"])) {
|
||||
$sql .= 'client_origine="' . $_SERVER["HTTP_REFERER"] . '", ';
|
||||
}
|
||||
$sql .= 'client_page="' . $_SERVER["REQUEST_URI"] . '", ';
|
||||
$sql .= 'client_delay=' . str_replace(',', '.', $delay) . ', ';
|
||||
$sql .= 'appname="' . $appname . '", ';
|
||||
$sql .= 'fk_user=' . $fk_user . ', ';
|
||||
$sql .= 'status="' . $_SERVER["REDIRECT_STATUS"] . '";';
|
||||
|
||||
// server : 51.255.35.214
|
||||
$mysqli = new mysqli("localhost", "logs_user", "d66,Logs.User", "logs");
|
||||
$mysqli->set_charset("utf8");
|
||||
$mysqli->query($sql);
|
||||
$mysqli->close();
|
||||
}
|
||||
}
|
||||
|
||||
//! *****************************************************************************************//
|
||||
//! nettoie_input : prépare une zone d'un formulaire avant son enregistrement dans la base //
|
||||
//! En paramètre, on passe la valeur à nettoyer //
|
||||
//! *****************************************************************************************//
|
||||
function nettoie_input($data) {
|
||||
if (ctype_digit($data)) {
|
||||
$data = intval($data);
|
||||
} else {
|
||||
global $Conf;
|
||||
$dbn = $Conf->_dbname;
|
||||
$mysqli = new mysqli($Conf->_dbhost, $Conf->_dbuser, $Conf->_dbpass, $dbn);
|
||||
$mysqli->set_charset("utf8");
|
||||
$data = mysqli_real_escape_string($mysqli, $data);
|
||||
// $data = addcslashes($data, '%_');
|
||||
$mysqli->close();
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
function str_normalize($string, $minuscules = true) {
|
||||
//! Normalise une chaîne de caractères en remplaçant tous les caractères accentués, les espaces et caractères spéciaux
|
||||
$result = "";
|
||||
$string = trim($string); // on efface tous les espaces à gauche et à droite
|
||||
if (strlen($string) > 0) {
|
||||
if ($minuscules) {
|
||||
$result = strtolower($string);
|
||||
} else {
|
||||
$result = $string;
|
||||
}
|
||||
$result = str_replace(" ", "_", $result);
|
||||
//$result = str_replace("-", "_", $result);
|
||||
//$result = str_replace(".", "_", $result);
|
||||
$result = str_replace("é", "e", $result);
|
||||
$result = str_replace("è", "e", $result);
|
||||
$result = str_replace("ê", "e", $result);
|
||||
$result = str_replace("ë", "e", $result);
|
||||
$result = str_replace("à", "a", $result);
|
||||
$result = str_replace("â", "a", $result);
|
||||
$result = str_replace("ä", "a", $result);
|
||||
$result = str_replace("ô", "o", $result);
|
||||
$result = str_replace("ö", "o", $result);
|
||||
$result = str_replace("ù", "u", $result);
|
||||
$result = str_replace("û", "u", $result);
|
||||
$result = str_replace("ü", "u", $result);
|
||||
$result = str_replace("ç", "c", $result);
|
||||
$result = str_replace("'", "", $result);
|
||||
$result = str_replace("\"", "", $result);
|
||||
$result = str_replace("/", "", $result);
|
||||
$result = str_replace("(", "_", $result);
|
||||
$result = str_replace(")", "_", $result);
|
||||
$result = str_replace("!", "_", $result);
|
||||
//! Ajout du 08/12/2015
|
||||
$result = str_replace("?", "_", $result);
|
||||
|
||||
$result = trim($result);
|
||||
}
|
||||
return $result;
|
||||
// Pour l'instant, on ne fait rien
|
||||
// TODO: Créer la table z_stats si besoin de statistiques
|
||||
return true;
|
||||
}
|
||||
|
||||
function affiche_date($ladate) {
|
||||
/**
|
||||
* This is a sample function to illustrate additional PHP formatter
|
||||
* options.
|
||||
* @param $ladate date au format MySQL
|
||||
*
|
||||
* @return String date au format Fr dd/mm/yyyy
|
||||
* @author D6SOFT
|
||||
*
|
||||
*/
|
||||
//! Retourne une date MySQL yyyy-mm-dd HH:ii:ss au format dd/mm/yyyy
|
||||
// Retourne une date MySQL yyyy-mm-dd HH:ii:ss au format dd/mm/yyyy
|
||||
$ladate = trim($ladate);
|
||||
if ($ladate == "" || substr($ladate, 0, 2) == "00") {
|
||||
return "";
|
||||
@@ -330,9 +42,9 @@ function affiche_date($ladate) {
|
||||
}
|
||||
|
||||
function d6GetDate($laDate, $transform = "MF", $hours = false, $seconds = false) {
|
||||
//! Retourne une date
|
||||
//! $format="MF" du format MySQL yyyy-mm-dd au format Fr dd/mm/yyyy
|
||||
//! $format="FM" du format Fr dd/mm/yyyy au format MySQL yyyy-mm-dd
|
||||
// Retourne une date
|
||||
// $transform="MF" du format MySQL yyyy-mm-dd au format Fr dd/mm/yyyy
|
||||
// $transform="FM" du format Fr dd/mm/yyyy au format MySQL yyyy-mm-dd
|
||||
|
||||
$ret = "";
|
||||
if (strlen($laDate) >= 10) {
|
||||
@@ -345,26 +57,200 @@ function d6GetDate($laDate, $transform = "MF", $hours = false, $seconds = false)
|
||||
return $ret;
|
||||
}
|
||||
|
||||
function loadtel($numero, $prefix = "+33") {
|
||||
//! retourne un numéro de téléphone sans espace et . et avec le préfixe devant : +33 par défaut
|
||||
$lenumero = trim($numero);
|
||||
$lenumero = preg_replace('/[^0-9]/', '', $lenumero);
|
||||
if (strlen($lenumero) == 10) {
|
||||
$lenumero = substr($lenumero, 1);
|
||||
}
|
||||
if (strlen($lenumero) == 9) {
|
||||
$lenumero = $prefix . $lenumero;
|
||||
}
|
||||
return $lenumero;
|
||||
function hashPsswd($p) {
|
||||
$options = [
|
||||
'cost' => 11,
|
||||
];
|
||||
$psswd = password_hash($p, PASSWORD_BCRYPT, $options);
|
||||
return $psswd;
|
||||
}
|
||||
|
||||
function formattel($numero, $separateur = " ") {
|
||||
//! formate le n° de téléphone de 651234567 ou 0651234567 en 06 51 23 45 67
|
||||
if (strlen($numero) == 9) {
|
||||
$numero = "0" . $numero;
|
||||
}
|
||||
if (strlen($numero) == 10) {
|
||||
$numero = substr($numero, 0, 2) . $separateur . substr($numero, 2, 2) . $separateur . substr($numero, 4, 2) . $separateur . substr($numero, 6, 2) . $separateur . substr($numero, 8, 2);
|
||||
}
|
||||
return $numero;
|
||||
function checkPsswd($p, $pCr) {
|
||||
// Vérification du MDP saisi par l'utilisateur
|
||||
// $p : le pass en clair, $pCr : le pass enregistré et hashé
|
||||
return password_verify($p, $pCr);
|
||||
}
|
||||
|
||||
function createPsswd($id, $p, $dbgen = "gen") {
|
||||
global $Conf;
|
||||
global $Route;
|
||||
|
||||
$psswd = hashPsswd($p);
|
||||
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
|
||||
$table = $Conf->_tbusers ?? 'users';
|
||||
$sql = "UPDATE $table SET password = :password WHERE rowid = :id";
|
||||
|
||||
$result = $db->query($sql, ['password' => $psswd, 'id' => $id]);
|
||||
|
||||
if ($result instanceof PDOStatement && $result->rowCount() > 0) {
|
||||
eLog(0, "Changement de mot de passe réussi pour l'utilisateur ID: $id");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log("Erreur createPsswd: " . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function vPassword($p, $hashed) {
|
||||
if (password_verify($p, $hashed)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function nettoie_chaine($input) {
|
||||
if (is_null($input)) {
|
||||
$input = "";
|
||||
}
|
||||
$res = trim(str_replace("'", "'", $input));
|
||||
$res = trim(str_replace('"', """, $res));
|
||||
$res = str_replace('<', '<', $res);
|
||||
$res = str_replace('>', '>', $res);
|
||||
return $res;
|
||||
}
|
||||
|
||||
function nettoie_input($input) {
|
||||
if (is_null($input)) {
|
||||
$input = "";
|
||||
}
|
||||
$input = trim($input);
|
||||
$input = stripslashes($input);
|
||||
$input = htmlspecialchars($input, ENT_QUOTES, 'UTF-8');
|
||||
return $input;
|
||||
}
|
||||
|
||||
function nettoie($input) {
|
||||
if (is_null($input)) {
|
||||
$input = "";
|
||||
}
|
||||
$res = trim($input);
|
||||
$res = str_replace("'", "'", $res);
|
||||
$res = str_replace('"', '"', $res);
|
||||
$res = str_replace('<', '', $res);
|
||||
$res = str_replace('>', '', $res);
|
||||
return $res;
|
||||
}
|
||||
|
||||
function dateEN($date) {
|
||||
if ($date == '') return '';
|
||||
if (strpos($date, '/') !== false) {
|
||||
list($jour, $mois, $annee) = explode('/', $date);
|
||||
return $annee . '-' . $mois . '-' . $jour;
|
||||
}
|
||||
return $date;
|
||||
}
|
||||
|
||||
function dateFR($date) {
|
||||
if ($date == '' || $date == '0000-00-00') return '';
|
||||
if (strpos($date, '-') !== false) {
|
||||
list($annee, $mois, $jour) = explode('-', substr($date, 0, 10));
|
||||
return $jour . '/' . $mois . '/' . $annee;
|
||||
}
|
||||
return $date;
|
||||
}
|
||||
|
||||
function datetimeFR($datetime) {
|
||||
if ($datetime == '' || $datetime == '0000-00-00 00:00:00') return '';
|
||||
list($date, $time) = explode(' ', $datetime);
|
||||
return dateFR($date) . ' ' . substr($time, 0, 5);
|
||||
}
|
||||
|
||||
function eLog($user = 0, $comment = "", $notif = false) {
|
||||
global $Conf;
|
||||
global $Session;
|
||||
global $Route;
|
||||
|
||||
if ($comment == "") return;
|
||||
|
||||
$script = isset($Route->_script) ? $Route->_script : "";
|
||||
$dt = date("Y-m-d H:i:s");
|
||||
|
||||
if (!empty($_SERVER["HTTP_CLIENT_IP"])) {
|
||||
$ip = $_SERVER["HTTP_CLIENT_IP"];
|
||||
} elseif (!empty($_SERVER["HTTP_X_FORWARDED_FOR"])) {
|
||||
$ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
|
||||
} else {
|
||||
$ip = $_SERVER["REMOTE_ADDR"];
|
||||
}
|
||||
|
||||
$hn = getHostByName($ip);
|
||||
$ha = @getHostByAddr($hn);
|
||||
$us = substr($_SERVER["HTTP_USER_AGENT"] ?? '', 0, 100);
|
||||
|
||||
if (isset($Session->_user["rowid"])) {
|
||||
$user = $Session->_user["rowid"];
|
||||
if ($user == "") {
|
||||
$user = 0;
|
||||
}
|
||||
}
|
||||
|
||||
$appname = isset($Conf->_appname) ? $Conf->_appname : '';
|
||||
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
|
||||
$sql = "INSERT INTO z_logs (fk_user, script, user_agent, http_host, ip_client, appname, commentaire, date_histo, notif)
|
||||
VALUES (:user, :script, :user_agent, :host, :ip, :appname, :comment, :date, :notif)";
|
||||
|
||||
$params = [
|
||||
'user' => $user,
|
||||
'script' => $script,
|
||||
'user_agent' => $us,
|
||||
'host' => $ha,
|
||||
'ip' => $ip,
|
||||
'appname' => $appname,
|
||||
'comment' => $comment,
|
||||
'date' => $dt,
|
||||
'notif' => $notif ? 1 : 0
|
||||
];
|
||||
|
||||
$db->query($sql, $params);
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log("Erreur eLog: " . $e->getMessage());
|
||||
}
|
||||
|
||||
if (strpos(strtolower($comment), 'erreur') !== false) {
|
||||
error_log($dt . ";" . $ip . ";" . $script . ";" . $comment . "\r\n", 3, "./" . $Conf->_appname . ".log");
|
||||
}
|
||||
}
|
||||
|
||||
function debug($data, $type = 'DEBUG', $level = 3) {
|
||||
global $Conf;
|
||||
|
||||
if (!isset($Conf)) return;
|
||||
|
||||
if (method_exists($Conf, 'debug')) {
|
||||
$Conf->debug($data, $type, $level);
|
||||
} else {
|
||||
if ($Conf->_debug_level >= $level) {
|
||||
$timestamp = date('Y-m-d H:i:s');
|
||||
$message = "[$timestamp] [$type] " . (is_array($data) ? json_encode($data) : $data);
|
||||
error_log($message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function timeStart() {
|
||||
return microtime(true);
|
||||
}
|
||||
|
||||
function timeEnd($start, $label = '') {
|
||||
$end = microtime(true);
|
||||
$time = round(($end - $start) * 1000, 2);
|
||||
|
||||
global $Conf;
|
||||
if (isset($Conf) && $Conf->_log_performance) {
|
||||
debug("Performance [$label]: {$time}ms", 'PERFORMANCE', 3);
|
||||
}
|
||||
|
||||
return $time;
|
||||
}
|
||||
254
pub/res/d6/d6_tools_new.php
Normal file
254
pub/res/d6/d6_tools_new.php
Normal file
@@ -0,0 +1,254 @@
|
||||
<?php
|
||||
setlocale(LC_ALL, 'fr', 'fr_FR', 'french', 'fra', 'fra_FRA', 'fr_FR.ISO_8859-1', 'fra_FRA.ISO_8859-1', 'fr_FR.utf8', 'fr_FR.utf-8', 'fra_FRA.utf8', 'fra_FRA.utf-8');
|
||||
|
||||
require_once dirname(__DIR__, 3) . '/config/Database.php';
|
||||
|
||||
$today = date("Y-m-d H:i:s");
|
||||
$dateFr = date("d/m/Y");
|
||||
$dateTimeFr = date("d/m/Y H:i:s");
|
||||
$timeFr = date("H:i:s");
|
||||
|
||||
$jour = array("Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi");
|
||||
$jour_abr = array("Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam");
|
||||
$mois = array("", "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre");
|
||||
$mois_abr = array("", "Jan", "Fév", "Mar", "Avr", "Mai", "Jui", "Jul", "Aoû", "Sep", "Oct", "Nov", "Déc");
|
||||
|
||||
function getinfos($cSQL, $dbn = "gen", $format = "normal") {
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
$result = $db->fetchAll($cSQL);
|
||||
|
||||
if (strtolower($format) == "json") {
|
||||
return json_encode($result);
|
||||
}
|
||||
return $result;
|
||||
|
||||
} catch (Exception $e) {
|
||||
if ($_ENV['APP_DEBUG'] ?? false) {
|
||||
error_log("Erreur getinfos: " . $e->getMessage());
|
||||
}
|
||||
return ($format == "json") ? json_encode([]) : [];
|
||||
}
|
||||
}
|
||||
|
||||
function qSQL($qsql, $dbn = "gen", $lastid = false) {
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
|
||||
$queryType = strtoupper(substr(trim($qsql), 0, 6));
|
||||
|
||||
if ($queryType === 'INSERT' || $queryType === 'UPDATE' || $queryType === 'DELETE') {
|
||||
$stmt = $db->query($qsql);
|
||||
|
||||
if ($lastid && $queryType === 'INSERT') {
|
||||
return $db->lastInsertId();
|
||||
}
|
||||
|
||||
if ($stmt instanceof PDOStatement) {
|
||||
return $stmt->rowCount() > 0;
|
||||
}
|
||||
|
||||
return $stmt;
|
||||
} else {
|
||||
return $db->query($qsql);
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
if ($_ENV['APP_DEBUG'] ?? false) {
|
||||
error_log("Erreur qSQL: " . $e->getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function hashPsswd($p) {
|
||||
$options = [
|
||||
'cost' => 11,
|
||||
];
|
||||
$psswd = password_hash($p, PASSWORD_BCRYPT, $options);
|
||||
return $psswd;
|
||||
}
|
||||
|
||||
function createPsswd($id, $p, $dbgen = "gen") {
|
||||
global $Conf;
|
||||
global $Route;
|
||||
|
||||
$psswd = hashPsswd($p);
|
||||
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
|
||||
$table = $Conf->_tbusers ?? 'users';
|
||||
$sql = "UPDATE $table SET password = :password WHERE rowid = :id";
|
||||
|
||||
$result = $db->query($sql, ['password' => $psswd, 'id' => $id]);
|
||||
|
||||
if ($result instanceof PDOStatement && $result->rowCount() > 0) {
|
||||
eLog(0, "Changement de mot de passe réussi pour l'utilisateur ID: $id");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log("Erreur createPsswd: " . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function vPassword($p, $hashed) {
|
||||
if (password_verify($p, $hashed)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function nettoie_chaine($input) {
|
||||
if (is_null($input)) {
|
||||
$input = "";
|
||||
}
|
||||
$res = trim(str_replace("'", "'", $input));
|
||||
$res = trim(str_replace('"', """, $res));
|
||||
$res = str_replace('<', '<', $res);
|
||||
$res = str_replace('>', '>', $res);
|
||||
return $res;
|
||||
}
|
||||
|
||||
function nettoie_input($input) {
|
||||
if (is_null($input)) {
|
||||
$input = "";
|
||||
}
|
||||
$input = trim($input);
|
||||
$input = stripslashes($input);
|
||||
$input = htmlspecialchars($input, ENT_QUOTES, 'UTF-8');
|
||||
return $input;
|
||||
}
|
||||
|
||||
function nettoie($input) {
|
||||
if (is_null($input)) {
|
||||
$input = "";
|
||||
}
|
||||
$res = trim($input);
|
||||
$res = str_replace("'", "'", $res);
|
||||
$res = str_replace('"', '"', $res);
|
||||
$res = str_replace('<', '', $res);
|
||||
$res = str_replace('>', '', $res);
|
||||
return $res;
|
||||
}
|
||||
|
||||
function dateEN($date) {
|
||||
if ($date == '') return '';
|
||||
if (strpos($date, '/') !== false) {
|
||||
list($jour, $mois, $annee) = explode('/', $date);
|
||||
return $annee . '-' . $mois . '-' . $jour;
|
||||
}
|
||||
return $date;
|
||||
}
|
||||
|
||||
function dateFR($date) {
|
||||
if ($date == '' || $date == '0000-00-00') return '';
|
||||
if (strpos($date, '-') !== false) {
|
||||
list($annee, $mois, $jour) = explode('-', substr($date, 0, 10));
|
||||
return $jour . '/' . $mois . '/' . $annee;
|
||||
}
|
||||
return $date;
|
||||
}
|
||||
|
||||
function datetimeFR($datetime) {
|
||||
if ($datetime == '' || $datetime == '0000-00-00 00:00:00') return '';
|
||||
list($date, $time) = explode(' ', $datetime);
|
||||
return dateFR($date) . ' ' . substr($time, 0, 5);
|
||||
}
|
||||
|
||||
function eLog($user = 0, $comment = "", $notif = false) {
|
||||
global $Conf;
|
||||
global $Session;
|
||||
global $Route;
|
||||
|
||||
if ($comment == "") return;
|
||||
|
||||
$script = isset($Route->_script) ? $Route->_script : "";
|
||||
$dt = date("Y-m-d H:i:s");
|
||||
|
||||
if (!empty($_SERVER["HTTP_CLIENT_IP"])) {
|
||||
$ip = $_SERVER["HTTP_CLIENT_IP"];
|
||||
} elseif (!empty($_SERVER["HTTP_X_FORWARDED_FOR"])) {
|
||||
$ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
|
||||
} else {
|
||||
$ip = $_SERVER["REMOTE_ADDR"];
|
||||
}
|
||||
|
||||
$hn = getHostByName($ip);
|
||||
$ha = @getHostByAddr($hn);
|
||||
$us = substr($_SERVER["HTTP_USER_AGENT"] ?? '', 0, 100);
|
||||
|
||||
if (isset($Session->_user["rowid"])) {
|
||||
$user = $Session->_user["rowid"];
|
||||
if ($user == "") {
|
||||
$user = 0;
|
||||
}
|
||||
}
|
||||
|
||||
$appname = isset($Conf->_appname) ? $Conf->_appname : '';
|
||||
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
|
||||
$sql = "INSERT INTO z_logs (fk_user, script, user_agent, http_host, ip_client, appname, commentaire, date_histo, notif)
|
||||
VALUES (:user, :script, :user_agent, :host, :ip, :appname, :comment, :date, :notif)";
|
||||
|
||||
$params = [
|
||||
'user' => $user,
|
||||
'script' => $script,
|
||||
'user_agent' => $us,
|
||||
'host' => $ha,
|
||||
'ip' => $ip,
|
||||
'appname' => $appname,
|
||||
'comment' => $comment,
|
||||
'date' => $dt,
|
||||
'notif' => $notif ? 1 : 0
|
||||
];
|
||||
|
||||
$db->query($sql, $params);
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log("Erreur eLog: " . $e->getMessage());
|
||||
}
|
||||
|
||||
if (strpos(strtolower($comment), 'erreur') !== false) {
|
||||
error_log($dt . ";" . $ip . ";" . $script . ";" . $comment . "\r\n", 3, "./" . $Conf->_appname . ".log");
|
||||
}
|
||||
}
|
||||
|
||||
function debug($data, $type = 'DEBUG', $level = 3) {
|
||||
global $Conf;
|
||||
|
||||
if (!isset($Conf)) return;
|
||||
|
||||
if (method_exists($Conf, 'debug')) {
|
||||
$Conf->debug($data, $type, $level);
|
||||
} else {
|
||||
if ($Conf->_debug_level >= $level) {
|
||||
$timestamp = date('Y-m-d H:i:s');
|
||||
$message = "[$timestamp] [$type] " . (is_array($data) ? json_encode($data) : $data);
|
||||
error_log($message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function timeStart() {
|
||||
return microtime(true);
|
||||
}
|
||||
|
||||
function timeEnd($start, $label = '') {
|
||||
$end = microtime(true);
|
||||
$time = round(($end - $start) * 1000, 2);
|
||||
|
||||
global $Conf;
|
||||
if (isset($Conf) && $Conf->_log_performance) {
|
||||
debug("Performance [$label]: {$time}ms", 'PERFORMANCE', 3);
|
||||
}
|
||||
|
||||
return $time;
|
||||
}
|
||||
559
pub/res/d6/d6_tools_old.php
Normal file
559
pub/res/d6/d6_tools_old.php
Normal file
@@ -0,0 +1,559 @@
|
||||
<?php
|
||||
setlocale(LC_ALL, 'fr', 'fr_FR', 'french', 'fra', 'fra_FRA', 'fr_FR.ISO_8859-1', 'fra_FRA.ISO_8859-1', 'fr_FR.utf8', 'fr_FR.utf-8', 'fra_FRA.utf8', 'fra_FRA.utf-8');
|
||||
|
||||
$today = date("Y-m-d H:i:s");
|
||||
|
||||
$dateFr = date("d/m/Y");
|
||||
$dateTimeFr = date("d/m/Y H:i:s");
|
||||
$timeFr = date("H:i:s");
|
||||
|
||||
$jour = array("Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi");
|
||||
$jour_abr = array("Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam");
|
||||
$mois = array("", "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre");
|
||||
$mois_abr = array("", "Jan", "Fév", "Mar", "Avr", "Mai", "Jui", "Jul", "Aoû", "Sep", "Oct", "Nov", "Déc");
|
||||
|
||||
function getinfos($cSQL, $dbn = "gen", $format = "normal") {
|
||||
$result = array();
|
||||
|
||||
$resql = qSQL($cSQL, $dbn);
|
||||
while ($rec = $resql->fetch_assoc()) {
|
||||
$result[] = $rec;
|
||||
}
|
||||
if (strtolower($format) == "json") {
|
||||
$jsonresult = json_encode($result);
|
||||
$lignes = $jsonresult;
|
||||
return $lignes;
|
||||
} else {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
//! qSQL : fonction de requête SQL à la base de données
|
||||
function qSQL($qsql, $dbn = "gen", $lastid = false) {
|
||||
global $Conf;
|
||||
$dbh = $Conf->_dbhost;
|
||||
//! si en paramètre on spécifie une base de données $dbn, on s'y connecte,
|
||||
//! sinon on regarde si la base utilisateur est renseignée, si c'est le cas on s'y connecte, sinon on prend la base par défaut
|
||||
if ($dbn == "gen") {
|
||||
if ($Conf->_dbuname == "") {
|
||||
$dbn = $Conf->_dbname;
|
||||
$dbu = $Conf->_dbuser;
|
||||
$dbp = $Conf->_dbpass;
|
||||
} else {
|
||||
$dbn = $Conf->_dbuname;
|
||||
$dbu = $Conf->_dbuuser;
|
||||
$dbp = $Conf->_dbupass;
|
||||
}
|
||||
} else {
|
||||
if (strtolower($dbn) == "principale" || strtolower($dbn) == "frontal") {
|
||||
$dbn = $Conf->_dbname;
|
||||
$dbu = $Conf->_dbuser;
|
||||
$dbp = $Conf->_dbpass;
|
||||
} else {
|
||||
if (strtolower($dbn) == "credemo") {
|
||||
$dbn = $Conf->_dbcname;
|
||||
$dbu = $Conf->_dbcuser;
|
||||
$dbp = $Conf->_dbcpass;
|
||||
} else {
|
||||
//! sinon on prend le groupe
|
||||
$dbn = $Conf->_dbgname;
|
||||
$dbu = $Conf->_dbguser;
|
||||
$dbp = $Conf->_dbgpass;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Logger la requête SQL si le mode debug SQL est activé
|
||||
if (isset($Conf->_log_sql) && $Conf->_log_sql) {
|
||||
$start_time = microtime(true);
|
||||
}
|
||||
|
||||
$mysqli = new mysqli($dbh, $dbu, $dbp, $dbn);
|
||||
$mysqli->set_charset("utf8");
|
||||
if ($mysqli->connect_error) {
|
||||
// la connexion ne s'est pas faite
|
||||
if (isset($Conf->_log_sql) && $Conf->_log_sql) {
|
||||
debug("Erreur de connexion MySQL: " . $mysqli->connect_error . " | DB: $dbn", "SQL_ERROR", 1);
|
||||
}
|
||||
$mysqli->close();
|
||||
return false;
|
||||
} else {
|
||||
// la connexion s'est faite correctement
|
||||
if ($qres = $mysqli->query($qsql)) {
|
||||
if ($lastid) {
|
||||
$qres = $mysqli->insert_id;
|
||||
}
|
||||
|
||||
// Logger la requête SQL réussie
|
||||
if (isset($Conf->_log_sql) && $Conf->_log_sql) {
|
||||
$exec_time = round((microtime(true) - $start_time) * 1000, 2); // en ms
|
||||
$query_type = strtoupper(substr(trim($qsql), 0, 6));
|
||||
$log_data = array(
|
||||
'query' => $qsql,
|
||||
'database' => $dbn,
|
||||
'exec_time_ms' => $exec_time,
|
||||
'type' => $query_type
|
||||
);
|
||||
|
||||
// Pour les INSERT avec lastid, ajouter l'ID inséré
|
||||
if ($lastid && $query_type == 'INSERT') {
|
||||
$log_data['insert_id'] = $qres;
|
||||
}
|
||||
|
||||
debug($log_data, "SQL_QUERY", 2);
|
||||
}
|
||||
|
||||
$mysqli->close();
|
||||
return $qres;
|
||||
} else {
|
||||
// Erreur dans la requête SQL
|
||||
$error_msg = $mysqli->error;
|
||||
|
||||
if (isset($Conf->_log_sql) && $Conf->_log_sql) {
|
||||
$exec_time = isset($start_time) ? round((microtime(true) - $start_time) * 1000, 2) : 0;
|
||||
debug(array(
|
||||
'query' => $qsql,
|
||||
'database' => $dbn,
|
||||
'error' => $error_msg,
|
||||
'exec_time_ms' => $exec_time
|
||||
), "SQL_ERROR", 1);
|
||||
}
|
||||
|
||||
$mysqli->close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function hashPsswd($p) {
|
||||
$options = [
|
||||
'cost' => 11, // Cout algorithmique
|
||||
];
|
||||
// Génération du MDP
|
||||
$psswd = password_hash($p, PASSWORD_BCRYPT, $options);
|
||||
return $psswd;
|
||||
}
|
||||
|
||||
function createPsswd($id, $p, $dbgen = "gen") {
|
||||
global $Conf;
|
||||
global $Route;
|
||||
|
||||
$psswd = hashPsswd($p);
|
||||
|
||||
if ($Conf::admin) {
|
||||
if (substr($Conf->_appname, 0, 3) == "ce_") {
|
||||
if ($Route->_script == "salaries") {
|
||||
$sql = 'UPDATE salaries SET userpswd="' . $psswd . '", userpass="xxx" WHERE rowid=' . $id . ';';
|
||||
} else {
|
||||
$sql = 'UPDATE users SET userpswd="' . $psswd . '", userpass="xxx" WHERE rowid=' . $id . ';';
|
||||
}
|
||||
} else {
|
||||
$sql = 'UPDATE users SET userpswd="' . $psswd . '", userpass="xxx" WHERE rowid=' . $id . ';';
|
||||
}
|
||||
} else {
|
||||
$sql = 'UPDATE salaries SET userpswd="' . $psswd . '", userpass="xxx" WHERE rowid=' . $id . ';';
|
||||
}
|
||||
|
||||
qSQL($sql);
|
||||
|
||||
eLog($sql);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function checkPsswd($p, $pCr) {
|
||||
// Récupération et vérification du MDP saisi par l'utilisateur
|
||||
// $p : le pass en clair, $pCr : le pass enregistré et hashé
|
||||
if (password_verify($p, $pCr)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function generateRandomPassword() {
|
||||
//Initialize the random password
|
||||
$password = '';
|
||||
|
||||
//Initialize a random desired length
|
||||
$desired_length = rand(8, 12);
|
||||
|
||||
for ($length = 0; $length < $desired_length; $length++) {
|
||||
//Append a random ASCII character (including symbols)
|
||||
$password .= chr(rand(44, 122));
|
||||
}
|
||||
// On remplace quelques caractères non désirés
|
||||
$password = str_replace("/", "&", $password);
|
||||
$password = str_replace("<", "!", $password);
|
||||
$password = str_replace(">", "!", $password);
|
||||
$password = str_replace("=", "#", $password);
|
||||
$password = str_replace("\\", "&", $password);
|
||||
$password = str_replace("^", "%", $password);
|
||||
$password = str_replace(chr(96), "#", $password);
|
||||
|
||||
return $password;
|
||||
}
|
||||
|
||||
function eLog($comment, $notif = false) {
|
||||
global $Session;
|
||||
global $Route;
|
||||
global $Conf;
|
||||
|
||||
if (!empty($_SERVER["HTTP_CLIENT_IP"])) {
|
||||
$ip = $_SERVER["HTTP_CLIENT_IP"];
|
||||
} elseif (!empty($_SERVER["HTTP_X_FORWARDED_FOR"])) {
|
||||
$ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
|
||||
} else {
|
||||
$ip = $_SERVER["REMOTE_ADDR"];
|
||||
}
|
||||
$hn = getHostByName($ip);
|
||||
$ha = @getHostByAddr($hn);
|
||||
$us = substr($_SERVER["HTTP_USER_AGENT"], 0, 100);
|
||||
if (isset($Session->_user["rowid"])) {
|
||||
$user = $Session->_user["rowid"];
|
||||
if ($user == "") {
|
||||
$user = 0;
|
||||
}
|
||||
} else {
|
||||
$user = 0;
|
||||
}
|
||||
$script = $Route->_script;
|
||||
$comment = nettoie_input($comment);
|
||||
$dt = date("Y-m-d H:i:s");
|
||||
if ($notif) {
|
||||
$not = 1;
|
||||
} else {
|
||||
$not = 2;
|
||||
}
|
||||
$sql = 'INSERT INTO z_logs (date, ip, host, adrhost, infos, fk_user, page, commentaire, chk_notif) VALUES ("' . $dt . '", "' . $ip . '", "' . $hn . '", "' . $ha . '", "' . $us . '", "' . $user . '", "' . $script . '", "' . $comment . '", ' . $not . ');';
|
||||
qSQL($sql, "gen");
|
||||
|
||||
if (strpos(strtolower($comment), 'erreur') !== false) {
|
||||
//! S'il y a spécifiquement une erreur on l'enregistre dans un fichier log à la racine du site
|
||||
$log_dir = dirname(dirname(dirname(__DIR__))) . "/log/";
|
||||
$log_file = $log_dir . $Conf->_appname . "_" . date('Y-m-d') . ".log";
|
||||
|
||||
// Vérifier que le répertoire existe
|
||||
if (!is_dir($log_dir)) {
|
||||
@mkdir($log_dir, 0775, true);
|
||||
}
|
||||
|
||||
// Si le fichier n'existe pas, le créer avec les bonnes permissions
|
||||
if (!file_exists($log_file)) {
|
||||
@touch($log_file);
|
||||
@chmod($log_file, 0664);
|
||||
}
|
||||
|
||||
// Purger les anciens logs (garder seulement les 10 derniers jours)
|
||||
purge_old_logs($log_dir, $Conf->_appname, 10);
|
||||
|
||||
// Écrire dans le log seulement si on peut
|
||||
if (is_writable($log_file)) {
|
||||
error_log($dt . ";" . $ip . ";" . $script . ";" . $comment . "\r\n", 3, $log_file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! *****************************************************************************************//
|
||||
//! Fonction de debug globale
|
||||
function debug($data, $label = '', $level = 4) {
|
||||
global $Conf;
|
||||
|
||||
// Vérifier si le debug est activé et si le niveau est suffisant
|
||||
if (!isset($Conf->_debug_level) || $Conf->_debug_level < $level) {
|
||||
return;
|
||||
}
|
||||
|
||||
$debug_info = array(
|
||||
'timestamp' => date('Y-m-d H:i:s'),
|
||||
'level' => $level,
|
||||
'label' => $label,
|
||||
'type' => gettype($data),
|
||||
'file' => '',
|
||||
'line' => '',
|
||||
'function' => ''
|
||||
);
|
||||
|
||||
// Récupérer les informations de debug
|
||||
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
|
||||
if (isset($backtrace[0])) {
|
||||
$debug_info['file'] = $backtrace[0]['file'];
|
||||
$debug_info['line'] = $backtrace[0]['line'];
|
||||
}
|
||||
if (isset($backtrace[1])) {
|
||||
$debug_info['function'] = $backtrace[1]['function'];
|
||||
}
|
||||
|
||||
// Préparer le message de debug
|
||||
$debug_message = "[{$debug_info['timestamp']}] ";
|
||||
$debug_message .= "DEBUG LVL{$level}";
|
||||
if ($label) {
|
||||
$debug_message .= " - {$label}";
|
||||
}
|
||||
$debug_message .= " | {$debug_info['file']}:{$debug_info['line']}";
|
||||
if ($debug_info['function']) {
|
||||
$debug_message .= " in {$debug_info['function']}()";
|
||||
}
|
||||
$debug_message .= "\n";
|
||||
|
||||
// Formatter les données
|
||||
if (is_array($data) || is_object($data)) {
|
||||
$debug_message .= print_r($data, true);
|
||||
} elseif (is_bool($data)) {
|
||||
$debug_message .= $data ? 'true' : 'false';
|
||||
} elseif (is_null($data)) {
|
||||
$debug_message .= 'null';
|
||||
} else {
|
||||
$debug_message .= $data;
|
||||
}
|
||||
$debug_message .= "\n" . str_repeat('-', 80) . "\n";
|
||||
|
||||
// Écrire dans le fichier de log si configuré
|
||||
if (isset($Conf->_log_file_path) && $Conf->_log_file_path) {
|
||||
// Remplacer la date dans le chemin du fichier si elle existe déjà
|
||||
$log_file = preg_replace('/_debug_\d{4}-\d{2}-\d{2}\.log$/', '_debug_' . date('Y-m-d') . '.log', $Conf->_log_file_path);
|
||||
|
||||
// Si le pattern n'a pas matché, c'est un ancien format, on ajoute la date
|
||||
if ($log_file == $Conf->_log_file_path && !preg_match('/_' . date('Y-m-d') . '\.log$/', $log_file)) {
|
||||
$log_file = str_replace('.log', '_' . date('Y-m-d') . '.log', $log_file);
|
||||
}
|
||||
|
||||
// Vérifier que le répertoire existe et est accessible en écriture
|
||||
$log_dir = dirname($log_file);
|
||||
if (!is_dir($log_dir)) {
|
||||
@mkdir($log_dir, 0775, true);
|
||||
}
|
||||
|
||||
// Si le fichier n'existe pas, le créer avec les bonnes permissions
|
||||
if (!file_exists($log_file)) {
|
||||
@touch($log_file);
|
||||
@chmod($log_file, 0664);
|
||||
}
|
||||
|
||||
// Purger les anciens logs
|
||||
$app_name = isset($Conf->_appname) ? $Conf->_appname : 'app';
|
||||
purge_old_logs($log_dir, $app_name, 10);
|
||||
|
||||
// Écrire dans le log seulement si on peut
|
||||
if (is_writable($log_file)) {
|
||||
error_log($debug_message, 3, $log_file);
|
||||
}
|
||||
}
|
||||
|
||||
// Afficher à l'écran si display_errors est activé et niveau >= 3
|
||||
if (ini_get('display_errors') && $level >= 3) {
|
||||
echo "<pre style='background:#f0f0f0; border:1px solid #ccc; padding:10px; margin:10px; font-size:12px;'>";
|
||||
echo htmlspecialchars($debug_message);
|
||||
echo "</pre>";
|
||||
}
|
||||
}
|
||||
|
||||
function logstats($delay = 0, $fk_user = 0, $appname = "") {
|
||||
global $Conf;
|
||||
$dt = date("Y-m-d H:i:s");
|
||||
|
||||
$exclude_clients_ip = "aucune";
|
||||
if (isset($Conf->_excludeIp)) {
|
||||
$exclude_clients_ip = $Conf->_excludeIp;
|
||||
}
|
||||
|
||||
if (isset($Conf->_clientIp)) {
|
||||
$client_ip = $Conf->_clientIp;
|
||||
} else {
|
||||
if (!empty($_SERVER["HTTP_CLIENT_IP"])) {
|
||||
$client_ip = $_SERVER["HTTP_CLIENT_IP"];
|
||||
} elseif (!empty($_SERVER["HTTP_X_FORWARDED_FOR"])) {
|
||||
$client_ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
|
||||
} else {
|
||||
$client_ip = $_SERVER["REMOTE_ADDR"];
|
||||
}
|
||||
}
|
||||
$verif_ip = strpos($exclude_clients_ip, $client_ip);
|
||||
|
||||
if ($verif_ip === false) {
|
||||
|
||||
$home = $_SERVER["HOME"];
|
||||
$doc_root = $_SERVER["DOCUMENT_ROOT"];
|
||||
$doc_root = substr($doc_root, strlen($home));
|
||||
|
||||
$sql = 'INSERT INTO z_stats SET ';
|
||||
$sql .= 'date="' . $dt . '", ';
|
||||
$sql .= 'root="' . $doc_root . '", ';
|
||||
$sql .= 'server_ip="' . $_SERVER["SERVER_ADDR"] . '", ';
|
||||
$sql .= 'server_soft="' . $_SERVER["SERVER_SOFTWARE"] . '", ';
|
||||
$sql .= 'server_name="' . $_SERVER["SERVER_NAME"] . '", ';
|
||||
$sql .= 'client_ip="' . $client_ip . '", ';
|
||||
$sql .= 'client_browser="' . $_SERVER["HTTP_USER_AGENT"] . '", ';
|
||||
if (isset($_SERVER["HTTP_REFERER"])) {
|
||||
$sql .= 'client_origine="' . $_SERVER["HTTP_REFERER"] . '", ';
|
||||
}
|
||||
$sql .= 'client_page="' . $_SERVER["REQUEST_URI"] . '", ';
|
||||
$sql .= 'client_delay=' . str_replace(',', '.', $delay) . ', ';
|
||||
$sql .= 'appname="' . $appname . '", ';
|
||||
$sql .= 'fk_user=' . $fk_user . ', ';
|
||||
$sql .= 'status="' . $_SERVER["REDIRECT_STATUS"] . '";';
|
||||
|
||||
// server : 51.255.35.214
|
||||
$mysqli = new mysqli("localhost", "logs_user", "d66,Logs.User", "logs");
|
||||
$mysqli->set_charset("utf8");
|
||||
$mysqli->query($sql);
|
||||
$mysqli->close();
|
||||
}
|
||||
}
|
||||
|
||||
//! *****************************************************************************************//
|
||||
//! nettoie_input : prépare une zone d'un formulaire avant son enregistrement dans la base //
|
||||
//! En paramètre, on passe la valeur à nettoyer //
|
||||
//! *****************************************************************************************//
|
||||
function nettoie_input($data) {
|
||||
if (ctype_digit((string)$data)) {
|
||||
$data = intval($data);
|
||||
} else {
|
||||
global $Conf;
|
||||
$dbn = $Conf->_dbname;
|
||||
$mysqli = new mysqli($Conf->_dbhost, $Conf->_dbuser, $Conf->_dbpass, $dbn);
|
||||
$mysqli->set_charset("utf8");
|
||||
$data = mysqli_real_escape_string($mysqli, $data);
|
||||
// $data = addcslashes($data, '%_');
|
||||
$mysqli->close();
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
function str_normalize($string, $minuscules = true) {
|
||||
//! Normalise une chaîne de caractères en remplaçant tous les caractères accentués, les espaces et caractères spéciaux
|
||||
$result = "";
|
||||
$string = trim($string); // on efface tous les espaces à gauche et à droite
|
||||
if (strlen($string) > 0) {
|
||||
if ($minuscules) {
|
||||
$result = strtolower($string);
|
||||
} else {
|
||||
$result = $string;
|
||||
}
|
||||
$result = str_replace(" ", "_", $result);
|
||||
//$result = str_replace("-", "_", $result);
|
||||
//$result = str_replace(".", "_", $result);
|
||||
$result = str_replace("é", "e", $result);
|
||||
$result = str_replace("è", "e", $result);
|
||||
$result = str_replace("ê", "e", $result);
|
||||
$result = str_replace("ë", "e", $result);
|
||||
$result = str_replace("à", "a", $result);
|
||||
$result = str_replace("â", "a", $result);
|
||||
$result = str_replace("ä", "a", $result);
|
||||
$result = str_replace("ô", "o", $result);
|
||||
$result = str_replace("ö", "o", $result);
|
||||
$result = str_replace("ù", "u", $result);
|
||||
$result = str_replace("û", "u", $result);
|
||||
$result = str_replace("ü", "u", $result);
|
||||
$result = str_replace("ç", "c", $result);
|
||||
$result = str_replace("'", "", $result);
|
||||
$result = str_replace("\"", "", $result);
|
||||
$result = str_replace("/", "", $result);
|
||||
$result = str_replace("(", "_", $result);
|
||||
$result = str_replace(")", "_", $result);
|
||||
$result = str_replace("!", "_", $result);
|
||||
//! Ajout du 08/12/2015
|
||||
$result = str_replace("?", "_", $result);
|
||||
|
||||
$result = trim($result);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
function affiche_date($ladate) {
|
||||
/**
|
||||
* This is a sample function to illustrate additional PHP formatter
|
||||
* options.
|
||||
* @param $ladate date au format MySQL
|
||||
*
|
||||
* @return String date au format Fr dd/mm/yyyy
|
||||
* @author D6SOFT
|
||||
*
|
||||
*/
|
||||
//! Retourne une date MySQL yyyy-mm-dd HH:ii:ss au format dd/mm/yyyy
|
||||
$ladate = trim($ladate);
|
||||
if ($ladate == "" || substr($ladate, 0, 2) == "00") {
|
||||
return "";
|
||||
} else {
|
||||
if (strlen($ladate) < 10) {
|
||||
return "";
|
||||
} else {
|
||||
$theday = substr($ladate, 8, 2) . "/" . substr($ladate, 5, 2) . "/" . substr($ladate, 0, 4);
|
||||
return $theday;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function d6GetDate($laDate, $transform = "MF", $hours = false, $seconds = false) {
|
||||
//! Retourne une date
|
||||
//! $format="MF" du format MySQL yyyy-mm-dd au format Fr dd/mm/yyyy
|
||||
//! $format="FM" du format Fr dd/mm/yyyy au format MySQL yyyy-mm-dd
|
||||
|
||||
$ret = "";
|
||||
if (strlen($laDate) >= 10) {
|
||||
if ($transform == "FM") {
|
||||
$ret = substr($laDate, -4) . "-" . substr($laDate, 3, 2) . "-" . substr($laDate, 0, 2);
|
||||
} else {
|
||||
$ret = substr($laDate, -2) . "/" . substr($laDate, 5, 2) . "/" . substr($laDate, 0, 4);
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
function loadtel($numero, $prefix = "+33") {
|
||||
//! retourne un numéro de téléphone sans espace et . et avec le préfixe devant : +33 par défaut
|
||||
$lenumero = trim($numero);
|
||||
$lenumero = preg_replace('/[^0-9]/', '', $lenumero);
|
||||
if (strlen($lenumero) == 10) {
|
||||
$lenumero = substr($lenumero, 1);
|
||||
}
|
||||
if (strlen($lenumero) == 9) {
|
||||
$lenumero = $prefix . $lenumero;
|
||||
}
|
||||
return $lenumero;
|
||||
}
|
||||
|
||||
function formattel($numero, $separateur = " ") {
|
||||
//! formate le n° de téléphone de 651234567 ou 0651234567 en 06 51 23 45 67
|
||||
if (strlen($numero) == 9) {
|
||||
$numero = "0" . $numero;
|
||||
}
|
||||
if (strlen($numero) == 10) {
|
||||
$numero = substr($numero, 0, 2) . $separateur . substr($numero, 2, 2) . $separateur . substr($numero, 4, 2) . $separateur . substr($numero, 6, 2) . $separateur . substr($numero, 8, 2);
|
||||
}
|
||||
return $numero;
|
||||
}
|
||||
|
||||
//! *****************************************************************************************//
|
||||
//! Fonction pour purger les anciens fichiers de log
|
||||
function purge_old_logs($log_dir, $app_name, $days_to_keep = 10) {
|
||||
// Vérifier que le répertoire existe
|
||||
if (!is_dir($log_dir)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Date limite pour conserver les logs
|
||||
$date_limit = strtotime("-{$days_to_keep} days");
|
||||
|
||||
// Patterns des fichiers à purger
|
||||
$patterns = array(
|
||||
$app_name . '_????-??-??.log',
|
||||
$app_name . '_debug_????-??-??.log'
|
||||
);
|
||||
|
||||
foreach ($patterns as $pattern) {
|
||||
$files = glob($log_dir . $pattern);
|
||||
if ($files) {
|
||||
foreach ($files as $file) {
|
||||
// Extraire la date du nom de fichier
|
||||
if (preg_match('/(\d{4}-\d{2}-\d{2})\.log$/', $file, $matches)) {
|
||||
$file_date = strtotime($matches[1]);
|
||||
// Si le fichier est plus ancien que la limite, le supprimer
|
||||
if ($file_date < $date_limit) {
|
||||
@unlink($file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,11 @@ class Session {
|
||||
//! ce n'est pas un intranet, donc un site vitrine public, on doit laisser passer mais mémoriser
|
||||
$sql = "SELECT s.* FROM z_sessions s WHERE s.sid='" . session_id() . "';";
|
||||
$res = qSQL($sql, "gen");
|
||||
$this->_user = $res->fetch_assoc();
|
||||
if ($res instanceof PDOStatement) {
|
||||
$this->_user = $res->fetch(PDO::FETCH_ASSOC);
|
||||
} else {
|
||||
$this->_user = false;
|
||||
}
|
||||
if (empty($this->_user)) {
|
||||
//! pas de session pour lui, on en crée une
|
||||
if (!empty($_SERVER["HTTP_CLIENT_IP"])) {
|
||||
@@ -64,7 +68,11 @@ class Session {
|
||||
function getUserInfos($leScript, $Conf) {
|
||||
$sql = "SELECT s.data, s.ip, s.browser, u.* FROM z_sessions s INNER JOIN users u ON s.sid='" . session_id() . "' AND s.fk_user=u.rowid;";
|
||||
$res = qSQL($sql, "gen");
|
||||
$this->_user = $res->fetch_assoc();
|
||||
if ($res instanceof PDOStatement) {
|
||||
$this->_user = $res->fetch(PDO::FETCH_ASSOC);
|
||||
} else {
|
||||
$this->_user = false;
|
||||
}
|
||||
if (empty($this->_user)) {
|
||||
eLog('Erreur Session.getUserInfos User inconnu dans Session ' . session_id());
|
||||
$this->_user = FALSE;
|
||||
@@ -88,7 +96,7 @@ class Session {
|
||||
eLog("Erreur cet utilisateur " . $this->_user["username"] . " a changé de navigateur");
|
||||
}
|
||||
}
|
||||
$res->free();
|
||||
// PDO ne nécessite pas de free()
|
||||
}
|
||||
|
||||
public function set_data($cle, $valeur) {
|
||||
@@ -113,8 +121,11 @@ class Session {
|
||||
global $Conf;
|
||||
$sql = "SELECT s.data FROM z_sessions s WHERE s.sid='" . session_id() . "';";
|
||||
$res = qSQL($sql, "gen");
|
||||
$rec = $res->fetch_assoc();
|
||||
$res->free();
|
||||
if ($res instanceof PDOStatement) {
|
||||
$rec = $res->fetch(PDO::FETCH_ASSOC);
|
||||
} else {
|
||||
$rec = false;
|
||||
}
|
||||
if ($rec["data"] == "") {
|
||||
$tabdata = array();
|
||||
} else {
|
||||
@@ -149,8 +160,12 @@ class Session {
|
||||
if ($niveau >= 0 && $niveau < 10) {
|
||||
$sql = "SELECT s.a" . $niveau . " as data FROM z_sessions s WHERE s.sid='" . session_id() . "';";
|
||||
$res = qSQL($sql, "gen");
|
||||
$rec = $res->fetch_assoc();
|
||||
$res->free();
|
||||
if ($res instanceof PDOStatement) {
|
||||
$rec = $res->fetch(PDO::FETCH_ASSOC);
|
||||
} else {
|
||||
$rec = false;
|
||||
}
|
||||
// PDO ne nécessite pas de free()
|
||||
return $rec["data"];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
<div class="left ml-1">© <?= $Conf->_brandname; ?> <?= date("Y"); ?></div>
|
||||
<div class="center">Version
|
||||
<?php
|
||||
echo $Conf->_appversion . ' - IP : ' . $Conf->_clientIp;
|
||||
echo $Conf->_appversion . ' - ' . $Conf->_clientIp;
|
||||
$delay = round(microtime(true) - $tpsdebut, 3);
|
||||
echo ' - Page générée en ' . $delay . ' secondes';
|
||||
echo ' - ' . $delay . 's';
|
||||
logstats($delay);
|
||||
?>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user