DELETED src/include/class.champs_membres.php
Index: src/include/class.champs_membres.php
==================================================================
--- src/include/class.champs_membres.php
+++ src/include/class.champs_membres.php
@@ -1,470 +0,0 @@
- 'Adresse E-Mail',
- 'url' => 'Adresse URL',
- 'checkbox' => 'Case à cocher',
- 'date' => 'Date',
- 'datetime' => 'Date et heure',
- //'file' => 'Fichier',
- 'password' => 'Mot de passe',
- 'number' => 'Numéro',
- 'tel' => 'Numéro de téléphone',
- 'select' => 'Sélecteur à choix unique',
- 'multiple' => 'Sélecteur à choix multiple',
- 'country' => 'Sélecteur de pays',
- 'text' => 'Texte',
- 'textarea' => 'Texte multi-lignes',
- ];
-
- protected $text_types = [
- 'email',
- 'text',
- 'select',
- 'textarea',
- 'url',
- 'password',
- 'country'
- ];
-
- protected $config_fields = [
- 'type',
- 'title',
- 'help',
- 'editable',
- 'list_row',
- 'mandatory',
- 'private',
- 'options'
- ];
-
- static protected $presets = null;
-
- public function __toString()
- {
- return utils::write_ini_string($this->champs);
- }
-
- public function toString()
- {
- return utils::write_ini_string($this->champs);
- }
-
- static public function importInstall()
- {
- $champs = parse_ini_file(ROOT . '/include/data/champs_membres.ini', true);
- $champs = array_filter($champs, function ($row) { return !empty($row['install']); });
- return new Champs_Membres($champs);
- }
-
- static public function importPresets()
- {
- if (is_null(self::$presets))
- {
- self::$presets = parse_ini_file(ROOT . '/include/data/champs_membres.ini', true);
- }
-
- return self::$presets;
- }
-
- static public function listUnusedPresets(Champs_Membres $champs)
- {
- return array_diff_key(self::importPresets(), $champs->getAll());
- }
-
- public function __construct($champs)
- {
- if ($champs instanceOf Champs_Membres)
- {
- $this->champs = $champs->getAll();
- }
- elseif (is_array($champs))
- {
- foreach ($champs as $key=>&$config)
- {
- $this->_checkField($key, $config);
- }
-
- $this->champs = $champs;
- }
- else
- {
- $champs = parse_ini_string((string)$champs, true);
-
- foreach ($champs as $key=>&$config)
- {
- $this->_checkField($key, $config);
- }
-
- $this->champs = $champs;
- }
- }
-
- public function getTypes()
- {
- return $this->types;
- }
-
- public function get($champ, $key = null)
- {
- if ($champ == 'id')
- {
- return ['title' => 'Numéro unique', 'type' => 'number'];
- }
-
- if (!array_key_exists($champ, $this->champs))
- return null;
-
- if ($key !== null)
- {
- if (array_key_exists($key, $this->champs[$champ]))
- return $this->champs[$champ][$key];
- else
- return null;
- }
-
- return $this->champs[$champ];
- }
-
- public function isText($champ)
- {
- if (!array_key_exists($champ, $this->champs))
- return null;
-
- if (in_array($this->champs[$champ]['type'], $this->text_types))
- return true;
- else
- return false;
- }
-
- public function getAll()
- {
- $this->champs['passe']['title'] = 'Mot de passe';
- return $this->champs;
- }
-
- public function getList()
- {
- $champs = $this->champs;
- unset($champs['passe']);
- return $champs;
- }
-
- public function getFirst()
- {
- reset($this->champs);
- return key($this->champs);
- }
-
- public function getListedFields()
- {
- $champs = $this->champs;
-
- $champs = array_filter($champs, function ($a) {
- return empty($a['list_row']) ? false : true;
- });
-
- uasort($champs, function ($a, $b) {
- if ($a['list_row'] == $b['list_row'])
- return 0;
-
- return ($a['list_row'] > $b['list_row']) ? 1 : -1;
- });
-
- return $champs;
- }
-
- /**
- * Vérifie la cohérence et la présence des bons éléments pour un champ
- * @param string $name Nom du champ
- * @param array $config Configuration du champ
- * @return boolean true
- */
- protected function _checkField($name, &$config)
- {
- if (!preg_match('!^\w+(_\w+)*$!', $name))
- {
- throw new UserException('Le nom du champ est invalide.');
- }
-
- foreach ($config as $key=>&$value)
- {
- // Champ install non pris en compte
- if ($key == 'install')
- {
- unset($config[$key]);
- continue;
- }
-
- if (!in_array($key, $this->config_fields))
- {
- throw new \BadMethodCallException('Champ '.$key.' non valide.');
- }
-
- if ($key == 'editable' || $key == 'private' || $key == 'mandatory')
- {
- $value = (bool) (int) $value;
- }
- elseif ($key == 'list_row')
- {
- $value = (int) $value;
- }
- elseif ($key == 'help' || $key == 'title')
- {
- $value = trim((string) $value);
- }
- elseif ($key == 'options')
- {
- $value = (array) $value;
-
- foreach ($value as $option_key=>$option_value)
- {
- if (trim($option_value) == '')
- {
- unset($value[$option_key]);
- }
- }
- }
- }
-
- if (empty($config['title']) && $name != 'passe')
- {
- throw new UserException('Champ "'.$name.'" : Le titre est obligatoire.');
- }
-
- if (empty($config['type']) || !array_key_exists($config['type'], $this->types))
- {
- throw new UserException('Champ "'.$name.'" : Le type est vide ou non valide.');
- }
-
- if ($name == 'email' && $config['type'] != 'email')
- {
- throw new UserException('Le champ email ne peut être d\'un type différent de email.');
- }
-
- if ($name == 'passe' && $config['type'] != 'password')
- {
- throw new UserException('Le champ mot de passe ne peut être d\'un type différent de mot de passe.');
- }
-
- if (($config['type'] == 'multiple' || $config['type'] == 'select') && empty($config['options']))
- {
- throw new UserException('Le champ "'.$name.'" nécessite de comporter au moins une option possible.');
- }
-
- if (!array_key_exists('editable', $config))
- {
- $config['editable'] = false;
- }
-
- if (!array_key_exists('mandatory', $config))
- {
- $config['mandatory'] = false;
- }
-
- if (!array_key_exists('private', $config))
- {
- $config['private'] = false;
- }
-
- return true;
- }
-
- /**
- * Ajouter un nouveau champ
- * @param string $name Nom du champ
- * @param array $config Configuration du champ
- * @return boolean true
- */
- public function add($name, $config)
- {
- if (!preg_match('!^[a-z0-9]+(_[a-z0-9]+)*$!', $name))
- {
- throw new UserException('Le nom du champ est invalide : ne sont acceptés que des lettres minuscules et chiffres.');
- }
-
- $this->_checkField($name, $config);
-
- $this->champs[$name] = $config;
-
- return true;
- }
-
- /**
- * Modifie un champ particulier
- * @param string $champ Nom du champ
- * @param string $key Nom de la clé à modifier
- * @param mixed $value Valeur à affecter
- * @return boolean true
- */
- public function set($champ, $key, $value)
- {
- if (!isset($this->champs[$champ]))
- {
- throw new \LogicException('Champ "'.$champ.'" inconnu.');
- }
-
- // Vérification
- $config = $this->champs[$champ];
- $config[$key] = $value;
- $this->_checkField($champ, $config);
-
- $this->champs[$champ] = $config;
- return true;
- }
-
- /**
- * Modifie les champs en interne en vérifiant que tout va bien
- * @param array $champs Liste des champs
- * @return boolean true
- */
- public function setAll($champs)
- {
- if (!array_key_exists('email', $champs))
- {
- throw new UserException('Le champ E-Mail ne peut être supprimé des fiches membres.');
- }
-
- if (!array_key_exists('passe', $champs))
- {
- throw new UserException('Le champ Mot de passe ne peut être supprimé des fiches membres.');
- }
-
- $config = Config::getInstance();
-
- if (!array_key_exists($config->get('champ_identite'), $champs))
- {
- throw new UserException('Le champ '.$config->get('champ_identite')
- .' est défini comme identité des membres et ne peut donc être supprimé des fiches membres.');
- }
-
- if (!array_key_exists($config->get('champ_identifiant'), $champs))
- {
- throw new UserException('Le champ '.$config->get('champ_identifiant')
- .' est défini comme identifiant à la connexion et ne peut donc être supprimé des fiches membres.');
- }
-
- foreach ($champs as $name=>&$config)
- {
- $this->_checkField($name, $config);
- }
-
- $this->champs = $champs;
-
- return true;
- }
-
- /**
- * Enregistre les changements de champs en base de données
- * @param boolean $enable_copy Recopier les anciennes champs dans les nouveaux ?
- * @return boolean true
- */
- public function save($enable_copy = true)
- {
- $db = DB::getInstance();
- $config = Config::getInstance();
-
- // Champs à créer
- $create = [
- 'id INTEGER PRIMARY KEY, -- Numéro attribué automatiquement',
- 'id_categorie INTEGER NOT NULL, -- Numéro de catégorie',
- 'date_connexion TEXT NULL, -- Date de dernière connexion',
- 'date_inscription TEXT NOT NULL DEFAULT CURRENT_DATE, -- Date d\'inscription',
- ];
-
- $create_keys = [
- 'FOREIGN KEY (id_categorie) REFERENCES membres_categories (id)'
- ];
-
- // Champs à recopier
- $copy = [
- 'id',
- 'id_categorie',
- 'date_connexion',
- 'date_inscription',
- ];
-
- $anciens_champs = $config->get('champs_membres');
- $anciens_champs = is_null($anciens_champs) ? $this->champs : $anciens_champs->getAll();
-
- foreach ($this->champs as $key=>$cfg)
- {
- if ($cfg['type'] == 'number')
- $type = 'FLOAT';
- elseif ($cfg['type'] == 'multiple' || $cfg['type'] == 'checkbox')
- $type = 'INTEGER';
- elseif ($cfg['type'] == 'file')
- $type = 'BLOB';
- else
- $type = 'TEXT';
-
- $line = $key . ' ' . $type . ',';
-
- if (!empty($cfg['title']))
- {
- $line .= ' -- ' . str_replace(["\n", "\r"], '', $cfg['title']);
- }
-
- $create[] = $line;
-
- if (array_key_exists($key, $anciens_champs))
- {
- $copy[] = $key;
- }
- }
-
- $create = array_merge($create, $create_keys);
-
- $create = 'CREATE TABLE membres_tmp (' . "\n\t" . implode("\n\t", $create) . "\n);";
- $copy = 'INSERT INTO membres_tmp (' . implode(', ', $copy) . ') SELECT ' . implode(', ', $copy) . ' FROM membres;';
-
- $db->exec('PRAGMA foreign_keys = OFF;');
- $db->exec('BEGIN;');
- $db->exec($create);
-
- if ($enable_copy) {
- $db->exec($copy);
- }
-
- $db->exec('DROP TABLE IF EXISTS membres;');
- $db->exec('ALTER TABLE membres_tmp RENAME TO membres;');
- $db->exec('CREATE INDEX membres_id_categorie ON membres (id_categorie);'); // Index
-
- if ($config->get('champ_identifiant'))
- {
- // Mettre les champs identifiant vides à NULL pour pouvoir créer un index unique
- $db->exec('UPDATE membres SET '.$config->get('champ_identifiant').' = NULL
- WHERE '.$config->get('champ_identifiant').' = "";');
-
- // Création de l'index unique
- $db->exec('CREATE UNIQUE INDEX membres_identifiant ON membres ('.$config->get('champ_identifiant').');');
- }
-
- // Création des index pour les champs affichés dans la liste des membres
- $listed_fields = array_keys($this->getListedFields());
- foreach ($listed_fields as $field)
- {
- if ($field === $config->get('champ_identifiant'))
- {
- // Il y a déjà un index
- continue;
- }
-
- $db->exec('CREATE INDEX membres_liste_' . $field . ' ON membres (' . $field . ');');
- }
-
- $db->exec('END;');
- $db->exec('PRAGMA foreign_keys = ON;');
-
- $config->set('champs_membres', $this);
- $config->save();
-
- return true;
- }
-}
DELETED src/include/class.compta_categories.php
Index: src/include/class.compta_categories.php
==================================================================
--- src/include/class.compta_categories.php
+++ src/include/class.compta_categories.php
@@ -1,126 +0,0 @@
-exec(file_get_contents(ROOT . '/include/data/categories_comptables.sql'));
- }
-
- public function add($data)
- {
- $this->_checkFields($data);
-
- $db = DB::getInstance();
-
- if (empty($data['compte']) || !trim($data['compte']))
- {
- throw new UserException('Le compte associé ne peut rester vide.');
- }
-
- $data['compte'] = trim($data['compte']);
-
- if (!$db->simpleQuerySingle('SELECT 1 FROM compta_comptes WHERE id = ?;', false, $data['compte']))
- {
- throw new UserException('Le compte associé n\'existe pas.');
- }
-
- if (!isset($data['type']) ||
- ($data['type'] != self::DEPENSES && $data['type'] != self::RECETTES))
- {
- // Catégories "autres" pas possibles pour le moment
- throw new UserException('Type de catégorie inconnu.');
- }
-
- $db->simpleInsert('compta_categories', [
- 'intitule' => $data['intitule'],
- 'description'=> $data['description'],
- 'compte' => $data['compte'],
- 'type' => (int)$data['type'],
- ]);
-
- return $db->lastInsertRowId();
- }
-
- public function edit($id, $data)
- {
- $this->_checkFields($data);
-
- $db = DB::getInstance();
-
- $db->simpleUpdate('compta_categories',
- [
- 'intitule' => $data['intitule'],
- 'description'=> $data['description'],
- ],
- 'id = \''.$db->escapeString(trim($id)).'\'');
-
- return true;
- }
-
- public function delete($id)
- {
- $db = DB::getInstance();
-
- // Ne pas supprimer une catégorie qui est utilisée !
- if ($db->simpleQuerySingle('SELECT 1 FROM compta_journal WHERE id_categorie = ? LIMIT 1;', false, $id))
- {
- throw new UserException('Cette catégorie ne peut être supprimée car des opérations comptables y sont liées.');
- }
-
- $db->simpleExec('DELETE FROM compta_categories WHERE id = ?;', $id);
-
- return true;
- }
-
- public function get($id)
- {
- $db = DB::getInstance();
- return $db->simpleQuerySingle('SELECT * FROM compta_categories WHERE id = ?;', true, (int)$id);
- }
-
- public function getList($type = null)
- {
- $db = DB::getInstance();
- $type = is_null($type) ? '' : 'cat.type = '.(int)$type;
- return $db->simpleStatementFetchAssocKey('
- SELECT cat.id, cat.*, cc.libelle AS compte_libelle
- FROM compta_categories AS cat INNER JOIN compta_comptes AS cc
- ON cc.id = cat.compte
- WHERE '.$type.' ORDER BY cat.intitule;', SQLITE3_ASSOC);
- }
-
- public function listMoyensPaiement()
- {
- $db = DB::getInstance();
- return $db->simpleStatementFetchAssocKey('SELECT code, nom FROM compta_moyens_paiement ORDER BY nom COLLATE NOCASE;');
- }
-
- public function getMoyenPaiement($code)
- {
- $db = DB::getInstance();
- return $db->simpleQuerySingle('SELECT nom FROM compta_moyens_paiement WHERE code = ?;', false, $code);
- }
-
- protected function _checkFields(&$data)
- {
- if (empty($data['intitule']) || !trim($data['intitule']))
- {
- throw new UserException('L\'intitulé ne peut rester vide.');
- }
-
- $data['intitule'] = trim($data['intitule']);
- $data['description'] = isset($data['description']) ? trim($data['description']) : '';
-
- return true;
- }
-}
-
-?>
DELETED src/include/class.compta_comptes.php
Index: src/include/class.compta_comptes.php
==================================================================
--- src/include/class.compta_comptes.php
+++ src/include/class.compta_comptes.php
@@ -1,325 +0,0 @@
-exec('BEGIN;');
- $ids = [];
-
- foreach ($plan as $id=>$compte)
- {
- $ids[] = $id;
-
- if ($db->simpleQuerySingle('SELECT 1 FROM compta_comptes WHERE id = ?;', false, $id))
- {
- $db->simpleUpdate('compta_comptes', [
- 'parent' => $compte['parent'],
- 'libelle' => $compte['nom'],
- 'position' => $compte['position'],
- 'plan_comptable' => 1,
- ], 'id = \''.$db->escapeString($id).'\'');
- }
- else
- {
- $db->simpleInsert('compta_comptes', [
- 'id' => $id,
- 'parent' => $compte['parent'],
- 'libelle' => $compte['nom'],
- 'position' => $compte['position'],
- 'plan_comptable' => 1,
- ]);
- }
- }
-
- $db->exec('DELETE FROM compta_comptes WHERE id NOT IN(\''.implode('\', \'', $ids).'\') AND plan_comptable = 1;');
-
- $db->exec('END;');
-
- return true;
- }
-
- public function add($data)
- {
- $this->_checkFields($data, true);
-
- $db = DB::getInstance();
-
- if (empty($data['id']))
- {
- $new_id = $data['parent'];
- $nb_sous_comptes = $db->simpleQuerySingle('SELECT COUNT(*) FROM compta_comptes WHERE parent = ?;', false, $new_id);
-
- // Pas plus de 26 sous-comptes par compte, parce que l'alphabet s'arrête à 26 lettres
- if ($nb_sous_comptes >= 26)
- {
- throw new UserException('Nombre de sous-comptes maximal atteint pour ce compte parent-ci.');
- }
-
- $new_id .= chr(65+(int)$nb_sous_comptes);
- }
- else
- {
- $new_id = $data['id'];
- }
-
- if (isset($data['position']))
- {
- $position = (int) $data['position'];
- }
- else
- {
- $position = $db->simpleQuerySingle('SELECT position FROM compta_comptes WHERE id = ?;', false, $data['parent']);
- }
-
- $db->simpleInsert('compta_comptes', [
- 'id' => $new_id,
- 'libelle' => trim($data['libelle']),
- 'parent' => $data['parent'],
- 'plan_comptable' => 0,
- 'position' => (int)$position,
- ]);
-
- return $new_id;
- }
-
- public function edit($id, $data)
- {
- $db = DB::getInstance();
-
- // Vérification que l'on peut éditer ce compte
- if ($db->simpleQuerySingle('SELECT plan_comptable FROM compta_comptes WHERE id = ?;', false, $id))
- {
- throw new UserException('Ce compte fait partie du plan comptable et n\'est pas modifiable.');
- }
-
- if (isset($data['position']) && empty($data['position']))
- {
- throw new UserException('Aucune position du compte n\'a été indiquée.');
- }
-
- $this->_checkFields($data);
-
- $update = [
- 'libelle' => trim($data['libelle']),
- ];
-
- if (isset($data['position']))
- {
- $update['position'] = (int) trim($data['position']);
- }
-
- $db->simpleUpdate('compta_comptes', $update, 'id = \''.$db->escapeString(trim($id)).'\'');
-
- return true;
- }
-
- public function delete($id)
- {
- $db = DB::getInstance();
-
- // Ne pas supprimer un compte qui est utilisé !
- if ($db->simpleQuerySingle('SELECT 1 FROM compta_journal WHERE compte_debit = ? OR compte_debit = ? LIMIT 1;', false, $id, $id))
- {
- throw new UserException('Ce compte ne peut être supprimé car des opérations comptables y sont liées.');
- }
-
- if ($db->simpleQuerySingle('SELECT 1 FROM compta_comptes_bancaires WHERE id = ? LIMIT 1;', false, $id))
- {
- throw new UserException('Ce compte ne peut être supprimé car il est lié à un compte bancaire.');
- }
-
- if ($db->simpleQuerySingle('SELECT 1 FROM compta_categories WHERE compte = ? LIMIT 1;', false, $id))
- {
- throw new UserException('Ce compte ne peut être supprimé car des catégories y sont liées.');
- }
-
- $db->simpleExec('DELETE FROM compta_comptes WHERE id = ?;', trim($id));
-
- return true;
- }
-
- /**
- * Peut-on supprimer ce compte ? (OUI s'il n'a pas d'écriture liée)
- * @param string $id Numéro du compte
- * @return boolean TRUE si le compte n'a pas d'écriture liée
- */
- public function canDelete($id)
- {
- $db = DB::getInstance();
-
- if ($db->simpleQuerySingle('SELECT 1 FROM compta_journal
- WHERE compte_debit = ? OR compte_debit = ? LIMIT 1;', false, $id, $id))
- {
- return false;
- }
-
- if ($db->simpleQuerySingle('SELECT 1 FROM compta_categories WHERE compte = ? LIMIT 1;', false, $id))
- {
- return false;
- }
-
- return true;
- }
-
- /**
- * Peut-on désactiver ce compte ? (OUI s'il n'a pas d'écriture liée dans l'exercice courant)
- * @param string $id Numéro du compte
- * @return boolean TRUE si le compte n'a pas d'écriture liée dans l'exercice courant
- */
- public function canDisable($id)
- {
- $db = DB::getInstance();
-
- if ($db->simpleQuerySingle('SELECT 1 FROM compta_journal
- WHERE id_exercice = (SELECT id FROM compta_exercices WHERE cloture = 0 LIMIT 1)
- AND (compte_debit = ? OR compte_debit = ?) LIMIT 1;', false, $id, $id))
- {
- return false;
- }
-
- if ($db->simpleQuerySingle('SELECT 1 FROM compta_categories WHERE compte = ? LIMIT 1;', false, $id))
- {
- return false;
- }
-
- return true;
- }
-
- /**
- * Désactiver un compte
- * Le compte ne sera plus utilisable pour les écritures ou les catégories mais restera en base de données
- * @param string $id Numéro du compte
- * @return boolean TRUE si la désactivation a fonctionné, une exception utilisateur si
- * la désactivation n'est pas possible.
- */
- public function disable($id)
- {
- $db = DB::getInstance();
-
- // Ne pas désactiver un compte utilisé dans l'exercice courant
- if ($db->simpleQuerySingle('SELECT 1 FROM compta_journal
- WHERE id_exercice = (SELECT id FROM compta_exercices WHERE cloture = 0 LIMIT 1)
- AND (compte_debit = ? OR compte_debit = ?) LIMIT 1;', false, $id, $id))
- {
- throw new UserException('Ce compte ne peut être désactivé car des écritures y sont liées sur l\'exercice courant. '
- . 'Il faut supprimer ou ré-attribuer ces écritures avant de pouvoir supprimer le compte.');
- }
-
- // Ne pas désactiver un compte utilisé pour une catégorie
- if ($db->simpleQuerySingle('SELECT 1 FROM compta_categories WHERE compte = ? LIMIT 1;', false, $id))
- {
- throw new UserException('Ce compte ne peut être désactivé car des catégories y sont liées.');
- }
-
- return $db->simpleUpdate('compta_comptes', ['desactive' => 1], 'id = \''.$db->escapeString(trim($id)).'\'');
- }
-
- public function get($id)
- {
- $db = DB::getInstance();
- return $db->simpleQuerySingle('SELECT * FROM compta_comptes WHERE id = ?;', true, trim($id));
- }
-
- public function getList($parent = 0)
- {
- $db = DB::getInstance();
- return $db->simpleStatementFetchAssocKey('SELECT id, * FROM compta_comptes WHERE parent = ? ORDER BY id;', SQLITE3_ASSOC, $parent);
- }
-
- public function getListAll($parent = 0)
- {
- $db = DB::getInstance();
- return $db->queryFetchAssoc('SELECT id, libelle FROM compta_comptes ORDER BY id;');
- }
-
- public function listTree($parent = 0, $include_children = true)
- {
- $db = DB::getInstance();
-
- if ($include_children)
- {
- $parent = $parent ? 'WHERE parent LIKE \''.$db->escapeString($parent).'%\' ' : '';
- }
- else
- {
- $parent = $parent ? 'WHERE parent = \''.$db->escapeString($parent).'\' ' : 'WHERE parent = 0';
- }
-
- return $db->simpleStatementFetch('SELECT * FROM compta_comptes '.$parent.' ORDER BY id;');
- }
-
- protected function _checkFields(&$data, $force_parent_check = false)
- {
- $db = DB::getInstance();
-
- if (empty($data['libelle']) || !trim($data['libelle']))
- {
- throw new UserException('Le libellé ne peut rester vide.');
- }
-
- $data['libelle'] = trim($data['libelle']);
-
- if (isset($data['id']))
- {
- $force_parent_check = true;
- $data['id'] = trim($data['id']);
-
- if ($db->simpleQuerySingle('SELECT 1 FROM compta_comptes WHERE id = ?;', false, $data['id']))
- {
- throw new UserException('Le compte numéro '.$data['id'].' existe déjà.');
- }
- }
-
- if (isset($data['parent']) || $force_parent_check)
- {
- if (empty($data['parent']) && !trim($data['parent']))
- {
- throw new UserException('Le compte ne peut pas ne pas avoir de compte parent.');
- }
-
- if (!($id = $db->simpleQuerySingle('SELECT id FROM compta_comptes WHERE id = ?;', false, $data['parent'])))
- {
- throw new UserException('Le compte parent indiqué n\'existe pas.');
- }
-
- $data['parent'] = trim($id);
- }
-
- if (isset($data['id']))
- {
- if (strncmp($data['id'], $data['parent'], strlen($data['parent'])) !== 0)
- {
- throw new UserException('Le compte '.$data['id'].' n\'est pas un sous-compte de '.$data['parent'].'.');
- }
- }
-
- return true;
- }
-
- public function getPositions()
- {
- return [
- self::ACTIF => 'Actif',
- self::PASSIF => 'Passif',
- self::ACTIF | self::PASSIF => 'Actif ou passif (déterminé automatiquement au bilan selon le solde du compte)',
- self::CHARGE => 'Charge',
- self::PRODUIT => 'Produit',
- self::CHARGE | self::PRODUIT => 'Charge et produit',
- ];
- }
-}
-
-?>
DELETED src/include/class.compta_comptes_bancaires.php
Index: src/include/class.compta_comptes_bancaires.php
==================================================================
--- src/include/class.compta_comptes_bancaires.php
+++ src/include/class.compta_comptes_bancaires.php
@@ -1,164 +0,0 @@
-_checkBankFields($data);
-
- $new_id = parent::add($data);
-
- $db->simpleInsert('compta_comptes_bancaires', [
- 'id' => $new_id,
- 'banque' => $data['banque'],
- 'iban' => $data['iban'],
- 'bic' => $data['bic'],
- ]);
-
- return $new_id;
- }
-
- public function edit($id, $data)
- {
- $db = DB::getInstance();
-
- if (!$db->simpleQuerySingle('SELECT 1 FROM compta_comptes_bancaires WHERE id = ?;', false, $id))
- {
- throw new UserException('Ce compte n\'est pas un compte bancaire.');
- }
-
- $this->_checkBankFields($data);
- $result = parent::edit($id, $data);
-
- if (!$result)
- {
- return $result;
- }
-
- $db->simpleUpdate('compta_comptes_bancaires', [
- 'banque' => $data['banque'],
- 'iban' => $data['iban'],
- 'bic' => $data['bic'],
- ], 'id = \''.$db->escapeString(trim($id)).'\'');
-
- return true;
- }
-
- /**
- * Supprime un compte bancaire
- * La suppression sera refusée si le compte est utilisé dans l'exercice en cours
- * ou dans une catégorie.
- * Le compte bancaire sera supprimé et le compte au plan comptable seulement désactivé
- * si le compte est utilisé dans un exercice précédent.
- *
- * La désactivation d'un compte fait qu'il n'est plus utilisable dans l'exercice courant
- * ou les exercices suivants, mais il est possible de le réactiver.
- * @param string $id Numéro du compte
- * @return boolean TRUE si la suppression ou désactivation a été effectuée, une exception ou FALSE sinon
- */
- public function delete($id)
- {
- $db = DB::getInstance();
- if (!$db->simpleQuerySingle('SELECT 1 FROM compta_comptes_bancaires WHERE id = ?;', false, trim($id)))
- {
- throw new UserException('Ce compte n\'est pas un compte bancaire.');
- }
-
- // Ne pas supprimer/désactiver un compte qui est utilisé dans l'exercice courant
- if ($db->simpleQuerySingle('SELECT 1 FROM compta_journal
- WHERE id_exercice = (SELECT id FROM compta_exercices WHERE cloture = 0 LIMIT 1)
- AND (compte_debit = ? OR compte_debit = ?) LIMIT 1;', false, $id, $id))
- {
- throw new UserException('Ce compte ne peut être supprimé car des écritures y sont liées sur l\'exercice courant. '
- . 'Il faut supprimer ou ré-attribuer ces écritures avant de pouvoir supprimer le compte.');
- }
-
- // Il n'est pas possible de supprimer ou désactiver un compte qui est lié à des catégories
- if ($db->simpleQuerySingle('SELECT 1 FROM compta_categories WHERE compte = ? LIMIT 1;', false, $id))
- {
- throw new UserException('Ce compte ne peut être supprimé car des catégories y sont liées. '
- . 'Merci de supprimer ou modifier les catégories liées avant de le supprimer.');
- }
-
- $db->simpleExec('DELETE FROM compta_comptes_bancaires WHERE id = ?;', trim($id));
-
- try {
- $return = parent::delete($id);
- }
- catch (UserException $e) {
- // Impossible de supprimer car des opérations y sont encore liées
- // sur les exercices précédents, alors on le désactive
- $return = parent::disable($id);
- }
-
- return $return;
- }
-
- public function get($id)
- {
- $db = DB::getInstance();
- return $db->simpleQuerySingle('SELECT * FROM compta_comptes AS c
- INNER JOIN compta_comptes_bancaires AS cc
- ON c.id = cc.id
- WHERE c.id = ?;', true, $id);
- }
-
- public function getList($parent = false)
- {
- $db = DB::getInstance();
- return $db->simpleStatementFetchAssocKey('SELECT c.id AS id, * FROM compta_comptes AS c
- INNER JOIN compta_comptes_bancaires AS cc ON c.id = cc.id
- WHERE c.parent = '.self::NUMERO_PARENT_COMPTES.' ORDER BY c.id;');
- }
-
- protected function _checkBankFields(&$data)
- {
- if (empty($data['banque']) || !trim($data['banque']))
- {
- throw new UserException('Le nom de la banque ne peut rester vide.');
- }
-
- if (empty($data['bic']))
- {
- $data['bic'] = '';
- }
- else
- {
- $data['bic'] = trim(strtoupper($data['bic']));
- $data['bic'] = preg_replace('![^\dA-Z]!', '', $data['bic']);
-
- if (!utils::checkBIC($data['bic']))
- {
- throw new UserException('Code BIC/SWIFT invalide.');
- }
- }
-
- if (empty($data['iban']))
- {
- $data['iban'] = '';
- }
- else
- {
- $data['iban'] = trim(strtoupper($data['iban']));
- $data['iban'] = preg_replace('![^\dA-Z]!', '', $data['iban']);
-
- if (!utils::checkIBAN($data['iban']))
- {
- throw new UserException('Code IBAN invalide.');
- }
- }
-
- return true;
- }
-}
-
-?>
DELETED src/include/class.compta_exercices.php
Index: src/include/class.compta_exercices.php
==================================================================
--- src/include/class.compta_exercices.php
+++ src/include/class.compta_exercices.php
@@ -1,611 +0,0 @@
-_checkFields($data);
-
- $db = DB::getInstance();
-
- if ($db->simpleQuerySingle('SELECT 1 FROM compta_exercices WHERE
- (debut <= :debut AND fin >= :debut) OR (debut <= :fin AND fin >= :fin);', false,
- ['debut' => $data['debut'], 'fin' => $data['fin']]))
- {
- throw new UserException('La date de début ou de fin se recoupe avec un autre exercice.');
- }
-
- if ($db->querySingle('SELECT 1 FROM compta_exercices WHERE cloture = 0;'))
- {
- throw new UserException('Il n\'est pas possible de créer un nouvel exercice tant qu\'il existe un exercice non-clôturé.');
- }
-
- $db->simpleInsert('compta_exercices', [
- 'libelle' => trim($data['libelle']),
- 'debut' => $data['debut'],
- 'fin' => $data['fin'],
- ]);
-
- return $db->lastInsertRowId();
- }
-
- public function edit($id, $data)
- {
- $db = DB::getInstance();
-
- $this->_checkFields($data);
-
- // Evitons que les exercices se croisent
- if ($db->simpleQuerySingle('SELECT 1 FROM compta_exercices WHERE id != :id AND
- ((debut <= :debut AND fin >= :debut) OR (debut <= :fin AND fin >= :fin));', false,
- ['debut' => $data['debut'], 'fin' => $data['fin'], 'id' => (int) $id]))
- {
- throw new UserException('La date de début ou de fin se recoupe avec un autre exercice.');
- }
-
- // On vérifie qu'on ne va pas mettre des opérations en dehors de tout exercice
- if ($db->simpleQuerySingle('SELECT 1 FROM compta_journal WHERE id_exercice = ?
- AND date < ? LIMIT 1;', false, (int)$id, $data['debut']))
- {
- throw new UserException('Des opérations de cet exercice ont une date antérieure à la date de début de l\'exercice.');
- }
-
- if ($db->simpleQuerySingle('SELECT 1 FROM compta_journal WHERE id_exercice = ?
- AND date > ? LIMIT 1;', false, (int)$id, $data['fin']))
- {
- throw new UserException('Des opérations de cet exercice ont une date postérieure à la date de fin de l\'exercice.');
- }
-
- $db->simpleUpdate('compta_exercices', [
- 'libelle' => trim($data['libelle']),
- 'debut' => $data['debut'],
- 'fin' => $data['fin'],
- ], 'id = \''.(int)$id.'\'');
-
- return true;
- }
-
- /**
- * Clôturer un exercice et en ouvrir un nouveau
- * Le report à nouveau n'est pas effectué automatiquement par cette fonction, voir doReports pour ça.
- * @param integer $id ID de l'exercice à clôturer
- * @param string $end Date de clôture de l'exercice au format Y-m-d
- * @return integer L'ID du nouvel exercice créé
- */
- public function close($id, $end)
- {
- $db = DB::getInstance();
-
- if (!utils::checkDate($end))
- {
- throw new UserException('Date de fin vide ou invalide.');
- }
-
- $db->exec('BEGIN;');
-
- // Clôture de l'exercice
- $db->simpleUpdate('compta_exercices', [
- 'cloture' => 1,
- 'fin' => $end,
- ], 'id = \''.(int)$id.'\'');
-
- // Date de début du nouvel exercice : lendemain de la clôture du précédent exercice
- $new_begin = utils::modifyDate($end, '+1 day');
-
- // Date de fin du nouvel exercice : un an moins un jour après l'ouverture
- $new_end = utils::modifyDate($new_begin, '+1 year -1 day');
-
- // Enfin sauf s'il existe déjà des opérations après cette date, auquel cas la date de fin
- // est fixée à la date de la dernière opération, ceci pour ne pas avoir d'opération
- // orpheline d'exercice
- $last = $db->simpleQuerySingle('SELECT date FROM compta_journal WHERE id_exercice = ? AND date >= ? ORDER BY date DESC LIMIT 1;', false, $id, $new_end);
- $new_end = $last ?: $new_end;
-
- // Création du nouvel exercice
- $new_id = $this->add([
- 'debut' => $new_begin,
- 'fin' => $new_end,
- 'libelle' => 'Nouvel exercice'
- ]);
-
- // Ré-attribution des opérations de l'exercice à clôturer qui ne sont pas dans son
- // intervale au nouvel exercice
- $db->simpleExec('UPDATE compta_journal SET id_exercice = ? WHERE id_exercice = ? AND date >= ?;',
- $new_id, $id, $new_begin);
-
- $db->exec('END;');
-
- return $new_id;
- }
-
- /**
- * Créer les reports à nouveau issus de l'exercice $old_id dans le nouvel exercice courant
- * @param integer $old_id ID de l'ancien exercice
- * @param integer $new_id ID du nouvel exercice
- * @param string $date Date Y-m-d donnée aux opérations créées
- * @return boolean true si succès
- */
- public function doReports($old_id, $date)
- {
- $db = DB::getInstance();
-
- $db->exec('BEGIN;');
-
- $this->solderResultat($old_id, $date);
-
- $report_crediteur = 110;
- $report_debiteur = 119;
-
- // Récupérer chacun des comptes de bilan et leurs soldes (uniquement les classes 1 à 5)
- $statement = $db->simpleStatement('SELECT compta_comptes.id AS compte, compta_comptes.position AS position,
- COALESCE((SELECT SUM(montant) FROM compta_journal WHERE compte_debit = compta_comptes.id AND id_exercice = :id), 0)
- - COALESCE((SELECT SUM(montant) FROM compta_journal WHERE compte_credit = compta_comptes.id AND id_exercice = :id), 0) AS solde
- FROM compta_comptes
- INNER JOIN compta_journal ON compta_comptes.id = compta_journal.compte_debit
- OR compta_comptes.id = compta_journal.compte_credit
- WHERE id_exercice = :id AND solde != 0 AND CAST(substr(compta_comptes.id, 1, 1) AS INTEGER) <= 5
- GROUP BY compta_comptes.id;', ['id' => $old_id]);
-
- $diff = 0;
- $journal = new Compta_Journal;
-
- while ($row = $statement->fetchArray(SQLITE3_ASSOC))
- {
- $solde = abs($row['solde']);
- $solde = round($solde, 2);
-
- $diff += $solde;
-
- if (empty($solde))
- {
- continue;
- }
-
- // Chaque solde de compte est reporté dans le nouvel exercice
- $journal->add([
- 'libelle' => 'Report à nouveau',
- 'date' => $date,
- 'montant' => abs($solde),
- 'compte_debit' => ($solde < 0 ? NULL : $row['compte']),
- 'compte_credit' => ($solde > 0 ? NULL : $row['compte']),
- 'remarques' => 'Report de solde créé automatiquement à la clôture de l\'exercice précédent',
- ]);
- }
-
- // FIXME utiliser $diff pour équilibrer
-
- $db->exec('END;');
-
- return true;
- }
-
- /**
- * Solder les comptes de charge et de produits de l'exercice N
- * et les inscrire au résultat de l'exercice N+1
- * @param integer $exercice ID de l'exercice à solder
- * @param string $date Date de début de l'exercice Y-m-d
- * @return boolean true en cas de succès
- */
- public function solderResultat($exercice, $date)
- {
- $db = DB::getInstance();
-
- $resultat_excedent = 120;
- $resultat_debiteur = 129;
-
- $resultat = $this->getCompteResultat($exercice);
- $resultat = $resultat['resultat'];
-
- if ($resultat != 0)
- {
- $journal = new Compta_Journal;
- $journal->add([
- 'libelle' => 'Résultat de l\'exercice précédent',
- 'date' => $date,
- 'montant' => abs($resultat),
- 'compte_debit' => $resultat < 0 ? 129 : NULL,
- 'compte_credit' => $resultat > 0 ? 120 : NULL,
- ]);
- }
-
- return true;
- }
-
- public function delete($id)
- {
- $db = DB::getInstance();
-
- // Ne pas supprimer un compte qui est utilisé !
- if ($db->simpleQuerySingle('SELECT 1 FROM compta_journal WHERE id_exercice = ? LIMIT 1;', false, $id))
- {
- throw new UserException('Cet exercice ne peut être supprimé car des opérations comptables y sont liées.');
- }
-
- $db->simpleExec('DELETE FROM compta_exercices WHERE id = ?;', (int)$id);
-
- return true;
- }
-
- public function get($id)
- {
- $db = DB::getInstance();
- return $db->simpleQuerySingle('SELECT *, strftime(\'%s\', debut) AS debut,
- strftime(\'%s\', fin) AS fin FROM compta_exercices WHERE id = ?;', true, (int)$id);
- }
-
- public function getCurrent()
- {
- $db = DB::getInstance();
- return $db->querySingle('SELECT *, strftime(\'%s\', debut) AS debut, strftime(\'%s\', fin) FROM compta_exercices
- WHERE cloture = 0 LIMIT 1;', true);
- }
-
- public function getCurrentId()
- {
- $db = DB::getInstance();
- return $db->querySingle('SELECT id FROM compta_exercices WHERE cloture = 0 LIMIT 1;');
- }
-
- public function getList()
- {
- $db = DB::getInstance();
- return $db->simpleStatementFetchAssocKey('SELECT id, *, strftime(\'%s\', debut) AS debut,
- strftime(\'%s\', fin) AS fin,
- (SELECT COUNT(*) FROM compta_journal WHERE id_exercice = compta_exercices.id) AS nb_operations
- FROM compta_exercices ORDER BY fin DESC;', SQLITE3_ASSOC);
- }
-
- protected function _checkFields(&$data)
- {
- if (empty($data['libelle']) || !trim($data['libelle']))
- {
- throw new UserException('Le libellé ne peut rester vide.');
- }
-
- $data['libelle'] = trim($data['libelle']);
-
- if (empty($data['debut']) || !checkdate(substr($data['debut'], 5, 2), substr($data['debut'], 8, 2), substr($data['debut'], 0, 4)))
- {
- throw new UserException('Date de début vide ou invalide.');
- }
-
- if (empty($data['fin']) || !checkdate(substr($data['fin'], 5, 2), substr($data['fin'], 8, 2), substr($data['fin'], 0, 4)))
- {
- throw new UserException('Date de fin vide ou invalide.');
- }
-
- return true;
- }
-
-
- public function getJournal($exercice)
- {
- $db = DB::getInstance();
- $query = 'SELECT *, strftime(\'%s\', date) AS date FROM compta_journal
- WHERE id_exercice = '.(int)$exercice.' ORDER BY date, id;';
- return $db->simpleStatementFetch($query);
- }
-
- public function getGrandLivre($exercice)
- {
- $db = DB::getInstance();
- $livre = ['classes' => [], 'debit' => 0.0, 'credit' => 0.0];
-
- $res = $db->prepare('SELECT compte FROM
- (SELECT compte_debit AS compte FROM compta_journal
- WHERE id_exercice = '.(int)$exercice.' GROUP BY compte_debit
- UNION
- SELECT compte_credit AS compte FROM compta_journal
- WHERE id_exercice = '.(int)$exercice.' GROUP BY compte_credit)
- ORDER BY base64(compte) COLLATE BINARY ASC;'
- )->execute();
-
- while ($row = $res->fetchArray(SQLITE3_NUM))
- {
- $compte = $row[0];
-
- if (is_null($compte))
- continue;
-
- $classe = substr($compte, 0, 1);
- $parent = substr($compte, 0, 2);
-
- if (!array_key_exists($classe, $livre['classes']))
- {
- $livre['classes'][$classe] = [];
- }
-
- if (!array_key_exists($parent, $livre['classes'][$classe]))
- {
- $livre['classes'][$classe][$parent] = [
- 'total' => 0.0,
- 'comptes' => [],
- ];
- }
-
- $livre['classes'][$classe][$parent]['comptes'][$compte] = ['debit' => 0.0, 'credit' => 0.0, 'journal' => []];
-
- $livre['classes'][$classe][$parent]['comptes'][$compte]['journal'] = $db->simpleStatementFetch(
- 'SELECT *, strftime(\'%s\', date) AS date FROM (
- SELECT * FROM compta_journal WHERE compte_debit = :compte AND id_exercice = '.(int)$exercice.'
- UNION
- SELECT * FROM compta_journal WHERE compte_credit = :compte AND id_exercice = '.(int)$exercice.'
- )
- ORDER BY date, numero_piece, id;', SQLITE3_ASSOC, ['compte' => $compte]);
-
- $solde = 0.0;
- foreach ($livre['classes'][$classe][$parent]['comptes'][$compte]['journal'] as &$ligne)
- {
- if ($ligne["compte_credit"] == $compte)
- {
- $solde += $ligne['montant'];
- }
- else
- {
- $solde -= $ligne['montant'];
- }
- $ligne['solde'] = $solde;
- }
-
- $debit = (float) $db->simpleQuerySingle(
- 'SELECT SUM(montant) FROM compta_journal WHERE compte_debit = ? AND id_exercice = '.(int)$exercice.';',
- false, $compte);
-
- $credit = (float) $db->simpleQuerySingle(
- 'SELECT SUM(montant) FROM compta_journal WHERE compte_credit = ? AND id_exercice = '.(int)$exercice.';',
- false, $compte);
-
- $livre['classes'][$classe][$parent]['comptes'][$compte]['debit'] = $debit;
- $livre['classes'][$classe][$parent]['comptes'][$compte]['credit'] = $credit;
- $livre['classes'][$classe][$parent]['comptes'][$compte]['solde'] = $credit - $debit;
-
- $livre['classes'][$classe][$parent]['total'] += $debit;
- $livre['classes'][$classe][$parent]['total'] -= $credit;
-
- $livre['debit'] += $debit;
- $livre['credit'] += $credit;
- }
-
- $res->finalize();
-
- return $livre;
- }
-
- public function getCompteResultat($exercice)
- {
- $db = DB::getInstance();
-
- $charges = ['comptes' => [], 'total' => 0.0];
- $produits = ['comptes' => [], 'total' => 0.0];
- $resultat = 0.0;
-
- $res = $db->prepare('SELECT compte, SUM(debit), SUM(credit)
- FROM
- (SELECT compte_debit AS compte, SUM(montant) AS debit, 0 AS credit
- FROM compta_journal WHERE id_exercice = '.(int)$exercice.' GROUP BY compte_debit
- UNION
- SELECT compte_credit AS compte, 0 AS debit, SUM(montant) AS credit
- FROM compta_journal WHERE id_exercice = '.(int)$exercice.' GROUP BY compte_credit)
- WHERE compte LIKE \'6%\' OR compte LIKE \'7%\'
- GROUP BY compte
- ORDER BY base64(compte) COLLATE BINARY ASC;'
- )->execute();
-
- while ($row = $res->fetchArray(SQLITE3_NUM))
- {
- list($compte, $debit, $credit) = $row;
- $classe = substr($compte, 0, 1);
- $parent = substr($compte, 0, 2);
-
- if ($classe == 6)
- {
- if (!isset($charges['comptes'][$parent]))
- {
- $charges['comptes'][$parent] = ['comptes' => [], 'solde' => 0.0];
- }
-
- $solde = round($debit - $credit, 2);
-
- if (empty($solde))
- continue;
-
- $charges['comptes'][$parent]['comptes'][$compte] = $solde;
- $charges['total'] += $solde;
- $charges['comptes'][$parent]['solde'] += $solde;
- }
- elseif ($classe == 7)
- {
- if (!isset($produits['comptes'][$parent]))
- {
- $produits['comptes'][$parent] = ['comptes' => [], 'solde' => 0.0];
- }
-
- $solde = round($credit - $debit, 2);
-
- if (empty($solde))
- continue;
-
- $produits['comptes'][$parent]['comptes'][$compte] = $solde;
- $produits['total'] += $solde;
- $produits['comptes'][$parent]['solde'] += $solde;
- }
- }
-
- $res->finalize();
-
- $resultat = $produits['total'] - $charges['total'];
-
- return ['charges' => $charges, 'produits' => $produits, 'resultat' => $resultat];
- }
-
- /**
- * Calculer le bilan comptable pour l'exercice $exercice
- * @param integer $exercice ID de l'exercice dont il faut produire le bilan
- * @param boolean $resultat true s'il faut calculer le résultat de l'exercice (utile pour un exercice en cours)
- * @return array Un tableau multi-dimensionnel avec deux clés : actif et passif
- */
- public function getBilan($exercice)
- {
- $db = DB::getInstance();
-
- $include = [Compta_Comptes::ACTIF, Compta_Comptes::PASSIF,
- Compta_Comptes::PASSIF | Compta_Comptes::ACTIF];
-
- $actif = ['comptes' => [], 'total' => 0.0];
- $passif = ['comptes' => [], 'total' => 0.0];
- $actif_ou_passif = ['comptes' => [], 'total' => 0.0];
-
- $resultat = $this->getCompteResultat($exercice);
-
- if ($resultat['resultat'] >= 0)
- {
- $passif['comptes']['12'] = [
- 'comptes' => ['120' => $resultat['resultat']],
- 'solde' => $resultat['resultat']
- ];
-
- $passif['total'] = $resultat['resultat'];
- }
- else
- {
- $passif['comptes']['12'] = [
- 'comptes' => ['129' => $resultat['resultat']],
- 'solde' => $resultat['resultat']
- ];
-
- $passif['total'] = $resultat['resultat'];
- }
-
- // Y'a sûrement moyen d'améliorer tout ça pour que le maximum de travail
- // soit fait au niveau du SQL, mais pour le moment ça marche
- $res = $db->prepare('SELECT compte, debit, credit, (SELECT position FROM compta_comptes WHERE id = compte) AS position
- FROM
- (SELECT compte_debit AS compte, SUM(montant) AS debit, NULL AS credit
- FROM compta_journal WHERE id_exercice = '.(int)$exercice.' GROUP BY compte_debit
- UNION
- SELECT compte_credit AS compte, NULL AS debit, SUM(montant) AS credit
- FROM compta_journal WHERE id_exercice = '.(int)$exercice.' GROUP BY compte_credit)
- WHERE compte IN (SELECT id FROM compta_comptes WHERE position IN ('.implode(', ', $include).'))
- ORDER BY base64(compte) COLLATE BINARY ASC;'
- )->execute();
-
- while ($row = $res->fetchArray(SQLITE3_NUM))
- {
- list($compte, $debit, $credit, $position) = $row;
- $parent = substr($compte, 0, 2);
- $classe = $compte[0];
-
- if (($position & Compta_Comptes::ACTIF) && ($position & Compta_Comptes::PASSIF))
- {
- $position = 'actif_ou_passif';
- $solde = $debit - $credit;
- }
- else if ($position & Compta_Comptes::ACTIF)
- {
- $position = 'actif';
- $solde = $debit - $credit;
- }
- else if ($position & Compta_Comptes::PASSIF)
- {
- $position = 'passif';
- $solde = $credit - $debit;
- }
- else
- {
- continue;
- }
-
- if (!isset(${$position}['comptes'][$parent]))
- {
- ${$position}['comptes'][$parent] = ['comptes' => [], 'solde' => 0];
- }
-
- if (!isset(${$position}['comptes'][$parent]['comptes'][$compte]))
- {
- ${$position}['comptes'][$parent]['comptes'][$compte] = 0;
- }
-
- $solde = round($solde, 2);
- ${$position}['comptes'][$parent]['comptes'][$compte] += $solde;
- ${$position}['total'] += $solde;
- ${$position}['comptes'][$parent]['solde'] += $solde;
- }
-
- $res->finalize();
-
- foreach ($actif_ou_passif['comptes'] as $parent=>$p)
- {
- foreach ($p['comptes'] as $compte=>$solde)
- {
- if ($solde > 0)
- {
- $position = 'actif';
- }
- else if ($solde < 0)
- {
- $position = 'passif';
- $solde = -$solde;
- }
- else
- {
- continue;
- }
-
- if (!isset(${$position}['comptes'][$parent]))
- {
- ${$position}['comptes'][$parent] = ['comptes' => [], 'solde' => 0];
- }
-
- if (!isset(${$position}['comptes'][$parent]['comptes'][$compte]))
- {
- ${$position}['comptes'][$parent]['comptes'][$compte] = 0;
- }
-
- ${$position}['comptes'][$parent]['comptes'][$compte] += $solde;
- ${$position}['total'] += $solde;
- ${$position}['comptes'][$parent]['solde'] += $solde;
- }
- }
-
- // Suppression des soldes nuls
- foreach ($passif['comptes'] as $parent=>$p)
- {
- if ($p['solde'] == 0)
- {
- unset($passif['comptes'][$parent]);
- continue;
- }
-
- foreach ($p['comptes'] as $id=>$solde)
- {
- if ($solde == 0)
- {
- unset($passif['comptes'][$parent]['comptes'][$id]);
- }
- }
- }
-
- foreach ($actif['comptes'] as $parent=>$p)
- {
- if (empty($p['solde']))
- {
- unset($actif['comptes'][$parent]);
- continue;
- }
-
- foreach ($p['comptes'] as $id=>$solde)
- {
- if (empty($solde))
- {
- unset($actif['comptes'][$parent]['comptes'][$id]);
- }
- }
- }
-
- return ['actif' => $actif, 'passif' => $passif];
- }
-}
-
-?>
DELETED src/include/class.compta_import.php
Index: src/include/class.compta_import.php
==================================================================
--- src/include/class.compta_import.php
+++ src/include/class.compta_import.php
@@ -1,387 +0,0 @@
-prepare('SELECT
- journal.id,
- strftime(\'%d/%m/%Y\', date) AS date,
- (CASE cat.type WHEN 1 THEN \'Recette\' WHEN -1 THEN \'Dépense\' ELSE \'Autre\' END) AS type,
- (CASE cat.intitule WHEN NULL THEN \'\' ELSE cat.intitule END) AS cat,
- journal.libelle,
- montant,
- compte_debit,
- debit.libelle AS libelle_debit,
- compte_credit,
- credit.libelle AS libelle_credit,
- (CASE moyen_paiement WHEN NULL THEN \'\' ELSE moyen.nom END) AS moyen,
- numero_cheque,
- numero_piece,
- remarques
- FROM compta_journal AS journal
- LEFT JOIN compta_categories AS cat ON cat.id = journal.id_categorie
- LEFT JOIN compta_comptes AS debit ON debit.id = journal.compte_debit
- LEFT JOIN compta_comptes AS credit ON credit.id = journal.compte_credit
- LEFT JOIN compta_moyens_paiement AS moyen ON moyen.code = journal.moyen_paiement
- WHERE id_exercice = '.(int)$exercice.'
- ORDER BY journal.date;
- ')->execute();
-
- $fp = fopen('php://output', 'w');
-
- fputcsv($fp, $this->csv_header);
-
- while ($row = $res->fetchArray(SQLITE3_ASSOC))
- {
- fputcsv($fp, $row);
- }
-
- fclose($fp);
-
- return true;
- }
-
- public function fromCSV($path)
- {
- if (!file_exists($path) || !is_readable($path))
- {
- throw new \RuntimeException('Fichier inconnu : '.$path);
- }
-
- $fp = fopen($path, 'r');
-
- if (!$fp)
- {
- return false;
- }
-
- $db = DB::getInstance();
- $db->exec('BEGIN;');
- $comptes = new Compta_Comptes;
- $banques = new Compta_Comptes_Bancaires;
- $cats = new Compta_Categories;
- $journal = new Compta_Journal;
-
- $columns = array_flip($this->csv_header);
- $liste_comptes = $db->simpleStatementFetchAssoc('SELECT id, id FROM compta_comptes;');
- $liste_cats = $db->simpleStatementFetchAssoc('SELECT intitule, id FROM compta_categories;');
- $liste_moyens = $cats->listMoyensPaiement();
-
- $col = function($column) use (&$row, &$columns)
- {
- if (!isset($columns[$column]))
- return null;
-
- if (!isset($row[$columns[$column]]))
- return null;
-
- return $row[$columns[$column]];
- };
-
- $line = 0;
- $delim = utils::find_csv_delim($fp);
-
- while (!feof($fp))
- {
- $row = fgetcsv($fp, 4096, $delim);
- $line++;
-
- if (empty($row))
- {
- continue;
- }
-
- if ($line === 1)
- {
- if (trim($row[0]) != 'Numéro mouvement')
- {
- throw new UserException('Erreur sur la ligne ' . $line . ' : l\'entête des colonnes est absent ou incorrect.');
- }
-
- continue;
- }
-
- if (count($row) != count($columns))
- {
- $db->exec('ROLLBACK;');
- throw new UserException('Erreur sur la ligne ' . $line . ' : le nombre de colonnes est incorrect.');
- }
-
- if (trim($row[0]) !== '' && !is_numeric($row[0]))
- {
- $db->exec('ROLLBACK;');
- throw new UserException('Erreur sur la ligne ' . $line . ' : la première colonne doit être vide ou contenir le numéro unique d\'opération.');
- }
-
- $id = $col('Numéro mouvement');
- $date = $col('Date');
-
- if (!preg_match('!^\d{2}/\d{2}/\d{4}$!', $date))
- {
- $db->exec('ROLLBACK;');
- throw new UserException('Erreur sur la ligne ' . $line . ' : la date n\'est pas au format jj/mm/aaaa.');
- }
-
- $date = explode('/', $date);
- $date = $date[2] . '-' . $date[1] . '-' . $date[0];
-
- // En dehors de l'exercice courant
- if ($db->simpleQuerySingle('SELECT 1 FROM compta_exercices
- WHERE (? < debut OR ? > fin) AND cloture = 0;', false, $date, $date))
- {
- continue;
- }
-
- $debit = $col('Compte de débit - numéro');
- $credit = $col('Compte de crédit - numéro');
-
- if (trim($debit) == '' && trim($credit) != '')
- {
- $debit = null;
- }
- elseif (trim($debit) != '' && trim($credit) == '')
- {
- $credit = null;
- }
-
- $cat = $col('Catégorie');
- $moyen = strtoupper(substr($col('Moyen de paiement'), 0, 2));
-
- if (!$moyen || !array_key_exists($moyen, $liste_moyens))
- {
- $moyen = false;
- $cat = false;
- }
-
- if ($cat && !array_key_exists($cat, $liste_cats))
- {
- $cat = $moyen = false;
- }
-
- $data = [
- 'libelle' => $col('Libellé'),
- 'montant' => (float) $col('Montant'),
- 'date' => $date,
- 'compte_credit' => $credit,
- 'compte_debit' => $debit,
- 'numero_piece' => $col('Numéro de pièce'),
- 'remarques' => $col('Remarques'),
- ];
-
- if ($cat)
- {
- $data['moyen_paiement'] = $moyen;
- $data['numero_cheque'] = $col('Numéro de chèque');
- $data['id_categorie'] = $liste_cats[$cat];
- }
-
- if (empty($id))
- {
- $journal->add($data);
- }
- else
- {
- $journal->edit($id, $data);
- }
- }
-
- $db->exec('END;');
-
- fclose($fp);
- return true;
- }
-
- public function fromCitizen($path)
- {
- if (!file_exists($path) || !is_readable($path))
- {
- throw new \RuntimeException('Fichier inconnu : '.$path);
- }
-
- $fp = fopen($path, 'r');
-
- if (!$fp)
- {
- return false;
- }
-
- $db = DB::getInstance();
- $db->exec('BEGIN;');
- $comptes = new Compta_Comptes;
- $banques = new Compta_Comptes_Bancaires;
- $cats = new Compta_Categories;
- $journal = new Compta_Journal;
-
- $columns = [];
- $liste_comptes = $db->simpleStatementFetchAssoc('SELECT id, id FROM compta_comptes;');
- $liste_cats = $db->simpleStatementFetchAssoc('SELECT intitule, id FROM compta_categories;');
- $liste_moyens = $cats->listMoyensPaiement();
-
- $get_compte = function ($compte, $intitule) use (&$liste_comptes, &$comptes, &$banques)
- {
- if (substr($compte, 0, 2) == '51')
- {
- $compte = '512' . substr($compte, -1);
- }
-
- // Création comptes
- if (!array_key_exists($compte, $liste_comptes))
- {
- if (substr($compte, 0, 3) == '512')
- {
- $liste_comptes[$compte] = $banques->add([
- 'libelle' => $intitule,
- 'banque' => 'Inconnue',
- ]);
- }
- else
- {
- $liste_comptes[$compte] = $comptes->add([
- 'id' => $compte,
- 'libelle' => $intitule,
- 'parent' => substr($compte, 0, -1)
- ]);
- }
- }
-
- return $compte;
- };
-
- $col = function($column) use (&$row, &$columns)
- {
- if (!isset($columns[$column]))
- return null;
-
- if (!isset($row[$columns[$column]]))
- return null;
-
- return $row[$columns[$column]];
- };
-
- $line = 0;
- $delim = utils::find_csv_delim($fp);
-
- while (!feof($fp))
- {
- $row = fgetcsv($fp, 4096, $delim);
- $line++;
-
- if (empty($row))
- {
- continue;
- }
-
- if (empty($columns))
- {
- $columns = $row;
- $columns = array_flip($columns);
- continue;
- }
-
- $date = $col('Date');
-
- if (!preg_match('!^\d{2}/\d{2}/\d{4}$!', $date))
- {
- $db->exec('ROLLBACK;');
- throw new UserException('Erreur sur la ligne ' . $line . ' : la date n\'est pas au format jj/mm/aaaa.');
- }
-
- $date = explode('/', $date);
- $date = $date[2] . '-' . $date[1] . '-' . $date[0];
-
- if ($db->simpleQuerySingle('SELECT 1 FROM compta_exercices
- WHERE (? < debut OR ? > fin) AND cloture = 0;', false, $date, $date))
- {
- continue;
- }
-
- $debit = $get_compte($col('Compte débité - Numéro'), $col('Compte débité - Intitulé'));
- $credit = $get_compte($col('Compte crédité - Numéro'), $col('Compte crédité - Intitulé'));
-
- $cat = $col('Rubrique');
- $moyen = strtoupper(substr($col('Moyen de paiement'), 0, 2));
-
- if (!$moyen || !array_key_exists($moyen, $liste_moyens))
- {
- $moyen = false;
- $cat = false;
- }
-
- if ($cat && !array_key_exists($cat, $liste_cats))
- {
- if ($col('Nature') == 'Recette')
- {
- $type = $cats::RECETTES;
- $compte = $credit;
- }
- elseif ($col('Nature') == 'Dépense')
- {
- $type = $cats::DEPENSES;
- $compte = $debit;
- }
- else
- {
- $type = $cats::AUTRES;
- $cat = false;
- }
-
- if ($type != $cats::AUTRES)
- {
- $liste_cats[$cat] = $cats->add([
- 'intitule' => $cat,
- 'type' => $type,
- 'compte' => $compte
- ]);
- }
- }
-
- $data = [
- 'libelle' => $col('Libellé'),
- 'montant' => $col('Montant'),
- 'date' => $date,
- 'compte_credit' => $credit,
- 'compte_debit' => $debit,
- 'numero_piece' => $col('Numéro de pièce'),
- 'remarques' => $col('Remarques'),
- ];
-
- if ($cat)
- {
- $data['moyen_paiement'] = $moyen;
- $data['numero_cheque'] = $col('Numéro de chèque');
- $data['id_categorie'] = $liste_cats[$cat];
- }
-
- $journal->add($data);
- }
-
- $db->exec('END;');
-
- fclose($fp);
- return true;
- }
-}
-
-?>
DELETED src/include/class.compta_journal.php
Index: src/include/class.compta_journal.php
==================================================================
--- src/include/class.compta_journal.php
+++ src/include/class.compta_journal.php
@@ -1,372 +0,0 @@
-querySingle('SELECT id FROM compta_exercices WHERE cloture = 0 LIMIT 1;');
-
- if (!$id)
- {
- throw new UserException('Aucun exercice en cours.');
- }
-
- return $id;
- }
-
- public function checkExercice()
- {
- return $this->_getCurrentExercice();
- }
-
- protected function _checkOpenExercice($id)
- {
- if (is_null($id))
- return true;
-
- $db = DB::getInstance();
- $id = $db->simpleQuerySingle('SELECT id FROM compta_exercices
- WHERE cloture = 0 AND id = ? LIMIT 1;', false, (int)$id);
-
- if ($id)
- return true;
-
- return false;
- }
-
- public function getSolde($id_compte, $inclure_sous_comptes = false)
- {
- $db = DB::getInstance();
- $exercice = $this->_getCurrentExercice();
- $compte = $inclure_sous_comptes
- ? 'LIKE \'' . $db->escapeString(trim($id_compte)) . '%\''
- : '= \'' . $db->escapeString(trim($id_compte)) . '\'';
-
- $debit = 'COALESCE((SELECT SUM(montant) FROM compta_journal WHERE compte_debit '.$compte.' AND id_exercice = '.(int)$exercice.'), 0)';
- $credit = 'COALESCE((SELECT SUM(montant) FROM compta_journal WHERE compte_credit '.$compte.' AND id_exercice = '.(int)$exercice.'), 0)';
-
- // L'actif augmente au débit, le passif au crédit
- $position = $db->simpleQuerySingle('SELECT position FROM compta_comptes WHERE id = ?;', false, $id_compte);
-
- if (($position & Compta_Comptes::ACTIF) || ($position & Compta_Comptes::CHARGE))
- {
- $query = $debit . ' - ' . $credit;
- }
- else
- {
- $query = $credit . ' - ' . $debit;
- }
-
- return $db->querySingle('SELECT ' . $query . ';');
- }
-
- public function getJournalCompte($compte, $inclure_sous_comptes = false)
- {
- $db = DB::getInstance();
-
- $position = $db->simpleQuerySingle('SELECT position FROM compta_comptes WHERE id = ?;', false, $compte);
-
- $exercice = $this->_getCurrentExercice();
- $compte = $inclure_sous_comptes
- ? 'LIKE \'' . $db->escapeString(trim($compte)) . '%\''
- : '= \'' . $db->escapeString(trim($compte)) . '\'';
-
- // L'actif et les charges augmentent au débit, le passif et les produits au crédit
- if (($position & Compta_Comptes::ACTIF) || ($position & Compta_Comptes::CHARGE))
- {
- $d = '';
- $c = '-';
- }
- else
- {
- $d = '-';
- $c = '';
- }
-
- $query = 'SELECT *, strftime(\'%s\', date) AS date,
- (CASE WHEN compte_debit '.$compte.' THEN '.$d.'montant ELSE '.$c.'montant END) AS solde
- FROM compta_journal WHERE (compte_debit '.$compte.' OR compte_credit '.$compte.')
- AND id_exercice = '.(int)$exercice.'
- ORDER BY date ASC;';
-
- $result = $db->simpleStatementFetch($query);
- $solde = 0.0;
-
- foreach ($result as &$row)
- {
- $solde += $row['solde'];
- $row['solde'] = $solde;
- }
-
- return $result;
- }
-
- public function add($data)
- {
- $this->_checkFields($data);
-
- $db = DB::getInstance();
-
- $data['id_exercice'] = $this->_getCurrentExercice();
-
- $db->simpleInsert('compta_journal', $data);
- $id = $db->lastInsertRowId();
-
- return $id;
- }
-
- public function edit($id, $data)
- {
- $db = DB::getInstance();
-
- // Vérification que l'on peut éditer cette opération
- if (!$this->_checkOpenExercice($db->simpleQuerySingle('SELECT id_exercice FROM compta_journal WHERE id = ?;', false, $id)))
- {
- throw new UserException('Cette opération fait partie d\'un exercice qui a été clôturé.');
- }
-
- $this->_checkFields($data);
-
- $db->simpleUpdate('compta_journal', $data,
- 'id = \''.trim($id).'\'');
-
- return true;
- }
-
- public function delete($id)
- {
- $db = DB::getInstance();
-
- // Vérification que l'on peut éditer cette opération
- if (!$this->_checkOpenExercice($db->simpleQuerySingle('SELECT id_exercice FROM compta_journal WHERE id = ?;', false, $id)))
- {
- throw new UserException('Cette opération fait partie d\'un exercice qui a été clôturé.');
- }
-
- $db->simpleExec('DELETE FROM membres_operations WHERE id_operation = ?;', (int)$id);
- $db->simpleExec('DELETE FROM compta_journal WHERE id = ?;', (int)$id);
-
- return true;
- }
-
- public function get($id)
- {
- $db = DB::getInstance();
- return $db->simpleQuerySingle('SELECT *, strftime(\'%s\', date) AS date FROM compta_journal WHERE id = ?;', true, $id);
- }
-
- public function countForMember($id)
- {
- $db = DB::getInstance();
- return $db->simpleQuerySingle('SELECT COUNT(*)
- FROM compta_journal WHERE id_auteur = ?;', false, (int)$id);
- }
-
- public function listForMember($id, $exercice)
- {
- $db = DB::getInstance();
- return $db->simpleStatementFetch('SELECT * FROM compta_journal
- WHERE id_auteur = ? AND id_exercice = ?;', \SQLITE3_ASSOC, (int)$id, (int)$exercice);
- }
-
- protected function _checkFields(&$data)
- {
- $db = DB::getInstance();
-
- if (empty($data['libelle']) || !trim($data['libelle']))
- {
- throw new UserException('Le libellé ne peut rester vide.');
- }
-
- $data['libelle'] = trim($data['libelle']);
-
- if (!empty($data['moyen_paiement'])
- && !$db->simpleQuerySingle('SELECT 1 FROM compta_moyens_paiement WHERE code = ?;', false, $data['moyen_paiement']))
- {
- throw new UserException('Moyen de paiement invalide.');
- }
-
- if (empty($data['date']) || !utils::checkDate($data['date']))
- {
- throw new UserException('Date vide ou invalide.');
- }
-
- if (!$db->simpleQuerySingle('SELECT 1 FROM compta_exercices WHERE cloture = 0
- AND debut <= :date AND fin >= :date;', false, ['date' => $data['date']]))
- {
- throw new UserException('La date ne correspond pas à l\'exercice en cours.');
- }
-
- if (empty($data['moyen_paiement']))
- {
- $data['moyen_paiement'] = null;
- $data['numero_cheque'] = null;
- }
- else
- {
- $data['moyen_paiement'] = strtoupper($data['moyen_paiement']);
-
- if ($data['moyen_paiement'] != 'CH')
- {
- $data['numero_cheque'] = null;
- }
-
- if (!$db->simpleQuerySingle('SELECT 1 FROM compta_moyens_paiement WHERE code = ? LIMIT 1;',
- false, $data['moyen_paiement']))
- {
- throw new UserException('Moyen de paiement invalide.');
- }
- }
-
- $data['montant'] = str_replace(',', '.', $data['montant']);
- $data['montant'] = (float)$data['montant'];
-
- if ($data['montant'] <= 0)
- {
- throw new UserException('Le montant ne peut être égal ou inférieur à zéro.');
- }
-
- foreach (['remarques', 'numero_piece', 'numero_cheque'] as $champ)
- {
- if (empty($data[$champ]) || !trim($data[$champ]))
- {
- $data[$champ] = '';
- }
- else
- {
- $data[$champ] = trim($data[$champ]);
- }
- }
-
- if (!array_key_exists('compte_debit', $data) ||
- (!is_null($data['compte_debit']) &&
- !$db->simpleQuerySingle('SELECT 1 FROM compta_comptes WHERE id = ?;', false, $data['compte_debit'])))
- {
- throw new UserException('Compte débité inconnu.');
- }
-
- if (!array_key_exists('compte_credit', $data) ||
- (!is_null($data['compte_credit']) &&
- !$db->simpleQuerySingle('SELECT 1 FROM compta_comptes WHERE id = ?;', false, $data['compte_credit'])))
- {
- throw new UserException('Compte crédité inconnu.');
- }
-
- $data['compte_credit'] = is_null($data['compte_credit']) ? null : strtoupper(trim($data['compte_credit']));
- $data['compte_debit'] = is_null($data['compte_debit']) ? null : strtoupper(trim($data['compte_debit']));
-
- if ($data['compte_credit'] == $data['compte_debit'])
- {
- throw new UserException('Compte crédité identique au compte débité.');
- }
-
- if (isset($data['id_categorie']))
- {
- if (!$db->simpleQuerySingle('SELECT 1 FROM compta_categories WHERE id = ?;', false, (int)$data['id_categorie']))
- {
- throw new UserException('Catégorie inconnue.');
- }
-
- $data['id_categorie'] = (int)$data['id_categorie'];
- }
- else
- {
- $data['id_categorie'] = NULL;
- }
-
- if (isset($data['id_auteur']))
- {
- $data['id_auteur'] = (int)$data['id_auteur'];
- }
-
- return true;
- }
-
- public function getListForCategory($type = null, $cat = null)
- {
- $db = DB::getInstance();
- $exercice = $this->_getCurrentExercice();
-
- $query = 'SELECT compta_journal.*, strftime(\'%s\', compta_journal.date) AS date ';
-
- if (is_null($cat) && !is_null($type))
- {
- $query.= ', compta_categories.intitule AS categorie
- FROM compta_journal LEFT JOIN compta_categories
- ON compta_journal.id_categorie = compta_categories.id ';
- }
- else
- {
- $query.= ' FROM compta_journal ';
- }
-
- $query .= ' WHERE ';
-
- if (!is_null($cat))
- {
- $query .= 'id_categorie = ' . (int)$cat;
- }
- elseif (is_null($type) && is_null($cat))
- {
- $query .= 'id_categorie IS NULL';
- }
- else
- {
- $query.= 'id_categorie IN (SELECT id FROM compta_categories WHERE type = '.(int)$type.')';
- }
-
- $query .= ' AND id_exercice = ' . (int)$exercice;
- $query .= ' ORDER BY date;';
-
- return $db->simpleStatementFetch($query);
- }
-
- public function searchSQL($query)
- {
- $db = DB::getInstance();
-
- if (!preg_match('/LIMIT\s+/i', $query))
- {
- $query = preg_replace('/;?\s*$/', '', $query);
- $query .= ' LIMIT 100';
- }
-
- if (preg_match('/;\s*(.+?)$/', $query))
- {
- throw new UserException('Une seule requête peut être envoyée en même temps.');
- }
-
- $st = $db->prepare($query);
-
- if (!$st->readOnly())
- {
- throw new UserException('Seules les requêtes en lecture sont autorisées.');
- }
-
- $res = $st->execute();
- $out = [];
-
- while ($row = $res->fetchArray(SQLITE3_ASSOC))
- {
- $out[] = $row;
- }
-
- return $out;
- }
-
- public function schemaSQL()
- {
- $db = DB::getInstance();
-
- $tables = [
- 'journal' => $db->querySingle('SELECT sql FROM sqlite_master WHERE type = \'table\' AND name = \'compta_journal\';'),
- ];
-
- return $tables;
- }
-}
-
-?>
DELETED src/include/class.compta_stats.php
Index: src/include/class.compta_stats.php
==================================================================
--- src/include/class.compta_stats.php
+++ src/include/class.compta_stats.php
@@ -1,122 +0,0 @@
-simpleStatementFetch('SELECT COUNT(*) AS nb, id_categorie
- FROM compta_journal
- WHERE id_categorie IN (SELECT id FROM compta_categories WHERE type = ?)
- AND id_exercice = (SELECT id FROM compta_exercices WHERE cloture = 0)
- GROUP BY id_categorie ORDER BY nb DESC;', SQLITE3_ASSOC, $type);
- }
-
- public function repartitionRecettes()
- {
- return $this->_parRepartitionCategorie(Compta_Categories::RECETTES);
- }
-
- public function repartitionDepenses()
- {
- return $this->_parRepartitionCategorie(Compta_Categories::DEPENSES);
- }
-
- protected function _parType($type)
- {
- return $this->getStats('SELECT strftime(\'%Y%m\', date) AS date,
- SUM(montant) FROM compta_journal
- WHERE id_categorie IN (SELECT id FROM compta_categories WHERE type = '.$type.')
- AND id_exercice = (SELECT id FROM compta_exercices WHERE cloture = 0)
- GROUP BY strftime(\'%Y-%m\', date) ORDER BY date;');
- }
-
- public function recettes()
- {
- return $this->_parType(Compta_Categories::RECETTES);
- }
-
- public function depenses()
- {
- return $this->_parType(Compta_Categories::DEPENSES);
- }
-
- public function soldeCompte($compte, $augmente = 'debit', $diminue = 'credit')
- {
- $db = DB::getInstance();
-
- if (strpos($compte, '%') !== false)
- {
- $compte = 'LIKE \''. $db->escapeString($compte) . '\'';
- }
- else
- {
- $compte = '= \''. $db->escapeString($compte) . '\'';
- }
-
- $stats = $this->getStats('SELECT strftime(\'%Y%m\', date) AS date,
- (COALESCE((SELECT SUM(montant) FROM compta_journal
- WHERE compte_'.$augmente.' '.$compte.' AND id_exercice = cj.id_exercice
- AND date >= strftime(\'%Y-%m-01\', cj.date)
- AND date <= strftime(\'%Y-%m-31\', cj.date)), 0)
- - COALESCE((SELECT SUM(montant) FROM compta_journal
- WHERE compte_'.$diminue.' '.$compte.' AND id_exercice = cj.id_exercice
- AND date >= strftime(\'%Y-%m-01\', cj.date)
- AND date <= strftime(\'%Y-%m-31\', cj.date)), 0)
- ) AS solde
- FROM compta_journal AS cj
- WHERE (compte_debit '.$compte.' OR compte_credit '.$compte.')
- AND id_exercice = (SELECT id FROM compta_exercices WHERE cloture = 0)
- GROUP BY strftime(\'%Y-%m\', date) ORDER BY date;');
-
- $c = 0;
- foreach ($stats as $k=>$v)
- {
- $c += $v;
- $stats[$k] = $c;
- }
-
- return $stats;
- }
-
- public function getStats($query)
- {
- $db = DB::getInstance();
-
- $data = $db->simpleStatementFetchAssoc($query);
-
- $e = $db->querySingle('SELECT *, strftime(\'%s\', debut) AS debut,
- strftime(\'%s\', fin) AS fin FROM compta_exercices WHERE cloture = 0;', true);
-
- $y = date('Y', $e['debut']);
- $m = date('m', $e['debut']);
- $max = date('Ym', $e['fin']);
-
- while ($y . $m <= $max)
- {
- if (!isset($data[$y . $m]))
- {
- $data[$y . $m] = 0;
- }
-
- if ($m == 12)
- {
- $m = '01';
- $y++;
- }
- else
- {
- $m++;
- $m = str_pad((int)$m, 2, '0', STR_PAD_LEFT);
- }
- }
-
- ksort($data);
-
- return $data;
- }
-}
-
-?>
DELETED src/include/class.config.php
Index: src/include/class.config.php
==================================================================
--- src/include/class.config.php
+++ src/include/class.config.php
@@ -1,326 +0,0 @@
-fields_types = [
- 'nom_asso' => $string,
- 'adresse_asso' => $string,
- 'email_asso' => $string,
- 'site_asso' => $string,
-
- 'monnaie' => $string,
- 'pays' => $string,
-
- 'champs_membres' => $object,
-
- 'email_envoi_automatique'=> $string,
-
- 'categorie_membres' => $int,
-
- 'categorie_dons' => $int,
- 'categorie_cotisations' => $int,
-
- 'accueil_wiki' => $string,
- 'accueil_connexion' => $string,
-
- 'frequence_sauvegardes' => $int,
- 'nombre_sauvegardes' => $int,
-
- 'champ_identifiant' => $string,
- 'champ_identite' => $string,
-
- 'version' => $string,
- ];
-
- $db = DB::getInstance();
-
- $this->config = $db->simpleStatementFetchAssoc('SELECT cle, valeur FROM config ORDER BY cle;');
-
- foreach ($this->config as $key=>&$value)
- {
- if (!array_key_exists($key, $this->fields_types))
- {
- // Ancienne clé de config qui n'est plus utilisée
- continue;
- }
-
- if (is_array($this->fields_types[$key]))
- {
- $value = explode(',', $value);
- }
- elseif ($key == 'champs_membres')
- {
- $value = new Champs_Membres((string)$value);
- }
- else
- {
- settype($value, gettype($this->fields_types[$key]));
- }
- }
- }
-
- public function __destruct()
- {
- if (!empty($this->modified))
- {
- //echo '
Il y a des champs modifiés non sauvés dans '.__CLASS__.' !
';
- }
- }
-
- public function save()
- {
- if (empty($this->modified))
- return true;
-
- $values = [];
-
- $db = DB::getInstance();
- $db->exec('BEGIN;');
-
- foreach ($this->modified as $key=>$modified)
- {
- $value = $this->config[$key];
-
- if (is_array($value))
- {
- $value = implode(',', $value);
- }
- elseif (is_object($value))
- {
- $value = (string) $value;
- }
-
- $db->simpleExec('INSERT OR REPLACE INTO config (cle, valeur) VALUES (?, ?);',
- $key, $value);
- }
-
- if (!empty($this->modified['champ_identifiant']))
- {
- // Mettre les champs identifiant vides à NULL pour pouvoir créer un index unique
- $db->exec('UPDATE membres SET '.$this->get('champ_identifiant').' = NULL
- WHERE '.$this->get('champ_identifiant').' = "";');
-
- // Création de l'index unique
- $db->exec('DROP INDEX IF EXISTS membres_identifiant;');
- $db->exec('CREATE UNIQUE INDEX membres_identifiant ON membres ('.$this->get('champ_identifiant').');');
- }
-
- $db->exec('END;');
-
- $this->modified = [];
-
- return true;
- }
-
- public function get($key)
- {
- if (!array_key_exists($key, $this->fields_types))
- {
- throw new \OutOfBoundsException('Ce champ est inconnu.');
- }
-
- if (!array_key_exists($key, $this->config))
- {
- return null;
- }
-
- return $this->config[$key];
- }
-
- public function getVersion()
- {
- if (!array_key_exists('version', $this->config))
- {
- return '0';
- }
-
- return $this->config['version'];
- }
-
- public function setVersion($version)
- {
- $this->config['version'] = $version;
-
- $db = DB::getInstance();
- $db->simpleExec('INSERT OR REPLACE INTO config (cle, valeur) VALUES (?, ?);',
- 'version', $version);
-
- return true;
- }
-
- public function set($key, $value)
- {
- if (!array_key_exists($key, $this->fields_types))
- {
- throw new \OutOfBoundsException('Ce champ est inconnu.');
- }
-
- if (is_array($this->fields_types[$key]))
- {
- $value = !empty($value) ? (array) $value : [];
- }
- elseif (is_int($this->fields_types[$key]))
- {
- $value = (int) $value;
- }
- elseif (is_float($this->fields_types[$key]))
- {
- $value = (float) $value;
- }
- elseif (is_bool($this->fields_types[$key]))
- {
- $value = (bool) $value;
- }
- elseif (is_string($this->fields_types[$key]))
- {
- $value = (string) $value;
- }
-
- switch ($key)
- {
- case 'nom_asso':
- {
- if (!trim($value))
- {
- throw new UserException('Le nom de l\'association ne peut rester vide.');
- }
- break;
- }
- case 'accueil_wiki':
- case 'accueil_connexion':
- {
- if (!trim($value))
- {
- $key = str_replace('accueil_', '', $key);
- throw new UserException('Le nom de la page d\'accueil ' . $key . ' ne peut rester vide.');
- }
- break;
- }
- case 'email_asso':
- case 'email_envoi_automatique':
- {
- if (!filter_var($value, FILTER_VALIDATE_EMAIL))
- {
- throw new UserException('Adresse e-mail invalide.');
- }
- break;
- }
- case 'champs_membres':
- {
- if (!($value instanceOf Champs_Membres))
- {
- throw new \UnexpectedValueException('$value doit être de type Champs_Membres');
- }
- break;
- }
- case 'champ_identite':
- case 'champ_identifiant':
- {
- $champs = $this->get('champs_membres');
- $db = DB::getInstance();
-
- // Vérification que le champ existe bien
- if (!$champs->get($value))
- {
- throw new UserException('Le champ '.$value.' n\'existe pas pour la configuration de '.$key);
- }
-
- // Vérification que le champ est unique pour l'identifiant
- if ($key == 'champ_identifiant'
- && !$db->simpleQuerySingle('SELECT (COUNT(DISTINCT '.$value.') = COUNT(*))
- FROM membres WHERE '.$value.' IS NOT NULL AND '.$value.' != \'\';'))
- {
- throw new UserException('Le champ '.$value.' comporte des doublons et ne peut donc pas servir comme identifiant pour la connexion.');
- }
- break;
- }
- case 'categorie_cotisations':
- case 'categorie_dons':
- {
- return false;
- $db = DB::getInstance();
- if (!$db->simpleQuerySingle('SELECT 1 FROM compta_categories WHERE id = ?;', false, $value))
- {
- throw new UserException('Champ '.$key.' : La catégorie comptable numéro \''.$value.'\' ne semble pas exister.');
- }
- break;
- }
- case 'categorie_membres':
- {
- $db = DB::getInstance();
- if (!$db->simpleQuerySingle('SELECT 1 FROM membres_categories WHERE id = ?;', false, $value))
- {
- throw new UserException('La catégorie de membres par défaut numéro \''.$value.'\' ne semble pas exister.');
- }
- break;
- }
- case 'monnaie':
- {
- if (!trim($value))
- {
- throw new UserException('La monnaie doit être renseignée.');
- }
-
- break;
- }
- case 'pays':
- {
- if (!trim($value) || !utils::getCountryName($value))
- {
- throw new UserException('Le pays renseigné est invalide.');
- }
-
- break;
- }
- default:
- break;
- }
-
- if (!isset($this->config[$key]) || $value !== $this->config[$key])
- {
- $this->config[$key] = $value;
- $this->modified[$key] = true;
- }
-
- return true;
- }
-
- public function getFieldsTypes()
- {
- return $this->fields_types;
- }
-
- public function getConfig()
- {
- return $this->config;
- }
-}
-
-?>
DELETED src/include/class.cotisations.php
Index: src/include/class.cotisations.php
==================================================================
--- src/include/class.cotisations.php
+++ src/include/class.cotisations.php
@@ -1,170 +0,0 @@
-simpleQuerySingle('SELECT 1 FROM compta_categories WHERE id = ?;', false, (int) $data['id_categorie_compta']))
- {
- throw new UserException('Catégorie comptable inconnue');
- }
-
- $data['id_categorie_compta'] = (int) $data['id_categorie_compta'];
- }
- }
-
- /**
- * Ajouter une cotisation
- * @param array $data Tableau des champs à insérer
- * @return integer ID de la cotisation créée
- */
- public function add($data)
- {
- $db = DB::getInstance();
-
- $this->_checkFields($data);
-
- $db->simpleInsert('cotisations', $data);
- $id = $db->lastInsertRowId();
-
- return $id;
- }
-
- /**
- * Modifier une cotisation
- * @param integer $id ID de la cotisation à modifier
- * @param array $data Tableau des champs à modifier
- * @return bool true si succès
- */
- public function edit($id, $data)
- {
- $db = DB::getInstance();
-
- $this->_checkFields($data);
-
- return $db->simpleUpdate('cotisations', $data, 'id = \''.(int) $id.'\'');
- }
-
- /**
- * Supprimer une cotisation
- * @param integer $id ID de la cotisation à supprimer
- * @return integer true en cas de succès
- */
- public function delete($id)
- {
- $db = DB::getInstance();
-
- $db->exec('BEGIN;');
- $db->simpleExec('DELETE FROM cotisations_membres WHERE id_cotisation = ?;', (int) $id);
- $db->simpleExec('DELETE FROM cotisations WHERE id = ?;', (int) $id);
- $db->exec('END;');
-
- return true;
- }
-
- /**
- * Renvoie les infos sur une cotisation
- * @param integer $id Numéro de la cotisation
- * @return array Infos de la cotisation
- */
- public function get($id)
- {
- $db = DB::getInstance();
- return $db->simpleQuerySingle('SELECT co.*,
- (SELECT COUNT(DISTINCT id_membre) FROM cotisations_membres WHERE id_cotisation = co.id) AS nb_membres,
- (SELECT COUNT(DISTINCT id_membre) FROM cotisations_membres AS cm WHERE id_cotisation = co.id
- AND ((co.duree IS NOT NULL AND date(cm.date, \'+\'||co.duree||\' days\') >= date())
- OR (co.fin IS NOT NULL AND co.debut <= cm.date AND co.fin >= cm.date))) AS nb_a_jour
- FROM cotisations AS co WHERE id = :id;', true, ['id' => (int) $id]);
- }
-
- public function listByName()
- {
- $db = DB::getInstance();
- return $db->simpleStatementFetch('SELECT * FROM cotisations ORDER BY intitule;');
- }
-
- public function listCurrent()
- {
- $db = DB::getInstance();
- return $db->simpleStatementFetch('SELECT * FROM cotisations WHERE fin >= date(\'now\') OR fin IS NULL
- ORDER BY transliterate_to_ascii(intitule) COLLATE NOCASE;');
- }
-
- public function listCurrentWithStats()
- {
- $db = DB::getInstance();
- return $db->simpleStatementFetch('SELECT co.*,
- (SELECT COUNT(DISTINCT id_membre) FROM cotisations_membres WHERE id_cotisation = co.id) AS nb_membres,
- (SELECT COUNT(DISTINCT id_membre) FROM cotisations_membres AS cm WHERE id_cotisation = co.id
- AND ((co.duree IS NOT NULL AND date(cm.date, \'+\'||co.duree||\' days\') >= date())
- OR (co.fin IS NOT NULL AND co.debut <= cm.date AND co.fin >= cm.date))) AS nb_a_jour
- FROM cotisations AS co WHERE fin >= date(\'now\') OR fin IS NULL
- ORDER BY transliterate_to_ascii(intitule) COLLATE NOCASE;');
- }
-}
-
-?>
DELETED src/include/class.cotisations_membres.php
Index: src/include/class.cotisations_membres.php
==================================================================
--- src/include/class.cotisations_membres.php
+++ src/include/class.cotisations_membres.php
@@ -1,336 +0,0 @@
-simpleQuerySingle('SELECT 1 FROM cotisations WHERE id = ?;', false, (int) $data['id_cotisation']))
- {
- throw new UserException('Cotisation inconnue.');
- }
-
- $data['id_cotisation'] = (int) $data['id_cotisation'];
-
- if (empty($data['id_membre'])
- || !$db->simpleQuerySingle('SELECT 1 FROM membres WHERE id = ?;', false, (int) $data['id_membre']))
- {
- throw new UserException('Membre inconnu ou invalide.');
- }
-
- $data['id_membre'] = (int) $data['id_membre'];
-
- if ($compta)
- {
- if (!isset($data['moyen_paiement']) || trim($data['moyen_paiement']) === '')
- {
- throw new UserException('Moyen de paiement inconnu ou invalide.');
- }
-
- if ($data['moyen_paiement'] != 'ES')
- {
- if (trim($data['banque']) == '')
- {
- throw new UserException('Le compte bancaire choisi est invalide.');
- }
-
- if (!$db->simpleQuerySingle('SELECT 1 FROM compta_comptes_bancaires WHERE id = ?;',
- false, $data['banque']))
- {
- throw new UserException('Le compte bancaire choisi n\'existe pas.');
- }
- }
-
- if (empty($data['montant']) || !is_numeric($data['montant']))
- {
- throw new UserException('Le montant indiqué n\'est pas un nombre valide.');
- }
- }
- }
-
- /**
- * Enregistrer un événement de cotisation
- * @param array $data Tableau des champs à insérer
- * @return integer ID de l'événement créé
- */
- public function add($data)
- {
- $db = DB::getInstance();
-
- $co = $db->simpleQuerySingle('SELECT * FROM cotisations WHERE id = ?;',
- true, (int)$data['id_cotisation']);
-
- $this->_checkFields($data, !empty($co['id_categorie_compta']));
-
- $check = $db->simpleQuerySingle('SELECT 1 FROM cotisations_membres
- WHERE id_cotisation = ? AND id_membre = ? AND date = ?;',
- false, (int)$data['id_cotisation'], (int)$data['id_membre'], $data['date']);
-
- if ($check)
- {
- throw new UserException('Cette cotisation a déjà été enregistrée pour ce jour-ci et ce membre-ci.');
- }
-
- $db->begin();
-
- $db->simpleInsert('cotisations_membres', [
- 'date' => $data['date'],
- 'id_cotisation' => $data['id_cotisation'],
- 'id_membre' => $data['id_membre'],
- ]);
-
- $id = $db->lastInsertRowId();
-
- if ($co['id_categorie_compta'] && $co['montant'] > 0)
- {
- try {
- $id_operation = $this->addOperationCompta($id, [
- 'id_categorie' => $co['id_categorie_compta'],
- 'libelle' => 'Cotisation (automatique)',
- 'montant' => $data['montant'],
- 'date' => $data['date'],
- 'moyen_paiement'=> $data['moyen_paiement'],
- 'numero_cheque' => isset($data['numero_cheque']) ? $data['numero_cheque'] : null,
- 'id_auteur' => $data['id_auteur'],
- 'banque' => isset($data['banque']) ? $data['banque'] : null,
- 'id_membre' => $data['id_membre'],
- ]);
- }
- catch (\Exception $e)
- {
- $db->rollback();
- throw $e;
- }
- }
-
- $db->commit();
-
- return $id;
- }
-
- /**
- * Supprimer un événement de cotisation
- * @param integer $id ID de l'événement à supprimer
- * @return integer true en cas de succès
- */
- public function delete($id)
- {
- $db = DB::getInstance();
- $db->simpleExec('DELETE FROM membres_operations WHERE id_cotisation = ?;', (int)$id);
- return $db->simpleExec('DELETE FROM cotisations_membres WHERE id = ?;', (int) $id);
- }
-
- public function get($id)
- {
- $db = DB::getInstance();
- return $db->simpleQuerySingle('SELECT * FROM cotisations_membres WHERE id = ?;', true, (int)$id);
- }
-
- /**
- * Renvoie une liste des écritures comptables liées à une cotisation
- * @param int $id Numéro de la cotisation membre
- * @return array Liste des écritures
- */
- public function listOperationsCompta($id)
- {
- $db = DB::getInstance();
- return $db->simpleStatementFetch('SELECT * FROM compta_journal
- WHERE id IN (SELECT id_operation FROM membres_operations
- WHERE id_cotisation = ?);', \SQLITE3_ASSOC, (int)$id);
- }
-
- /**
- * Ajouter une écriture comptable pour un paiemement membre
- * @param int $id Numéro de la cotisation membre
- * @param array $data Données
- */
- public function addOperationCompta($id, $data)
- {
- $journal = new Compta_Journal;
- $db = DB::getInstance();
-
- if (!isset($data['libelle']) || trim($data['libelle']) == '')
- {
- throw new UserException('Le libellé ne peut rester vide.');
- }
-
- $data['libelle'] = trim($data['libelle']);
-
- if (!isset($data['montant']) || !is_numeric($data['montant']) || (float)$data['montant'] < 0)
- {
- throw new UserException('Le montant doit être un nombre positif et valide.');
- }
-
- $data['montant'] = (float) $data['montant'];
-
- if ($data['moyen_paiement'] != 'ES')
- {
- $debit = $data['banque'];
- }
- else
- {
- $debit = Compta_Comptes::CAISSE;
- }
-
- $credit = $db->simpleQuerySingle('SELECT compte FROM compta_categories WHERE id = ?;',
- false, $data['id_categorie']);
-
- $id_operation = $journal->add([
- 'libelle' => $data['libelle'],
- 'montant' => $data['montant'],
- 'date' => $data['date'],
- 'moyen_paiement'=> $data['moyen_paiement'],
- 'numero_cheque' => isset($data['numero_cheque']) ? $data['numero_cheque'] : null,
- 'compte_debit' => $debit,
- 'compte_credit' => $credit,
- 'id_categorie' => (int)$data['id_categorie'],
- 'id_auteur' => (int)$data['id_auteur'],
- ]);
-
- $db->simpleInsert('membres_operations', [
- 'id_operation' => $id_operation,
- 'id_membre' => $data['id_membre'],
- 'id_cotisation' => (int)$id,
- ]);
-
- return $id_operation;
- }
-
- /**
- * Nombre de membres pour une cotisation
- * @param integer $id Numéro de la cotisation
- * @return integer Nombre d'événements pour cette cotisation
- */
- public function countMembersForCotisation($id)
- {
- $db = DB::getInstance();
- return $db->simpleQuerySingle('SELECT COUNT(DISTINCT id_membre) FROM cotisations_membres
- WHERE id_cotisation = ?;',
- false, (int)$id);
- }
-
- /**
- * Liste des membres qui sont inscrits à une cotisation
- * @param integer $id Numéro de la cotisation
- * @return array Liste des membres
- */
- public function listMembersForCotisation($id, $page = 1, $order = null, $desc = true)
- {
- $begin = ($page - 1) * self::ITEMS_PER_PAGE;
-
- $db = DB::getInstance();
- $champ_id = Config::getInstance()->get('champ_identite');
-
- if (empty($order))
- $order = 'date';
-
- switch ($order)
- {
- case 'date':
- case 'a_jour':
- break;
- case 'identite':
- $order = 'transliterate_to_ascii('.$champ_id.') COLLATE NOCASE';
- break;
- default:
- $order = 'cm.id_membre';
- break;
- }
-
- $desc = $desc ? 'DESC' : 'ASC';
-
- return $db->simpleStatementFetch('SELECT cm.id_membre, cm.date, cm.id,
- (SELECT '.$champ_id.' FROM membres WHERE id = cm.id_membre) AS nom, c.montant,
- CASE WHEN c.duree IS NOT NULL THEN date(cm.date, \'+\'||c.duree||\' days\') >= date()
- WHEN c.fin IS NOT NULL THEN c.fin >= date() ELSE 1 END AS a_jour
- FROM cotisations_membres AS cm
- INNER JOIN cotisations AS c ON c.id = cm.id_cotisation
- WHERE
- cm.id_cotisation = ?
- GROUP BY cm.id_membre ORDER BY '.$order.' '.$desc.' LIMIT ?,?;',
- \SQLITE3_ASSOC, (int)$id, $begin, self::ITEMS_PER_PAGE);
- }
-
- /**
- * Liste des événements d'un membre
- * @param integer $id Numéro de membre
- * @return array Liste des événements de cotisation fait par ce membre
- */
- public function listForMember($id)
- {
- $db = DB::getInstance();
- return $db->simpleStatementFetch('SELECT cm.*, c.intitule, c.duree, c.debut, c.fin, c.montant,
- (SELECT COUNT(*) FROM membres_operations WHERE id_cotisation = cm.id) AS nb_operations
- FROM cotisations_membres AS cm
- LEFT JOIN cotisations AS c ON c.id = cm.id_cotisation
- WHERE cm.id_membre = ? ORDER BY cm.date DESC;', \SQLITE3_ASSOC, (int)$id);
- }
-
- /**
- * Liste des cotisations / activités en cours pour ce membre
- * @param integer $id Numéro de membre
- * @return array Liste des cotisations en cours de validité
- */
- public function listSubscriptionsForMember($id)
- {
- $db = DB::getInstance();
- return $db->simpleStatementFetch('SELECT c.*,
- CASE WHEN c.duree IS NOT NULL THEN date(cm.date, \'+\'||c.duree||\' days\') >= date()
- WHEN c.fin IS NOT NULL THEN c.fin >= date()
- WHEN cm.id IS NOT NULL THEN 1 ELSE 0 END AS a_jour,
- CASE WHEN c.duree IS NOT NULL THEN date(cm.date, \'+\'||c.duree||\' days\')
- WHEN c.fin IS NOT NULL THEN c.fin ELSE 1 END AS expiration,
- (julianday(date()) - julianday(CASE WHEN c.duree IS NOT NULL THEN date(cm.date, \'+\'||c.duree||\' days\')
- WHEN c.fin IS NOT NULL THEN c.fin END)) AS nb_jours
- FROM cotisations_membres AS cm
- INNER JOIN cotisations AS c ON c.id = cm.id_cotisation
- WHERE cm.id_membre = ?
- GROUP BY cm.id_cotisation
- ORDER BY cm.date DESC;', \SQLITE3_ASSOC, (int)$id);
- }
-
- /**
- * Ce membre est-il à jour sur cette cotisation ?
- * @param integer $id Numéro de membre
- * @param integer $id_cotisation Numéro de cotisation
- * @return array Infos sur la cotisation, et champ expiration
- * (si NULL = cotisation jamais enregistrée, si 1 = cotisation ponctuelle enregistrée, sinon date d'expiration)
- */
- public function isMemberUpToDate($id, $id_cotisation)
- {
- $db = DB::getInstance();
- return $db->simpleQuerySingle('SELECT c.*,
- CASE WHEN c.duree IS NOT NULL THEN date(cm.date, \'+\'||c.duree||\' days\') >= date()
- WHEN c.fin IS NOT NULL THEN c.fin >= date()
- WHEN cm.id IS NOT NULL THEN 1 ELSE 0 END AS a_jour,
- CASE WHEN c.duree IS NOT NULL THEN date(cm.date, \'+\'||c.duree||\' days\')
- WHEN c.fin IS NOT NULL THEN c.fin ELSE 1 END AS expiration
- FROM cotisations AS c
- LEFT JOIN cotisations_membres AS cm ON cm.id_cotisation = c.id AND cm.id_membre = ?
- WHERE c.id = ? ORDER BY cm.date DESC;',
- true, (int)$id, (int)$id_cotisation);
- }
-
- public function countForMember($id)
- {
- $db = DB::getInstance();
- return $db->simpleQuerySingle('SELECT COUNT(DISTINCT id_cotisation) FROM cotisations_membres
- WHERE id_membre = ?;', false, (int)$id);
- }
-}
DELETED src/include/class.db.php
Index: src/include/class.db.php
==================================================================
--- src/include/class.db.php
+++ src/include/class.db.php
@@ -1,389 +0,0 @@
-enableExceptions(true);
-
- // Activer les contraintes des foreign keys
- $this->exec('PRAGMA foreign_keys = ON;');
-
- $this->createFunction('transliterate_to_ascii', ['Garradin\utils', 'transliterateToAscii']);
- $this->createFunction('base64', 'base64_encode');
- $this->createFunction('rank', [$this, 'sql_rank']);
- }
-
- public function sql_rank($aMatchInfo)
- {
- $iSize = 4; // byte size
- $iPhrase = (int) 0; // Current phrase //
- $score = (double)0.0; // Value to return //
-
- /* Check that the number of arguments passed to this function is correct.
- ** If not, jump to wrong_number_args. Set aMatchinfo to point to the array
- ** of unsigned integer values returned by FTS function matchinfo. Set
- ** nPhrase to contain the number of reportable phrases in the users full-text
- ** query, and nCol to the number of columns in the table.
- */
- $aMatchInfo = (string) func_get_arg(0);
- $nPhrase = ord(substr($aMatchInfo, 0, $iSize));
- $nCol = ord(substr($aMatchInfo, $iSize, $iSize));
-
- if (func_num_args() > (1 + $nCol))
- {
- throw new \Exception("Invalid number of arguments : ".$nCol);
- }
-
- // Iterate through each phrase in the users query. //
- for ($iPhrase = 0; $iPhrase < $nPhrase; $iPhrase++)
- {
- $iCol = (int) 0; // Current column //
-
- /* Now iterate through each column in the users query. For each column,
- ** increment the relevancy score by:
- **
- ** ( / ) *
- **
- ** aPhraseinfo[] points to the start of the data for phrase iPhrase. So
- ** the hit count and global hit counts for each column are found in
- ** aPhraseinfo[iCol*3] and aPhraseinfo[iCol*3+1], respectively.
- */
- $aPhraseinfo = substr($aMatchInfo, (2 + $iPhrase * $nCol * 3) * $iSize);
-
- for ($iCol = 0; $iCol < $nCol; $iCol++)
- {
- $nHitCount = ord(substr($aPhraseinfo, 3 * $iCol * $iSize, $iSize));
- $nGlobalHitCount = ord(substr($aPhraseinfo, (3 * $iCol + 1) * $iSize, $iSize));
- $weight = ($iCol < func_num_args() - 1) ? (double) func_get_arg($iCol + 1) : 0;
-
- if ($nHitCount > 0)
- {
- $score += ((double)$nHitCount / (double)$nGlobalHitCount) * $weight;
- }
- }
- }
-
- return $score;
- }
-
- public function escape($str)
- {
- return $this->escapeString($str);
- }
-
- public function e($str)
- {
- return $this->escapeString($str);
- }
-
- public function begin()
- {
- if (!$this->_transaction)
- {
- $this->exec('BEGIN;');
- }
-
- $this->_transaction++;
-
- return $this->_transaction == 1 ? true : false;
- }
-
- public function commit()
- {
- if ($this->_transaction == 1)
- {
- $this->exec('END;');
- }
-
- if ($this->_transaction > 0)
- {
- $this->_transaction--;
- }
-
- return $this->_transaction ? false : true;
- }
-
- public function rollback()
- {
- $this->exec('ROLLBACK;');
- $this->_transaction = 0;
- return true;
- }
-
- protected function _getArgType($arg, $name = '')
- {
- if (is_float($arg))
- return SQLITE3_FLOAT;
- elseif (is_int($arg))
- return SQLITE3_INTEGER;
- elseif (is_bool($arg))
- return SQLITE3_INTEGER;
- elseif (is_null($arg))
- return SQLITE3_NULL;
- elseif (is_string($arg))
- return SQLITE3_TEXT;
- else
- throw new \InvalidArgumentException('Argument '.$name.' is of invalid type '.gettype($arg));
- }
-
- public function simpleStatement($query, $args = [])
- {
- $statement = $this->prepare($query);
- $nb = $statement->paramCount();
-
- if (!empty($args))
- {
- if (is_array($args) && count($args) == 1 && is_array(current($args)))
- {
- $args = current($args);
- }
-
- if (count($args) != $nb)
- {
- throw new \LengthException('Arguments error: '.count($args).' supplied, but '.$nb.' are required by query.');
- }
-
- reset($args);
-
- if (is_int(key($args)))
- {
- foreach ($args as $i=>$arg)
- {
- $statement->bindValue((int)$i+1, $arg, $this->_getArgType($arg, $i+1));
- }
- }
- else
- {
- foreach ($args as $key=>$value)
- {
- if (is_int($key))
- {
- throw new \InvalidArgumentException(__FUNCTION__ . ' requires argument to be a named-associative array, but key '.$key.' is an integer.');
- }
-
- $statement->bindValue(':'.$key, $value, $this->_getArgType($value, $key));
- }
- }
- }
-
- try {
- return $statement->execute();
- }
- catch (\Exception $e)
- {
- throw new \Exception($e->getMessage() . "\n" . $query . "\n" . json_encode($args, true));
- }
- }
-
- public function simpleStatementFetch($query, $mode = SQLITE3_BOTH)
- {
- if ($mode != SQLITE3_BOTH && $mode != SQLITE3_ASSOC && $mode != SQLITE3_NUM)
- {
- throw new \InvalidArgumentException('Mode argument should be either SQLITE3_BOTH, SQLITE3_ASSOC or SQLITE3_NUM.');
- }
-
- $args = array_slice(func_get_args(), 2);
- return $this->fetchResult($this->simpleStatement($query, $args), $mode);
- }
-
- public function simpleStatementFetchAssoc($query)
- {
- $args = array_slice(func_get_args(), 1);
- return $this->fetchResultAssoc($this->simpleStatement($query, $args));
- }
-
- public function simpleStatementFetchAssocKey($query, $mode = SQLITE3_BOTH)
- {
- if ($mode != SQLITE3_BOTH && $mode != SQLITE3_ASSOC && $mode != SQLITE3_NUM)
- {
- throw new \InvalidArgumentException('Mode argument should be either SQLITE3_BOTH, SQLITE3_ASSOC or SQLITE3_NUM.');
- }
-
- $args = array_slice(func_get_args(), 2);
- return $this->fetchResultAssocKey($this->simpleStatement($query, $args), $mode);
- }
-
- public function escapeAuto($value, $name = '')
- {
- $type = $this->_getArgType($value, $name);
-
- switch ($type)
- {
- case SQLITE3_FLOAT:
- return floatval($value);
- case SQLITE3_INTEGER:
- return intval($value);
- case SQLITE3_NULL:
- return 'NULL';
- case SQLITE3_TEXT:
- return '\'' . $this->escapeString($value) . '\'';
- }
- }
-
- /**
- * Simple INSERT query
- */
- public function simpleInsert($table, $fields)
- {
- $fields_names = array_keys($fields);
- return $this->simpleStatement('INSERT INTO '.$table.' ('.implode(', ', $fields_names).')
- VALUES (:'.implode(', :', $fields_names).');', $fields);
- }
-
- public function simpleUpdate($table, $fields, $where)
- {
- if (empty($fields))
- return false;
-
- $query = 'UPDATE '.$table.' SET ';
-
- foreach ($fields as $key=>$value)
- {
- $query .= $key . ' = :'.$key.', ';
- }
-
- $query = substr($query, 0, -2);
- $query .= ' WHERE '.$where.';';
- return $this->simpleStatement($query, $fields);
- }
-
- /**
- * Formats and escapes a statement and then returns the result of exec()
- */
- public function simpleExec($query)
- {
- return $this->simpleStatement($query, array_slice(func_get_args(), 1));
- }
-
- public function simpleQuerySingle($query, $all_columns = false)
- {
- $res = $this->simpleStatement($query, array_slice(func_get_args(), 2));
-
- $row = $res->fetchArray($all_columns ? SQLITE3_ASSOC : SQLITE3_NUM);
-
- if (!$all_columns)
- {
- if (isset($row[0]))
- return $row[0];
- return false;
- }
- else
- {
- return $row;
- }
- }
-
- public function queryFetch($query, $mode = SQLITE3_BOTH)
- {
- return $this->fetchResult($this->query($query), $mode);
- }
-
- public function queryFetchAssoc($query)
- {
- return $this->fetchResultAssoc($this->query($query));
- }
-
- public function queryFetchAssocKey($query, $mode = SQLITE3_BOTH)
- {
- return $this->fetchResultAssocKey($this->query($query), $mode);
- }
-
- public function fetchResult($result, $mode = \SQLITE3_BOTH)
- {
- $out = [];
-
- while ($row = $result->fetchArray($mode))
- {
- $out[] = $row;
- }
-
- $result->finalize();
- unset($result, $row);
-
- return $out;
- }
-
- protected function fetchResultAssoc($result)
- {
- $out = [];
-
- while ($row = $result->fetchArray(SQLITE3_NUM))
- {
- $out[$row[0]] = $row[1];
- }
-
- $result->finalize();
- unset($result, $row);
-
- return $out;
- }
-
- protected function fetchResultAssocKey($result, $mode = \SQLITE3_BOTH)
- {
- $out = [];
-
- while ($row = $result->fetchArray($mode))
- {
- $key = current($row);
- $out[$key] = $row;
- }
-
- $result->finalize();
- unset($result, $row);
-
- return $out;
- }
-
- public function countRows($result)
- {
- $i = 0;
-
- while ($result->fetchArray(SQLITE3_NUM))
- $i++;
-
- return $i;
- }
-}
-
-?>
DELETED src/include/class.membres.php
Index: src/include/class.membres.php
==================================================================
--- src/include/class.membres.php
+++ src/include/class.membres.php
@@ -1,785 +0,0 @@
-_getSalt(22);
- return crypt($password, $salt);
- }
-
- protected function _checkPassword($password, $stored_hash)
- {
- return crypt($password, $stored_hash) == $stored_hash;
- }
-
- protected function _sessionStart($force = false)
- {
- if (!isset($_SESSION) && ($force || isset($_COOKIE[session_name()])))
- {
- session_start();
- }
-
- return true;
- }
-
- public function keepSessionAlive()
- {
- $this->_sessionStart(true);
- }
-
- public function login($id, $passe)
- {
- $db = DB::getInstance();
- $champ_id = Config::getInstance()->get('champ_identifiant');
-
- $r = $db->simpleQuerySingle('SELECT id, passe, id_categorie FROM membres WHERE '.$champ_id.' = ? LIMIT 1;', true, trim($id));
-
- if (empty($r))
- return false;
-
- if (!$this->_checkPassword(trim($passe), $r['passe']))
- return false;
-
- $droits = $this->getDroits($r['id_categorie']);
-
- if ($droits['connexion'] == self::DROIT_AUCUN)
- return false;
-
- $this->_sessionStart(true);
- $db->simpleExec('UPDATE membres SET date_connexion = datetime(\'now\') WHERE id = ?;', $r['id']);
-
- return $this->updateSessionData($r['id'], $droits);
- }
-
- public function recoverPasswordCheck($id)
- {
- $db = DB::getInstance();
- $config = Config::getInstance();
-
- $champ_id = $config->get('champ_identifiant');
-
- $membre = $db->simpleQuerySingle('SELECT id, email FROM membres WHERE '.$champ_id.' = ? LIMIT 1;', true, trim($id));
-
- if (!$membre || trim($membre['email']) == '')
- {
- return false;
- }
-
- $this->_sessionStart(true);
- $hash = sha1($membre['email'] . $membre['id'] . 'recover' . ROOT . time());
- $_SESSION['recover_password'] = [
- 'id' => (int) $membre['id'],
- 'email' => $membre['email'],
- 'hash' => $hash
- ];
-
- $message = "Bonjour,\n\nVous avez oublié votre mot de passe ? Pas de panique !\n\n";
- $message.= "Il vous suffit de cliquer sur le lien ci-dessous pour recevoir un nouveau mot de passe.\n\n";
- $message.= WWW_URL . 'admin/password.php?c=' . substr($hash, -10);
- $message.= "\n\nSi vous n'avez pas demandé à recevoir ce message, ignorez-le, votre mot de passe restera inchangé.";
-
- return utils::mail($membre['email'], '['.$config->get('nom_asso').'] Mot de passe perdu ?', $message);
- }
-
- public function recoverPasswordConfirm($hash)
- {
- $this->_sessionStart();
-
- if (empty($_SESSION['recover_password']['hash']))
- return false;
-
- if (substr($_SESSION['recover_password']['hash'], -10) != $hash)
- return false;
-
- $config = Config::getInstance();
- $db = DB::getInstance();
-
- $password = utils::suggestPassword();
-
- $dest = $_SESSION['recover_password']['email'];
- $id = (int)$_SESSION['recover_password']['id'];
-
- $message = "Bonjour,\n\nVous avez demandé un nouveau mot de passe pour votre compte.\n\n";
- $message.= "Votre adresse email : ".$dest."\n";
- $message.= "Votre nouveau mot de passe : ".$password."\n\n";
- $message.= "Si vous n'avez pas demandé à recevoir ce message, merci de nous le signaler.";
-
- $password = $this->_hashPassword($password);
-
- $db->simpleUpdate('membres', ['passe' => $password], 'id = '.(int)$id);
-
- return utils::mail($dest, '['.$config->get('nom_asso').'] Nouveau mot de passe', $message);
- }
-
- public function updateSessionData($membre = null, $droits = null)
- {
- if (is_null($membre))
- {
- $membre = $this->get($_SESSION['logged_user']['id']);
- }
- elseif (is_int($membre))
- {
- $membre = $this->get($membre);
- }
-
- if (is_null($droits))
- {
- $droits = $this->getDroits($membre['id_categorie']);
- }
-
- $membre['droits'] = $droits;
- $_SESSION['logged_user'] = $membre;
- return true;
- }
-
- public function localLogin()
- {
- if (!defined('Garradin\LOCAL_LOGIN'))
- return false;
-
- if (trim(LOCAL_LOGIN) == '')
- return false;
-
- $db = DB::getInstance();
- $config = Config::getInstance();
- $champ_id = $config->get('champ_identifiant');
-
- if (is_int(LOCAL_LOGIN) && $db->simpleQuerySingle('SELECT 1 FROM membres WHERE id = ? LIMIT 1;', true, LOCAL_LOGIN))
- {
- $this->_sessionStart(true);
- return $this->updateSessionData(LOCAL_LOGIN);
- }
- elseif ($id = $db->simpleQuerySingle('SELECT id FROM membres WHERE '.$champ_id.' = ? LIMIT 1;', true, LOCAL_LOGIN))
- {
- $this->_sessionStart(true);
- return $this->updateSessionData($membre);
- }
-
- throw new UserException('Le membre ' . LOCAL_LOGIN . ' n\'existe pas, merci de modifier la directive Garradin\LOCAL_LOGIN.');
- }
-
- public function isLogged()
- {
- $this->_sessionStart();
-
- if (empty($_SESSION['logged_user']))
- {
- if (defined('Garradin\LOCAL_LOGIN'))
- {
- return $this->localLogin();
- }
-
- return false;
- }
-
- return true;
- }
-
- public function getLoggedUser()
- {
- if (!$this->isLogged())
- return false;
-
- return $_SESSION['logged_user'];
- }
-
- public function logout()
- {
- $_SESSION = [];
- setcookie(session_name(), '', 0, '/');
- return true;
- }
-
- public function sessionStore($key, $value)
- {
- if (!isset($_SESSION['storage']))
- {
- $_SESSION['storage'] = [];
- }
-
- if ($value === null)
- {
- unset($_SESSION['storage'][$key]);
- }
- else
- {
- $_SESSION['storage'][$key] = $value;
- }
-
- return true;
- }
-
- public function sessionGet($key)
- {
- if (!isset($_SESSION['storage'][$key]))
- {
- return null;
- }
-
- return $_SESSION['storage'][$key];
- }
-
- public function sendMessage($dest, $sujet, $message, $copie = false)
- {
- if (!$this->isLogged())
- {
- throw new \LogicException('Cette fonction ne peut être appelée que par un utilisateur connecté.');
- }
-
- $from = $this->getLoggedUser();
- $from = $from['email'];
- // Uniquement adresse email pour le moment car faudrait trouver comment
- // indiquer le nom mais qu'il soit correctement échappé FIXME
-
- $config = Config::getInstance();
-
- $message .= "\n\n--\nCe message a été envoyé par un membre de ".$config->get('nom_asso');
- $message .= ", merci de contacter ".$config->get('email_asso')." en cas d'abus.";
-
- if ($copie)
- {
- utils::mail($from, $sujet, $message);
- }
-
- return utils::mail($dest, $sujet, $message, ['From' => $from]);
- }
-
- // Gestion des données ///////////////////////////////////////////////////////
-
- public function _checkFields(&$data, $check_editable = true, $check_password = true)
- {
- $champs = Config::getInstance()->get('champs_membres');
-
- foreach ($champs->getAll() as $key=>$config)
- {
- if (!$check_editable && (!empty($config['private']) || empty($config['editable'])))
- {
- unset($data[$key]);
- continue;
- }
-
- if (!isset($data[$key]) || (!is_array($data[$key]) && trim($data[$key]) === '')
- || (is_array($data[$key]) && empty($data[$key])))
- {
- if (!empty($config['mandatory']) && ($check_password || $key != 'passe'))
- {
- throw new UserException('Le champ "' . $config['title'] . '" doit obligatoirement être renseigné.');
- }
- elseif (!empty($config['mandatory']))
- {
- continue;
- }
- }
-
- if (isset($data[$key]))
- {
- if ($config['type'] == 'email' && trim($data[$key]) !== '' && !filter_var($data[$key], FILTER_VALIDATE_EMAIL))
- {
- throw new UserException('Adresse e-mail invalide dans le champ "' . $config['title'] . '".');
- }
- elseif ($config['type'] == 'url' && trim($data[$key]) !== '' && !filter_var($data[$key], FILTER_VALIDATE_URL))
- {
- throw new UserException('Adresse URL invalide dans le champ "' . $config['title'] . '".');
- }
- elseif ($config['type'] == 'date' && trim($data[$key]) !== '' && !utils::checkDate($data[$key]))
- {
- throw new UserException('Date invalide "' . $config['title'] . '", format attendu : AAAA-MM-JJ.');
- }
- elseif ($config['type'] == 'datetime' && trim($data[$key]) !== '')
- {
- if (!utils::checkDateTime($data[$key]) || !($dt = new DateTime($data[$key])))
- {
- throw new UserException('Date invalide "' . $config['title'] . '", format attendu : AAAA-MM-JJ HH:mm.');
- }
-
- $data[$key] = $dt->format('Y-m-d H:i');
- }
- elseif ($config['type'] == 'tel')
- {
- $data[$key] = utils::normalizePhoneNumber($data[$key]);
- }
- elseif ($config['type'] == 'country')
- {
- $data[$key] = strtoupper(substr($data[$key], 0, 2));
- }
- elseif ($config['type'] == 'checkbox')
- {
- $data[$key] = empty($data[$key]) ? 0 : 1;
- }
- elseif ($config['type'] == 'number' && trim($data[$key]) !== '')
- {
- if (empty($data[$key]))
- {
- $data[$key] = 0;
- }
-
- if (!is_numeric($data[$key]))
- throw new UserException('Le champ "' . $config['title'] . '" doit contenir un chiffre.');
- }
- elseif ($config['type'] == 'select' && !in_array($data[$key], $config['options']))
- {
- throw new UserException('Le champ "' . $config['title'] . '" ne correspond pas à un des choix proposés.');
- }
- elseif ($config['type'] == 'multiple')
- {
- if (empty($data[$key]) || !is_array($data[$key]))
- {
- $data[$key] = 0;
- continue;
- }
-
- $binary = 0;
-
- foreach ($data[$key] as $k => $v)
- {
- if (array_key_exists($k, $config['options']) && !empty($v))
- {
- $binary |= 0x01 << $k;
- }
- }
-
- $data[$key] = $binary;
- }
-
- // Un champ texte vide c'est un champ NULL
- if (is_string($data[$key]) && trim($data[$key]) === '')
- {
- $data[$key] = null;
- }
- }
- }
-
- if (isset($data['code_postal']) && trim($data['code_postal']) != '')
- {
- if (!empty($data['pays']) && $data['pays'] == 'FR' && !preg_match('!^\d{5}$!', $data['code_postal']))
- {
- throw new UserException('Code postal invalide.');
- }
- }
-
- if (!empty($data['passe']) && strlen($data['passe']) < 5)
- {
- throw new UserException('Le mot de passe doit faire au moins 5 caractères.');
- }
-
- return true;
- }
-
- public function add($data = [])
- {
- $this->_checkFields($data);
- $db = DB::getInstance();
- $config = Config::getInstance();
- $id = $config->get('champ_identifiant');
-
- if (!empty($data[$id])
- && $db->simpleQuerySingle('SELECT 1 FROM membres WHERE '.$id.' = ? LIMIT 1;', false, $data[$id]))
- {
- throw new UserException('La valeur du champ '.$id.' est déjà utilisée par un autre membre, hors ce champ doit être unique à chaque membre.');
- }
-
- if (isset($data['passe']) && trim($data['passe']) != '')
- {
- $data['passe'] = $this->_hashPassword($data['passe']);
- }
- else
- {
- unset($data['passe']);
- }
-
- if (empty($data['id_categorie']))
- {
- $data['id_categorie'] = Config::getInstance()->get('categorie_membres');
- }
-
- $db->simpleInsert('membres', $data);
- return $db->lastInsertRowId();
- }
-
- public function edit($id, $data = [], $check_editable = true)
- {
- $db = DB::getInstance();
- $config = Config::getInstance();
-
- if (isset($data['id']) && ($data['id'] == $id || empty($data['id'])))
- {
- unset($data['id']);
- }
-
- $this->_checkFields($data, $check_editable, false);
- $champ_id = $config->get('champ_identifiant');
-
- if (!empty($data[$champ_id])
- && $db->simpleQuerySingle('SELECT 1 FROM membres WHERE '.$champ_id.' = ? AND id != ? LIMIT 1;', false, $data[$champ_id], (int)$id))
- {
- throw new UserException('La valeur du champ '.$champ_id.' est déjà utilisée par un autre membre, hors ce champ doit être unique à chaque membre.');
- }
-
- if (!empty($data['id']))
- {
- if ($db->simpleQuerySingle('SELECT 1 FROM membres WHERE id = ?;', false, (int)$data['id']))
- {
- throw new UserException('Ce numéro est déjà attribué à un autre membre.');
- }
-
- // Si on ne vérifie pas toutes les tables qui sont liées ici à un ID de membre
- // la requête de modification provoquera une erreur de contrainte de foreign key
- // ce qui est normal. Donc : il n'est pas possible de changer l'ID d'un membre qui
- // a participé au wiki, à la compta, etc.
- if ($db->simpleQuerySingle('SELECT 1 FROM wiki_revisions WHERE id_auteur = ?;', false, (int)$id)
- || $db->simpleQuerySingle('SELECT 1 FROM compta_journal WHERE id_auteur = ?;', false, (int)$id))
- # FIXME || $db->simpleQuerySingle('SELECT 1 FROM wiki_suivi WHERE id_membre = ?;', false, (int)$id))
- {
- throw new UserException('Le numéro n\'est pas modifiable pour ce membre car des contenus sont liés à ce numéro de membre (wiki, compta, etc.).');
- }
- }
-
- if (!empty($data['passe']) && trim($data['passe']))
- {
- $data['passe'] = $this->_hashPassword($data['passe']);
- }
- else
- {
- unset($data['passe']);
- }
-
- if (isset($data['id_categorie']) && empty($data['id_categorie']))
- {
- $data['id_categorie'] = Config::getInstance()->get('categorie_membres');
- }
-
- if (empty($data))
- {
- return true;
- }
-
- return $db->simpleUpdate('membres', $data, 'id = '.(int)$id);
- }
-
- public function get($id)
- {
- $db = DB::getInstance();
- $config = Config::getInstance();
-
- return $db->simpleQuerySingle('SELECT *,
- '.$config->get('champ_identite').' AS identite,
- strftime(\'%s\', date_inscription) AS date_inscription,
- strftime(\'%s\', date_connexion) AS date_connexion
- FROM membres WHERE id = ? LIMIT 1;', true, (int)$id);
- }
-
- public function delete($ids)
- {
- if (!is_array($ids))
- {
- $ids = [(int)$ids];
- }
-
- if ($this->isLogged())
- {
- $user = $this->getLoggedUser();
-
- foreach ($ids as $id)
- {
- if ($user['id'] == $id)
- {
- throw new UserException('Il n\'est pas possible de supprimer son propre compte.');
- }
- }
- }
-
- return self::_deleteMembres($ids);
- }
-
- public function getNom($id)
- {
- $db = DB::getInstance();
- $config = Config::getInstance();
-
- return $db->simpleQuerySingle('SELECT '.$config->get('champ_identite').' FROM membres WHERE id = ? LIMIT 1;', false, (int)$id);
- }
-
- public function getDroits($id)
- {
- $db = DB::getInstance();
- $droits = $db->simpleQuerySingle('SELECT * FROM membres_categories WHERE id = ?;', true, (int)$id);
-
- foreach ($droits as $key=>$value)
- {
- unset($droits[$key]);
- $key = str_replace('droit_', '', $key, $found);
-
- if ($found)
- {
- $droits[$key] = (int) $value;
- }
- }
-
- return $droits;
- }
-
- public function search($field, $query)
- {
- $db = DB::getInstance();
- $config = Config::getInstance();
-
- $champs = $config->get('champs_membres');
-
- if ($field != 'id' && !$champs->get($field))
- {
- throw new \UnexpectedValueException($field . ' is not a valid field');
- }
-
- $champ = $champs->get($field);
-
- if ($champ['type'] == 'multiple')
- {
- $where = 'WHERE '.$field.' & (1 << '.(int)$query.')';
- $order = false;
- }
- elseif ($champ['type'] == 'tel')
- {
- $query = utils::normalizePhoneNumber($query);
- $query = preg_replace('!^0+!', '', $query);
-
- if ($query == '')
- {
- return false;
- }
-
- $where = 'WHERE '.$field.' LIKE \'%'.$db->escapeString($query).'\'';
- $order = $field;
- }
- elseif (!$champs->isText($field))
- {
- $where = 'WHERE '.$field.' = \''.$db->escapeString($query).'\'';
- $order = $field;
- }
- else
- {
- $where = 'WHERE transliterate_to_ascii('.$field.') LIKE transliterate_to_ascii(\'%'.$db->escapeString($query).'%\')';
- $order = 'transliterate_to_ascii('.$field.') COLLATE NOCASE';
- }
-
- $fields = array_keys($champs->getListedFields());
-
- if (!in_array($field, $fields))
- {
- $fields[] = $field;
- }
-
- if (!in_array('email', $fields))
- {
- $fields[] = 'email';
- }
-
- return $db->simpleStatementFetch(
- 'SELECT id, id_categorie, ' . implode(', ', $fields) . ',
- '.$config->get('champ_identite').' AS identite,
- strftime(\'%s\', date_inscription) AS date_inscription
- FROM membres ' . $where . ($order ? ' ORDER BY ' . $order : '') . '
- LIMIT 1000;',
- SQLITE3_ASSOC
- );
- }
-
- public function listByCategory($cat, $fields, $page = 1, $order = null, $desc = false)
- {
- $begin = ($page - 1) * self::ITEMS_PER_PAGE;
-
- $db = DB::getInstance();
- $config = Config::getInstance();
-
- $champs = $config->get('champs_membres');
-
- if (is_int($cat) && $cat)
- $where = 'WHERE id_categorie = '.(int)$cat;
- elseif (is_array($cat))
- $where = 'WHERE id_categorie IN ('.implode(',', $cat).')';
- else
- $where = '';
-
- if (is_null($order) || !$champs->get($order))
- $order = 'id';
-
- if (!empty($fields) && $order != 'id' && $champs->isText($order))
- {
- $order = 'transliterate_to_ascii('.$order.') COLLATE NOCASE';
- }
-
- if ($desc)
- {
- $order .= ' DESC';
- }
-
- if (!in_array('email', $fields))
- {
- $fields []= 'email';
- }
-
- $fields = implode(', ', $fields);
-
- $query = 'SELECT id, id_categorie, '.$fields.', '.$config->get('champ_identite').' AS identite,
- strftime(\'%s\', date_inscription) AS date_inscription
- FROM membres '.$where.'
- ORDER BY '.$order.' LIMIT ?, ?;';
-
- return $db->simpleStatementFetch($query, SQLITE3_ASSOC, $begin, self::ITEMS_PER_PAGE);
- }
-
- public function countByCategory($cat = 0)
- {
- $db = DB::getInstance();
-
- if (is_int($cat) && $cat)
- $where = 'WHERE id_categorie = '.(int)$cat;
- elseif (is_array($cat))
- $where = 'WHERE id_categorie IN ('.implode(',', $cat).')';
- else
- $where = '';
-
- return $db->simpleQuerySingle('SELECT COUNT(*) FROM membres '.$where.';');
- }
-
- public function countAllButHidden()
- {
- $db = DB::getInstance();
- return $db->simpleQuerySingle('SELECT COUNT(*) FROM membres WHERE id_categorie NOT IN (SELECT id FROM membres_categories WHERE cacher = 1);');
- }
-
- static public function changeCategorie($id_cat, $membres)
- {
- foreach ($membres as &$id)
- {
- $id = (int) $id;
- }
-
- $db = DB::getInstance();
- return $db->simpleUpdate('membres',
- ['id_categorie' => (int)$id_cat],
- 'id IN ('.implode(',', $membres).')'
- );
- }
-
- static protected function _deleteMembres($membres)
- {
- foreach ($membres as &$id)
- {
- $id = (int) $id;
- }
-
- $membres = implode(',', $membres);
-
- $db = DB::getInstance();
- $db->exec('UPDATE wiki_revisions SET id_auteur = NULL WHERE id_auteur IN ('.$membres.');');
- $db->exec('UPDATE compta_journal SET id_auteur = NULL WHERE id_auteur IN ('.$membres.');');
- //$db->exec('DELETE FROM wiki_suivi WHERE id_membre IN ('.$membres.');');
- return $db->exec('DELETE FROM membres WHERE id IN ('.$membres.');');
- }
-
- public function sendMessageToCategory($dest, $sujet, $message, $subscribed_only = false)
- {
- $config = Config::getInstance();
-
- $headers = [
- 'From' => '"'.$config->get('nom_asso').'" <'.$config->get('email_asso').'>',
- ];
- $message .= "\n\n--\n".$config->get('nom_asso')."\n".$config->get('site_asso');
-
- if ($dest == 0)
- $where = 'id_categorie NOT IN (SELECT id FROM membres_categories WHERE cacher = 1)';
- else
- $where = 'id_categorie = '.(int)$dest;
-
- if ($subscribed_only)
- {
- $where .= ' AND lettre_infos = 1';
- }
-
- $db = DB::getInstance();
- $res = $db->query('SELECT email FROM membres WHERE LENGTH(email) > 0 AND '.$where.' ORDER BY id;');
-
- $sujet = '['.$config->get('nom_asso').'] '.$sujet;
-
- while ($row = $res->fetchArray(SQLITE3_ASSOC))
- {
- utils::mail($row['email'], $sujet, $message, $headers);
- }
-
- return true;
- }
-
- public function searchSQL($query)
- {
- $db = DB::getInstance();
-
- if (!preg_match('/LIMIT\s+/i', $query))
- {
- $query = preg_replace('/;?\s*$/', '', $query);
- $query .= ' LIMIT 100';
- }
-
- if (preg_match('/;\s*(.+?)$/', $query))
- {
- throw new UserException('Une seule requête peut être envoyée en même temps.');
- }
-
- $st = $db->prepare($query);
-
- if (!$st->readOnly())
- {
- throw new UserException('Seules les requêtes en lecture sont autorisées.');
- }
-
- $res = $st->execute();
- $out = [];
-
- while ($row = $res->fetchArray(SQLITE3_ASSOC))
- {
- if (array_key_exists('passe', $row))
- {
- unset($row['passe']);
- }
-
- $out[] = $row;
- }
-
- return $out;
- }
-
- public function schemaSQL()
- {
- $db = DB::getInstance();
-
- $tables = [
- 'membres' => $db->querySingle('SELECT sql FROM sqlite_master WHERE type = \'table\' AND name = \'membres\';'),
- 'categories'=> $db->querySingle('SELECT sql FROM sqlite_master WHERE type = \'table\' AND name = \'membres_categories\';'),
- ];
-
- return $tables;
- }
-}
-
-?>
DELETED src/include/class.membres_categories.php
Index: src/include/class.membres_categories.php
==================================================================
--- src/include/class.membres_categories.php
+++ src/include/class.membres_categories.php
@@ -1,150 +0,0 @@
- Membres::DROIT_AUCUN,
- 'connexion' => Membres::DROIT_ACCES,
- 'membres' => Membres::DROIT_ACCES,
- 'compta' => Membres::DROIT_ACCES,
- 'wiki' => Membres::DROIT_ACCES,
- 'config' => Membres::DROIT_AUCUN,
- ];
-
- static public function getDroitsDefaut()
- {
- return $this->droits;
- }
-
- protected function _checkData(&$data)
- {
- $db = DB::getInstance();
-
- if (!isset($data['nom']) || !trim($data['nom']))
- {
- throw new UserException('Le nom de catégorie ne peut rester vide.');
- }
-
- if (!empty($data['id_cotisation_obligatoire'])
- && !$db->simpleQuerySingle('SELECT 1 FROM cotisations WHERE id = ?;',
- false, (int)$data['id_cotisation_obligatoire']))
- {
- throw new UserException('Numéro de cotisation inconnu.');
- }
-
- if (isset($data['id_cotisation_obligatoire']) && empty($data['id_cotisation_obligatoire']))
- {
- $data['id_cotisation_obligatoire'] = null;
- }
- }
-
- public function add($data)
- {
- $this->_checkData($data);
-
- if (!isset($data['description']))
- {
- $data['description'] = '';
- }
-
- foreach ($this->droits as $key=>$value)
- {
- if (!isset($data['droit_'.$key]))
- $data['droit_'.$key] = $value;
- else
- $data['droit_'.$key] = (int)$data['droit_'.$key];
- }
-
- $db = DB::getInstance();
- $db->simpleInsert('membres_categories', $data);
-
- return $db->lastInsertRowID();
- }
-
- public function edit($id, $data)
- {
- $this->_checkData($data);
-
- foreach ($this->droits as $key=>$value)
- {
- if (isset($data['droit_'.$key]))
- $data['droit_'.$key] = (int)$data['droit_'.$key];
- }
-
- if (!isset($data['cacher']) || $data['cacher'] != 1)
- $data['cacher'] = 0;
-
- $db = DB::getInstance();
- return $db->simpleUpdate('membres_categories', $data, 'id = '.(int)$id);
- }
-
- public function get($id)
- {
- $db = DB::getInstance();
-
- return $db->simpleQuerySingle('SELECT * FROM membres_categories WHERE id = ?;',
- true, (int) $id);
- }
-
- public function remove($id)
- {
- $db = DB::getInstance();
- $config = Config::getInstance();
-
- if ($id == $config->get('categorie_membres'))
- {
- throw new UserException('Il est interdit de supprimer la catégorie définie par défaut dans la configuration.');
- }
-
- if ($db->simpleQuerySingle('SELECT 1 FROM membres WHERE id_categorie = ?;', false, (int)$id))
- {
- throw new UserException('La catégorie contient encore des membres, il n\'est pas possible de la supprimer.');
- }
-
- $db->simpleUpdate(
- 'wiki_pages',
- [
- 'droit_lecture' => Wiki::LECTURE_NORMAL,
- 'droit_ecriture' => Wiki::ECRITURE_NORMAL,
- ],
- 'droit_lecture = '.(int)$id.' OR droit_ecriture = '.(int)$id
- );
-
- return $db->simpleExec('DELETE FROM membres_categories WHERE id = ?;', (int) $id);
- }
-
- public function listSimple()
- {
- $db = DB::getInstance();
- return $db->queryFetchAssoc('SELECT id, nom FROM membres_categories ORDER BY nom;');
- }
-
- public function listComplete()
- {
- $db = DB::getInstance();
- return $db->queryFetch('SELECT * FROM membres_categories ORDER BY nom;');
- }
-
- public function listCompleteWithStats()
- {
- $db = DB::getInstance();
- return $db->queryFetch('SELECT *, (SELECT COUNT(*) FROM membres WHERE id_categorie = membres_categories.id) AS nombre FROM membres_categories ORDER BY nom;');
- }
-
-
- public function listHidden()
- {
- $db = DB::getInstance();
- return $db->queryFetchAssoc('SELECT id, nom FROM membres_categories WHERE cacher = 1;');
- }
-
- public function listNotHidden()
- {
- $db = DB::getInstance();
- return $db->queryFetchAssoc('SELECT id, nom FROM membres_categories WHERE cacher = 0;');
- }
-}
-
-?>
DELETED src/include/class.membres_import.php
Index: src/include/class.membres_import.php
==================================================================
--- src/include/class.membres_import.php
+++ src/include/class.membres_import.php
@@ -1,272 +0,0 @@
- 'date_inscription']
- * @return boolean TRUE en cas de succès
- */
- public function fromGalette($path, $translation_table)
- {
- if (!file_exists($path) || !is_readable($path))
- {
- throw new \RuntimeException('Fichier inconnu : '.$path);
- }
-
- $fp = fopen($path, 'r');
-
- if (!$fp)
- {
- return false;
- }
-
- $db = DB::getInstance();
- $db->exec('BEGIN;');
- $membres = new Membres;
-
- $columns = array_flip($this->galette_fields);
-
- $col = function($column) use (&$row, &$columns)
- {
- if (!isset($columns[$column]))
- return null;
-
- if (!isset($row[$columns[$column]]))
- return null;
-
- return $row[$columns[$column]];
- };
-
- $line = 0;
- $delim = utils::find_csv_delim($fp);
-
- while (!feof($fp))
- {
- $row = fgetcsv($fp, 4096, $delim);
- $line++;
-
- if (empty($row))
- {
- continue;
- }
-
- if (count($row) != count($columns))
- {
- $db->exec('ROLLBACK;');
- throw new UserException('Erreur sur la ligne ' . $line . ' : le nombre de colonnes est incorrect.');
- }
-
- $data = [];
-
- foreach ($translation_table as $galette=>$garradin)
- {
- // Champs qu'on ne veut pas importer
- if (empty($garradin))
- continue;
-
- // Concaténer plusieurs champs
- if (isset($data[$garradin]))
- $data[$garradin] .= "\n" . $col($galette);
- else
- $data[$garradin] = $col($galette);
- }
-
- try {
- $membres->add($data);
- }
- catch (UserException $e)
- {
- $db->exec('ROLLBACK;');
- throw new UserException('Erreur sur la ligne ' . $line . ' : ' . $e->getMessage());
- }
- }
-
- $db->exec('END;');
-
- fclose($fp);
- return true;
- }
-
- /**
- * Importer un CSV de la liste des membres depuis un export Garradin
- * @param string $path Chemin vers le CSV
- * @return boolean TRUE en cas de succès
- */
- public function fromCSV($path)
- {
- if (!file_exists($path) || !is_readable($path))
- {
- throw new \RuntimeException('Fichier inconnu : '.$path);
- }
-
- $fp = fopen($path, 'r');
-
- if (!$fp)
- {
- return false;
- }
-
- $db = DB::getInstance();
- $db->exec('BEGIN;');
- $membres = new Membres;
-
- // On récupère les champs qu'on peut importer
- $champs = Config::getInstance()->get('champs_membres')->getAll();
- $champs = array_keys($champs);
- $champs[] = 'date_inscription';
- $champs[] = 'date_connexion';
- $champs[] = 'id';
- $champs[] = 'id_categorie';
-
- $line = 0;
- $delim = utils::find_csv_delim($fp);
-
- while (!feof($fp))
- {
- $row = fgetcsv($fp, 4096, $delim);
-
- $line++;
-
- if (empty($row))
- {
- continue;
- }
-
- if ($line == 1)
- {
- if (is_numeric($row[0]))
- {
- throw new UserException('Erreur sur la ligne 1 : devrait contenir l\'en-tête des colonnes.');
- }
-
- $columns = array_flip($row);
- continue;
- }
-
- if (count($row) != count($columns))
- {
- $db->exec('ROLLBACK;');
- throw new UserException('Erreur sur la ligne ' . $line . ' : le nombre de colonnes est incorrect.');
- }
-
- $data = [];
-
- foreach ($columns as $name=>$id)
- {
- $name = trim($name);
-
- // Champs qui n'existent pas dans le schéma actuel
- if (!in_array($name, $champs))
- continue;
-
- if (trim($row[$id]) !== '')
- $data[$name] = $row[$id];
- }
-
- if (!empty($data['id']))
- {
- $id = (int)$data['id'];
- unset($data['id']);
- }
- else
- {
- $id = false;
- }
-
- try {
- if ($id)
- $membres->edit($id, $data);
- else
- $membres->add($data);
- }
- catch (UserException $e)
- {
- $db->exec('ROLLBACK;');
- throw new UserException('Erreur sur la ligne ' . $line . ' : ' . $e->getMessage());
- }
- }
-
- $db->exec('END;');
-
- fclose($fp);
- return true;
- }
-
- public function toCSV()
- {
- $db = DB::getInstance();
-
- $res = $db->prepare('SELECT m.id, c.nom AS categorie, m.* FROM membres AS m
- LEFT JOIN membres_categories AS c ON m.id_categorie = c.id ORDER BY c.id;')->execute();
-
- $fp = fopen('php://output', 'w');
- $header = false;
-
- while ($row = $res->fetchArray(SQLITE3_ASSOC))
- {
- unset($row['passe']);
-
- if (!$header)
- {
- fputcsv($fp, array_keys($row));
- $header = true;
- }
-
- fputcsv($fp, $row);
- }
-
- fclose($fp);
-
- return true;
- }
-}
DELETED src/include/class.plugin.php
Index: src/include/class.plugin.php
==================================================================
--- src/include/class.plugin.php
+++ src/include/class.plugin.php
@@ -1,542 +0,0 @@
- 'text/css',
- 'gif' => 'image/gif',
- 'htm' => 'text/html',
- 'html' => 'text/html',
- 'ico' => 'image/x-ico',
- 'jpe' => 'image/jpeg',
- 'jpg' => 'image/jpeg',
- 'jpeg' => 'image/jpeg',
- 'js' => 'application/x-javascript',
- 'pdf' => 'application/pdf',
- 'png' => 'image/png',
- 'swf' => 'application/shockwave-flash',
- 'xml' => 'text/xml',
- 'svg' => 'image/svg+xml',
- ];
-
- /**
- * Construire un objet Plugin pour un plugin
- * @param string $id Identifiant du plugin
- * @throws UserException Si le plugin n'est pas installé (n'existe pas en DB)
- */
- public function __construct($id)
- {
- $db = DB::getInstance();
- $this->plugin = $db->simpleQuerySingle('SELECT * FROM plugins WHERE id = ?;', true, $id);
-
- if (!$this->plugin)
- {
- throw new UserException('Ce plugin n\'existe pas ou n\'est pas installé correctement.');
- }
-
- $this->plugin['config'] = json_decode($this->plugin['config'], true);
-
- if (!is_array($this->plugin['config']))
- {
- $this->plugin['config'] = [];
- }
-
- $this->id = $id;
- }
-
- /**
- * Enregistrer les changements dans la config
- */
- public function __destruct()
- {
- if ($this->config_changed)
- {
- $db = DB::getInstance();
- $db->simpleUpdate('plugins',
- ['config' => json_encode($this->plugin['config'])],
- 'id = \'' . $this->id . '\'');
- }
- }
-
- /**
- * Renvoie le chemin absolu vers l'archive du plugin
- * @return string Chemin PHAR vers l'archive
- */
- public function path()
- {
- return 'phar://' . PLUGINS_ROOT . '/' . $this->id . '.tar.gz';
- }
-
- /**
- * Renvoie une entrée de la configuration ou la configuration complète
- * @param string $key Clé à rechercher, ou NULL si on désire toutes les entrées de la
- * @return mixed L'entrée demandée (mixed), ou l'intégralité de la config (array),
- * ou NULL si l'entrée demandée n'existe pas.
- */
- public function getConfig($key = null)
- {
- if (is_null($key))
- {
- return $this->plugin['config'];
- }
-
- if (array_key_exists($key, $this->plugin['config']))
- {
- return $this->plugin['config'][$key];
- }
-
- return null;
- }
-
- /**
- * Enregistre une entrée dans la configuration du plugin
- * @param string $key Clé à modifier
- * @param mixed $value Valeur à enregistrer, choisir NULL pour effacer cette clé de la configuration
- * @return boolean TRUE si tout se passe bien
- */
- public function setConfig($key, $value = null)
- {
- if (is_null($value))
- {
- unset($this->plugin['config'][$key]);
- }
- else
- {
- $this->plugin['config'][$key] = $value;
- }
-
- $this->config_changed = true;
-
- return true;
- }
-
- /**
- * Renvoie une information ou toutes les informations sur le plugin
- * @param string $key Clé de l'info à retourner, ou NULL pour recevoir toutes les infos
- * @return mixed Info demandée ou tableau des infos.
- */
- public function getInfos($key = null)
- {
- if (is_null($key))
- {
- return $this->plugin;
- }
-
- if (array_key_exists($key, $this->plugin))
- {
- return $this->plugin[$key];
- }
-
- return null;
- }
-
- /**
- * Renvoie l'identifiant du plugin
- * @return string Identifiant du plugin
- */
- public function id()
- {
- return $this->id;
- }
-
- /**
- * Inclure un fichier depuis le plugin (dynamique ou statique)
- * @param string $file Chemin du fichier à aller chercher : si c'est un .php il sera inclus,
- * sinon il sera juste affiché
- * @return void
- * @throws UserException Si le fichier n'existe pas ou fait partie des fichiers qui ne peuvent
- * être appelés que par des méthodes de Plugin.
- * @throws RuntimeException Si le chemin indiqué tente de sortir du contexte du PHAR
- */
- public function call($file)
- {
- $file = preg_replace('!^[./]*!', '', $file);
-
- if (preg_match('!(?:\.\.|[/\\\\]\.|\.[/\\\\])!', $file))
- {
- throw new \RuntimeException('Chemin de fichier incorrect.');
- }
-
- $forbidden = ['install.php', 'garradin_plugin.ini', 'upgrade.php', 'uninstall.php', 'signals.php'];
-
- if (in_array($file, $forbidden))
- {
- throw new UserException('Le fichier ' . $file . ' ne peut être appelé par cette méthode.');
- }
-
- if (!file_exists($this->path() . '/www/' . $file))
- {
- throw new UserException('Le fichier ' . $file . ' n\'existe pas dans le plugin ' . $this->id);
- }
-
- $plugin = $this;
- global $tpl, $config, $user, $membres;
-
- if (substr($file, -4) === '.php')
- {
- include $this->path() . '/www/' . $file;
- }
- else
- {
- // Récupération du type MIME à partir de l'extension
- $ext = substr($file, strrpos($file, '.')+1);
-
- if (isset($this->mimes[$ext]))
- {
- $mime = $this->mimes[$ext];
- }
- else
- {
- $mime = 'text/plain';
- }
-
- header('Content-Type: ' .$this->mimes[$ext]);
- header('Content-Length: ' . filesize($this->path() . '/www/' . $file));
-
- readfile($this->path() . '/www/' . $file);
- }
- }
-
- /**
- * Désinstaller le plugin
- * @return boolean TRUE si la suppression a fonctionné
- */
- public function uninstall()
- {
- if (file_exists($this->path() . '/uninstall.php'))
- {
- include $this->path() . '/uninstall.php';
- }
-
- unlink(PLUGINS_ROOT . '/' . $this->id . '.tar.gz');
-
- $db = DB::getInstance();
- return $db->simpleExec('DELETE FROM plugins WHERE id = ?;', $this->id);
- }
-
- /**
- * Renvoie TRUE si le plugin a besoin d'être mis à jour
- * (si la version notée dans la DB est différente de la version notée dans garradin_plugin.ini)
- * @return boolean TRUE si le plugin doit être mis à jour, FALSE sinon
- */
- public function needUpgrade()
- {
- $infos = parse_ini_file($this->path() . '/garradin_plugin.ini', false);
-
- if (version_compare($this->plugin['version'], $infos['version'], '!='))
- return true;
-
- return false;
- }
-
- /**
- * Mettre à jour le plugin
- * Appelle le fichier upgrade.php dans l'archive si celui-ci existe.
- * @return boolean TRUE si tout a fonctionné
- */
- public function upgrade()
- {
- if (file_exists($this->path() . '/upgrade.php'))
- {
- include $this->path() . '/upgrade.php';
- }
-
- $db = DB::getInstance();
- return $db->simpleUpdate('plugins',
- 'id = \''.$db->escapeString($this->id).'\'',
- ['version' => $infos['version']]);
- }
-
- /**
- * Liste des plugins installés (en DB)
- * @return array Liste des plugins triés par nom
- */
- static public function listInstalled()
- {
- $db = DB::getInstance();
- $plugins = $db->simpleStatementFetchAssocKey('SELECT id, * FROM plugins ORDER BY nom;');
- $system = explode(',', PLUGINS_SYSTEM);
-
- foreach ($plugins as &$row)
- {
- $row['system'] = in_array($row['id'], $system);
- }
-
- return $plugins;
- }
-
- /**
- * Liste les plugins qui doivent être affichés dans le menu
- * @return array Tableau associatif id => nom (ou un tableau vide si aucun plugin ne doit être affiché)
- */
- static public function listMenu()
- {
- $db = DB::getInstance();
- return $db->simpleStatementFetchAssoc('SELECT id, nom FROM plugins WHERE menu = 1 ORDER BY nom;');
- }
-
- /**
- * Liste les plugins téléchargés mais non installés
- * @return array Liste des plugins téléchargés
- */
- static public function listDownloaded()
- {
- $installed = self::listInstalled();
-
- $list = [];
- $dir = dir(PLUGINS_ROOT);
-
- while ($file = $dir->read())
- {
- if (substr($file, 0, 1) == '.')
- continue;
-
- if (!preg_match('!^([a-z0-9_.-]+)\.tar\.gz$!', $file, $match))
- continue;
-
- if (array_key_exists($match[1], $installed))
- continue;
-
- $list[$match[1]] = parse_ini_file('phar://' . PLUGINS_ROOT . '/' . $match[1] . '.tar.gz/garradin_plugin.ini', false);
- }
-
- $dir->close();
-
- return $list;
- }
-
- /**
- * Liste des plugins officiels depuis le repository signé
- * @return array Liste des plugins
- */
- static public function listOfficial()
- {
- // La liste est stockée en cache une heure pour ne pas tuer le serveur distant
- if (Static_Cache::expired('plugins_list', 3600 * 24))
- {
- $url = parse_url(PLUGINS_URL);
-
- $context_options = [
- 'ssl' => [
- 'verify_peer' => TRUE,
- // On vérifie en utilisant le certificat maître de CACert
- 'cafile' => ROOT . '/include/data/cacert.pem',
- 'verify_depth' => 5,
- 'CN_match' => $url['host'],
- 'SNI_enabled' => true,
- 'SNI_server_name' => $url['host'],
- 'disable_compression' => true,
- ]
- ];
-
- $context = stream_context_create($context_options);
-
- try {
- $result = file_get_contents(PLUGINS_URL, NULL, $context);
- }
- catch (\Exception $e)
- {
- throw new UserException('Le téléchargement de la liste des plugins a échoué : ' . $e->getMessage());
- }
-
- Static_Cache::store('plugins_list', $result);
- }
- else
- {
- $result = Static_Cache::get('plugins_list');
- }
-
- $list = json_decode($result, true);
- return $list;
- }
-
- /**
- * Vérifier le hash du plugin $id pour voir s'il correspond au hash du fichier téléchargés
- * @param string $id Identifiant du plugin
- * @return boolean TRUE si le hash correspond (intégrité OK), sinon FALSE
- */
- static public function checkHash($id)
- {
- $list = self::fetchOfficialList();
-
- if (!array_key_exists($id, $list))
- return null;
-
- $hash = sha1_file(PLUGINS_ROOT . '/' . $id . '.tar.gz');
-
- return ($hash === $list[$id]['hash']);
- }
-
- /**
- * Est-ce que le plugin est officiel ?
- * @param string $id Identifiant du plugin
- * @return boolean TRUE si le plugin est officiel, FALSE sinon
- */
- static public function isOfficial($id)
- {
- $list = self::fetchOfficialList();
- return array_key_exists($id, $list);
- }
-
- /**
- * Télécharge un plugin depuis le repository officiel, et l'installe
- * @param string $id Identifiant du plugin
- * @return boolean TRUE si ça marche
- * @throws LogicException Si le plugin n'est pas dans la liste des plugins officiels
- * @throws UserException Si le plugin est déjà installé ou que le téléchargement a échoué
- * @throws RuntimeException Si l'archive téléchargée est corrompue (intégrité du hash ne correspond pas)
- */
- static public function download($id)
- {
- $list = self::fetchOfficialList();
-
- if (!array_key_exists($id, $list))
- {
- throw new \LogicException($id . ' n\'est pas un plugin officiel (absent de la liste)');
- }
-
- if (file_exists(PLUGINS_ROOT . '/' . $id . '.tar.gz'))
- {
- throw new UserException('Le plugin '.$id.' existe déjà.');
- }
-
- $url = parse_url(PLUGINS_URL);
-
- $context_options = [
- 'ssl' => [
- 'verify_peer' => TRUE,
- 'cafile' => ROOT . '/include/data/cacert.pem',
- 'verify_depth' => 5,
- 'CN_match' => $url['host'],
- 'SNI_enabled' => true,
- 'SNI_server_name' => $url['host'],
- 'disable_compression' => true,
- ]
- ];
-
- $context = stream_context_create($context_options);
-
- try {
- copy($list[$id]['phar'], PLUGINS_ROOT . '/' . $id . '.tar.gz', $context);
- }
- catch (\Exception $e)
- {
- throw new UserException('Le téléchargement du plugin '.$id.' a échoué : ' . $e->getMessage());
- }
-
- if (!self::checkHash($id))
- {
- unlink(PLUGINS_ROOT . '/' . $id . '.tar.gz');
- throw new \RuntimeException('L\'archive du plugin '.$id.' est corrompue (le hash SHA1 ne correspond pas).');
- }
-
- self::install($id, true);
-
- return true;
- }
-
- /**
- * Installer un plugin
- * @param string $id Identifiant du plugin
- * @param boolean $official TRUE si le plugin est officiel
- * @return boolean TRUE si tout a fonctionné
- */
- static public function install($id, $official = false)
- {
- if (!file_exists('phar://' . PLUGINS_ROOT . '/' . $id . '.tar.gz'))
- {
- throw new \RuntimeException('Le plugin ' . $id . ' ne semble pas exister et ne peut donc être installé.');
- }
-
- if (!file_exists('phar://' . PLUGINS_ROOT . '/' . $id . '.tar.gz/garradin_plugin.ini'))
- {
- throw new UserException('L\'archive '.$id.'.tar.gz n\'est pas une extension Garradin : fichier garradin_plugin.ini manquant.');
- }
-
- $infos = parse_ini_file('phar://' . PLUGINS_ROOT . '/' . $id . '.tar.gz/garradin_plugin.ini', false);
-
- $required = ['nom', 'description', 'auteur', 'url', 'version', 'menu', 'config'];
-
- foreach ($required as $key)
- {
- if (!array_key_exists($key, $infos))
- {
- throw new \RuntimeException('Le fichier garradin_plugin.ini ne contient pas d\'entrée "'.$key.'".');
- }
- }
-
- if (!empty($infos['min_version']) && !version_compare(garradin_version(), $infos['min_version'], '>='))
- {
- throw new \RuntimeException('Le plugin '.$id.' nécessite Garradin version '.$infos['min_version'].' ou supérieure.');
- }
-
- if (!empty($infos['menu']) && !file_exists('phar://' . PLUGINS_ROOT . '/' . $id . '.tar.gz/www/admin/index.php'))
- {
- throw new \RuntimeException('Le plugin '.$id.' ne comporte pas de fichier www/admin/index.php alors qu\'il demande à figurer au menu.');
- }
-
- $config = '';
-
- if ((bool)$infos['config'])
- {
- if (!file_exists('phar://' . PLUGINS_ROOT . '/' . $id . '.tar.gz/config.json'))
- {
- throw new \RuntimeException('L\'archive '.$id.'.tar.gz ne comporte pas de fichier config.json
- alors que le plugin nécessite le stockage d\'une configuration.');
- }
-
- if (!file_exists('phar://' . PLUGINS_ROOT . '/' . $id . '.tar.gz/www/admin/config.php'))
- {
- throw new \RuntimeException('L\'archive '.$id.'.tar.gz ne comporte pas de fichier www/admin/config.php
- alors que le plugin nécessite le stockage d\'une configuration.');
- }
-
- $config = json_decode(file_get_contents('phar://' . PLUGINS_ROOT . '/' . $id . '.tar.gz/config.json'), true);
-
- if (is_null($config))
- {
- throw new \RuntimeException('config.json invalide. Code erreur JSON: ' . json_last_error());
- }
-
- $config = json_encode($config);
- }
-
- $db = DB::getInstance();
- $db->simpleInsert('plugins', [
- 'id' => $id,
- 'officiel' => (int)(bool)$official,
- 'nom' => $infos['nom'],
- 'description'=> $infos['description'],
- 'auteur' => $infos['auteur'],
- 'url' => $infos['url'],
- 'version' => $infos['version'],
- 'menu' => (int)(bool)$infos['menu'],
- 'config' => $config,
- ]);
-
- if (file_exists('phar://' . PLUGINS_ROOT . '/' . $id . '.tar.gz/install.php'))
- {
- $plugin = new Plugin($id);
-
- include 'phar://' . PLUGINS_ROOT . '/' . $id . '.tar.gz/install.php';
- }
-
- return true;
- }
-
- /**
- * Renvoie la version installée d'un plugin ou FALSE s'il n'est pas installé
- * @param string $id Identifiant du plugin
- * @return mixed Numéro de version du plugin ou FALSE
- */
- static public function getInstalledVersion($id)
- {
- return DB::getInstance()->simpleQuerySingle('SELECT version FROM plugins WHERE id = ?;');
- }
-}
DELETED src/include/class.rappels.php
Index: src/include/class.rappels.php
==================================================================
--- src/include/class.rappels.php
+++ src/include/class.rappels.php
@@ -1,208 +0,0 @@
-simpleQuerySingle('SELECT 1 FROM cotisations WHERE id = ?;', false, (int) $data['id_cotisation']))
- {
- throw new UserException('Cotisation inconnue.');
- }
-
- $data['id_cotisation'] = (int) $data['id_cotisation'];
-
- if ((trim($data['delai']) === '') || !is_numeric($data['delai']))
- {
- throw new UserException('Délai avant rappel invalide : doit être indiqué en nombre de jours.');
- }
-
- $data['delai'] = (int) $data['delai'];
-
- if (!isset($data['sujet']) || trim($data['sujet']) === '')
- {
- throw new UserException('Le sujet du rappel ne peut être vide.');
- }
-
- $data['sujet'] = trim($data['sujet']);
-
- if (!isset($data['texte']) || trim($data['texte']) === '')
- {
- throw new UserException('Le contenu du rappel ne peut être vide.');
- }
-
- $data['texte'] = trim($data['texte']);
- }
-
- /**
- * Ajouter un rappel
- * @param array $data Données du rappel
- * @return integer Numéro ID du rappel créé
- */
- public function add($data)
- {
- $db = DB::getInstance();
-
- $this->_checkFields($data);
-
- $db->simpleInsert('rappels', $data);
-
- return $db->lastInsertRowId();
- }
-
- /**
- * Modifier un rappel automatique
- * @param integer $id Numéro du rappel
- * @param array $data Données du rappel
- * @return boolean TRUE si tout s'est bien passé
- * @throws UserException En cas d'erreur dans une donnée à modifier
- */
- public function edit($id, $data)
- {
- $db = DB::getInstance();
-
- $this->_checkFields($data);
-
- return $db->simpleUpdate('rappels', $data, 'id = ' . (int)$id);
- }
-
- /**
- * Supprimer un rappel automatique
- * @param integer $id Numéro du rappel
- * @param boolean $delete_history Effacer aussi l'historique des rappels envoyés
- * @return boolean TRUE en cas de succès
- */
- public function delete($id, $delete_history = false)
- {
- $db = DB::getInstance();
-
- $db->exec('BEGIN;');
-
- if ($delete_history)
- {
- $db->simpleExec('DELETE FROM rappels_envoyes WHERE id_rappel = ?;', (int) $id);
- }
- else
- {
- $db->simpleExec('UPDATE rappels_envoyes SET id_rappel = NULL WHERE id_rappel = ?;', (int) $id);
- }
-
- $db->simpleExec('DELETE FROM rappels WHERE id = ?;', (int) $id);
- $db->exec('END;');
-
- return true;
- }
-
- /**
- * Renvoie les données sur un rappel
- * @param integer $id Numéro du rappel
- * @return array Données du rappel
- */
- public function get($id)
- {
- return DB::getInstance()->simpleQuerySingle('SELECT * FROM rappels WHERE id = ?;', true, (int)$id);
- }
-
- /**
- * Renvoie le nombre de rappels automatiques enregistrés
- * @return integer Nombre de rappels
- */
- public function countAll()
- {
- return DB::getInstance()->simpleQuerySingle('SELECT COUNT(*) FROM rappels;');
- }
-
- /**
- * Liste des rappels triés par cotisation
- * @return array Liste des rappels
- */
- public function listByCotisation()
- {
- return DB::getInstance()->simpleStatementFetch('SELECT r.*,
- c.intitule, c.montant, c.duree, c.debut, c.fin
- FROM rappels AS r
- INNER JOIN cotisations AS c ON c.id = r.id_cotisation
- ORDER BY r.id_cotisation, r.delai, r.sujet;');
- }
-
- /**
- * Liste des rappels pour une cotisation donnée
- * @param integer $id Numéro du rappel
- * @return array Liste des rappels
- */
- public function listForCotisation($id)
- {
- return DB::getInstance()->simpleStatementFetch('SELECT * FROM rappels
- WHERE id_cotisation = ? ORDER BY delai, sujet;', \SQLITE3_ASSOC, (int)$id);
- }
-
- /**
- * Envoi des rappels automatiques par e-mail
- * @return boolean TRUE en cas de succès
- */
- public function sendPending()
- {
- $db = DB::getInstance();
- $config = Config::getInstance();
-
- // Requête compliquée qui fait tout le boulot
- // la logique est un JOIN des tables rappels, cotisations, cotisations_membres et membres
- // pour récupérer la liste des membres qui doivent recevoir une cotisation
- $query = '
- SELECT
- *,
- /* Nombre de jours avant ou après expiration */
- (julianday(date()) - julianday(expiration)) AS nb_jours,
- /* Date de mise en œuvre du rappel */
- date(expiration, delai || \' days\') AS date_rappel
- FROM (
- SELECT m.*, r.delai, r.sujet, r.texte, r.id_cotisation,
- m.'.$config->get('champ_identite').' AS identite,
- CASE WHEN c.duree IS NOT NULL THEN date(cm.date, \'+\'||c.duree||\' days\')
- WHEN c.fin IS NOT NULL THEN c.fin ELSE 0 END AS expiration
- FROM rappels AS r
- INNER JOIN cotisations AS c ON c.id = r.id_cotisation
- INNER JOIN cotisations_membres AS cm ON cm.id_cotisation = c.id
- INNER JOIN membres AS m ON m.id = cm.id_membre
- WHERE
- /* Inutile de sélectionner les membres sans email */
- m.email IS NOT NULL AND m.email != \'\'
- /* Les cotisations ponctuelles ne comptent pas */
- AND (c.fin IS NOT NULL OR c.duree IS NOT NULL)
- /* Rien nest envoyé aux membres des catégories cachées, logique */
- AND m.id_categorie NOT IN (SELECT id FROM membres_categories WHERE cacher = 1)
- /* Grouper par membre, pour n\'envoyer qu\'un seul rappel par membre/cotise */
- GROUP BY m.id, r.id_cotisation
- ORDER BY r.delai ASC
- )
- WHERE nb_jours >= delai
- /* Pour ne pas spammer on n\'envoie pas de rappel antérieur au dernier rappel déjà effectué */
- AND id NOT IN (SELECT id_membre FROM rappels_envoyes AS re
- WHERE id_cotisation = re.id_cotisation
- AND re.date >= date(expiration, delai || \' days\')
- )
- ORDER BY nb_jours DESC;';
-
- $db->exec('BEGIN');
- $st = $db->prepare($query);
- $res = $st->execute();
- $re = new Rappels_Envoyes;
-
- while ($row = $res->fetchArray(DB::ASSOC))
- {
- $re->sendAuto($row);
- }
-
- $db->exec('END;');
- return true;
- }
-}
DELETED src/include/class.rappels_envoyes.php
Index: src/include/class.rappels_envoyes.php
==================================================================
--- src/include/class.rappels_envoyes.php
+++ src/include/class.rappels_envoyes.php
@@ -1,231 +0,0 @@
-simpleQuerySingle('SELECT 1 FROM cotisations WHERE id = ?;', false, (int) $data['id_cotisation']))
- {
- throw new UserException('Cotisation inconnue.');
- }
-
- $data['id_cotisation'] = (int) $data['id_cotisation'];
- }
-
- if (empty($data['id_membre'])
- || !$db->simpleQuerySingle('SELECT 1 FROM membres WHERE id = ?;', false, (int) $data['id_membre']))
- {
- throw new UserException('Membre inconnu.');
- }
-
- $data['id_membre'] = (int) $data['id_membre'];
-
- if (empty($data['media']) || !is_numeric($data['media'])
- || !in_array((int)$data['media'], [self::MEDIA_EMAIL, self::MEDIA_COURRIER, self::MEDIA_TELEPHONE, self::MEDIA_AUTRE]))
- {
- throw new UserException('Média invalide.');
- }
-
- $data['media'] = (int) $data['media'];
-
- if (empty($data['date']) || !utils::checkDate($data['date']))
- {
- throw new UserException('La date indiquée n\'est pas valide.');
- }
- }
-
- /**
- * Enregistrer un rappel
- * @param array $data Données du rappel
- * @return integer Numéro ID du rappel créé
- */
- public function add($data)
- {
- $db = DB::getInstance();
-
- $this->_checkFields($data);
-
- $db->simpleInsert('rappels_envoyes', $data);
-
- return $db->lastInsertRowId();
- }
-
- /**
- * Supprimer un rappel enregistré
- * @param integer $id Numéro du rappel
- * @return boolean TRUE en cas de succès
- */
- public function delete($id)
- {
- $db = DB::getInstance();
- $db->simpleExec('DELETE FROM rappels_envoyes WHERE id = ?;', (int) $id);
- return true;
- }
-
- /**
- * Renvoie les données sur un rappel
- * @param integer $id Numéro du rappel
- * @return array Données du rappel
- */
- public function get($id)
- {
- return DB::getInstance()->simpleQuerySingle('SELECT * FROM rappels_envoyes WHERE id = ?;', true, (int)$id);
- }
-
- /**
- * Remplacer les tags dans le contenu/sujet du mail
- * @param string $content Chaîne à traiter
- * @param array $data Données supplémentaires à utiliser comme tags (tableau associatif)
- * @return string $content dont les tags ont été remplacés par le contenu correct
- */
- public function replaceTagsInContent($content, $data = null)
- {
- $config = Config::getInstance();
- $tags = [
- '#NOM_ASSO' => $config->get('nom_asso'),
- '#ADRESSE_ASSO' => $config->get('adresse_asso'),
- '#EMAIL_ASSO' => $config->get('email_asso'),
- '#SITE_ASSO' => $config->get('site_asso'),
- '#URL_RACINE' => WWW_URL,
- '#URL_SITE' => WWW_URL,
- '#URL_ADMIN' => WWW_URL . 'admin/',
- ];
-
- if (!empty($data) && is_array($data))
- {
- foreach ($data as $key=>$value)
- {
- $key = '#' . strtoupper($key);
- $tags[$key] = $value;
- }
- }
-
- return strtr($content, $tags);
- }
-
- /**
- * Envoi de mail pour rappel automatisé
- * @param array $data Données du rappel automatisé
- * @return boolean TRUE
- */
- public function sendAuto($data)
- {
- $replace = $data;
- $replace['date_rappel'] = utils::sqliteDateToFrench($replace['date_rappel']);
- $replace['date_expiration'] = utils::sqliteDateToFrench($replace['expiration']);
- $replace['nb_jours'] = abs($replace['nb_jours']);
- $replace['delai'] = abs($replace['delai']);
-
- $subject = $this->replaceTagsInContent($data['sujet'], $replace);
- $text = $this->replaceTagsInContent($data['texte'], $replace);
-
- // Envoi du mail
- utils::mail($data['email'], $subject, $text);
-
- // Enregistrement en DB
- $this->add([
- 'id_cotisation' => $data['id_cotisation'],
- 'id_membre' => $data['id'],
- 'media' => Rappels_Envoyes::MEDIA_EMAIL,
- // On enregistre la date de mise en œuvre du rappel
- // et non pas la date d'envoi effective du rappel
- // car l'envoi du rappel peut ne pas être effectué
- // le jour où il aurait dû être envoyé (la magie des cron)
- 'date' => $data['date_rappel'],
- ]);
-
- return true;
- }
-
- /**
- * Liste des rappels envoyés à un membre
- * @param integer $id Numéro du membre
- * @return array Liste des rappels
- */
- public function listForMember($id)
- {
- return DB::getInstance()->simpleStatementFetch('SELECT
- re.*, c.intitule, c.montant
- FROM rappels_envoyes AS re
- INNER JOIN cotisations AS c ON c.id = re.id_cotisation
- WHERE re.id_membre = ?
- ORDER BY re.date DESC;', \SQLITE3_ASSOC, (int)$id);
- }
-
- /**
- * Liste des rappels pour une cotisation donnée
- * @param integer $id Numéro de la cotisation
- * @param integer $page Numéro de page de liste
- * @return array Liste des rappels
- */
- public function listForCotisation($id, $page = 1)
- {
- $begin = ($page - 1) * self::ITEMS_PER_PAGE;
-
- return DB::getInstance()->simpleStatementFetch('SELECT * FROM rappels_envoyes
- WHERE id_rappel IN (SELECT id FROM rappels WHERE id_cotisation = ?)
- ORDER BY date DESC;', \SQLITE3_ASSOC, (int)$id);
- }
-
- /**
- * Nombre de rappels pour une cotisation donnée
- * @param integer $id Numéro de la cotisation
- * @return integer Nombre de rappels envoyés
- */
- public function countForCotisation($id)
- {
- return DB::getInstance()->simpleQuerySingle('SELECT COUNT(*) FROM rappels_envoyes
- WHERE id_rappel IN (SELECT id FROM rappels WHERE id_cotisation = ?);',
- false, (int)$id);
- }
-
- /**
- * Liste des rappels envoyés pour un rappel automatique
- * @param integer $id Numéro du rappel
- * @param integer $page Numéro de page de liste
- * @return array Liste des rappels envoyés
- */
- public function listForRappel($id, $page = 1)
- {
- $begin = ($page - 1) * self::ITEMS_PER_PAGE;
-
- return DB::getInstance()->simpleStatementFetch('SELECT * FROM rappels_envoyes
- WHERE id_rappel = ? ORDER BY date DESC LIMIT ?,?;',
- \SQLITE3_ASSOC, (int)$id, (int)$begin, self::ITEMS_PER_PAGE);
- }
-
- /**
- * Nombre de rappels envoyés pour un rappel automatique
- * @param integer $id Numéro du rappel
- * @return integer Nombre de rappels envoyés pour ce rappel
- */
- public function countForRappel($id)
- {
- return DB::getInstance()->simpleQuerySingle('SELECT COUNT(*) FROM rappels_envoyes
- WHERE id_rappel = ?;', false, (int)$id);
- }
-}
DELETED src/include/class.sauvegarde.php
Index: src/include/class.sauvegarde.php
==================================================================
--- src/include/class.sauvegarde.php
+++ src/include/class.sauvegarde.php
@@ -1,263 +0,0 @@
-read())
- {
- if ($file[0] != '.' && is_file(DATA_ROOT . '/' . $file)
- && preg_match('![\w\d._-]+\.' . $ext . '$!i', $file) && $file != basename(DB_FILE))
- {
- $out[$file] = filemtime(DATA_ROOT . '/' . $file);
- }
- }
-
- $dir->close();
-
- ksort($out);
-
- return $out;
- }
-
- /**
- * Crée une nouvelle sauvegarde
- * @param boolean $auto Si true le nom de fichier sera celui de la sauvegarde automatique courante,
- * sinon le nom sera basé sur la date (sauvegarde manuelle)
- * @return string Le nom de fichier de la sauvegarde ainsi créée
- */
- public function create($auto = false)
- {
- $backup = str_replace('.sqlite', ($auto ? '.auto.1' : date('.Y-m-d-His')) . '.sqlite', DB_FILE);
- copy(DB_FILE, $backup);
- return basename($backup);
- }
-
- /**
- * Effectue une rotation des sauvegardes automatiques
- * association.auto.1.sqlite deviendra association.auto.2.sqlite par exemple
- * @return boolean true
- */
- public function rotate()
- {
- $config = Config::getInstance();
- $nb = $config->get('nombre_sauvegardes');
-
- $list = $this->getList(true);
- krsort($list);
-
- if (count($list) >= $nb)
- {
- $this->remove(key($list));
- array_shift($list);
- }
-
- foreach ($list as $f=>$d)
- {
- $new = preg_replace_callback('!\.auto\.(\d+)\.sqlite$!', function ($m) {
- return '.auto.' . ((int) $m[1] + 1) . '.sqlite';
- }, $f);
-
- rename(DATA_ROOT . '/' . $f, DATA_ROOT . '/' . $new);
- }
-
- return true;
- }
-
- /**
- * Crée une sauvegarde automatique si besoin est
- * @return boolean true
- */
- public function auto()
- {
- $config = Config::getInstance();
-
- // Pas besoin d'aller plus loin si on ne fait pas de sauvegarde auto
- if ($config->get('frequence_sauvegardes') == 0 || $config->get('nombre_sauvegardes') == 0)
- return true;
-
- $list = $this->getList(true);
-
- if (count($list) > 0)
- {
- $last = current($list);
- }
- else
- {
- $last = false;
- }
-
- // Test de la date de création de la dernière sauvegarde
- if ($last >= (time() - ($config->get('frequence_sauvegardes') * 3600 * 24)))
- {
- return true;
- }
-
- // Si pas de modif depuis la dernière sauvegarde, ça sert à rien d'en faire
- if ($last >= filemtime(DB_FILE))
- {
- return true;
- }
-
- $this->rotate();
- $this->create(true);
-
- return true;
- }
-
- /**
- * Efface une sauvegarde locale
- * @param string $file Nom du fichier à supprimer
- * @return boolean true si le fichier a bien été supprimé, false sinon
- */
- public function remove($file)
- {
- if (preg_match('!\.\.+!', $file) || !preg_match('!^[\w\d._-]+\.sqlite$!i', $file)
- || $file == basename(DB_FILE))
- {
- throw new UserException('Nom de fichier non valide.');
- }
-
- return unlink(DATA_ROOT . '/' . $file);
- }
-
- /**
- * Renvoie sur la sortie courante le contenu du fichier de base de données courant
- * @return boolean true
- */
- public function dump()
- {
- $in = fopen(DB_FILE, 'r');
- $out = fopen('php://output', 'w');
-
- while (!feof($in))
- {
- fwrite($out, fread($in, 8192));
- }
-
- fclose($in);
- fclose($out);
- return true;
- }
-
- /**
- * Restaure une sauvegarde locale
- * @param string $file Le nom de fichier à utiliser comme point de restauration
- * @return boolean true si la restauration a fonctionné, false sinon
- */
- public function restoreFromLocal($file)
- {
- if (preg_match('!\.\.+!', $file) || !preg_match('!^[\w\d._-]+$!i', $file))
- {
- throw new UserException('Nom de fichier non valide.');
- }
-
- if (!file_exists(DATA_ROOT . '/' . $file))
- {
- throw new UserException('Le fichier fourni n\'existe pas.');
- }
-
- return $this->restoreDB(DATA_ROOT . '/' . $file);
- }
-
- /**
- * Restaure une copie distante (fichier envoyé)
- * @param array $file Tableau provenant de $_FILES
- * @return boolean true
- */
- public function restoreFromUpload($file)
- {
- if (empty($file['size']) || empty($file['tmp_name']) || !empty($file['error']))
- {
- throw new UserException('Le fichier n\'a pas été correctement envoyé. Essayer de le renvoyer à nouveau.');
- }
-
- $r = $this->restoreDB($file['tmp_name']);
-
- if ($r)
- {
- unlink($file['tmp_name']);
- }
-
- return $r;
- }
-
- /**
- * Restauration de base de données, la fonction qui le fait vraiment
- * @param string $file Chemin absolu vers la base de données à utiliser
- * @return mixed true si rien ne va plus, ou self::NEED_UPGRADE si la version de la DB
- * ne correspond pas à la version de Garradin (mise à jour nécessaire).
- */
- protected function restoreDB($file)
- {
- // Essayons déjà d'ouvrir la base de données à restaurer en lecture
- try {
- $db = new \SQLite3($file, SQLITE3_OPEN_READONLY);
- }
- catch (\Exception $e)
- {
- throw new UserException('Le fichier fourni n\'est pas une base de données valide. ' .
- 'Message d\'erreur de SQLite : ' . $e->getMessage());
- }
-
- // Regardons ensuite si la base de données n'est pas corrompue
- $check = $db->querySingle('PRAGMA integrity_check;');
-
- if (strtolower(trim($check)) != 'ok')
- {
- throw new UserException('Le fichier fourni est corrompu. SQLite a trouvé ' . $check . ' erreurs.');
- }
-
- // On ne peut pas faire de vérifications très poussées sur la structure de la base de données,
- // celle-ci pouvant changer d'une version à l'autre et on peut vouloir importer une base
- // un peu vieille, mais on vérifie quand même que ça ressemble un minimum à une base garradin
- $table = $db->querySingle('SELECT 1 FROM sqlite_master WHERE type=\'table\' AND tbl_name=\'config\';');
-
- if (!$table)
- {
- throw new UserException('Le fichier fourni ne semble pas contenir de données liées à Garradin.');
- }
-
- // On récupère la version pour plus tard
- $version = $db->querySingle('SELECT valeur FROM config WHERE cle=\'version\';');
-
- $db->close();
-
- $backup = str_replace('.sqlite', date('.Y-m-d-His') . '.avant_restauration.sqlite', DB_FILE);
-
- if (!rename(DB_FILE, $backup))
- {
- throw new \RuntimeException('Unable to backup current DB file.');
- }
-
- if (!copy($file, DB_FILE))
- {
- rename($backup, DB_FILE);
- throw new \RuntimeException('Unable to copy backup DB to main location.');
- }
-
- if ($version != garradin_version())
- {
- return self::NEED_UPGRADE;
- }
-
- return true;
- }
-
-}
-
-?>
DELETED src/include/class.squelette.php
Index: src/include/class.squelette.php
==================================================================
--- src/include/class.squelette.php
+++ src/include/class.squelette.php
@@ -1,756 +0,0 @@
-_getType($type, $value);
-
- if ($type == self::OBJ)
- {
- $this->_content = $value->get();
- }
- else
- {
- $this->_content[] = (string) (int) $type . $value;
- }
-
- unset($value);
- }
-
- public function prepend($type = self::TEXT, $value, $pos = false)
- {
- $type = $this->_getType($type, $value);
-
- if ($type == self::OBJ)
- {
- if ($pos)
- {
- array_splice($this->_content, $pos, 0, $value->get());
- }
- else
- {
- $this->_content = array_merge($value->get(), $this->_content);
- }
- }
- else
- {
- $value = (string) (int) $type . $value;
-
- if ($pos)
- {
- array_splice($this->_content, $pos, 0, $value);
- }
- else
- {
- array_unshift($this->_content, $value);
- }
- }
-
- unset($value);
- }
-
- public function append($type = self::TEXT, $value, $pos = false)
- {
- $type = $this->_getType($type, $value);
-
- if ($type == self::OBJ)
- {
- if ($pos)
- {
- array_splice($this->_content, $pos + 1, 0, $value->get());
- }
- else
- {
- $this->_content = array_merge($this->_content, $value->get());
- }
- }
- else
- {
- $value = (string) (int) $type . $value;
-
- if ($pos)
- {
- array_splice($this->_content, $pos + 1, 0, $value);
- }
- else
- {
- array_push($this->_content, $value);
- }
- }
-
- unset($value);
- }
-
- public function output($in_php = false)
- {
- $out = '';
- $php = $in_php ?: false;
-
- foreach ($this->_content as $line)
- {
- if ($line[0] == self::PHP && !$php)
- {
- $php = true;
- $out .= '';
- }
-
- $out .= substr($line, 1);
-
- if ($line[0] == self::PHP)
- {
- $out .= "\n";
- }
- }
-
- if ($php && !$in_php)
- {
- $out .= ' ?>';
- }
-
- $this->_content = [];
-
- return $out;
- }
-
- public function __toString()
- {
- return $this->output(false);
- }
-
- public function get()
- {
- return $this->_content;
- }
-
- public function replace($key, $type = self::TEXT, $value)
- {
- $type = $this->_getType($type, $value);
-
- if ($type == self::OBJ)
- {
- array_splice($this->_content, $key, 1, $value->get());
- }
- else
- {
- $this->_content[$key] = (string) (int) $type . $value;
- }
-
- unset($value);
- }
-}
-
-class Squelette extends \miniSkel
-{
- private $parent = null;
- private $current = null;
- private $_vars = [];
-
- private function _registerDefaultModifiers()
- {
- foreach (Squelette_Filtres::$filtres_php as $func=>$name)
- {
- if (is_string($func))
- $this->register_modifier($name, $func);
- else
- $this->register_modifier($name, $name);
- }
-
- foreach (get_class_methods('Garradin\Squelette_Filtres') as $name)
- {
- $this->register_modifier($name, ['Garradin\Squelette_Filtres', $name]);
- }
-
- foreach (Squelette_Filtres::$filtres_alias as $name=>$func)
- {
- $this->register_modifier($name, ['Garradin\Squelette_Filtres', $func]);
- }
-
- if (file_exists(DATA_ROOT . '/www/squelettes/mes_filtres.php'))
- {
- require_once DATA_ROOT . '/www/squelettes/mes_filtres.php';
- }
- }
-
- public function __construct()
- {
- $this->_registerDefaultModifiers();
-
- $config = Config::getInstance();
-
- $this->assign('nom_asso', $config->get('nom_asso'));
- $this->assign('adresse_asso', $config->get('adresse_asso'));
- $this->assign('email_asso', $config->get('email_asso'));
- $this->assign('site_asso', $config->get('site_asso'));
-
- $this->assign('url_racine', WWW_URL);
- $this->assign('url_site', WWW_URL);
- $this->assign('url_atom', WWW_URL . 'feed/atom/');
- $this->assign('url_elements', WWW_URL . 'squelettes/');
- $this->assign('url_admin', WWW_URL . 'admin/');
- }
-
- protected function processInclude($args)
- {
- if (empty($args))
- throw new \miniSkelMarkupException("Le tag INCLURE demande à préciser le fichier à inclure.");
-
- $file = key($args);
-
- if (empty($file) || !preg_match('!^[\w\d_-]+(?:\.[\w\d_-]+)*$!', $file))
- throw new \miniSkelMarkupException("INCLURE: le nom de fichier ne peut contenir que des caractères alphanumériques.");
-
- return new Squelette_Snippet(1, '$this->fetch("'.$file.'", false);');
- }
-
- protected function processVariable($name, $value, $applyDefault, $modifiers, $pre, $post, $context)
- {
- if ($context == self::CONTEXT_IN_ARG)
- {
- $out = new Squelette_Snippet(1, '$this->getVariable(\''.$name.'\')');
-
- if ($pre)
- {
- $out->prepend(2, $pre);
- }
-
- if ($post)
- {
- $out->append(2, $post);
- }
-
- return $out;
- }
-
- $out = new Squelette_Snippet(1, '$value = $this->getVariable(\''.$name.'\');');
-
- // We process modifiers
- foreach ($modifiers as &$modifier)
- {
- if (!isset($this->modifiers[$modifier['name']]))
- {
- throw new \miniSkelMarkupException('Filtre '.$modifier['name'].' inconnu !');
- }
-
- $out->append(1, '$value = call_user_func_array('.var_export($this->modifiers[$modifier['name']], true).', [$value, ');
-
- foreach ($modifier['arguments'] as $arg)
- {
- if ($arg == 'debut_liste')
- {
- $out->append(1, '$this->getVariable(\'debut_liste\')');
- }
- elseif ($arg instanceOf Squelette_Snippet)
- {
- $out->append(3, $arg);
- }
- else
- {
- //if (preg_match('!getVariable!', $arg)) throw new Exception("lol");
- $out->append(1, '"'.str_replace('"', '\\"', $arg).'"');
- }
-
- $out->append(1, ', ');
- }
-
- $out->append(1, ']);');
-
- if (in_array($modifier['name'], Squelette_Filtres::$desactiver_defaut))
- {
- $applyDefault = false;
- }
- }
-
- if ($applyDefault)
- {
- $out->append(1, 'if (is_string($value) && trim($value)) $value = htmlspecialchars($value, ENT_QUOTES, \'UTF-8\', false);');
- }
-
- $out->append(1, 'if ($value === true || trim($value) !== \'\'):');
-
- // Getting pre-content
- if ($pre)
- {
- $out->append(2, $pre);
- }
-
- $out->append(1, 'echo is_bool($value) ? "" : $value;');
-
- // Getting post-content
- if ($post)
- {
- $out->append(2, $post);
- }
-
- $out->append(1, 'endif;');
-
- return $out;
- }
-
- protected function processLoop($loopName, $loopType, $loopCriterias, $loopContent, $preContent, $postContent, $altContent)
- {
- if ($loopType != 'articles' && $loopType != 'rubriques' && $loopType != 'pages')
- {
- throw new \miniSkelMarkupException("Le type de boucle '".$loopType."' est inconnu.");
- }
-
- $loopStart = '';
- $query = $where = $order = '';
- $limit = $begin = 0;
-
- $query = 'SELECT w.*, strftime(\\\'%s\\\', w.date_creation) AS date_creation, strftime(\\\'%s\\\', w.date_modification) AS date_modification';
-
- if (trim($loopContent))
- {
- $query .= ', r.contenu AS texte FROM wiki_pages AS w LEFT JOIN wiki_revisions AS r ON (w.id = r.id_page AND w.revision = r.revision) ';
- }
- else
- {
- $query .= '\'\' AS texte ';
- }
-
- $where = 'WHERE w.droit_lecture = -1 ';
-
- if ($loopType == 'articles')
- {
- $where .= 'AND (SELECT COUNT(id) FROM wiki_pages WHERE parent = w.id) = 0 ';
- }
- elseif ($loopType == 'rubriques')
- {
- $where .= 'AND (SELECT COUNT(id) FROM wiki_pages WHERE parent = w.id) > 0 ';
- }
-
- $allowed_fields = ['id', 'uri', 'titre', 'date', 'date_creation', 'date_modification',
- 'parent', 'rubrique', 'revision', 'points', 'recherche', 'texte'];
- $search = $search_rank = false;
-
- foreach ($loopCriterias as $criteria)
- {
- if (isset($criteria['field']))
- {
- if (!in_array($criteria['field'], $allowed_fields))
- {
- throw new \miniSkelMarkupException("Critère '".$criteria['field']."' invalide pour la boucle '$loopName' de type '$loopType'.");
- }
- elseif ($criteria['field'] == 'rubrique')
- {
- $criteria['field'] = 'parent';
- }
- elseif ($criteria['field'] == 'date')
- {
- $criteria['field'] = 'date_creation';
- }
- elseif ($criteria['field'] == 'points')
- {
- if ($criteria['action'] != \miniSkel::ACTION_ORDER_BY)
- {
- throw new \miniSkelMarkupException("Le critère 'points' n\'est pas valide dans ce contexte.");
- }
-
- $search_rank = true;
- }
- }
-
- switch ($criteria['action'])
- {
- case \miniSkel::ACTION_ORDER_BY:
- if (!$order)
- $order = 'ORDER BY '.$criteria['field'].'';
- else
- $order .= ', '.$criteria['field'].'';
- break;
- case \miniSkel::ACTION_ORDER_DESC:
- if ($order)
- $order .= ' DESC';
- break;
- case \miniSkel::ACTION_LIMIT:
- $begin = $criteria['begin'];
- $limit = $criteria['number'];
- break;
- case \miniSkel::ACTION_MATCH_FIELD_BY_VALUE:
- $where .= ' AND '.$criteria['field'].' '.$criteria['comparison'].' \\\'\'.$db->escapeString(\''.$criteria['value'].'\').\'\\\'';
- break;
- case \miniSkel::ACTION_MATCH_FIELD:
- {
- if ($criteria['field'] == 'recherche')
- {
- $query = 'SELECT w.*, r.contenu AS texte, rank(matchinfo(wiki_recherche), 0, 1.0, 1.0) AS points FROM wiki_pages AS w INNER JOIN wiki_recherche AS r ON (w.id = r.id) ';
- $where .= ' AND wiki_recherche MATCH \\\'\'.$db->escapeString($this->getVariable(\''.$criteria['field'].'\')).\'\\\'';
- $search = true;
- }
- else
- {
- if ($criteria['field'] == 'parent')
- $field = 'id';
- else
- $field = $criteria['field'];
-
- $where .= ' AND '.$criteria['field'].' = \\\'\'.$db->escapeString($this->getVariable(\''.$field.'\')).\'\\\'';
- }
- break;
- }
- default:
- break;
- }
- }
-
- if ($search_rank && !$search)
- {
- throw new \miniSkelMarkupException("Le critère par points n'est possible que dans les boucles de recherche.");
- }
-
- if (trim($loopContent))
- {
- $loopStart .= '$row[\'url\'] = WWW_URL . $row[\'uri\']; ';
- }
-
- $query .= $where . ' ' . $order;
-
- if (!$limit || $limit > 100)
- $limit = 100;
-
- if ($limit)
- {
- $query .= ' LIMIT '.(is_numeric($begin) ? (int) $begin : '\'.$this->variables[\'debut_liste\'].\'').','.(int)$limit;
- }
-
- $hash = sha1(uniqid(mt_rand(), true));
- $out = new Squelette_Snippet();
- $out->append(1, '$parent_hash = $this->current[\'_self_hash\'];');
- $out->append(1, '$this->parent =& $parent_hash ? $this->_vars[$parent_hash] : null;');
-
- if ($search)
- {
- $out->append(1, 'if (trim($this->getVariable(\'recherche\'))) { ');
- }
-
- $out->append(1, '$statement = $db->prepare(\''.$query.'\'); ');
- // Sécurité anti injection
- $out->append(1, 'if (!$statement->readOnly()) { throw new \\miniSkelMarkupException("Requête en écriture illégale: '.$query.'"); } ');
- $out->append(1, '$result_'.$hash.' = $statement->execute(); ');
- $out->append(1, '$nb_rows = $db->countRows($result_'.$hash.'); ');
-
- if ($search)
- {
- $out->append(1, '} else { $result_'.$hash.' = false; $nb_rows = 0; }');
- }
-
- $out->append(1, '$this->_vars[\''.$hash.'\'] = [\'_self_hash\' => \''.$hash.'\', \'_parent_hash\' => $parent_hash, \'total_boucle\' => $nb_rows, \'compteur_boucle\' => 0];');
- $out->append(1, '$this->current =& $this->_vars[\''.$hash.'\']; ');
- $out->append(1, 'if ($nb_rows > 0):');
-
- if ($preContent)
- {
- $out->append(2, $this->parse($preContent, $loopName, self::PRE_CONTENT));
- }
-
- $out->append(1, 'while ($row = $result_'.$hash.'->fetchArray(SQLITE3_ASSOC)): ');
- $out->append(1, '$this->_vars[\''.$hash.'\'][\'compteur_boucle\'] += 1; ');
- $out->append(1, $loopStart);
- $out->append(1, '$this->_vars[\''.$hash.'\'] = array_merge($this->_vars[\''.$hash.'\'], $row); ');
-
- $out->append(2, $this->parseVariables($loopContent));
-
- $out->append(1, 'endwhile;');
-
- // we put the post-content after the loop content
- if ($postContent)
- {
- $out->append(2, $this->parse($postContent, $loopName, self::POST_CONTENT));
- }
-
- if ($altContent)
- {
- $out->append(1, 'else:');
- $out->append(2, $this->parse($altContent, $loopName, self::ALT_CONTENT));
- }
-
- $out->append(1, 'endif; ');
- $out->append(1, '$parent_hash = $this->_vars[\''.$hash.'\'][\'_parent_hash\']; ');
- $out->append(1, 'unset($result_'.$hash.', $nb_rows, $this->_vars[\''.$hash.'\']); ');
- $out->append(1, 'if ($parent_hash) { $this->current =& $this->_vars[$parent_hash]; $parent_hash = $this->current[\'_parent_hash\']; } ');
- $out->append(1, 'else { $this->current = null; }');
- $out->append(1, '$this->parent =& $parent_hash ? $this->_vars[$_parent_hash] : null;');
-
- return $out;
- }
-
- public function fetch($template, $no_display = false)
- {
- $this->currentTemplate = $template;
-
- $path = file_exists(DATA_ROOT . '/www/squelettes/' . $template)
- ? DATA_ROOT . '/www/squelettes/' . $template
- : ROOT . '/www/squelettes-dist/' . $template;
-
- $tpl_id = basename(dirname($path)) . '/' . $template;
-
- if (!self::compile_check($tpl_id, $path))
- {
- if (!file_exists($path))
- {
- throw new \miniSkelMarkupException('Le squelette "'.$tpl_id.'" n\'existe pas.');
- }
-
- $content = file_get_contents($path);
- $content = strtr($content, [' '<?php', '' => '']);
-
- $out = new Squelette_Snippet(2, $this->parse($content));
- $out->prepend(1, '/* '.$tpl_id.' */ '.
- 'namespace Garradin; $db = DB::getInstance(); '.
- 'if ($this->parent) $parent_hash = $this->parent[\'_self_hash\']; '. // For included files
- 'else $parent_hash = false;');
-
- if (!$no_display)
- {
- self::compile_store($tpl_id, $out);
- }
- }
-
- if (!$no_display)
- {
- require self::compile_get_path($tpl_id);
- }
- else
- {
- eval($tpl_id);
- }
-
- return null;
- }
-
- public function dispatchURI()
- {
- $uri = !empty($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '/';
-
- header('HTTP/1.1 200 OK', 200, true);
-
- if ($pos = strpos($uri, '?'))
- {
- $uri = substr($uri, 0, $pos);
- }
- else
- {
- // WWW_URI inclus toujours le slash final, mais on veut le conserver ici
- $uri = substr($uri, strlen(WWW_URI) - 1);
- }
-
- if ($uri == '/')
- {
- $skel = 'sommaire.html';
- }
- elseif ($uri == '/feed/atom/')
- {
- header('Content-Type: application/atom+xml');
- $skel = 'atom.xml';
- }
- elseif (substr($uri, -1) == '/')
- {
- $skel = 'rubrique.html';
- $_GET['uri'] = $_REQUEST['uri'] = substr($uri, 1, -1);
- }
- elseif (preg_match('!^/admin/!', $uri))
- {
- throw new UserException('Cette page n\'existe pas.');
- }
- else
- {
- $_GET['uri'] = $_REQUEST['uri'] = substr($uri, 1);
-
- if (preg_match('!^[\w\d_-]+$!i', $_GET['uri'])
- && file_exists(DATA_ROOT . '/www/squelettes/' . strtolower($_GET['uri']) . '.html'))
- {
- $skel = strtolower($_GET['uri']) . '.html';
- }
- else
- {
- $skel = 'article.html';
- }
- }
-
- $this->display($skel);
- }
-
- static private function compile_get_path($path)
- {
- $hash = sha1($path);
- return DATA_ROOT . '/cache/compiled/s_' . $hash . '.php';
- }
-
- static private function compile_check($tpl, $check)
- {
- if (!file_exists(self::compile_get_path($tpl)))
- return false;
-
- $time = filemtime(self::compile_get_path($tpl));
-
- if (empty($time))
- {
- return false;
- }
-
- if ($time < filemtime($check))
- return false;
- return $time;
- }
-
- static private function compile_store($tpl, $content)
- {
- $path = self::compile_get_path($tpl);
-
- if (!file_exists(dirname($path)))
- {
- mkdir(dirname($path));
- }
-
- file_put_contents($path, $content);
- return true;
- }
-
- static public function compile_clear($tpl)
- {
- $path = self::compile_get_path($tpl);
-
- if (file_exists($path))
- unlink($path);
-
- return true;
- }
-
- protected function getVariable($var)
- {
- if (isset($this->current[$var]))
- {
- return $this->current[$var];
- }
- elseif (isset($this->parent[$var]))
- {
- return $this->parent[$var];
- }
- elseif (isset($this->variables[$var]))
- {
- return $this->variables[$var];
- }
- elseif (isset($_REQUEST[$var]))
- {
- return $_REQUEST[$var];
- }
- else
- {
- return null;
- }
- }
-
- static public function getSource($template)
- {
- if (!preg_match('!^[\w\d_-]+(?:\.[\w\d_-]+)*$!', $template))
- return false;
-
- $path = file_exists(DATA_ROOT . '/www/squelettes/' . $template)
- ? DATA_ROOT . '/www/squelettes/' . $template
- : ROOT . '/www/squelettes-dist/' . $template;
-
- if (!file_exists($path))
- return false;
-
- return file_get_contents($path);
- }
-
- static public function editSource($template, $content)
- {
- if (!preg_match('!^[\w\d_-]+(?:\.[\w\d_-]+)*$!', $template))
- return false;
-
- $path = DATA_ROOT . '/www/squelettes/' . $template;
-
- return file_put_contents($path, $content);
- }
-
- static public function resetSource($template)
- {
- if (!preg_match('!^[\w\d_-]+(?:\.[\w\d_-]+)*$!', $template))
- return false;
-
- if (file_exists(DATA_ROOT . '/www/squelettes/' . $template))
- {
- unlink(DATA_ROOT . '/www/squelettes/' . $template);
- }
-
- return true;
- }
-
- static public function listSources()
- {
- if (!file_exists(DATA_ROOT . '/www/squelettes'))
- {
- mkdir(DATA_ROOT . '/www/squelettes');
- }
-
- $sources = [];
-
- $dir = dir(ROOT . '/www/squelettes-dist');
-
- while ($file = $dir->read())
- {
- if ($file[0] == '.')
- continue;
-
- if (!preg_match('/\.(?:css|x?html?|atom|rss|xml|svg|txt)$/i', $file))
- continue;
-
- $sources[] = $file;
- }
-
- $dir->close();
-
- $dir = dir(DATA_ROOT . '/www/squelettes');
-
- while ($file = $dir->read())
- {
- if ($file[0] == '.')
- continue;
-
- if (!preg_match('/\.(?:css|x?html?|atom|rss|xml|svg|txt)$/i', $file))
- continue;
-
- $sources[] = $file;
- }
-
- $dir->close();
-
- $sources = array_unique($sources);
- sort($sources);
-
- return $sources;
- }
-
-}
DELETED src/include/class.wiki.php
Index: src/include/class.wiki.php
==================================================================
--- src/include/class.wiki.php
+++ src/include/class.wiki.php
@@ -1,528 +0,0 @@
-simpleQuerySingle('SELECT 1 FROM wiki_pages WHERE id = ?;', false, $data['parent']))
- {
- $data['parent'] = 0;
- }
- }
-
- return true;
- }
-
- public function create($data = [])
- {
- $this->_checkFields($data);
- $db = DB::getInstance();
-
- if (!empty($data['uri']))
- {
- $data['uri'] = self::transformTitleToURI($data['uri']);
-
- if ($db->simpleQuerySingle('SELECT 1 FROM wiki_pages WHERE uri = ? LIMIT 1;', false, $data['uri']))
- {
- throw new UserException('Cette adresse de page est déjà utilisée pour une autre page, il faut en choisir une autre.');
- }
- }
- else
- {
- $data['uri'] = self::transformTitleToURI($data['titre']);
-
- if (!trim($data['uri']) || $db->simpleQuerySingle('SELECT 1 FROM wiki_pages WHERE uri = ? LIMIT 1;', false, $data['uri']))
- {
- $data['uri'] .= '_' . date('d-m-Y_H-i-s');
- }
- }
-
- $db->simpleInsert('wiki_pages', $data);
- $id = $db->lastInsertRowId();
-
- // On ne peut utiliser un trigger pour insérer dans la recherche
- // car les tables virtuelles font des opérations qui modifient
- // last_insert_rowid() et donc résultat incohérent
- $db->simpleInsert('wiki_recherche', ['id' => $id, 'titre' => $data['titre']]);
-
- return $id;
- }
-
- public function edit($id, $data = [])
- {
- $db = DB::getInstance();
- $this->_checkFields($data);
-
- if (isset($data['uri']))
- {
- $data['uri'] = self::transformTitleToURI($data['uri']);
-
- if ($db->simpleQuerySingle('SELECT 1 FROM wiki_pages WHERE uri = ? AND id != ? LIMIT 1;', false, $data['uri'], (int)$id))
- {
- throw new UserException('Cette adresse de page est déjà utilisée pour une autre page, il faut en choisir une autre.');
- }
- }
-
- if (isset($data['droit_lecture']) && $data['droit_lecture'] >= self::LECTURE_CATEGORIE)
- {
- $data['droit_ecriture'] = $data['droit_lecture'];
- }
-
- if (isset($data['parent']) && (int)$data['parent'] == (int)$id)
- {
- $data['parent'] = 0;
- }
-
- $data['date_modification'] = gmdate('Y-m-d H:i:s');
-
- // Modification de la date de création
- if (isset($data['date_creation']))
- {
- // Si la date n'est pas valide tant pis
- if (!(strtotime($data['date_creation']) > 0))
- {
- unset($data['date_creation']);
- }
- else
- {
- $data['date_creation'] = gmdate('Y-m-d H:i:s', $data['date_creation']);
- }
- }
-
- $db->simpleUpdate('wiki_pages', $data, 'id = '.(int)$id);
- return true;
- }
-
- public function delete($id)
- {
- $db = DB::getInstance();
-
- if ($db->simpleQuerySingle('SELECT COUNT(*) FROM wiki_pages WHERE parent = ?;', false, (int)$id))
- {
- return false;
- }
-
- $db->simpleExec('DELETE FROM wiki_revisions WHERE id_page = ?;', (int)$id);
- //$db->simpleExec('DELETE FROM wiki_suivi WHERE id_page = ?;', (int)$id); FIXME
- $db->simpleExec('DELETE FROM wiki_recherche WHERE id = ?;', (int)$id);
- $db->simpleExec('DELETE FROM wiki_pages WHERE id = ?;', (int)$id);
- return true;
- }
-
- public function get($id)
- {
- $db = DB::getInstance();
- return $db->simpleQuerySingle('SELECT *,
- strftime(\'%s\', date_creation) AS date_creation,
- strftime(\'%s\', date_modification) AS date_modification
- FROM wiki_pages WHERE id = ? LIMIT 1;', true, (int)$id);
- }
-
- public function getTitle($id)
- {
- $db = DB::getInstance();
- return $db->simpleQuerySingle('SELECT titre FROM wiki_pages WHERE id = ? LIMIT 1;', false, (int)$id);
- }
-
- public function getRevision($id, $rev)
- {
- $db = DB::getInstance();
- $champ_id = Config::getInstance()->get('champ_identite');
-
- // FIXME pagination au lieu de bloquer à 1000
- return $db->simpleQuerySingle('SELECT r.revision, r.modification, r.id_auteur, r.contenu,
- strftime(\'%s\', r.date) AS date, LENGTH(r.contenu) AS taille, m.'.$champ_id.' AS nom_auteur,
- r.chiffrement
- FROM wiki_revisions AS r LEFT JOIN membres AS m ON m.id = r.id_auteur
- WHERE r.id_page = ? AND revision = ? LIMIT 1;', true, (int) $id, (int) $rev);
- }
-
- public function listRevisions($id)
- {
- $db = DB::getInstance();
- $champ_id = Config::getInstance()->get('champ_identite');
-
- // FIXME pagination au lieu de bloquer à 1000
- return $db->simpleStatementFetch('SELECT r.revision, r.modification, r.id_auteur,
- strftime(\'%s\', r.date) AS date, LENGTH(r.contenu) AS taille, m.'.$champ_id.' AS nom_auteur,
- LENGTH(r.contenu) - (SELECT LENGTH(contenu) FROM wiki_revisions WHERE id_page = r.id_page AND revision < r.revision ORDER BY revision DESC LIMIT 1)
- AS diff_taille, r.chiffrement
- FROM wiki_revisions AS r LEFT JOIN membres AS m ON m.id = r.id_auteur
- WHERE r.id_page = ? ORDER BY r.revision DESC LIMIT 1000;', SQLITE3_ASSOC, (int) $id);
- }
-
- public function editRevision($id, $revision_edition = 0, $data)
- {
- $db = DB::getInstance();
-
- $revision = $db->simpleQuerySingle('SELECT revision FROM wiki_pages WHERE id = ?;', false, (int)$id);
-
- // ?! L'ID fournit ne correspond à rien ?
- if ($revision === false)
- {
- throw new \RuntimeException('La page demandée n\'existe pas.');
- }
-
- // Pas de révision
- if ($revision == 0 && !trim($data['contenu']))
- {
- return true;
- }
-
- // Il faut obligatoirement fournir un ID d'auteur
- if (empty($data['id_auteur']) && $data['id_auteur'] !== null)
- {
- throw new \BadMethodCallException('Aucun ID auteur de fourni.');
- }
-
- $contenu = $db->simpleQuerySingle('SELECT contenu FROM wiki_revisions WHERE revision = ? AND id_page = ?;', false, (int)$revision, (int)$id);
-
- // Pas de changement au contenu, pas la peine d'enregistrer une nouvelle révision
- if (trim($contenu) == trim($data['contenu']))
- {
- return true;
- }
-
- // Révision sur laquelle est basée la nouvelle révision
- // utilisé pour vérifier que le contenu n'a pas été modifié depuis qu'on
- // a chargé la page d'édition
- if ($revision > $revision_edition)
- {
- throw new UserException('La page a été modifiée depuis le début de votre modification.');
- }
-
- if (empty($data['chiffrement']))
- $data['chiffrement'] = 0;
-
- if (!isset($data['modification']) || !trim($data['modification']))
- $data['modification'] = null;
-
- // Incrémentons le numéro de révision
- $revision++;
-
- $data['id_page'] = $id;
- $data['revision'] = $revision;
-
- $db->simpleInsert('wiki_revisions', $data);
- $db->simpleUpdate('wiki_pages', [
- 'revision' => $revision,
- 'date_modification' => gmdate('Y-m-d H:i:s'),
- ], 'id = '.(int)$id);
-
- return true;
- }
-
- public function search($query)
- {
- $db = DB::getInstance();
- return $db->simpleStatementFetch('SELECT
- p.uri, r.*, snippet(wiki_recherche, \'\', \'\', \'...\', -1, -50) AS snippet,
- rank(matchinfo(wiki_recherche), 0, 1.0, 1.0) AS points
- FROM wiki_recherche AS r INNER JOIN wiki_pages AS p ON p.id = r.id
- WHERE '.$this->_getLectureClause('p.').' AND wiki_recherche MATCH \''.$db->escapeString($query).'\'
- ORDER BY points DESC LIMIT 0,50;');
- }
-
- public function setRestrictionCategorie($id, $droit_wiki)
- {
- $this->restriction_categorie = $id;
- $this->restriction_droit = $droit_wiki;
- return true;
- }
-
- protected function _getLectureClause($prefix = '')
- {
- if (is_null($this->restriction_categorie))
- {
- throw new \UnexpectedValueException('setRestrictionCategorie doit être appelé auparavant.');
- }
-
- if ($this->restriction_droit == Membres::DROIT_AUCUN)
- {
- throw new UserException('Vous n\'avez pas accès au wiki.');
- }
-
- if ($this->restriction_droit == Membres::DROIT_ADMIN)
- return '1';
-
- return '('.$prefix.'droit_lecture = '.self::LECTURE_NORMAL.' OR '.$prefix.'droit_lecture = '.self::LECTURE_PUBLIC.'
- OR '.$prefix.'droit_lecture = '.(int)$this->restriction_categorie.')';
- }
-
- public function canReadPage($lecture)
- {
- if (is_null($this->restriction_categorie))
- {
- throw new \UnexpectedValueException('setRestrictionCategorie doit être appelé auparavant.');
- }
-
- if ($this->restriction_droit < Membres::DROIT_ACCES)
- {
- return false;
- }
-
- if ($this->restriction_droit == Membres::DROIT_ADMIN
- || $lecture == self::LECTURE_NORMAL || $lecture == self::LECTURE_PUBLIC
- || $lecture == $this->restriction_categorie)
- return true;
-
- return false;
- }
-
- public function canWritePage($ecriture)
- {
- if (is_null($this->restriction_categorie))
- {
- throw new \UnexpectedValueException('setRestrictionCategorie doit être appelé auparavant.');
- }
-
- if ($this->restriction_droit < Membres::DROIT_ECRITURE)
- {
- return false;
- }
-
- if ($this->restriction_droit == Membres::DROIT_ADMIN
- || $ecriture == self::ECRITURE_NORMAL
- || $ecriture == $this->restriction_categorie)
- return true;
-
- return false;
- }
-
- public function getList($parent = 0)
- {
- $db = DB::getInstance();
-
- return $db->simpleStatementFetch(
- 'SELECT id, revision, uri, titre,
- strftime(\'%s\', date_creation) AS date_creation,
- strftime(\'%s\', date_modification) AS date_modification
- FROM wiki_pages
- WHERE parent = ? AND '.$this->_getLectureClause().'
- ORDER BY transliterate_to_ascii(titre) COLLATE NOCASE LIMIT 500;',
- SQLITE3_ASSOC,
- (int) $parent
- );
- }
-
- public function getById($id)
- {
- $db = DB::getInstance();
- $page = $db->simpleQuerySingle('SELECT *,
- strftime(\'%s\', date_creation) AS date_creation,
- strftime(\'%s\', date_modification) AS date_modification
- FROM wiki_pages
- WHERE id = ?;', true, (int)$id);
-
- if (!$page)
- {
- return false;
- }
-
- if ($page['revision'] > 0)
- {
- $page['contenu'] = $db->simpleQuerySingle('SELECT * FROM wiki_revisions
- WHERE id_page = ? AND revision = ?;', true, (int)$page['id'], (int)$page['revision']);
- }
- else
- {
- $page['contenu'] = false;
- }
-
- return $page;
- }
-
- public function getByURI($uri)
- {
- $db = DB::getInstance();
- $page = $db->simpleQuerySingle('SELECT *,
- strftime(\'%s\', date_creation) AS date_creation,
- strftime(\'%s\', date_modification) AS date_modification
- FROM wiki_pages
- WHERE uri = ?;', true, trim($uri));
-
- if (!$page)
- {
- return false;
- }
-
- if ($page['revision'] > 0)
- {
- $page['contenu'] = $db->simpleQuerySingle('SELECT * FROM wiki_revisions
- WHERE id_page = ? AND revision = ?;', true, (int)$page['id'], (int)$page['revision']);
- }
- else
- {
- $page['contenu'] = false;
- }
-
- return $page;
- }
-
- public function listRecentModifications($page = 1)
- {
- $begin = ($page - 1) * self::ITEMS_PER_PAGE;
-
- $db = DB::getInstance();
-
- return $db->simpleStatementFetch('SELECT *,
- strftime(\'%s\', date_creation) AS date_creation,
- strftime(\'%s\', date_modification) AS date_modification
- FROM wiki_pages
- WHERE '.$this->_getLectureClause().'
- ORDER BY date_modification DESC;', SQLITE3_ASSOC);
- }
-
- public function countRecentModifications()
- {
- $db = DB::getInstance();
- return $db->simpleQuerySingle('SELECT COUNT(*) FROM wiki_pages WHERE '.$this->_getLectureClause().';');
- }
-
- public function listBackBreadCrumbs($id)
- {
- if ($id == 0)
- return [];
-
- $db = DB::getInstance();
- $flat = [];
-
- while ($id > 0)
- {
- $res = $db->simpleQuerySingle('SELECT parent, titre, uri
- FROM wiki_pages WHERE id = ? LIMIT 1;', true, (int)$id);
-
- $flat[] = [
- 'id' => $id,
- 'titre' => $res['titre'],
- 'uri' => $res['uri'],
- ];
-
- $id = (int)$res['parent'];
- }
-
- return array_reverse($flat);
- }
-
- public function listBackParentTree($id)
- {
- $db = DB::getInstance();
- $flat = [
- [
- 'id' => 0,
- 'parent' => null,
- 'titre' => 'Racine',
- 'children' => $db->simpleStatementFetchAssocKey('SELECT id, parent, titre FROM wiki_pages
- WHERE parent = ? ORDER BY transliterate_to_ascii(titre) COLLATE NOCASE;',
- SQLITE3_ASSOC, 0)
- ]
- ];
-
- do
- {
- $parent = $db->simpleQuerySingle('SELECT parent FROM wiki_pages WHERE id = ? LIMIT 1;', false, (int)$id);
-
- $flat[$id] = [
- 'id' => $id,
- 'parent' => $id ? (int)$parent : null,
- 'titre' => $id ? (string)$db->simpleQuerySingle('SELECT titre FROM wiki_pages WHERE id = ? LIMIT 1;', false, (int)$id) : 'Racine',
- 'children' => $db->simpleStatementFetchAssocKey('SELECT id, parent, titre FROM wiki_pages
- WHERE parent = ? ORDER BY transliterate_to_ascii(titre) COLLATE NOCASE;',
- SQLITE3_ASSOC, (int)$id)
- ];
-
- $id = (int)$parent;
- }
- while ($id != 0);
-
- $tree = [];
- foreach ($flat as $id=>&$node)
- {
- if (is_null($node['parent']))
- {
- $tree[$id] = &$node;
- }
- else
- {
- if (!isset($flat[$node['parent']]['children']))
- {
- $flat[$node['parent']]['children'] = [];
- }
-
- $flat[$node['parent']]['children'][$id] = &$node;
- }
- }
-
- return $tree;
- }
-}
-
-?>
DELETED src/include/index.html
Index: src/include/index.html
==================================================================
--- src/include/index.html
+++ src/include/index.html
@@ -1,1 +0,0 @@
-404 Not FoundNot Found
The requested URL was not found on this server.
Index: src/include/init.php
==================================================================
--- src/include/init.php
+++ src/include/init.php
@@ -271,61 +271,45 @@
* Already loaded filenames
* @var array
*/
static protected $loaded = [];
- static protected $libs = [
- 'utils',
- 'squelette_filtres',
- 'static_cache',
- 'template'
- ];
-
/**
* Loads a class from the $name
* @param stringg $classname
* @return bool true
*/
static public function load($classname)
{
$classname = ltrim($classname, '\\');
- $filename = '';
- $namespace = '';
-
- if ($lastnspos = strripos($classname, '\\'))
- {
- $namespace = substr($classname, 0, $lastnspos);
- $classname = substr($classname, $lastnspos + 1);
-
- if ($namespace != 'Garradin')
- {
- $filename = str_replace('\\', '/', $namespace) . '/';
- }
- }
-
- $classname = strtolower($classname);
-
- if (in_array($classname, self::$libs)) {
- $filename = 'lib.' . $classname . '.php';
- } else {
- $filename .= 'class.' . $classname . '.php';
- }
-
- $filename = ROOT . '/include/' . $filename;
-
- if (array_key_exists($filename, self::$loaded))
+
+ if (substr($classname, 0, 16) == 'Garradin\\Plugin\\')
+ {
+ $classname = substr($classname, 16);
+ $plugin_name = substr($classname, 0, strpos($classname, '\\'));
+ $filename = str_replace('\\', '/', substr($classname, strpos($classname, '\\')+1));
+
+ $path = 'phar://' . PLUGINS_ROOT . '/' . strtolower($plugin_name) . '.tar.gz/lib/' . $filename . '.php';
+ }
+ else
+ {
+ $filename = str_replace('\\', '/', $classname);
+ $path = ROOT . '/include/lib/' . $filename . '.php';
+ }
+
+ if (array_key_exists($path, self::$loaded))
{
return true;
}
- if (!file_exists($filename)) {
- throw new \Exception('File '.$filename.' doesn\'t exists');
+ if (!file_exists($path)) {
+ throw new \Exception('File '.$path.' doesn\'t exists');
}
- self::$loaded[$filename] = true;
+ self::$loaded[$path] = true;
- require $filename;
+ require $path;
}
}
\spl_autoload_register(['Garradin\Loader', 'load'], true);
DELETED src/include/lib.squelette_filtres.php
Index: src/include/lib.squelette_filtres.php
==================================================================
--- src/include/lib.squelette_filtres.php
+++ src/include/lib.squelette_filtres.php
@@ -1,350 +0,0 @@
- 'supprimer_tags',
- 'var_dump',
- ];
-
- static public $filtres_alias = [
- '!=' => 'different_de',
- '==' => 'egal_a',
- '?' => 'choixsivide',
- '>' => 'superieur_a',
- '>=' => 'superieur_ou_egal_a',
- '<' => 'inferieur_a',
- '<=' => 'inferieur_ou_egal_a',
- 'yes' => 'oui',
- 'no' => 'non',
- 'and' => 'et',
- 'or' => 'ou',
- 'xor' => 'xou',
- ];
-
- static public $desactiver_defaut = [
- 'formatter_texte',
- 'entites_html',
- 'proteger_contact',
- 'echapper_xml',
- ];
-
- static public function date_en_francais($date)
- {
- return ucfirst(strtolower(utils::strftime_fr('%A %e %B %Y', $date)));
- }
-
- static public function heure_en_francais($date)
- {
- return utils::strftime_fr('%Hh%I', $date);
- }
-
- static public function mois_en_francais($date)
- {
- return utils::strftime_fr('%B %Y', $date);
- }
-
- static public function date_perso($date, $format)
- {
- return utils::strftime_fr($format, $date);
- }
-
- static public function date_intelligente($date)
- {
- if (date('Ymd', $date) == date('Ymd'))
- return 'Aujourd\'hui, '.date('H\hi', $date);
- elseif (date('Ymd', $date) == date('Ymd', strtotime('yesterday')))
- return 'Hier, '.date('H\hi', $date);
- elseif (date('Y', $date) == date('Y'))
- return strtolower(utils::strftime_fr('%e %B, %Hh%M', $date));
- else
- return strtolower(utils::strftime_fr('%e %B %Y', $date));
- }
-
- static public function date_atom($date)
- {
- return date(DATE_ATOM, $date);
- }
-
- static public function alterner($v, $name, $valeur1, $valeur2)
- {
- if (!array_key_exists($name, self::$alt))
- {
- self::$alt[$name] = 0;
- }
-
- if (self::$alt[$name]++ % 2 == 0)
- return $valeur1;
- else
- return $valeur2;
- }
-
- static public function proteger_contact($contact)
- {
- if (!trim($contact))
- return '';
-
- if (strpos($contact, '@'))
- return ''.htmlspecialchars(strrev($contact), ENT_QUOTES, 'UTF-8').'';
- else
- return ''.htmlspecialchars($contact, ENT_QUOTES, 'UTF-8').'';
- }
-
- static public function entites_html($texte)
- {
- return htmlspecialchars($texte, ENT_QUOTES, 'UTF-8');
- }
-
- static public function echapper_xml($texte)
- {
- return str_replace(''', ''', htmlspecialchars($texte, ENT_QUOTES, 'UTF-8'));
- }
-
- static public function formatter_texte($texte)
- {
- $texte = utils::htmlLinksOnUrls($texte);
- $texte = utils::htmlSpip($texte);
- $texte = utils::htmlGarbage2xhtml($texte);
-
- $texte = self::typo_fr($texte);
-
- return $texte;
- }
-
- static public function typo_fr($str, $html = true)
- {
- $space = $html ? ' ' : ' ';
- $str = preg_replace('/(?:[\h]| )*([?!:»])(\s+|$)/u', $space.'\\1\\2', $str);
- $str = preg_replace('/(^|\s+)([«])(?:[\h]| )*/u', '\\1\\2'.$space, $str);
- return $str;
- }
-
- static public function pagination($total, $debut, $par_page)
- {
- $max_page = ceil($total / $par_page);
- $current = ($debut > 0) ? ceil($debut / $par_page) + 1 : 1;
- $out = '';
-
- if ($current > 1)
- {
- $out .= '« Page précédente - ';
- }
-
- for ($i = 1; $i <= $max_page; $i++)
- {
- $link = ($i == 1) ? './' : './+' . (($i - 1) * $par_page);
-
- if ($i == $current)
- $out .= ''.$i.' - ';
- else
- $out .= ''.$i.' - ';
- }
-
- if ($current < $max_page)
- {
- $out .= 'Page suivante »';
- }
- else
- {
- $out = substr($out, 0, -3);
- }
-
- return $out;
- }
-
- // Compatibilité SPIP
-
- static public function egal_a($value, $test)
- {
- if ($value == $test)
- return true;
- else
- return false;
- }
-
- static public function different_de($value, $test)
- {
- if ($value != $test)
- return true;
- else
- return false;
- }
-
- // disponible aussi avec : | ?{sioui, sinon}
- static public function choixsivide($value, $un, $deux = '')
- {
- if (empty($value) || !trim($value))
- return $deux;
- else
- return $un;
- }
-
- static public function sinon($value, $sinon = '')
- {
- if ($value)
- return $value;
- else
- return $sinon;
- }
-
- static public function choixsiegal($value, $test, $un, $deux)
- {
- return ($value == $test) ? $un : $deux;
- }
-
- static public function supprimer_tags($value, $replace = '')
- {
- return preg_replace('!<[^>]*>!', $replace, $value);
- }
-
- static public function supprimer_spip($value)
- {
- $value = preg_replace('!\[([^\]]+)(?:->[^\]]*)?\]!U', '$1', $value);
- $value = preg_replace('!\{+([^\}]*)\}+!', '$1', $value);
- return $value;
- }
-
- static public function couper($texte, $taille, $etc = ' (...)')
- {
- if (strlen($texte) > $taille)
- {
- $texte = substr($texte, 0, $taille);
- $taille -= ($taille * 0.1);
-
- $texte = preg_replace('!([\s.,;:\!?])[^\s.,;:\!?]*?$!', '\\1', $texte);
- $texte.= $etc;
- }
-
- return $texte;
- }
-
- static public function replace($texte, $expression, $replace, $modif='UsimsS')
- {
- return preg_replace('/'.$expression.'/'.$modif, $replace, $texte);
- }
-
- static public function plus($a, $b)
- {
- return $a + $b;
- }
-
- static public function moins($a, $b)
- {
- return $a - $b;
- }
-
- static public function mult($a, $b)
- {
- return $a * $b;
- }
-
- static public function div($a, $b)
- {
- return $b ? $a / $b : 0;
- }
-
- static public function modulo($a, $mod, $add)
- {
- return ($mod ? $nb % $mod : 0) + $add;
- }
-
- static public function vide($value)
- {
- return '';
- }
-
- static public function concat()
- {
- return implode('', func_get_args());
- }
-
- static public function singulier_ou_pluriel($nb, $singulier, $pluriel, $var = null)
- {
- if (!$nb)
- return '';
-
- if ($nb == 1)
- return str_replace('@'.$var.'@', $nb, $singulier);
- else
- return str_replace('@'.$var.'@', $nb, $pluriel);
- }
-
- static public function date_w3c($date)
- {
- return date(DATE_W3C, $date);
- }
-
- static public function et($value, $test)
- {
- return ($value && $test);
- }
-
- static public function ou($value, $test)
- {
- return ($value || $test);
- }
-
- static public function xou($value, $test)
- {
- return ($value XOR $test);
- }
-
- static public function oui($value)
- {
- return $value ? true : false;
- }
-
- static public function non($value)
- {
- return !$value ? true : false;
- }
-
- static public function superieur_a($value, $test)
- {
- return ($value > $test) ? true : false;
- }
-
- static public function superieur_ou_egal_a($value, $test)
- {
- return ($value >= $test) ? true : false;
- }
-
- static public function inferieur_a($value, $test)
- {
- return ($value < $test) ? true : false;
- }
-
- static public function inferieur_ou_egal_a($value, $test)
- {
- return ($value <= $test) ? true : false;
- }
-}
-
-?>
DELETED src/include/lib.static_cache.php
Index: src/include/lib.static_cache.php
==================================================================
--- src/include/lib.static_cache.php
+++ src/include/lib.static_cache.php
@@ -1,87 +0,0 @@
- (time() - (int)$expire)) ? false : true;
- }
-
- static public function get($id)
- {
- $path = self::_getCachePath($id);
- return file_get_contents($path);
- }
-
- static public function display($id)
- {
- $path = self::_getCachePath($id);
- return readfile($path);
- }
-
- static public function getPath($id)
- {
- return self::_getCachePath($id);
- }
-
- static public function remove($id)
- {
- $path = self::_getCachePath($id);
- return unlink($path);
- }
-
- static public function clean($expire = self::CLEAN_EXPIRE)
- {
- $dir = self::_getCacheDir();
- $d = dir($dir);
-
- $expire = time() - $expire;
-
- while ($file = $d->read())
- {
- if ($file[0] == '.')
- {
- continue;
- }
-
- if (filemtime($dir . '/' . $file) > $expire)
- {
- unlink($dir . '/' . $file);
- }
- }
-
- $d->close();
-
- return true;
- }
-}
DELETED src/include/lib.template.php
Index: src/include/lib.template.php
==================================================================
--- src/include/lib.template.php
+++ src/include/lib.template.php
@@ -1,604 +0,0 @@
-cache = false;
-
- $this->compile_dir = DATA_ROOT . '/cache/compiled';
- $this->template_dir = ROOT . '/templates';
-
- $this->compile_check = true;
-
- $this->reserved_template_varname = 'tpl';
-
- $this->assign('www_url', WWW_URL);
- $this->assign('self_url', utils::getSelfUrl());
-
- $this->assign('is_logged', false);
- }
-}
-
-$tpl = Template::getInstance();
-
-function tpl_csrf_field($params)
-{
- $name = utils::CSRF_field_name($params['key']);
- $value = utils::CSRF_create($params['key']);
-
- return '';
-}
-
-function tpl_form_field($params)
-{
- if (!isset($params['name']))
- throw new \BadFunctionCallException('name argument is mandatory');
-
- $name = $params['name'];
-
- if (isset($_POST[$name]))
- $value = $_POST[$name];
- elseif (isset($params['data']) && isset($params['data'][$name]))
- $value = $params['data'][$name];
- elseif (isset($params['default']))
- $value = $params['default'];
- else
- $value = '';
-
- if (is_array($value))
- {
- return $value;
- }
-
- if (isset($params['checked']))
- {
- if ($value == $params['checked'])
- return ' checked="checked" ';
-
- return '';
- }
- elseif (isset($params['selected']))
- {
- if ($value == $params['selected'])
- return ' selected="selected" ';
-
- return '';
- }
-
- return htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
-}
-
-function tpl_format_tel($n)
-{
- $n = preg_replace('![^\d\+]!', '', $n);
-
- if (substr($n, 0, 1) == '+')
- {
- $n = preg_replace('!^\+(?:1|2[07]|2\d{2}|3[0-469]|3\d{2}|4[013-9]|'
- . '4\d{2}|5[1-8]|5\d{2}|6[0-6]|6\d{2}|7\d|8[1-469]|8\d{2}|'
- . '9[0-58]|9\d{2})!', '\\0 ', $n);
- }
- elseif (preg_match('/^\d{10}$/', $n))
- {
- $n = preg_replace('!(\d{2})!', '\\1 ', $n);
- }
-
- return $n;
-}
-
-function tpl_strftime_fr($ts, $format)
-{
- return utils::strftime_fr($format, $ts);
-}
-
-function tpl_date_fr($ts, $format)
-{
- return utils::date_fr($format, $ts);
-}
-
-function tpl_format_droits($params)
-{
- $droits = $params['droits'];
-
- $out = ['connexion' => '', 'inscription' => '', 'membres' => '', 'compta' => '',
- 'wiki' => '', 'config' => ''];
- $classes = [
- Membres::DROIT_AUCUN => 'aucun',
- Membres::DROIT_ACCES => 'acces',
- Membres::DROIT_ECRITURE=> 'ecriture',
- Membres::DROIT_ADMIN => 'admin',
- ];
-
- foreach ($droits as $cle=>$droit)
- {
- $cle = str_replace('droit_', '', $cle);
-
- if (array_key_exists($cle, $out))
- {
-
- $class = $classes[$droit];
- $desc = false;
- $s = false;
-
- if ($cle == 'connexion')
- {
- if ($droit == Membres::DROIT_AUCUN)
- $desc = 'N\'a pas le droit de se connecter';
- else
- $desc = 'A le droit de se connecter';
- }
- elseif ($cle == 'inscription')
- {
- if ($droit == Membres::DROIT_AUCUN)
- $desc = 'N\'a pas le droit de s\'inscrire seul';
- else
- $desc = 'A le droit de s\'inscrire seul';
- }
- elseif ($cle == 'config')
- {
- $s = '☑';
-
- if ($droit == Membres::DROIT_AUCUN)
- $desc = 'Ne peut modifier la configuration';
- else
- $desc = 'Peut modifier la configuration';
- }
- elseif ($cle == 'compta')
- {
- $s = '€';
- }
-
- if (!$s)
- $s = strtoupper($cle[0]);
-
- if (!$desc)
- {
- $desc = ucfirst($cle). ' : ';
-
- if ($droit == Membres::DROIT_AUCUN)
- $desc .= 'Pas accès';
- elseif ($droit == Membres::DROIT_ACCES)
- $desc .= 'Lecture uniquement';
- elseif ($droit == Membres::DROIT_ECRITURE)
- $desc .= 'Lecture & écriture';
- else
- $desc .= 'Administration';
- }
-
- $out[$cle] = ''.$s.'';
- }
- }
-
- return implode(' ', $out);
-}
-
-function tpl_format_wiki($str)
-{
- $str = utils::htmlLinksOnUrls($str);
- $str = utils::htmlSpip($str);
- $str = utils::htmlGarbage2xhtml($str);
- return $str;
-}
-
-function tpl_liens_wiki($str, $prefix)
-{
- return preg_replace_callback('!!i', function ($matches) use ($prefix) {
- return '';
- }, $str);
-}
-
-function tpl_pagination($params)
-{
- if (!isset($params['url']) || !isset($params['page']) || !isset($params['bypage']) || !isset($params['total']))
- throw new \BadFunctionCallException("Paramètre manquant pour pagination");
-
- if ($params['total'] == -1)
- return '';
-
- $pagination = utils::getGenericPagination($params['page'], $params['total'], $params['bypage']);
-
- if (empty($pagination))
- return '';
-
- $out = '';
-
- return $out;
-}
-
-function tpl_diff($params)
-{
- if (!isset($params['old']) || !isset($params['new']))
- {
- throw new Template_Exception('Paramètres old et new requis.');
- }
-
- $old = $params['old'];
- $new = $params['new'];
-
- require_once ROOT . '/include/libs/diff/class.simplediff.php';
- $diff = \simpleDiff::diff_to_array(false, $old, $new, 3);
-
- $out = '';
- $prev = key($diff);
-
- foreach ($diff as $i=>$line)
- {
- if ($i > $prev + 1)
- {
- $out .= '
|
';
- }
-
- list($type, $old, $new) = $line;
-
- $class1 = $class2 = '';
- $t1 = $t2 = '';
-
- if ($type == \simpleDiff::INS)
- {
- $class2 = 'ins';
- $t2 = '➕';
- $old = htmlspecialchars($old, ENT_QUOTES, 'UTF-8');
- $new = htmlspecialchars($new, ENT_QUOTES, 'UTF-8');
- }
- elseif ($type == \simpleDiff::DEL)
- {
- $class1 = 'del';
- $t1 = '➖';
- $old = htmlspecialchars($old, ENT_QUOTES, 'UTF-8');
- $new = htmlspecialchars($new, ENT_QUOTES, 'UTF-8');
- }
- elseif ($type == \simpleDiff::CHANGED)
- {
- $class1 = 'del';
- $class2 = 'ins';
- $t1 = '➖';
- $t2 = '➕';
-
- $lineDiff = \simpleDiff::wdiff($old, $new);
- $lineDiff = htmlspecialchars($lineDiff, ENT_QUOTES, 'UTF-8');
-
- // Don't show new things in deleted line
- $old = preg_replace('!\{\+(?:.*)\+\}!U', '', $lineDiff);
- $old = str_replace(' ', ' ', $old);
- $old = str_replace('-] [-', ' ', $old);
- $old = preg_replace('!\[-(.*)-\]!U', '\\1', $old);
-
- // Don't show old things in added line
- $new = preg_replace('!\[-(?:.*)-\]!U', '', $lineDiff);
- $new = str_replace(' ', ' ', $new);
- $new = str_replace('+} {+', ' ', $new);
- $new = preg_replace('!\{\+(.*)\+\}!U', '\\1', $new);
- }
- else
- {
- $old = htmlspecialchars($old, ENT_QUOTES, 'UTF-8');
- $new = htmlspecialchars($new, ENT_QUOTES, 'UTF-8');
- }
-
- $out .= '';
- $out .= ''.($i+1).' | ';
- $out .= ''.$t1.' | ';
- $out .= ''.$old.' | ';
- $out .= ''.$t2.' | ';
- $out .= ''.$new.' | ';
- $out .= '
';
-
- $prev = $i;
- }
-
- $out .= '
';
- return $out;
-}
-
-function tpl_select_compte($params)
-{
- $name = $params['name'];
- $comptes = $params['comptes'];
- $selected = isset($params['data'][$params['name']]) ? $params['data'][$params['name']] : utils::post($name);
-
- $out = '