OSD_Aurox™

Documentation


Aurox Documentation

C'est un brouillon de documentation. 😉️

Globals variables

Activer le mode debug dans : conf.php

'debug' => true

API

Permet de retourner des réponses JSON dans un format standardisé compris par toute l'application, y compris par l'interface Front-end. Exemple d'utilisation :

$res = new Api();
$res->status = true;  // status de la réponse
$res->success[] = I18n::t('User updated');
$res->redirect_url = AppUrls::ADMIN_USERS;
$res->returnJsonResponse();
Base::dieOrThrow();

Attributs spéciaux

$res->status : `true` ou `false`.

$res->errors
$res->warnings
$res->infos
$res->success : Messages affichés sous forme de "toast" en JS.

$res->data : Contient les données à transmettre.
$res->html : Si le rendu HTML est fait côté Back-end.
$res->validators : Format spécifique pour la validation des formulaires côté JS côté Front-end.

Cache

Le cache est stocké dans sous forme de fichiers plats. /cache_system_h€re

$cache = new Cache();
$cache_key = "BLOG_CONTACT_MAIL:{$ip}";

// lire le cache
if ($cache->get($cache_key)) {
    // On fait semblant
    Flash::success("Votre message a bien été envoyé.");
    $pass = false;
}

// écrire dans le cache
$cache->set($cache_key, true, 120); // 120 secondes de timeout

// delete dans le cache
$cache->delete($key)

// supprimer tous le cache
$cache->clear()

Csrf

// protéger une vue avec un CSRF qui change à chaque Session
$csrf = Csrf::protect();
// protéger une vue sensible avec un CSRF qui change à chaque Requête
$csrf = Csrf::protect(forcePerRequest: true);
// écrire le token dans un form html
<?= Csrf::inputHtml(); ?>

Base

Base::isMobile()   // retourne bool vrai si tablette ou mobile
Base::dieOrThrow()   // termine l'exect du script via die() ou Throw exeception en cas de test unitaire
Base:asSelectList($array, $value_field = 'name', $key_field = 'id') // retourne un tableau ['id' => , 'name' => ]
Base:redirect($url) // redirect comme il faut
Base:scriptTag($path) // génère la balise script dans le dossier public ex Base:scriptTag('/js/test.js') donnera  <script src='/js/api-request.js?v=1748866031'></script>
Base:cssTag($path) // génère la baslise link css vers un fichier dans le dossier public idem que scriptUrl
<?= Base::scriptTag('/js/main.js') ?> // génère la balise script
<?= Base::cssTag('/css/osd.css') ?> // génère la baslise link 

BaseModel

Alias pour les requêtes SQL via PDO, ce n'est pas un ORM, juste des alias. Il faut faire attention et lire la doc, certains arguments des fonctions sont sensibles au Sqli, et c'est normal. Par contre les arguments utilisés pour la recherche sont sécurisés via bind et PDO.

BaseModel - Pas d'Objet & méthode statique

Une note pour moi-même car je fais souvent l'erreur.
Ne pas basculer en Objet
OSD_Aurox ne doit pas basculer dans le monde de la POO pour gérer ses données et les manipuler.
Si on commence à instancier des objets au lieu de manipuler des tableaux directement, on change de paradigme et on perd tous les bénéfices d’un langage commun et direct avec les enregistrements de la base de données via PDO.

Dès qu’on commence à devoir mettre en objet les données au lieu de simples tableaux, c’est qu’on a perdu l’état d’esprit du Brutalim Dev Design.
On peut faire des méthodes de classe qui prennent un tableau en entrée, injectent des champs ou autre, mais le format des données doit rester des tableaux.
Le format des données métier doit aussi être des tableaux.
Ce n’est pas au développeur d’ajouter des couches d’abstraction pour se faciliter la vie.
La référence des schémas et des relations, c’est la base de données — uniquement elle.
Le type des champs, c’est la base de données qui le définit.
La base de données, via son driver, manipule des tableaux : vos données métier doivent rester sous cette forme.

Méthodes statiques, pas d’état, pas d’effet de bord.
Dans un monde idéal, chaque méthode d’une classe devrait être statique pour manipuler les données.
La classe Model ne doit pas stocker d’état interne sur un enregistrement.
Elle ne fait que prendre des tableaux en entrée, les enrichir et les retourner.
Elle peut aussi retourner de nouveaux tableaux ou des valeurs, mais rien ne doit persister en tant qu’attribut ou état interne d’un objet instancié.

Une table valide doit obligatoirement avoir au minimum ces champs :


create table ma_table
(
    id            int unsigned auto_increment primary key,
    created_at    datetime    default CURRENT_TIMESTAMP null,
    updated_at    datetime    default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP,
    created_by    int         null,
    updated_by    int         null,
    doli_id       int         null, // Si intégration avec Dolibarr
);
                    

Méthode statiques génériques de BaseModel
use \OsdAurox\BaseModel

BaseModel::get(pdo, id: int, [select: string = '*']): mixed // retourne la row via son $id,  sqli possible sur $select
BaseModel::insert(\pdo $pdo, array $entity): int // insère une entité dans la table, retourne l'id de la nouvelle ligne
BaseModel::update(\pdo $pdo, array $entity): bool // met à jour une entité dans la table, retourne true si succès
BaseModel::delete(pdo, id): bool // $id sécurisé

BaseModel::getWithRelations(pdo: PDO, id: mixed): array|null // retourne la row via son $îd, avec les relations pas implémenté par défault
BaseModel::getBy(pdo, field: string, value: mixed): array|false // retourne la row via recherche sur champ, $value sécurisé, $field sqli possible
BaseModel::getAll(pdo: PDO, [orderBy: null|string = 'id'], [orderDir: string = 'ASC'], [limit: int|null = 100]): array
BaseModel::getAllBy(pdo, field: string, value: mixed): // retourne les rows via recherche sur champ, $value sécurisé, $field sqli possible
BaseModel::getByIds(pdo, table: string, ids: array, [select: string = '*']): array // retourne les row via PDO::FETCH_ASSOC , $table et $select sont sensibles au Sqli, par contre $ids est sécurisé
BaseModel::getValueFrom(PDO: PDO, id: mixed, field: string): null|string // Récupère une valeur spécifique d'une table en fonction de l'ID et du champ demandé.
BaseModel::count() // total d'un table
BaseModel::check_uniq(pdo, field, value): bool // regarde si la valeur pour le champ est unique en table, sqli possible sur $field, securisé sur $value

BaseModel::idsExistsOrEmpty(pdo, table: string, ids: array): bool // retourne True si $ids est vide ou si les $ids existent bien dans la table de la bdd, sinon False

BaseModel::getRules(): array // retourne une liste des OsdAurox\Validator liés à ce modele
BaseModel::canEdit(pdo: PDO, id : int) // retourne vrai si l'utilisateur logué actuel peut éditer cette entité pas implémenté par défault
BaseModel::canEditOrDie(pdo: PDO, id : int); // comme canEdit mais die() si pas accès à l'entitée

BaseModel::canView(pdo: PDO, id : int) // retourne vrai si l'utilisateur logué actuel peut acceder cette entité pas implémenté par défault
BaseModel::canViewOrDie(pdo: PDO, id : int); // comme canView mais die() si pas accès à l'entitée


BaseModel::validate(): bool


BaseModel::getSelect([required: bool = true], [selected: mixed|null = null], [domId: string = 'legalform-select'], [name: string = 'legalform-id'], [select2: bool = true]): string// retourne un element Select HTML

$array = BaseModel::jsonArrayAggDecode($wine, 'myKey');  // Raccourcis pour extraire un JSON_ARRAYAGG ou [ ] si erreur; d'un résultat Array PDO
// SELECT JSON_ARRAYAGG( JSON_OBJECT( 'id', wg.id, 'name', wg.name, 'name_translated', COALESCE(NULLIF(wg.name_$locale, ''), wg.name, '') )
>>> [ [ 'id' => 1, 'name' => 'foo', 'name_translated' => 'bar'], ... ]
                    
Conseils de nommage des méthodes
use \OsdAurox\BaseModel
// Conseils de nommage des méthodes

BaseModel::getWith<RelationName>(\PDO $pdo, mixed $id): array // Pour les méthodes qui retournent un array entité en chargeant des relations spécifiques
BaseModel::getAllFor<RelationName>(\PDO $pdo, mixed $id): array // Pour les méthodes qui retournent un array d'entitées dans un contexte spécifique
BaseModel::getSelectFor<FieldName>(\PDO $pdo, [required: bool = true], [selected: mixed|null = null], [domId: string = 'legalform-select'], [name: string = 'legalform-id'], [select2: bool = true])): string // Retourne un select HTML
BaseModel::calc<VarName>(\PDO $pdo, $entity): mixed value // Pour les méthodes qui calculent des champs dynamiques
BaseModel::fetch<FieldName>(\PDO $pdo, $entity): mixed value // Quand on doit aller récupérer un champ unique d'une relation ou autre
BaseModel::translate<VarName>(array $entity): string // Pour les méthodes qui retournent des noms internes traduits
BaseModel::format<VarName>(array $entity): string // Pour les méthodes qui formatent des noms internes pour affichage
BaseModel::gen<VarName>(array $entity): mixed value // Pour les méthodes qui génèrent des compteurs ou nom spéciaux, des path
BaseModel::count<Name>(\PDO $pdo): int // Pour les méthodes qui comptent des rows sans calculs COUNT != SUM
BaseModel::resolve<RelationName>(\PDO $pdo, array $entity): array // Pour les méthodes qui cherchent et injectent dans l'array une relation dans $array['<relation_table_name>'] = array
BaseModel::resolveAll(\PDO $pdo, array $entity): array // Pour les méthodes qui cherchent et injectent dans l'array tous les Resolve
BaseModel::update<fieldName>() // Pour les méthodes qui mettent à jour un Field spécifique et commit

Conseils de nommage des méthodes passerelle modéles locaux / Dolibarr
use \OsdAurox\BaseModel
// Conseils de nommage des méthodes
public const TABLE_DOLI  // stocker le nom de la table Dolibarr
BaseModel::doliExist(\PDO $pdo, array $entity): array // Vérifie si une entitée existe chez Dolibarr
BaseModel::doliInsert(\PDO $pdo, array $entity): array // Crée une entité chez Dolibarr + ajoute l'id Doli dans l'entitée actuelle
BaseModel::doliUpdate(\PDO $pdo, array $entity): array // Met à jour une entité chez Dolibarr
BaseModel::doliDelete(\PDO $pdo, array $entity): array // Supprime une entité chez Dolibarr
Validation de données via getRules()

La méthode Basemodel::getRules() renvoi un array qui sert pour le Classe Validator, il permet de valider une Entité provenant d'un formulaire avant de l'envoyer dans une Table.
OSD_Aurox s'inspire de la syntaxe de Dolibarr pour définir les règles de validations dans $fields.


$validator = new Validator($fields, $arrayDate);
$errors =  $validator->validate(); // valide l'entité et retourne les erreurs
$cleanedArray = $validator->clean(); // retourne un array avec uniquement les valeurs valides
                    

Types de champs
Type Description Options supplémentaires
integer | int Valeur entière
boolean | bool Valeur booléenne
fk Clé étrangère fkTableName, fkFieldName, fkClassModel
varchar Chaîne de caractères minLength, maxLength
text Texte long
html Texte avec HTML autorisé
float Valeur décimale
price Prix
date Date dateFormat
datetime Date et heure dateTimeFormat
mail Adresse email
phoneFr Numéro de téléphone français minLength, maxLength
url URL minLength, maxLength
Options générales
Option Description Exemple
options Valeurs du select array("0"=>"Draft","1"=>"Active","-1"=>"Cancel")
label Nom du champ (sera traduit via I18n)
default Valeur par défaut
notEditable Indique si le champ est éditable true/false
comment Commentaire interne (non affiché)
required Champ obligatoire true/false
optional Champ optionnel true/false
Validateurs
Validateur Type Description
minLength null | int Longueur minimale (alias dispo len)
maxLength null | int Longueur maximale (alias dispo len)
len null | [1, 255] Alias de minLength + maxLength
min null | int Valeur minimale
max null | int Valeur maximale
notEmpty null | bool Le champ doit avoir une valeur autre que '', ' ', null
startWith ['motif'] Le champ doit commencer par le motif spécifié
positive null | bool Le champ doit être un entier positif
inArray ['Val1', ...] La valeur du champ doit être dans ce tableau
regex null | bool Regex pour valider le champ
dateFormat null | bool Format de date, par défaut 'Y-m-d'
dateTimeFormat null | bool Format de date et heure, par défaut 'Y-m-d H:i:s'
fkTableName null | bool Nom de la classe
fkFieldName null | bool Champ de la classe
doublePrecision null | bool Précision pour les valeurs décimales (ex: 24)
doubleScale null | bool Échelle pour les valeurs décimales (ex: 8)
startWithCaseSensitive null | bool Indique si la règle startWith est sensible à la casse
alpha null | bool S'assurer que le champ est de type alphanumérique sans caractères spéciaux ni espaces
numericString null | bool S'assurer que le champ est de type string, mais contient uniquement des nombres. Ex : Zip
Options HTML/DOM // idée de Dolibarr pas encore utilisé
Option Description Exemple
class Style CSS en mode création/édition 'maxwidth200'
classView Style CSS en mode visualisation 'wordbreak'
classList Style CSS pour les colonnes en liste 'tdoverflowmax200'
help Texte d'aide
disabled Si le champ doit être désactivé 1
autoFocusOnCreate Si le champ doit avoir le focus lors de la création 1

Exemple :

                    
$rules = [
            'username' => ['type' => 'varchar', 'optional' => true, 'notEmpty' => true, 'minLength' => 3, 'maxLength' => 10],
            'mail' => ['type' => 'mail', 'required' => true, 'minLength' => 3, 'maxLength' => 10]
         ];
$entity = [
            'username' => 'foo',
            'mail' => 'mail@example.com'
         ];
$validator = new Validator($rules);
$errors = $validator->validate($entity);
if ($errors) {
    // $errors est un array de tableau associatif
}


$cleanedArray = $validator->clean();
// $cleanedArray est un array de tableau associatif avec uniquement les champs qui ont passé la validation sans erreurs
                    
                

LOG

Écris les logs dans /logs/

Log::info()
Log::debug()
Log::warning()
Log::error()

Dict

Utilitaire et Alias pour les dictionnaires

Dict::get(\$array, \$key, \$default == null)

Récupérer la valeur d'une clef ou defaut, null.

$tab = ['couleur' => 'bleu', 'prix' => 99]
Dict::get($tab, 'couleur')
>>> 'bleu'
Dict::get($tab, 'clef_existe_pas')
>>> null
Dict::get($tab, 'clef_existe_pas', 'defaut_vert')
>>> 'defaut_vert'

Dict:Base::isInArrayAndRevelant()

Retourne vrai si la clef existe Et qu'elle est pertinante. Ignore ces valeurs: ['null', 'undefined', 'None', '', '0', ' ']

$tab = ['ok' => '1', 'ko' => 'null']
Dict::isInArrayAndRevelant($tab, 'ok')
>>> true
Dict::isInArrayAndRevelant($tab, 'ko')
>>> false
Dict::isInArrayAndRevelant($tab, 'clef_existe_pas')
>>> false

Discord

Discord configuration

Ajouter le webhook dans conf.php

'discordWebhook' => 'https://discord.com/api/webhooks/{key}';

Discord::send(\$message)

Envoyer un message sur un chan discord via webhook

Discord::send($message);

ErrorMonitoring

Permet d'alerter sur discord en PROD Si des fatal errors arrivent

ErrorMonitoring::initialize();

Filter

Utilitaire pour les templates PHP

<?= Filter::truncate($text, $length, $ending= '...') ?>
>>> Mon super texte ...

<?= Filter::dateFr($date) ?>    // préférez I18n::date($date) pour le formatage automatique en fonction de la locale
>>> d/m/Y

<?= Filter::dateMonthFr($date) ?>
>>> Avril 2025

<?= Filter::dateUs($date) ?> // préférez I18n::date($date) pour le formatage automatique en fonction de la locale
>>> Y-m-d

<?= Filter::toDayDateUs($date) ?>
>>> Y-m-d // (date du jour direct)

Flash

Injecte les messages par catégorie dans $_SESSION['messages']

Flash::error()
Flash::success()
Flash::info()
Flash::warning()
Flash::add()
Flash::get($clear=false) // peut récupérer tous les messages et les effacer de $_SESSION

Fmt

Permet de changer l'affichage de certain champs dans les tempaltes / formulaire

Fmt::bool($field)
>>> Yes / No, Oui / non (I18n)

Forms

Alias et raccourcis pour générer des formulaires HTML Boostrap

todo

Forms()

Forms::valueAttrOrBlank(entity: array, key: string, [safe: bool = false]): string // Gère le champ value='' dans un input en lui passant une entité

Exemple d'utlisation

Forms()

$formValidator = new FormValidator();
$myEntity = ['title' => 'A title']

$form = new Forms(AppUrls::LOGIN, $formValidator, $myEntity);
<?= $form->input('title', required: true, id: 'title') ?>

Validator & FormValidator

Permet de créer des règles pour valider un tableau associatif

use OsdAurox\Validator

// règles
$rules = [
    'email' => Validator::create('email')->email(),
    'username' => Validator::create('username')->notEmpty(),
];

// données à validées
$data = [
'email' => 'invalid-email',
'username' => '',
];


// vérification d'une seule règle via Validator::validate()
$rule[0]->validate($data['email'])
>>> [ 0 => [ 'field' => 'email', 'valid' => false, 'msg' => 'must be valid email', ] ]


// FormValidator permet de valider directement un tableau provenant d'un Formulaire
// vérification via un FormValidator::validate($data, $rules)
$validator = new FormValidator();
$result = $validator->validate($data, $rules);
>>> $result == False // validation échouée
$errors = $validator->getErrors(); // on regarde les erreurs
>>> [ 'username' => [ 0 => 'must not be empty', ], 'email' => [ 0 => 'must be valid email' ] ]

Validator disponibles

Note : required() > optionnal()

use OsdAurox\Validator

Validator::optional() // la règle ne lève pas d'erreur si le champ est empty
Validator::required() // si présent le champ est requis, même si optional() est actif

Validator::notEmpty() // une valeur non vide
Validator::stringType()
Validator::intType()
Validator::floatType()

Validator::email()
Validator::positive() // int ou float, str > 0

Validator::date() // string date au format 'Y-m-d'
Validator::dateTime() // string date au format 'dateTime'

Validator::length([min: int|null = null], [max: int|null = null])
Validator::max(maximum: float|int)
Validator::min(minimum: float|int)
Validator::inArray(allowedValues: array, [strict: bool = false])

Validator::startWith(prefix: string, [caseSensitive: bool = true])

On peut les enchaîner

result = Validator::create('field')
    ->required()
    ->intType()
    ->min(0)
    ->max(100)
    ->validate(50);

Les traductions des Validateurs sont stockées dans : src/OsdAurox/Translations.php C'est chargé par le module I18n.php

FormsFilter

Query builder pour côté Admin

todo

Internationalization : I18n

Les fichiers de traductions sont recherchés dans : /translations/, exemple : /translations/fr.php
Aurox utilise aussi des traductions écrites en dur dans /src/OsdAurox/Translations.php

use OsdAurox\I18n;
// initialisation du traducteur dans le scope $GLOBALS
$GLOBALS['i18n'] = new I18n('en');

// support des traductions classiques via la recherche dans /translations/<locale>.php - protégé Xss
$r = I18n::t('English');
>>> English
I18n::t('English')
>>> Anglais

// Prend un tableau associatif, et retourne la traduction liée en fonction de la locale actuelle - protégé Xss
$entity = [
    'name' => 'default',
    'name_en' => 'trad_en',
    'name_fr' => 'trad_fr',
    'name_it' => 'trad_it',
];
$r = I18n::entity($entity);
>>> 'trad_en'
// avec une clef autre que name
$entity = [
    'key' => 'default',
    'key_en' => 'trad_en',
    'key_fr' => 'trad_fr',
    'key_it' => 'trad_it',
];
$r = I18n::entity($entity, fieldName: 'key');
>>> 'trad_en'

// Récupérer la traduction d'une date formatée en fonction de la locale actuelle - protégé Xss
$date = '2025-04-01';
I18n::date($date)
>>> '2025-04-01'

// Récpérer la traduction d'une dateTime formatée en fonction de la locale actuelle - protégé Xss
// on peut modifier les formats en ajoutant les clef '__date' et '__dateTime' dans /translations/<locale>.php
// les formats par défault sont définit dans /src/OsdAurox/Translations.php
// exemple : '__date' => 'd/m/Y H:i'
//
$date = '2025-04-01 12:00:00';
I18n::dateTime($date)
>>> '2025-04-01 12:00'
// Avec les secondes
I18n::dateTime($date, showSec: True)
>>> '2025-04-01 12:00'


// locale actuelle
$locale = I18n::currentLocale();
>>> 'fr'

// Modifier la locale actuelle
$GLOBALS['i18n']->setLocale('fr');


// Récupérer le d'un champ localisé en fonction de la locale actuelle
$field = getLocalizedFieldName([fieldName: string = 'name']): string;
>>> name_fr || name_en
$field = I18n::getLocalizedFieldName('otherField');
>>> otherField_fr || otherField_en

Mailer

Envoyer des mails via PHP

$mail_sent = Mailer::send(to: $mail_to, subject: $mail_subject, content: $html_content);

Paginator

todo

Sec

use OsdAurox\Sec

Sec::isPost() // true si POST
Sec::getParam(string $key, string $type, int $source)   // récupère un paramètre POST ou GET, en cas d'erreur retourne null - XSS possibles filtre d'entrée - POST est prioritaire sur GET voir Sec::getParam()
Sec:getAction(string $default,  int $source)  // lit 'action' en POST+GET et standardise sa lecture sécurisée - XSS protégé
Sec::sanitize(mixed $value, string $type = 'aZ09') // idem que getParam() mais appliqué à l'argument passé, au lieu de chercher dans POST / GET - XSS protégé
Sec::jsonDatas()   // Retourne une request JSON en tableau

Sec::getRealIpAddr()  // retourne vrai adresse ip du src request

Sec::h($string) // alias htmlspecialchars
Sec::hNoHtml($string) // alias htmlspecialchars + suppression tags HTML
Sec::hArrayKey(array: array, key: string): array // alias htmlspecialchars hNoHtml sur tableau
Sec::hArrayInt(array: array, key: string): array  // alias htmlspecialchars hNoHtml sur tableau + cast en (int)

Sec::safeForLikeStrong($string)   // sécurise fortement un string pour son utilisation en LIKE SQL
Sec::safeForLike($string)   // sécurise légerement un string pour son utilisation en LIKE SQL

Sec::isAdminOrDie($flash = true, $redirect = true)    // regarde le $_SESSION['user']['role']
Sec::isAdminBool()    // regarde le $_SESSION['user']['role'] == 'admin'
Sec::isRoleOrDie($role, $flash = true, $redirect = true)
Sec::isRoleBool($role)  // $role == 'user' , regarde si $_SESSION['user']['role'] == $role et retourne true / false
Sec::isLogged($flash = true, $redirect = true)
Sec::isLoggedBool()  // retourne true ou false si utilisateur connecté
Sec::getUserIdOrDie() // retour l'id de l'user courant ou lève une exception

Sec::setRateLimit(int $seconds, int $maxRequests = 10, string $endpoint = ''): bool // met un taux de requête par secondes et retourn un bool si atteint
Sec::setRateLimitOrDie(int $seconds, int $maxRequests = 10, string $endpoint = ''): void // idem  setRateLimit mais va die() si la limite est atteinte

Sec::noneCsp() // retourne le NONCE Csp courant (typo)

Sec::getPage() // méthode securisée pour lire le $_GET['page']
Sec::getPerPage() // méthode securisée pour lire le $_GET['per_page']

Sec::uuidV4() // génère un UUID v4

Sec::storeReferer(); // enregistre le referer de la req actuelle
Sec::getReferer(); // retourne le referer de la req precedente
Sec::redirectReferer(); // redirect sur Referer si existe

Sec::getParam()

Cette méthode permet de récupérer et nettoyer un paramètre depuis les variables globales $_GET, $_POST ou $_REQUEST.

Sec::getParam(string $key, string $type = 'aZ09extra', int $source = 3): mixed

Paramètres :

  • $key : Clé du paramètre à récupérer
  • $type : Type de nettoyage à appliquer (défaut: 'aZ09extra')
  • $source : Source du paramètre:
    • 0 pour GET
    • 1 pour POST
    • 2 pour REQUEST
    • 3 pour POST puis GET (défaut)

Retourne : La valeur nettoyée selon le type spécifié, ou null si non trouvée ou invalide

Exemple d'utilisation :

// Récupérer un paramètre GET 'id' comme entier
$id = Sec::getParam('id', 'int', 0);

// Récupérer un paramètre POST 'email' et le valider comme email
$email = Sec::getParam('email', 'email', 1);

// Récupérer un paramètre POST ou GET 'name' et nettoyer pour conserver uniquement caractères alphabétiques
$name = Sec::getParam('name', 'alpha');

Types de sanitisation disponibles

La méthode Sec::getParam() utilise en interne la méthode sanitize() qui propose plusieurs types de nettoyage :

Type Description Comportement
int Conversion en entier Transforme la valeur en entier via casting
float Conversion en nombre flottant Remplace la virgule par un point et convertit en float
date_us Date US Accepte uniquement une date au format YYYY-MM-DD (année-mois-jour), nettoie le HTML et valide la date. Retourne une chaîne vide si le format ou la date est invalide.
datetime_us DateTime US Accepte uniquement une date et heure au format YYYY-MM-DD HH:MM:SS, nettoie le HTML et valide la date/heure. Retourne une chaîne vide si le format ou la date/heure est invalide.
price Extraction et conversion pour un prix Supprime tous les caractères non numériques sauf ',' et '.' puis convertit en float
bool Conversion en booléen Transforme la valeur en booléen via casting
email Validation d'adresse email Utilise filter_var avec FILTER_VALIDATE_EMAIL
ip Validation d'adresse IP Utilise filter_var avec FILTER_VALIDATE_IP
ipv4 Validation d'adresse IPv4 Utilise filter_var avec FILTER_VALIDATE_IP et FILTER_FLAG_IPV4
ipv6 Validation d'adresse IPv6 Utilise filter_var avec FILTER_VALIDATE_IP et FILTER_FLAG_IPV6
url Validation d'URL Utilise filter_var avec FILTER_VALIDATE_URL
alpha Caractères alphabétiques uniquement Supprime tout sauf a-zA-Z
alphaextra Caractères alphabétiques, espaces et tirets Supprime tout sauf a-zA-Z, espaces et tirets
aZ09 Caractères alphanumériques uniquement Supprime tout sauf a-zA-Z0-9
aZ09extra Caractères alphanumériques uniquement, espaces et tirets Supprime tout sauf a-zA-Z0-9, espaces et tirets
09 Caractères numériques uniquement format string Supprime tout sauf 0-9
nohtml Suppression des balises HTML Applique strip_tags()
alphanohtml Caractères alphabétiques sans HTML Combine strip_tags() et suppression de tout sauf a-zA-Z
restricthtml HTML restreint Conserve uniquement certaines balises HTML basiques (<b>, <i>, <u>, <strong>, <em>)
raw Aucune modification Convertit en string + trim() ⚠️ XSS possible

Remarque importante : Les tableaux sont systématiquement rejetés et retournent null.

Exemples d'utilisation :

// Récupérer un paramètre GET 'price' et le nettoyer comme un prix
$price = Sec::getParam('price', 'price', 0); // 12,99€ -> 12.99

// Récupérer un paramètre POST 'description' en conservant seulement les balises HTML de base
$description = Sec::getParam('description', 'restricthtml', 1);

// Récupérer un paramètre 'username' en supprimant tous les caractères non alphanumériques
$username = Sec::getParam('username', 'aZ09');

Cette méthode constitue une couche de sécurité essentielle pour manipuler les données d'entrée utilisateur, en garantissant qu'elles sont correctement validées et nettoyées avant utilisation dans l'application.

Captcha

Le module Captcha ajoute une vérification humaine ultra-légère basée sur un code court rendu côté serveur (GD) et stocké en $_SESSION. L’utilisateur doit saisir un caractère affiché dans l’image.

Fonctions publiques

use OsdAurox\Captcha;

// (Ré)génère et stocke en session un code aléatoire (A-Z, a-z, 2-9, sans caractères ambigus)
Captcha::generateCode(int $length = 5): void

// Vérifie que la saisie correspond au premier caractère du code courant (insensible à la casse)
Captcha::verify(?string $input): bool

// Retourne un fragment HTML complet (image + label + input + bouton de rafraîchissement)
Captcha::captchaHtml(): string

Captcha - minimal (serveur)

use OsdAurox\Flash;
use OsdAurox\Sec;
use OsdAurox\Captcha;

// Au premier chargement
if (!Sec::isPost()) {
    Captcha::generateCode();
}

// À la soumission
if (Sec::isPost()) {
    $captcha = Sec::getParam('captcha'); // nettoyage de base
    if (Captcha::verify($captcha)) {
        Flash::success('Captcha valide ! Vous avez entré la bonne lettre.');
        // ... suite du traitement
    } else {
        Flash::error('Captcha invalide ! La lettre entrée est incorrecte.');
        Captcha::generateCode(); // on régénère pour la prochaine tentative
    }
}

Captcha - exemple (vue)

<form method="post">
    <div class="mb-3">
        <?= Captcha::captchaHtml() ?>
    </div>

    <button type="submit" class="btn btn-primary">Vérifier</button>
</form>

Personnalisation & i18n

  • Taille de l’image : ajuste $width/$height selon ton design.
  • Texte du label : passe la chaîne traduite au paramètre $label ou via I18n::t() :
    label: I18n::t('Entrez le 1er caractère').
  • Accessibilité : le fragment HTML génère un <label for="..."> et un alt sur l’image.
  • Rafraîchissement : le rendu inclut un bouton pour régénérer l’image côté serveur sans recharger la page.

Bonnes pratiques (sécurité)

  • CSRF : combine toujours avec Csrf::protect().
  • Rate-limit : pour limiter le brute-force, ajoute :
    Sec::setRateLimitOrDie(seconds: 5, maxRequests: 20, endpoint: 'captcha');
  • Ne jamais exposer le code complet côté client ; seule l’image (base64) est envoyée.
  • Régénère le code après un échec (Captcha::generateCode()) pour éviter la réutilisation.

Flux type recommandé

  1. Au premier affichage de la page : Captcha::generateCode().
  2. Dans le formulaire : Captcha::captchaHtml().
  3. À la soumission : Captcha::verify() → en cas d’échec, flash d’erreur + generateCode().

Dépendances

  • Extension PHP GD activée (rendu de l’image).
  • Session PHP active (stockage du code).

ViewsShortcuts

Vue complete en tant que méthode

ViewsShortCuts::ListThisDirView($dir)

Ban - Waf

// ban system
Ban::blockBlackListed();
Ban::checkRequest();

# La liste des words sensibles dans les urls est ici
Ban->$black_list_words

# Le waf de base s'utilise comme ça
Ban::blockBlackListed(); # 1 on regarde si l'ip est déjà bannie
Ban::checkRequest(); # 2 on regarde si la requete, son url actuelle mérite en ban

# Ban directement
Ban:ban()  # recherche l'ip réelle de la requête actuelle et la ban directement

# Ban sur detection de motif suspect en GET & POST
$r = Ban::banIfHackAttempt();
if($r) {
    Discord::send('[BAN] Hack attempt detected on ' . Sec::hNoHtml(AppConfig::get('appName')) . ' by ' . Sec::hNoHtml(Sec::getRealIpAddr()));
}

AppConfig

use OsdAurox\AppConfig
AppConfig::get('key', 'default') // recherche une clef dans /conf.php et retourne la valeur
AppConfig::isDebug() // retourne vrai si l'application est en mode debug conf['debug'] = true

Routage & Urls : AppUrls

OSD_Aurox utilise le routage traditionnel, càd par arborescence de dossiers.
C'est le plus simple, intuitif et efficace.
Il permet de ne charger que ce qui est utile sans avoir besoin d'un script de routage.
Néamoins, l'ensemble des End Point, url, route doivent être listés dans app/AppUrls.php
Si vous avez besoin de faire un lien interne dans l'application il faut utiliser la syntaxe suivante :

<?= Sec::hNoHtml(AppUrls::HOME) ?>
ou sans échappement vu que le contenu de AppUrls.php est normalement sûr
<?= AppUrls::HOME ?>

class AppUrls
{
    public const HOME = '/';
    public const LOGIN = '/auth/login.php';
    public const LOGOUT = '/auth/login.php?action=logout';
    //... à vous de completer
    public const PAGE_DOC = '/doc.php';
    public const PAGE_CONVENTION = '/convention.php';
    public const PAGE_CONF = '/config.php';

    // cron
    public const CRON_SYNC_CUSTOMERS = '/cron/sync_customers.php';
    //... à vous de completer

    // ajax
    public const AJAX_USERS = '/ajax/users.php';
    //... à vous de completer
}
                    

Utils protection view

$nonce_csp

Forms

TODO

$form = new Forms($action_url,
                    validator: $validator,
                    entity: $user ?? null,
                    ajax: isset($user));
<?= $form->formStart(autocomplete: false) ?>
<?= $form->input('email', type: 'email', required: true) ?>
<?= if($use ?? null) ? $form->input('password', type: 'password', placeholder: 'Mot de passe', required: true) : '' ?>
<?= $form->select2Ajax(
    ajax_url: AppUrls::ADMIN_COMPANIES . '?action=select2',
    name: 'id_company',
    id: 'id_company',
    label: 'Company',
    selected: $user['id_company'] ?? null,
)
?>
<?= $form->select2($l_users_types, 'id_user_type', selected: $user['type'] ?? 3) ?>
<?= $form->select($l_roles, 'role', value_field: 'value', name_field: 'label', selected: $user['role'] ?? 'user') ?>
<?= $form->checkbox('active', checked: $user['active'] ?? true) ?>
<?= $form->input('country') ?>
<?= $form->submit(I18n::t('Save')) ?>
<?= $form->formEnd() ?>
<?php if ($user ?? null): ?>
    <?= $form->ajaxSubmit() ?>
<?php endif; ?>


<?= $form->errorDiv('fieldName') ?> 

MobileDetect

Une re-implémentation de Detection\MobileDetect en version plus "light" intégré au Core de Aurox

À noter, une Table retournera "Vrai" aussi sur isMobile();

Il y a un Alias dans Base::isMobile() qui retourne Vrai si Mobile ou Tablet Il est recommandé d'utiliser directement Base::isMobile() au lieu de MobileDetect

use OsdAurox\MobileDetect();
$detect = new MobileDetect();
$detect->isMobile()
$detect->isTablet()

Images

use OsdAurox\Image

Image::resize(sourcePath: string, maxWidth: int, maxHeight: int): string   // redimensionne une image
Image::reduceToMaxSize(sourcePath: string, [maxSize: float|int = 2]): string // réduit la qualité d'une image par boucle jusqu'à la taille indiqué
Image::resizeAndReduce(sourcePath: string, maxWidth: int, maxHeight: int, maxSize: float): string // redimensionne puis réduit la taille

Modal

La classe Modal fournit un système léger pour créer et gérer des fenêtres modales Bootstrap 5 dans l'application Aurox.

Par default le template de la modale doit se trouver dans templates/core/modal.php

$modal = new Modal(title, msg, [type: string = 'info'], [template = null], [btnAccept = null], [btnCancel = null],
                                [id: string = 'modal-default'], [class: string = 'modal fade'], [showClose: true = true],
                                [showInput: false = false], [showBtn: true = true])
<?php
use OsdAurox\Modal;
?>
<?= Modal::newModal('Ma petite Modal', 'Contenu de la modal', 'info') ?>
<div class="row">
    <div class="col-12">
        <button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#modal-default">
            Modale classique #1
        </button>
    </div>
</div>

<?= Modal::newLoader(showClose: True) ?>
<div class="row mt-2">
    <div class="col-12">
        <button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#modal-loader">
            Modale de chargement #2
        </button>
    </div>
</div>

<?= Modal::newPrompt(showClose: True) ?>
<div class="row mt-2">
    <div class="col-12">
        <button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#modal-prompt">
            Modale de saisie #3
        </button>
    </div>
</div>

loader-manager.js

Permet d'afficher une modale bloquante de chargement

Js

src : Js.php

Js est un module un peu osé, josé.
Il permet de générer du Javascript depuis PHP, un peu Frankenstein mais pratique.
Ce ne sont que des alias.

Js::consoleLog
injecte <script>console.log('$msg')</script> dans la page via echo.
Usage :
Js::consoleLog(msg: mixed|string, [safe: bool = False]): void
Exemple :
Js::consoleLog('Hello World')

Cron

Les tâches CRON sont dans public/cron
Le préfixe pour AppUrls est AppUrls::CRON_MA_TACHE
Le résultat de la tâche doit être stocké dans API->datas.
Les tâches doivent répondre du JSON au format OsdAurox\Api.


use OsdAurox\Api;

$res = new Api();
$res->status = true;
$res->datas['updated'] = 1; // Exemple de données à renvoyer
$res->datas['created'] = 0; // Exemple de données à renvoyer
$res->datas['ignored'] = 0; // Exemple de données à renvoyer
$res->returnJsonResponse();

Base::dieOrThrow();

Ajax

Les route Ajax sont dans public/ajax Le préfixe pour AppUrls est AppUrls::AJAX_MA_TACHE Les route doivent répondre du JSON au format OsdAurox\Api.
Le contenu de la réponse doit être stocké dans API->datas.

Exemple : AJAX_ROULETTE
Code : /public/ajax/roulette.php


use OsdAurox\Api;

$res = new Api();
$res->status = true;
$res->datas['key'] = 'value'; // Exemple de données à renvoyer
$res->returnJsonResponse();

Base::dieOrThrow();

Mise à jour Doc : 2025-12-05 10:24
Dépôt osd84/aurox - Tests Passed ✅ - le 2025-12-05 08:28