Wiki [Tuto/HowTo] [Debian/Ubuntu] Clusteriser vos bases de données MariaDB avec Galera Cluster et HaProxy

0
21
sept.
2017

Sommaire

Présentation

Un Cluster de base de données est un ensemble de serveurs reliés entre eux via réseau afin de créer un ensemble virtuel utilisant la réplication des données pour protéger les bases de données contre une éventuelle panne (machine, réseau).

HaProxy va servir de pont (proxy) entre les clients et les serveurs du cluster de base de données. C'est un répartiteur de charge (load balancer) qui va choisir le serveur le plus facilement accessible (le moins occupés) lorsqu'un client veut effectuer une action sur les BDD. Il n'est pas obligatoire au bon fonctionnement du cluster, juste une belle optimisation.

Galera Cluster quant à lui permet de créer/gérer le cluster mariaDB. Il va aussi s'occuper de la redondance des données (leur multiplication dans la grappe).

Un serveur peut tout à fait cumuler répartiteur de charge HaProxy et serveur de base de données Galera Cluster.

Attention : Si vous devez reboot une machine du cluster, vous devrez probablement lancer cette commande sur un des Noeuds et relancer les autres.

sed -ie '/safe_to/c\safe_to_bootstrap: 1' /var/lib/mysql/grastate.dat
mysqld_safe --wsrep-new-cluster

Limitations

source : MariaDB Galera Cluster : la réplication multi maitres

Mise en place de Galera Cluster + mariadb

Passez en administrateur (root)
  • Sur Ubuntu / Raspbian
sudo su
  • Sur Debian / Ubuntu Minimal
su
Ajoutez clés et dépôts pour la dernière version (10.2.x)
  • Sur Ubuntu 16.xx
apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8
add-apt-repository 'deb [arch=amd64,i386,ppc64el] http://mariadb.cu.be/repo/10.2/ubuntu xenial main'
  • Sur Debian 8 (Jessie) / Raspbian Jessie
sudo apt-get install software-properties-common
sudo apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 0xcbcb082a1bb943db
sudo add-apt-repository 'deb [arch=amd64,i386,ppc64el] http://mariadb.mirror.nucleus.be/repo/10.2/debian jessie main'
  • Sur Debian 9 (stretch)
sudo apt-get install software-properties-common dirmngr
sudo apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 0xF1656F24C74CD1D8
sudo add-apt-repository 'deb [arch=amd64,i386,ppc64el] http://mariadb.mirror.nucleus.be/repo/10.2/debian stretch main'
Installez la dernière version de mariadb-server et galera
apt-get update
apt-get install -y mariadb-server galera-3

éventuellement l'Arbitrator (attention, ne réplique PAS les base de données mais reçoit autant de requête)

apt-get install galera-arbitrator-3
Créez /etc/mysql/conf.d/galera.cnf
nano /etc/mysql/conf.d/galera.cnf
  • Ensuite ajoutez dedans
[mysqld]
#mysql settings
binlog_format=ROW
default-storage-engine=innodb
innodb_autoinc_lock_mode=2
query_cache_size=0
query_cache_type=0
innodb_flush_log_at_trx_commit=0
innodb_buffer_pool_size=256M
bind-address=10.8.1.42

#Galera settings
wsrep_provider=/usr/lib/libgalera_smm.so
#SSL for Galera
#wsrep_provider_options="socket.ssl_key=/etc/mysql/ssl/server-key.pem;socket.ssl_cert=/etc/mysql/ssl/server-cert.pem;socket.ssl_ca=/etc/mysql/ssl/ca-cert.pem"
wsrep_cluster_name="monSuperCluster"
wsrep_cluster_address="gcomm://10.8.1.42,10.8.1.43,10.8.1.44"
wsrep_sst_method=rsync
wsrep_on=ON
wsrep_node_address="10.8.1.42"
wsrep_node_name="monJoliNom"
  • Ajoutez à wsrep_cluster_address= les hostnames de vos machines séparés par des virgules par exemple
wsrep_cluster_address="hostnameMachine1,hostnameMachine2,hostnameMachine3"

Note : il est déconseillé de spécifier des adresses IP, privilégiez plus tôt des noms de domaines dont vous ferez la correspondance soit dans votre serveur DNS, soit dans vos fichiers /etc/hosts.

  • Vérifiez à default_storage_engine= qu'InnoDB est bien le moteur par défaut (vous pouvez éventuellement le remplacer par un autre moteur tant qu'il est compatible avec galera)
default_storage_engine=InnoDB
  • Spécifiez éventuellement à innodb_buffer_pool_size= combien mémoire (RAM et Swap) InnoDB peut consommer
innodb_buffer_pool_size=256M

Note : la doc conseille de prendre la valeur qu'on utilise sur un serveur lambda et de réduire l'utilisation mémoire de 5% afin de ne pas subir une augmentation dû a l'utilisation du cluster.

  • Le nom du cluster (doit obligatoirement être identique sur chaque Node)
wsrep_cluster_name="monSuperCluster"
  • L'adresse du Node
wsrep_node_address="10.8.1.42"
  • Le nom du Node
wsrep_node_name="monJoliNom"
  • Le provider du Node (paramètre wsrep_provider)
wsrep_provider=/usr/lib/libgalera_smm.so
  • Au choix /usr/lib/libgalera_smm.so ou /usr/lib/galera/libgalera_smm.so
Autoriser dans AppArmor le cluster à utiliser des ports non root (source)
sudo ln -s /etc/apparmor.d/usr /etc/apparmor.d/disable/.sbin.mysqld
sudo service apparmor restart
Sur certaines machines le fichier /etc/mysql/my.cnf n'existe pas. Si c'est le cas, créez le en copiant le contenu suivant
[a vérifier] Si vous partez d'une base de données mysql/mariadb déjà existante, vous devez l'upgrade vers galera (source)
Sur un des nodes arrêtez mariadb
service mysql stop
Ensuite initialisez le cluster
sudo /usr/bin/galera_new_cluster
Relancez mariadb sur tout les Nodes
service mysql restart
Testez si ça fonctionne
mysql -u root -p -e "SHOW STATUS LIKE 'wsrep_cluster_size';"
Si vous avez l'erreur "ERROR 1524 (HY000): Plugin 'unix_socket' is not loaded", sur tout les nodes, resetez les password admin :
service mysql stop
mysqld_safe --skip-grant-tables &
mysql -uroot
use mysql;
update user set password=PASSWORD("MY_NEW_PASSWORD_HERE") where User='root';
update user set plugin="mysql_native_password";
quit;
/etc/init.d/mysql stop
kill -9 $(pgrep mysql)
/etc/init.d/mysql start

Installation d'un répartiteur de charge HaProxy pour Galera Cluster

Note : vous pouvez le ou les installer sur des machines dédiés, ou sur un ou plusieurs de vos serveurs de bases de données (dans ce dernier cas, veillez à écouter sur des ports différents si non conflit). Vous pouvez aussi directement l'installer sur un client.

Installez les pré-requis
apt-get update
apt-get install haproxy
Éditez la valeur ENABLED=0 à ENABLED=1 dans les fichiers /etc/default/haproxy et /etc/init.d/haproxy
sed -i "s/ENABLED=0/ENABLED=1/g" /etc/default/haproxy
sed -i "s/ENABLED=0/ENABLED=1/g" /etc/init.d/haproxy
Éditez /etc/haproxy/haproxy.cfg
sudo nano /etc/haproxy/haproxy.cfg
Adaptez puis ajoutez
# Load Balancing for Galera Cluster
listen galera
bind 10.8.0.66:3306
balance leastconn
mode tcp
option tcpka
option mysql-check user haproxy
server hostnameNode1 10.8.1.42:3306 check weight 1
server hostnameNode2 10.8.1.43:3306 check weight 1
server hostnameNode3 10.8.1.44:3306 check weight 1
  • listen galera => Format "listen numUnique". Identifie notre bloc de configuration.
  • bind 10.8.0.66:3306 => adresseIP:port sur quelle adresse le serveur HaProxy doit-il écouter (si vous passez par des tunnels SSH, choisissez 127.0.0.1). Si votre répartiteur est sur la même machine que le cluster de Base De Données, pensez à lui attribuer un port différent. (qu'il faudra mentionner aux clients) Le caractère magique * est autorisé.
  • mode tcp => choisissez tcp
  • balance leastconn => l’algorithme de répartition de charge (load balancing). Accepte : roundrobin , leastconn, source. (informations) option mysql-check user haproxy => on demande a HaProxy de tenter de se connecter à la base de données du cluster
  • stats => configurer la WEBUI pour administrer HaProxy depuis votre navigateur

    • listen stats 127.0.0.1:8080 => adresseIP:port sur quelle adresse le serveur Web doit écouter/répondre pour la WEBUI (si vous passez par tunnels SSH ou Tor Hidden Service indiquez 127.0.0.1 comme IP et prenez un port inutilisé (peu importe lequel tant que vos ne l’oubliez pas)
    • stats enable|disable => activer|désactiver la WEBUI
Commentez option httplog puis sauvez et quittez avec CTRL+X
Sur le cluster Galera, créez l'utilisateur dédié à HaProxy
mysql -u root -p -e "CREATE USER 'haproxy'@'10.8.1.%';"
  • 10.8.1.% => ici on autorise les connexions entrantes depuis les adresses IP allant de 10.8.1.0 à 10.8.1.255, remplacez par une seule adresse si vous le souhaitez (déconseilez si vous souhaitez pouvoir utiliser plusieurs répartiteur de charge)
Démarrez HaProxy
service haproxy restart

Ajouter un serveur à Galera Cluster

Installez votre serveur en suivant la procédure ci-haut.
Sur chacun de vos Nodes éditez le fichier /etc/mysql/conf.d/galera.cnf afin d'ajouter l'hostname de votre nouveau serveur. La valeur à éditer est wsrep_cluster_address (CTRL+W pour chercher), comme suit
wsrep_cluster_address="gcomm://hostnameServer1,hostnameServer2,hostnameServer3"
Sur chacun de vos Nodes éditez le fichier /etc/hosts afin d'ajouter la correspondance entre adresse IP et nom de domaine pour votre nouveau serveur. Par exemple
10.8.0.42 penséeprofonde
10.8.0.43 server1
10.8.0.44 server2
  • Note : A moins d'avoir spécifié "bind 0.0.0.0" (= écoute sur toutes les IP) sur vos différents Noeuds, il est primordiale de joindre les ip que vous avez spécifiez en écoute. Si par exemple sur server1 vous avez spécifiez "bind 10.8.0.43" (= écoute uniquement sur 10.8.0.43) alors il faut obligatoirement joindre ce serveur sur cette adresse (même 127.0.0.1 et localhost ne fonctionneront pas!).

Connecter un client au Cluster Galera

Installez le client mysql/mariadb

apt-get install -y mariadb-client

Si vous souhaitez pouvoir 'l'utiliser depuis php, installez le module php-mysql

apt-get install php-mysql

Pour vous connecter à vos Bases De Données, spécifiez comme host au choix votre Répartiteur de charge HaProxy ou directement un de vos serveurs Galera. N'oubliez pas de bien joindre les IP que vous avez spécifiez en écoute à moins d'avoir choisis "bind 0.0.0.0".

Du point de vue client le cluster va se comporter comme un simple serveur mysql/mariadb. N'oubliez pas néanmoins de toujours utiliser des clés primaires dans vos tables de données.


Quelques commandes

Afficher des infos à propos du cluster (toutes les variables "wsrep_").
mysql -u root -p -e "show status like 'wsrep%';"
Afficher des infos à propos des utilisateurs de vos Base de Données.
mysql -u root -p -e "select host, user, password from mysql.user;"
Créer un utilisateur et sa Base de Données
mysql -u root -p -e "CREATE DATABASE MA_BASE; GRANT ALL PRIVILEGES ON MA_BASE.* TO 'monUSER'@'10.8.1.%' identified by 'monPass'; FLUSH PRIVILEGES;"
  • Traduction : Créer la base de données intitulée MA_BASE. Ensuite donner accès à MA_BASE à l'utilisateur monUSER depuis n'importe quelle adresse du réseau 10.8.1.x et dont le mot de passe est monPass (en claire).
Changer mot de passe utilisateur
mysql -uroot -p -e "UPDATE mysql.user SET Password=PASSWORD('monNouveauPASS') WHERE USER='monUSER';"
Changer Host accepté pour un utilisateur
mysql -uroot -p -e "UPDATE mysql.user SET Host='%.%.%.%' WHERE USER='monUser';"
  • Dans l'exemple ici on autorise toutes les IP sources pour l'utilisateur monUser.
Checker combien de Nœuds sont connecté.
mysql -u root -p -e "SHOW STATUS LIKE 'wsrep_cluster_size';"
  • Cette commande est très utile pour vérifier qu'une machine est bien connectée au cluster.

screenshot-2017_08_22-Commade_Galera_Cluster_mariadb_Status_Cluster

Supprimer une Base de Données.
mysql -uroot -p -e "DROP DATABASE maBaseDeDonnées;"
Supprimer un utilisateur
mysql -uroot -p -e "DROP USER ‘identifiant’@’serveur’;"

OpenDBViewer 1.0.1, lecteur de base de données léger SQLite & MySQL

Posté par (page perso) . Édité par Davy Defaud, ZeroHeure, Yvan Munoz, Pierre Jarillon et palm123. Modéré par Xavier Claude. Licence CC by-sa
Tags :
27
12
sept.
2017
Base de données

OpenDBViewer est un petit logiciel qui permet dans une interface très simple de se connecter à une base de données SQLite ou MySQL.

Je l’avais d’abord conçu en Python pour mes besoins personnels et professionnels. Ce logiciel a été ensuite converti en C++ avec Qt. Bien qu’il soit opérationnel, beaucoup de choses pourraient l’améliorer. Pour cela, les contributions des utilisateurs et des développeurs sont chaleureusement espérées.

Arkiv : Sauvegarde de fichiers et bases MySQL + archivage sur Amazon S3 et Amazon Glacier

Posté par (page perso) . Édité par ZeroHeure, Davy Defaud et Xavier Claude. Modéré par Yvan Munoz. Licence CC by-sa
26
13
août
2017
Administration système

Pour mes besoins personnels et professionnels, j’ai développé un script pour sauvegarder mes données (fichiers présents sur le disque local et bases de données MySQL) et les archiver sur Amazon S3 et Amazon Glacier.

Il est possible de choisir la fréquence de sauvegarde (jusque toutes les heures si nécessaire) et de définir une politique précise pour la purge des données. Il est ainsi possible d’avoir un comportement du type :

  • sauvegarde toutes les heures : les données sont enregistrées en local et envoyées sur Amazon S3 et Amazon Glacier ;
  • toutes les sauvegardes sont gardées en local pendant deux jours, puis on garde quatre sauvegardes par jour (une toutes les six heures) pendant cinq jours, puis une par jour pendant deux semaines, puis elles sont effacées ;
  • toutes les sauvegardes sont gardées sur Amazon S3 pendant deux semaines, puis on garde six sauvegardes par jour (une toutes les quatre heures) pendant deux semaines, puis deux par jour pendant un mois, puis elles sont effacées ;
  • toutes les données sont gardées sans limite de temps sur Amazon Glacier.

Le choix des services cloud d’Amazon se veut pragmatique. Amazon S3 est très utilisé pour stocker des données auxquelles on veut pouvoir accéder rapidement. Amazon Glacier est très pratique pour enregistrer des données sur le long terme pour un coût très bas.

Ce script propose une interface de configuration en ligne de commande qui se veut facile à utiliser. Les fichiers journaux se veulent aussi les plus lisibles possibles.

Forum Linux.général --== GUIDE DE L'ADMINISTRATEUR LINUX ==--

Posté par (page perso) . Licence CC by-sa
13
23
juin
2017

Bonjour à toutes et à tous,

Je mets à disposition un guide sur l'installation et l'administration des systèmes Linux (et Unix).

Ce document de bientôt 80 pages est le fruit de quelques années d’expériences professionnelles, et continue à me servir régulièrement. Effectivement j'ai eu des responsabilités en tant qu'ingénieur systèmes, mais aussi en tant que consultant-formateur. Il ne s'agit pas simplement de théories ou de méthodes bidouillées dans mon coin, mais il s'agit bien d'un document de référence utilisé en (...)

Forum Linux.général Mysql refuse de démarrer sur ubuntu 12.04

Posté par . Licence CC by-sa
0
9
juin
2017

Hello all

Pouvez vous m'aider?
Je ne comprends pas pourquoi mysql s'est arrêté d'un coup sans qu'on ne touche à rien et refuse de redémarrer.

Merci de votre aide.

voici le contenu du fichier de log de mysql

#--------------mysql.err----------------------------
InnoDB: End of page dump
170609 18:10:10  InnoDB: Page checksum 918991256, prior-to-4.0.14-form checksum 1886869800
InnoDB: stored checksum 918991256, prior-to-4.0.14-form stored checksum 3700301661
InnoDB: Page lsn 2 835419976, low 4 bytes of lsn at page end 835419739
InnoDB:
(...)

Forum Programmation.SQL Optimisation MySQL : fail

Posté par . Licence CC by-sa
Tags :
4
20
mai
2017

Bonjour, j'ai eu l'idée saugrenue de vouloir optimiser mon serveur MySQL (5.5, Debian) vu que je suis passé de 32G à 64G de RAM.
Visiblement ce fut une très mauvaise idée car depuis mes requêtes sont horriblement lentes (CPU à 100%) et restaurer le my.cnf dans son état d'origine n'a rien changé ! Ni même rebooter le serveur (oui j'ai vraiment tout essayé …) Du coup je ne comprends pas.

Concrètement j'ai 2 bases, une Innodb d'environ 400Mo et une MyISAM (...)

Forum Linux.général [Tuto/HowTo] Protéger ses Bases de Données MySQL/MariaDB contre les pannes matérielles - Partie 1

2
27
avr.
2017

Préambule

  • Sur certains sites (LinuxFR par ex) on reproche souvent aux auto-hébergés d'avoir une faible résistance aux pannes et d'être incapable de créer une infrastructure capable de tenir à travers le temps ni de monter en charge. Ce tuto fais partie d'une série de tutos visant à résoudre cette problématique en apportant des systèmes et méthodologies compréhensible et applicable par des noobs.
  • Au moins 80% de la procédure est applicable via copier-coller.
  • Il va de soit que vous pouvez remplacer (...)

Wiki Tuto - Chercher présence d'une sous chaîne dans une chaîne avec MySQL grâce à LIKE

1
25
fév.
2017

Introduction

Admettons que nous possédions une table "articles" contenant une cellule "quelleCategorie". Dans cette cellule nous indiquons une ou plusieurs catégories pour chaque articles comme dans l'exemple suivant :

    id | nomArticle | quelleCategorie | dateCreation
    1 | banane | fruits | 5
    2 | jus d'orange | jus de fruits | 9
    3 | tomate | fruits ; legumes | 22
    4 | maison | immobilier | 42

Admettons que nous désirons récupérer tout les articles ayant "fruit" dans "quelleCategorie". Avec l'option LIKE nous allons pouvoir spécifier un filtrage par motif (ou "pattern matching") afin de récupérer banane, jus d'orange et tomate et ce même si chacun possède une version légèrement différente de la catégorie.
À noter que vous pouvez aussi utiliser NOT LIKE qui vous permet de faire exactement l'inverse : demander à MySQL de ne retourner que les chaînes où n'est PAS présent le pattern.
Attention : une mauvaise utilisation de LIKE peut engendrer une chute des performances et une augmentation du travail pour le CPU du serveur MariaDB/MySQL.

L'exemple suivant va sélectionner dans la table "articles" tout les éléments ayant dans leur cellule "quelleCategorie" la sous-chaîne contenue dans la variable $categorieChoisie, classés du plus récent aux plus anciens.

<?php
$bdd_hostname = "localhost";
$bdd_name = "nomDeMaBase";
$bdd_login = "loginDeMaBase";
$bdd_password = "passowrdDeMaBase";
try {
    $bdd = new PDO('mysql:host='.$bdd_hostname.';dbname='.$bdd_name.';charset=utf8', $bdd_login, $bdd_password);
} catch( Exception $e){
    error_log("Error BDD connexion from ".$_SERVER["PHP_SELF"]);
}

$categorieChoisie = "fruit";

$requestSQL = $bdd->prepare('SELECT `*` FROM articles WHERE `quelleCategorie` LIKE %{:categorieChoisie}%  ORDER BY `dateCreation`');
$requestSQL->bindParam(':categorieChoisie', strval($categorieChoisie), PDO::PARAM_STR);
$requestSQL->execute();
$myArticles = $requestSomeArticles->fetchAll(PDO::FETCH_CLASS);
print_r($myArticles);
?>

Explication en détails :

  1. On tente de connecter PDO à la base de données, si on réussi on obtient l'objet $bdd si non on retourne une erreur dans les logs (/var/log/apache2/error.log pour apache2)
try {
    $bdd = new PDO('mysql:host='.$bdd_hostname.';dbname='.$bdd_name.';charset=utf8', $bdd_login, $bdd_password);
} catch( Exception $e){
    error_log("Error BDD connexion from ".$_SERVER["PHP_SELF"]);
}
  1. On défini notre sous chaîne à rechercher : fruit
$categorieChoisie = "fruit";
  1. On demande a PDO de préparer notre requête à partir de l'objet $bdd
$requestSQL = $bdd->prepare('SELECT `*` FROM articles WHERE `quelleCategorie` LIKE %{:categorieChoisie}%  ORDER BY `dateCreation`');
  • Ici on lui demande de tout (*) récupérer dans "articles" où "quelleCategorie" ressemble à la chaîne injectée, ordonnée (ORDER BY) par leur date de création.
  1. On injecte le paramètre de recherche (fruit)
$requestSQL->bindParam(':categorieChoisie', strval($categorieChoisie), PDO::PARAM_STR);
  1. On exécute la requête SQL
$requestSQL->execute();
  1. On récupère le résultat de la requête SQL sous forme d'objet
$myArticles = $requestSomeArticles->fetchAll(PDO::FETCH_CLASS);
  1. Si vous préférez récupérer sous forme de tableau, remplacez la précédente ligne par les suivantes
$myArticles = array();
while($tmpArticle = $requestSomeArticles->fetch(PDO::FETCH_ASSOC)){
    $myArticles[] = $tmpArticle;
}
  1. On affiche le résultat
print_r($myArticles);

Wiki Tuto Ajax - afficher au format JSON des articles e-shop depuis MySQL-MariaDB grâce à PHP

0
23
fév.
2017

Sommaire

Niveau requis pour utilisation : moyen.
Nécessite au moins PHP5.4+ avec PDO (php-mysql)
Ce tutoriel s'intègre dans une suite de tutoriel permettant d'appréhender l'ajax voir Farm Link à la fin du wiki.

Introduction

  • Nous allons ici étudier un script PHP, rédigé par votre humble serviteur en programmation fonctionnelle, permettant de faire de l'ajax. L'objectif d'origine de ces fonctions est de recevoir les requêtes GET provenant d'une interface cliente (page web angularjs) d'une boutique en ligne, de récupérer des articles depuis une table de Base de Données puis afficher les informations au format JSON.
    Le but de ce topic est de vous aider a mettre en place le plus rapidement possible une fonction ajax côté serveur (pour les tuto côté client il faudra voir du côté du Farm Link en bas de page).

  • Donc ce script analyse les variables $_GET afin de récupérer les informations lui permettant de forger des requêtes SQL. Ensuite il récupère les informations de la base de données MySQL/MariaDB et les affiche dans un JSON.
    Pour fonctionner il faut bien entendu disposer d'une base de données contenant une table (nom gérable via $tableName) et contenant au moins les cellules : id, categorie.
    Afin d'éviter les doublons entre deux requêtes clientes lorsque des articles ont des informations recherchées quasi identique: lors d'une requête GET le client doit mentionner les articles qu'il a visionné dernièrement en ajoutant dans ses requêtes GET les variables banItemX = identifiant article à bannir comme dans l'exemple suivant : ajax.php?banItem1=6&banItem2=7&banItem3=8

  • La sécurité anti injection SQL est gérée suivant les cas par les requêtes préparées de PDO ou par une moulinette qui vérifie la correspondance entre la table de données et les infos postées par l'utilisateur puis qui injecte les infos depuis la base de données en lieu et place des données envoyées par l'user. Sauf pour les $_GET["banItemX"] qui eux sont directement convertis en integer afin de casser toutes injections.

Les paramètres GET acceptés par le script :

Paramètres obligatoires :

  • &articleMax=[integer] gère la LIMITE SQL (nombre d'entrées max à renvoyer)
  • &orderByAttributs=[string] l'attribut pour ORDER BY (par exemple l'id, le prix, etc)
  • &orderByAttributsLastValue=[float] la valeur la plus haute (ou basse selon la recherche) de l'attribut ORDER BY afin de commencer la recherche à partir de là
  • &categorie=[string] le nom de la catégorie d'article (peut facilement être remplacer par une seconde condition de recherche)
  • &orderByType=[1|-1] décide du sens de la recherche (1 pour plus petit au plus grand (> et ASC), -1 pour plus grand au plus petit (< et DESC))

Paramètres optionnels :

  • &forceChangeOrderSymbole=[1|2] 1 pour > (plus grand que) ou 2 pour < (plus petit que) permet de changer le sens de la recherche sans affecter le reste (ASC ou DESC). Par défaut 1 (>) est sélectionné.
  • &banItem1=[integer] reçoit les identifiants à bannir (peut avoir un nombre "infini" (voir limite GET) ex: banItem2, banItem3, etc). Par défaut aucun élément n'est bannis.

Exemples :

  • www.hostname.be/ajaxArticles.php?articleMax=10&orderByAttributsLastValue=42&orderByAttributs=prix&orderByType=1&categorie=film

    • On demande à voir les 10 prochains articles, classé par la cellule prix du plus petit au plus grand à partir du prix 42, de la catégorie film

Le code

Pour l'installer créez un ajaxArticles.php et collez le code suivant dedans.

<?php
/*  Licence GPLv3 - Papa :  voxdemonix
    infos : https://www.0rion.netlib.re/forum4/viewtopic.php?f=79&t=541&p=1156#p1156
*/
/*  Je vous conseil d'insérer tout le bloc try dans un fichier séparé protégé par un .htaccess (deny for all)  */
try {
    /*  éditez les informations nécessaire pour la connexion à la base de données   */
    $bdd = new PDO('mysql:host='.$main["bdd_Hostname"].';dbname='.$main['bdd_Name'].';charset=utf8', $main['bdd_Login'], $main['bdd_Pass']);
} catch( Exception $e){
    error_log("ajax -> Error BDD connexion from ".$_SERVER["PHP_SELF"]);
}

    $tableName = "Articles";



    function displayInJsonMyArray($myArray){
        header('Content-type: application/json');
        print_r( json_encode($myArray, JSON_NUMERIC_CHECK)  );
    }



    function articleOrderByList(){
            //MYSQL
        global $bdd;
        $searchCategorieArticle = $bdd->prepare('SELECT * FROM '.$tableName.' LIMIT 1');
        $searchCategorieArticle->execute();

            //RECOVER THE RESULT IN A TAB
        $tabCategorie = $searchCategorieArticle->fetch(PDO::FETCH_ASSOC);
        $tab = array();

            //READ THE TAB AND MAKE THE OPTIONS'S TAG
        foreach ($tabCategorie as $key => $value) { 
            $tab[] = $key;
        }
        return $tab;
    }


    function articleCategorieList(){
        $liste = array(); global $bdd;
        $searchCategorieArticle = $bdd->prepare('SELECT `categorie` FROM '.$tableName);
        $searchCategorieArticle->execute();

            //MAINTENANT LISTE LES CATEGORIES DANS $tmpCategorie, (PERMET AUSSI DE CRÉER UN FORMULAIRE SELECT)
        while($tmpCategorie = $searchCategorieArticle->fetch(PDO::FETCH_ASSOC)){
            if (!in_array($tmpCategorie["categorie"], $liste)) {
                $liste[] = $tmpCategorie["categorie"];
            //  var_dump($tmpCategorie); echo '<br />';
            }
        }
        return $liste;
    }


    function genBanItemForMySQLRequest(){
        $banRequest = '';
        foreach( $_GET as $key => $value){
            if (stripos( ' '.$key , 'banItem' )){
                $banRequest .= ' AND (id != '.intval($value).')';   
            }
        }
        return $banRequest;
    }


    /*
        EXPLICATIONS :
    reçoit des variables GET du style :
opt     &banItem1= reçoit les identifiants a bannir (peut avoir un nombre "infini" (voir limite GET) ex: banItem2, banItem3, etc)
        &articleMax= gère la LIMITE SQL (nombre d'entrée max a renvoier)
        &orderByAttributs= l'attribut pour ORDER BY (par exemple l'id, le prix, etc)
        &orderByAttributsLastValue= la valeur la plus haute (ou basse selon la recherche) de l'attribut ORDER BY afin de commencer la recherche a partir de là
        &categorie= la categorie d'article (peut facilement être remplacer par une seconde condition de recherche)
        &orderByType= decide du sens de la recherche (1 pour plus petit au plus grand (> et ASC), -1 pour plus grand au plus petit (< et DESC))
opt     &forceChangeOrderSymbole= permet de changer le sens (< ou >) de la recherche sans affecter le reste (ASC ou DESC)
    */




    $forceChangeOrderSymbole = 0; //if = 1 => > (plus grand que); if = 2 => < (plus petit que)
    if(filter_has_var(INPUT_GET, "forceChangeOrderSymbole")){
        if(isset($_GET["forceChangeOrderSymbole"]) & !empty($_GET["forceChangeOrderSymbole"])){
            switch(intval($_GET["forceChangeOrderSymbole"])){
                case 1 :
                case '1':
                    $forceChangeOrderSymbole = 1;
                break;
                case 2 :
                case '2':
                    $forceChangeOrderSymbole = 2;
                break;              
            }
        }
    }
    if ( filter_has_var(INPUT_GET, "articleMax") & filter_has_var(INPUT_GET, "orderByType") & filter_has_var(INPUT_GET, "orderByAttributs") & filter_has_var(INPUT_GET, "orderByAttributsLastValue")) {
        $wichCategorie = "all";
        if (filter_has_var(INPUT_GET, "categorie")) {
            $wichCategorie = strval($_GET["categorie"]); //categorie = idForTraduct, not the traducted version (https://www.0rion.netlib.re/forum4/viewtopic.php?f=9&t=211)
        }
        displaySomeArticleInJSONUniversal($_GET["articleMax"], $wichCategorie, $_GET["orderByAttributs"], $_GET["orderByAttributsLastValue"]);
    }


    function displaySomeArticleInJSONUniversal($nbLimit, $categorie, $inputOrderByAttributs, $inputOrderByAttributsLastValue){
        // $iMinimal = l'identifiant unique minimal de l'article, afin d'envoyer les suivants
        global $bdd; //PDO object
        global $forceChangeOrderSymbole;

        $orderByAttributs = 'id'; $orderByAttributsLastValue = 1;
        /* security */
        if(in_array(strval($inputOrderByAttributs) , articleOrderByList())){
            $orderByAttributs = strval($inputOrderByAttributs);
            $orderByAttributsLastValue = $inputOrderByAttributsLastValue;
        }
        $orderByType = 'ASC'; $orderSymbole = '>';
        if(strval($_GET["orderByType"]) == '-1'){
            $orderByType = 'DESC';
            $orderSymbole = '<';    
        }
        if($forceChangeOrderSymbole == 2){ $orderSymbole = '<'; }
        if( strval($categorie == "all") || !in_array(strval($categorie), articleCategorieList() )   ){
            $requestSomeArticles = $bdd->prepare("SELECT * FROM ".$tableName." WHERE `".$orderByAttributs."` ".$orderSymbole."= :orderByAttributsLastValue ".genBanItemForMySQLRequest()." ORDER BY `".$orderByAttributs."` ".$orderByType.", `id` ASC LIMIT :nbLimit");
        }else{
            $requestSomeArticles = $bdd->prepare("SELECT * FROM ".$tableName." WHERE `".$orderByAttributs."` ".$orderSymbole."= :orderByAttributsLastValue AND `categorie` = :categorie ORDER BY `".$orderByAttributs."` ".$orderByType.", `id` ASC LIMIT :nbLimit");
            $requestSomeArticles->bindParam(':categorie', strval($categorie), PDO::PARAM_STR);
        }

        $requestSomeArticles->bindParam(':nbLimit', intval($nbLimit), PDO::PARAM_INT);
        $requestSomeArticles->bindParam(':orderByAttributsLastValue', floatval($orderByAttributsLastValue), PDO::PARAM_STR);

        $requestSomeArticles->execute();
        //$myArticles = $requestSomeArticles->fetchAll(PDO::FETCH_CLASS); 
        $myArticles = array();
            while($tmpArticle = $requestSomeArticles->fetch(PDO::FETCH_ASSOC)){
                $myArticles[] = arrayUniversalTraductor($tmpArticle);
            }
        displayInJsonMyArray($myArticles);
    }
?>

Fonctionnement en détail :

Note : ne serons mentionné que les noms des fonctions, leur fonctionnement et les types de sorties (avec des exemples). Il n'y aura pas de copier-coller de morceaux de code afin d'éviter de devoir éditer le tutoriel à chaque édition du code source.

Listes des fonctions :

  1. articleOrderByList()
  2. articleCategorieList()
  3. genBanItemForMySQLRequest()
  4. displaySomeArticleInJSONUniversal($nbLimit, $categorie, $inputOrderByAttributs, $inputOrderByAttributsLastValue)
  5. displayInJsonMyArray($myArray)

articleOrderByList()

  • Récupère la liste des attributs possible (nom de cellule) pour la table de données.
    • Exemple de sorties :
$liste[1] = "film"
$liste[2] = "séries"
$liste[3] = "musiques"

articleCategorieList()

  • Retourne une liste sous forme d'un array contenant les noms des différentes catégories sans doublon.
    • Exemple de sorties :
$liste[1] = "id"
$liste[2] = "prix"
$liste[3] = "nom"
$liste[4] = "timeCreation"

genBanItemForMySQLRequest()

  • Récupère les identifiants des articles à bannir de la prochaine requête SQL. Utilise les variables $_GET[banItemX] afin de générer un morceau de requête SQL du type ' AND (id != '.intval($_GET[banItemX]).')' à insérer avant l'ORDER BY.
    • Exemple de sorties :
    $stringMorceauRequeteSQL = ' AND (id != 1) AND (id != 2) AND (id != 3) AND (id != 5) AND (id != 9) AND (id != 8)'

displaySomeArticleInJSONUniversal($nbLimit, $categorie, $inputOrderByAttributs, $inputOrderByAttributsLastValue)

  • La fonction displaySomeArticleInJSONUniversal($nbLimit, $categorie, $inputOrderByAttributs, $inputOrderByAttributsLastValue) est précédée d'un bloc de code chargé d'appréhender certaines informations envoyées par l'utilisateur avant d’exécuter la dite fonction. C'est la fonction principale : chargée de forger et exécuter la requête SQL, insérer les résultats dans un tableau (array) puis l'envoyer à displayInJsonMyArray($myArray).

displayInJsonMyArray($myArray)

  • Fonction toute banale recevant un tableau (array) et affichant les informations contenues via print_r() au format JSON avec la vérification des entiers.

-


-

-


-

Note pour la rédaction :

  • il faut encore simplifier le tuto, ajouter des exemples (et mettre en place un exemple en ligne afin que les lecteurs puissent tester (comme dans cet exemple lié à ce tuto))
  • le code aurait besoin d'une fraîcheur afin de le rendre plus compréhensible et généralisable au max (le but étant qu'un lecteur néophyte puisse copier-coller, éventuellement avec une légère modification puis en route)
  • des exemples d'utilisations suivront (un avec javascript et un avec angular 4)

Journal Gnew 2016.2

Posté par (page perso) . Licence CC by-sa
11
3
août
2016

Bonjour à tous,

Je souhaiterais vous faire part de la disponibilité de la version 2016.2 de Gnew (gestionnaire de contenu simple pour les publications web).

Voici la liste des nouveautés de cette version :

  • Ajout de la propriété CSS word-break dans les citations pour éviter les débordements
  • Ne pas afficher l'adresse e-mail dans les flux lorsque l'utilisateur ne le veut pas
  • Correction de la suppression des utilisateurs invalides sans utiliser le lien Purger les utilisateurs (administration)
  • Amélioration des suppressions (administration) (...)

Journal Présentation de freeostorrent.fr

27
16
juil.
2016

Freeostorrent.fr rassemble des OS libres (Systèmes d'exploitation) et les propose au téléchargement par l'intermédiaire du protocole Bittorrent.
Il est complémentaire des projets officiels qui possèdent déjà leurs services Bittorrent (distributions Gnu/Linux ou xBSD, projets divers, …) et s'adresse premièrement aux projets plus modestes qui recherchent un moyen simple de partager librement leurs travaux.

Conçu au départ comme une "étude de cas" pour un "béotien" désirant enfin apprendre - un peu - le PHP, le site est à l'origine un tracker (...)

Forum Programmation.php Gestion des accents dans un projet php/mysql...

Posté par . Licence CC by-sa
2
2
juin
2016

Bonjour à tous,

Avant de poser la question, je vais resituer le contexte : j'ai commencé à contribuer à un logiciel dont j'avais besoin pour mon boulot (non, je ne dirais pas lequel, non pas que ce soit hyper confidentiel, mais j'estime que ce n'est pas à moi de faire de la pub pour ce logiciel…). Comme indiqué dans le sujet, c'est un projet en PHP/Mysql qui n'a jamais pris le temps de gérer correctement le problème des accents.

Aujourd'hui (...)

Forum Programmation.php PHP7, passage de variable tableau d'un template blade à un autre

Posté par . Licence CC by-sa
Tags :
0
8
avr.
2016

Bonjour et bon vendredi, Robinsons,

J'ai un petit souci avec mon application php qui comporte actuellement un bogue.

L'application c'est un gestionnaire de fichiers en ligne, les fichiers sont soit stockés dans la base de données (si pas trop volumineux) soit sur le système de fichiers du serveur.

J'utilise Laravel 5.0

Pour l'explorateur de fichiers, j'ai deux vues importantes:
vue_liste.blade.php

        $assoc = json_decode($json_str);


        if ($assoc !== NULL) {
        foreach($assoc as $i => $row
(...)

Libertempo, gestion de congés, en version Quinnis

Posté par . Édité par Nÿco, Nils Ratusznik, tuiu pol, ZeroHeure, palm123 et Benoît Sibaud. Modéré par ZeroHeure. Licence CC by-sa
20
4
avr.
2016
Bureautique

Libertempo est une application libre (PHP/MySQL) permettant de gérer les congés en ligne (fork de php_conges). Publié sous licence GPL, Libertempo est sorti en version Quinnis.

Au menu, plein de corrections de bug et d'amélioration du code. Mais avant vous voulez certainement savoir pourquoi "Quinnis" ? Et bien, parce que nous sommes fan de Dr Who ! Donc, chaque nouvelle version s’accompagnera d’un nouveau nom basé sur les planètes du Whoniverse.

Quelques informations sont disponibles en seconde partie de dépêche.