Reprise projet été 2016

This commit is contained in:
xdrm-brackets 2016-07-02 17:10:41 +02:00
parent 8b26204bd2
commit 23dc72a64c
27 changed files with 1279 additions and 275 deletions

View File

@ -4,7 +4,10 @@
use \router\Router; use \router\Router;
use \manager\ResourceDispatcher; use \manager\ResourceDispatcher;
use \manager\ModuleRequest; use \manager\ModuleRequest;
use \manager\ModuleResponse;
use \manager\ManagerError;
/*******************************************/ /*******************************************/
/* DEBUGGER */ /* DEBUGGER */
@ -41,22 +44,19 @@
$R->get('f(?:/([\w-]+))*/?', function(){ new ResourceDispatcher($_GET['url'], true); }); $R->get('f(?:/([\w-]+))*/?', function(){ new ResourceDispatcher($_GET['url'], true); });
// Api // Api
$R->post('api/?', function(){ $R->post('api(?:/(.*))?', function($url){
$request = ModuleRequest::fromPost($_POST); $request = ModuleRequest::fromPost($url, $_POST);
$answer = $request->dispatch(); $answer = $request->dispatch();
echo $answer->serialize(); // Si c'est une réponse (et non un download)
if( $answer instanceof ModuleResponse )
echo $answer->serialize();
}); });
// N'importe -> page d'accueil // N'importe -> page d'accueil
$R->get('.+', function(){ header('Location: /dashboard/'); }); $R->get('.+', function(){ header('Location: /dashboard/'); });
$R->post('.+', function(){ header('Location: /dashboard/'); });
// $R->post('.*', function(){
// var_dump( 'Acces POST : '.$_GET['url'] );
// var_dump( $_POST );
// });

6
js/action-script-min.js vendored Normal file
View File

@ -0,0 +1,6 @@
DOM={WRAPPER:$("WRAPPER"),HEADER:$("HEADER"),MENUSIDE:$("MENU-SIDE"),CONTAINER:$("CONTAINER")};var pageManager=new pageManagerClass;pageManager.setPage(null,"/view",DOM.CONTAINER,"profile dashboard machines users groups analytics settings".split(" "));var api=new APIClass("/api/");
function navSubMenu(a){var c=document.querySelector('#CONTAINER > .sub-menu-side > span[data-sublink="'+pageManager.vars[0]+'"]'),b=null,b=a instanceof Element?a:null,b="string"==typeof a?document.querySelector('#CONTAINER > .sub-menu-side > span[data-sublink="'+a+'"]'):b,b=null==b?document.querySelector("#CONTAINER > .sub-menu-side > span[data-sublink]"):b;if(null==b)return!1;null!=c&&c.remClass("active");a=document.querySelectorAll("#CONTAINER > section[data-sublink].active");for(c=0;c<a.length;c++)a[c].remClass("active");
null!=b&&(b.addClass("active"),a=document.querySelector('#CONTAINER > section[data-sublink="'+b.getData("sublink")+'"]'),null!=a&&a.addClass("active"));if(!b.getData("sublink"))return!1;a=pageManager.vars[0]!=b.getData("sublink");pageManager.vars[0]=b.getData("sublink");a&&pageManager.updateURL()}
function navMenu(a){var c=document.querySelector('#WRAPPER > #MENU-SIDE > span[data-link="'+pageManager.page+'"]'),b=null,b=a instanceof Element?a:null,b="string"==typeof a?document.querySelector('#WRAPPER > #MENU-SIDE > span[data-link="'+a+'"]'):b,b=null==b?document.querySelector('#WRAPPER > #MENU-SIDE > span[data-link="'+pageManager.pagelist[0]+'"]'):b;if(null==b)return!1;null!=c&&c.remClass("active");null!=b&&b.addClass("active");b.getData("link")&&(DOM.HEADER.addClass("loading"),pageManager.setPage(b.getData("link")),
pageManager.activeXHR.addEventListener("loadend",function(){DOM.HEADER.remClass("loading");1<=pageManager.vars.length&&null!=document.querySelector('#CONTAINER > .sub-menu-side > [data-sublink="'+pageManager.vars[0]+'"]')?navSubMenu(pageManager.vars[0]):navSubMenu(null);document.querySelector("#CONTAINER > .sub-menu-side").addEventListener("click",function(a){for(a=a.target;a!=document.body&&!a.getData("sublink");)a=a.parentNode;a.getData("sublink")&&navSubMenu(a)},!1)},!1))}navMenu(pageManager.page);
DOM.MENUSIDE.addEventListener("click",function(a){for(a=a.target;a!=document.body&&!a.getData("link");)a=a.parentNode;a.getData("link")&&navMenu(a.getData("link"))},!1);

View File

@ -188,6 +188,3 @@ DOM.MENUSIDE.addEventListener('click', function(e){
if( target.getData('link') ) if( target.getData('link') )
navMenu(target.getData('link')); navMenu(target.getData('link'));
}, false); }, false);

4
js/lib/api-min.js vendored Normal file
View File

@ -0,0 +1,4 @@
function APIClass(c){this.target=c}
APIClass.prototype={xhr:[],buffer:null,optionalParams:[],send:function(c,f,g){c.hasOwnProperty("path")||f({ModuleError:4});for(var a=0;a<this.xhr.length;a++)4==this.xhr[a].readyState&&this.xhr.splice(a,1);this.xhr.push(null);a=this.xhr.length-1;this.optionalParams[a]=[];if(3<arguments.length)for(var d=3;d<arguments.length;d++)this.optionalParams[a].push(arguments[d]);this.xhr[a]=window.XMLHttpRequest?new XMLHttpRequest:new ActiveXObject("Microsoft.XMLHttpRequest");var e=this;this.xhr[a].onreadystatechange=
function(){if(4==e.xhr[a].readyState)if(e.buffer=e.xhr[a].responseText,console.log("api request",c),-1<[0,200].indexOf(e.xhr[a].status))try{f(JSON.parse(e.xhr[a].responseText),e.optionalParams[a])}catch(b){f({ModuleError:-1,ErrorDescription:"Erreur au niveau de api.js"},e.optionalParams[a]),console.warn(b)}else f({ModuleError:3})};var d=new FormData,b;for(b in c)"path"==b?d.append(b,c[b]):c[b]instanceof File?d.append(b,c[b]):d.append(b,JSON.stringify(c[b]));this.xhr[a].open("POST",this.target,!0);
null!=g&&this.xhr[a].setRequestHeader("Authorization","Digest "+g);this.xhr[a].setRequestHeader("X-Requested-With","XMLHttpRequest");this.xhr[a].send(d)}};

View File

@ -1,15 +1,17 @@
/* classe API */ /* classe API */
function APIClass(target){ this.target = target; }; function APIClass(target){ this.target = target; }
APIClass.prototype = { APIClass.prototype = {
xhr: [], // tableau d'objets pour les requêtes ajax xhr: [], // tableau d'objets pour les requêtes ajax
buffer: null, // Contiendra le buffer pour debugger si erreur de parsage
optionalParams: [], // Contiendra les paramètres que l'on veut passer au scope de @pHandler
/* transaction avec le serveur (http://host/api/) /* transaction avec le serveur (http://host/api/)
* *
* @param pRequest<Object> l'objet passé en JSON à http://host/api/ * @param pRequest<Object> l'objet passé en POST (attribut->postfield) à http://host/api/
* @param pHandler<Function> fonction qui s'éxécutera lors de la réponse (1 argument -> réponse<Object>) * @param pHandler<Function> fonction qui s'éxécutera lors de la réponse (1 argument -> réponse<Object>)
* @param pToken<String> Optionnel, token d'auth pour l'api
* @param pParams<Mixed> Optionnels, liste d'arguments à passer au scope de @pHandler
* *
* @return answer<Object> l'objet retourné par http://host/api/ via pHandler (1er argument) * @return answer<Object> l'objet retourné par http://host/api/ via pHandler (1er argument)
* *
@ -26,58 +28,84 @@ APIClass.prototype = {
* 3. on passe une fonction qui utilise un argument (sera la réponse de http://host/api/) (sous forme d'objet) * 3. on passe une fonction qui utilise un argument (sera la réponse de http://host/api/) (sous forme d'objet)
* *
*/ */
send: function(pRequest, pHandler){ send: function(pRequest, pHandler, pToken){
// Si le chemin de delegation n'est pas renseigne, on renvoie une erreur // Si le chemin de delegation n'est pas renseigne, on renvoie une erreur
if( !pRequest.hasOwnProperty('path') ) if( !pRequest.hasOwnProperty('path') )
pHandler({ModuleError:4}); pHandler({ModuleError:4});
// on efface les requêtes qui sont terminées (toutes celles de this.xhr) // on efface les requêtes qui sont terminées (toutes celles de this.xhr)
for( var i = 0 ; i < this.xhr.length ; i++ ){ for( var i = 0 ; i < this.xhr.length ; i++ )
if( this.xhr[i].readyState == 4 ) // si terminée if( this.xhr[i].readyState == 4 ) // si terminée
this.xhr = this.xhr.slice(0,i-1).concat(this.xhr.slice(i,this.xhr.length-1)); // suppression entrée this.xhr.splice(i, 1);
}
// on créé une nouvelle entrée // on créé une nouvelle entrée
this.xhr.push(null); this.xhr.push(null);
i = this.xhr.length-1; i = this.xhr.length-1;
// Gestion des paramètres optionnels à passer au scope de @pHandler
this.optionalParams[i] = [];
if( arguments.length > 3 )
for( var arg = 3 ; arg < arguments.length ; arg++ )
this.optionalParams[i].push( arguments[arg] );
// création de l'objet AJAX // création de l'objet AJAX
if(window.XMLHttpRequest) // IE7+, Firefox, Chrome, Opera, Safari if(window.XMLHttpRequest) // IE7+, Firefox, Chrome, Opera, Safari
this.xhr[i] = new XMLHttpRequest(); this.xhr[i] = new XMLHttpRequest();
else // IE5, IE6 else // IE5, IE6
this.xhr[i] = new ActiveXObject('Microsoft.XMLHttpRequest'); this.xhr[i] = new ActiveXObject('Microsoft.XMLHttpRequest');
console.log(pRequest);
var ptrAPI = this; var ptrAPI = this;
this.xhr[i].onreadystatechange = function(){ this.xhr[i].onreadystatechange = function(){
if( ptrAPI.xhr[i].readyState == 4 ){ // si la requête est terminée if( ptrAPI.xhr[i].readyState == 4 ){ // si la requête est terminée
ptrAPI.buffer = ptrAPI.xhr[i].responseText;
/* DEBUG : affiche la réponse BRUTE de http://host/api/ */ /* DEBUG : affiche la réponse BRUTE de http://host/api/ */
// console.log('http://host/api/ => '+ptrAPI.xhr[i].responseText); // console.log('http://host/api/ => '+ptrAPI.xhr[i].responseText);
// console.log( JSON.parse(ptrAPI.xhr[i].responseText) ); // console.log( JSON.parse(ptrAPI.xhr[i].responseText) );
console.log('api request', pRequest);
/* si success de requête */ /* si success de requête */
if( [0,200].indexOf(ptrAPI.xhr[i].status) > -1 ){ // si fichier existe et reçu if( [0,200].indexOf(ptrAPI.xhr[i].status) > -1 ){ // si fichier existe et reçu
try{ pHandler( JSON.parse(ptrAPI.xhr[i].responseText) ); } // si on peut parser, on envoie try{ pHandler( JSON.parse(ptrAPI.xhr[i].responseText), ptrAPI.optionalParams[i]); } // si on peut parser, on envoie
catch(e){ pHandler({ModuleError:1}); } // sinon on envoie obj.request = 'corrupted' catch(e){ pHandler({ModuleError:-1, ErrorDescription:'Erreur au niveau de api.js'}, ptrAPI.optionalParams[i]); console.warn(e); } // sinon on envoie obj.request = 'corrupted'
} }
/* sinon retourne obj.request = 'unreachable' */ /* sinon retourne obj.request = 'unreachable' */
else else
pHandler({ModuleError:3}); pHandler({ModuleError:3});
} }
} };
// on créé un formulaire POST (virtuel) // on créé un formulaire POST (virtuel)
var form = new FormData(); var form = new FormData();
form.append('path', pRequest.path ); // on créé la variable $_POST['json']=>request
if( pRequest.hasOwnProperty('data') ) // On ajoute tous les attributs en POST
form.append('data', JSON.stringify(pRequest.data) ); for( var key in pRequest )
// On envoie le 'path' tel quel <String>
if( key == 'path' ) form.append(key, pRequest[key]);
// On envoie un fichier tel quel <File>
else if( pRequest[key] instanceof File ) form.append(key, pRequest[key]);
// On envoie le reste en JSON
else form.append(key, JSON.stringify(pRequest[key]));
this.xhr[i].open('POST', this.target, true); this.xhr[i].open('POST', this.target, true);
// Gestion du token optionnel
if( pToken != null ) this.xhr[i].setRequestHeader('Authorization', 'Digest '+pToken);
// Header pour dire que c'est AJAX
this.xhr[i].setRequestHeader('X-Requested-With', 'XMLHttpRequest');
this.xhr[i].send( form ); this.xhr[i].send( form );
} }

5
js/lib/form-deflater-min.js vendored Normal file
View File

@ -0,0 +1,5 @@
function FormDeflater(b,c,a){for(var d=0;d<c.length;d++)c[d]=c[d].toLowerCase();for(d=0;d<a.length;d++)a[d]=a[d].toLowerCase();this.container=b;this.tags=c;this.attr=a}FormDeflater.prototype={container:this.container,tags:this.tags,attr:this.attr};
FormDeflater.prototype.deflate=function(){for(var b=this.getChildren(this.container),b=this.filterElements(b),c={},a=0;a<b.length;a++)for(var d=0;d<this.attr.length;d++){var e=b[a].getAttribute(this.attr[d]);if(null!==e&&0<e.length){c.hasOwnProperty(e)?c[e]instanceof Array?c[e].push({target:b[a],attr:this.attr[d],value:b[a].value,checked:b[a].checked}):c[e]=[c[e],{target:b[a],attr:this.attr[d],value:b[a].value,checked:b[a].checked}]:c[e]={target:b[a],attr:this.attr[d],value:b[a].value,checked:b[a].checked};
break}}return c=this.cleanOutput(c)};FormDeflater.prototype.checkable=function(b){return"INPUT"!=b.tagName||-1==["radio","checkbox"].indexOf(b.getAttribute("type").toLowerCase())?!1:!0};
FormDeflater.prototype.cleanOutput=function(b){var c={},a;for(a in b)if(b[a]instanceof Array){var d=!0,e=[],f;for(f in b[a])if(this.checkable(b[a][f].target))!0===b[a][f].checked&&e.push(f);else{d=!1;break}if(d)if(1==e.length)c[a]=b[a][e[0]].value;else for(f in c[a]=[],e)c[a].push(b[a][e[f]].value);else for(f in c[a]=[],b[a])c[a].push(b[a][f].value)}else this.checkable(b[a].target)?c[a]=b[a].checked?b[a].value:null:c[a]=b[a].value;return c};
FormDeflater.prototype.getChildren=function(b){if(!(b instanceof Element))return[];for(var c=b=[].slice.call(b.children),a=0;a<b.length;a++)c=c.concat([].slice.call(this.getChildren(b[a])));return c};FormDeflater.prototype.filterElements=function(b){for(var c=[],a=0;a<b.length;a++)-1<this.tags.indexOf(b[a].tagName.toLowerCase())&&c.push(b[a]);return c};

285
js/lib/form-deflater.js Normal file
View File

@ -0,0 +1,285 @@
/* CONSTRUCTEUR D'UN DEFLATER DE formulaire
*
* @container<Element> Formulaire ou autre élément contenant les champs
* @tags<Array> Tableau contenant les éléments à prendre en compte
* @attr<Array> Tableau contenant les attributs à prendre pour le nom (par ordre de priorité)
*
*/
function FormDeflater(container, tags, attr){
/* [0] Vérification des INPUT
=========================================================*/
var correctParams = container instanceof Element;
correctParams = correctParams && tags instanceof Array;
correctParams = correctParams && attr instanceof Array;
/* [1] On formatte les données
=========================================================*/
// On met les tags en minuscule
for( var i = 0 ; i < tags.length ; i++ )
tags[i] = tags[i].toLowerCase();
// On met les attributs en minuscule
for( var i = 0 ; i < attr.length ; i++ )
attr[i] = attr[i].toLowerCase();
/* [2] On enregistre les attributs
=========================================================*/
this.container = container;
this.tags = tags;
this.attr = attr;
}
FormDeflater.prototype = {
container: this.container, // Contiendra le 'formulaire' (<form> ou autre)
tags: this.tags, // Contiendra les balises HTML à ne pas prendre en compte
attr: this.attr // Contiendra la liste des attributs à prendre pour nom (par ordre de priorité)
};
/* RETOURNE UN OBJET CONTENANT LES DONNÉES DU FORMULAIRE
*
* @return form<Object> Objet correspondant aux données du formulaire
*
*/
FormDeflater.prototype.deflate = function(){
/* [1] On récupère tous les enfants
=========================================================*/
var children = this.getChildren( this.container );
/* [2] On filtre les éléments qui ont pas le bon tag
=========================================================*/
children = this.filterElements( children );
/* [3] On essaie de trouver les attributs primants (non vides et en premier dans la liste @this.attr)
=========================================================*/
/* (0) On initialise l'objet de retour */
var object = {};
/* (1) Pour chacun des éléments */
for( var c = 0 ; c < children.length ; c++ ){
/* (2) Pour chacun des attributs par ordre de priorité */
for( var a = 0 ; a < this.attr.length ; a++ ){
// On récupère l'attribut
var attr = children[c].getAttribute(this.attr[a]);
/* (3) Si l'attribut est défini (pas null ni vide) */
if( attr !== null && attr.length > 0 ){
/* (4) Si on a pas déja un champ de même nom */
if( object.hasOwnProperty(attr) ){
var existing = object[attr];
// {1} Si l'existant est un tableau, on ajoute notre valeur //
if( existing instanceof Array )
object[attr].push( { target: children[c], attr: this.attr[a], value: children[c].value, checked: children[c].checked } );
// {2} Sinon, si c'est une valeur seule, on crée un tableau //
else
object[attr] = [ object[attr], { target: children[c], attr: this.attr[a], value: children[c].value, checked: children[c].checked } ];
/* (5) Si c'est le premier champ avec ce nom, on le crée */
}else
object[attr] = { target: children[c], attr: this.attr[a], value: children[c].value, checked: children[c].checked };
// On en a fini pour cet élément
break;
}
}
}
/* [4] On met en forme les données
=========================================================*/
object = this.cleanOutput(object);
return object;
};
/* RETOURNE SI UN ELEMENT EST UN BOUTON DE TYPE RADIO/CHECKBOX OU NON
*
* @element<Element> Element en question
*
* @return result<Boolean> Renvoie si TRUE or FALSE il en est un
*
*/
FormDeflater.prototype.checkable = function(element){
if( element.tagName != 'INPUT' )
return false;
if( ['radio', 'checkbox'].indexOf( element.getAttribute('type').toLowerCase() ) == -1 )
return false;
return true;
};
/* NETTOIE LES DONNÉES EN SORTIE POUR QU'ELLES SOIENT UTILISABLES ET OPTIMISÉES
*
* @input<Object> Données "brutes"
*
* @return output<Object> Données sans les valeurs inutiles et explicitées
*
*/
FormDeflater.prototype.cleanOutput = function(input){
var output = {};
/* [1] On parcourt toutes les valeurs récupérées
=========================================================*/
for( var key in input ){
/* [2] Si c'est un tableau
=========================================================*/
if( input[key] instanceof Array ){
// VRAI si tous les éléments sont radio/checkbox
var areCheckable = true;
// Contiendra les indices des valeurs ou 'checked=TRUE'
var checkedIndexes = [];
/* (1) On vérifie si tous les champs sont checkables */
for( var i in input[key])
// si pas checkable, on arrête de vérifier
if( !this.checkable(input[key][i].target) ){
areCheckable = false;
break;
// Sinon si checkable et checked=TRUE, on incrémente @nbChecked
}else if( input[key][i].checked === true )
checkedIndexes.push(i);
/* (2) Si c'est que des radio ou des checkbox avec une seule valeur à TRUE */
if( areCheckable )
if( checkedIndexes.length == 1 )
output[key] = input[key][checkedIndexes[0]].value;
/* (3) Si c'est que des radio ou des checkbox avec plusieurs valeurs à TRUE */
else{
output[key] = [];
for( var i in checkedIndexes )
output[key].push( input[key][checkedIndexes[i]].value );
}
/* (4) Si c'est pas que des radio ou des checkbox, on met les valeurs */
else{
output[key] = [];
for( var i in input[key] )
output[key].push( input[key][i].value );
}
/* [3] S'il n'y a qu'une donnée (pas un tableau)
=========================================================*/
}else{
/* (1) Si de type 'radio' ou 'checkbox', on met la valeur de 'checked' */
if( this.checkable(input[key].target) )
output[key] = input[key].checked ? input[key].value : null;
/* (2) Sinon, on met la valeur de 'value' */
else
output[key] = input[key].value;
}
}
return output;
};
/* RETOURNE LA LISTE DE TOUS LES ÉLÉMENTS QUEL QUE SOIT LE NIVEAU HIÉRARCHIQUE
*
* @parent<Element> Parent duquel on veut les enfants
*
* @return children<Array> Tableau contenant tous les enfants
*
*/
FormDeflater.prototype.getChildren = function(parent){
// Si le parent n'est pas un élément, on retourne aucun enfant
if( !(parent instanceof Element) ) return [];
/* [1] Initialisation des variables
=========================================================*/
// Contient la liste des enfants directs
var children = [].slice.call(parent.children);
// Contiendra la liste des enfants directs et indirects
var allChildren = children;
/* [2] On parcourt tous les enfants
=========================================================*/
for( var i = 0 ; i < children.length ; i++ ){
// On relance la fonction récursivement sur tous les enfants
allChildren = allChildren.concat( [].slice.call(this.getChildren(children[i])) );
}
/* [3] On retourne le résultat
=========================================================*/
return allChildren;
};
/* FILTRE LES éléments en fonction de @this.tags et @this.attr
*
* @elements<Array> Le tableau contenant les éléments à trier
*
* @return filtered<Array> Retourne le tableau des éléments filtrés
*
*/
FormDeflater.prototype.filterElements = function(elements){
// Contiendra les éléments correspondants aux critères
var filtered = [];
/* [1] On parcourt tous les éléments
=========================================================*/
for( var i = 0 ; i < elements.length ; i++ )
// Si l'élément a le bon tag, on le garde
if( this.tags.indexOf( elements[i].tagName.toLowerCase() ) > -1 )
filtered.push(elements[i]);
/* [2] On retourne les éléments filtržés
=========================================================*/
return filtered;
};
/************/
/* USE CASE */
/************/
/* (1) Instanciation */
/*HIDDEN*/// var instance = new FormDeflater(
/*HIDDEN*/// document.getElementById('myform'),
/*HIDDEN*/// ['input', 'select'], // éléments à prendre en compte (tagName)
/*HIDDEN*/// ['id', 'name', 'data-elementname'] // Attributs par ordre de priorité
/*HIDDEN*/// );
/*HIDDEN*///
/* (2) On récupère l'objet */
/*HIDDEN*///
/*HIDDEN*/// var object = instance.deflate();
/*HIDDEN*///

7
js/lib/input-checker-min.js vendored Normal file
View File

@ -0,0 +1,7 @@
function formatChecker(a,c,b){this.value=a;this.pattern=c;this.rules=2<arguments.length?b:[]}
formatChecker.prototype={value:this.value,pattern:this.pattern,rules:this.rules,regexp:null,default_rules:{i:"[0-9]",a:"[a-z]",A:"[A-Z]",x:"[a-zA-Z]"},compile:function(){for(var a="^",c=[],b=0;b<this.pattern.length;b++)this.rules.hasOwnProperty(this.pattern[b])?(a+=this.rules[this.pattern[b]],c.push(this.rules[this.pattern[b]])):this.default_rules.hasOwnProperty(this.pattern[b])?(a+=this.default_rules[this.pattern[b]],c.push(this.default_rules[this.pattern[b]])):(a+=this.pattern[b],c.push(this.pattern[b]));
this.regexp=new RegExp(a+"$");this.regexp.patternDecomposition=c},check:function(a){null==this.regexp&&this.compile();if(0<arguments.length&&a instanceof Array)for(var c=0;c<this.pattern.length;c++){var b="^",b=this.rules.hasOwnProperty(this.pattern[c])?b+this.rules[this.pattern[c]]:this.default_rules.hasOwnProperty(this.pattern[c])?b+this.default_rules[this.pattern[c]]:b+this.pattern[c],b=b+"$";a.push(null!=this.value[c].match(new RegExp(b)))}return null!=this.value.match(this.regexp)}};
function inputChecker(){}
inputChecker.prototype={input:[],defval:[],checker:[],append:function(a,c,b){if(!(a instanceof HTMLInputElement&&c instanceof formatChecker))return!1;var d=this.input.push(a);if(d!=this.checker.push(c)||d!=this.defval.push(2<arguments.length?b:null))return!1},check:function(a){a=this.input.indexOf(a);if(0>a)return!1;this.checker[a].value=this.input[a].value;return this.checker[a].check()},checkAll:function(){for(var a=!0,c=0;c<this.input.length;c++)a=a&&this.check(this.input[c]);return a},correct:function(a,
c){if(0>(index=this.input.indexOf(a)))return null;c=1<arguments.length?c:!0;this.checker[index].value=this.input[index].value;this.checker[index].compile();var b=this.checker[index].regexp.patternDecomposition,d=this.input[index].value;if(!this.check(a)){for(var e=0;e<b.length&&(c||!(e>=this.input[index].value.length));e++){var f=new RegExp("^"+b[e]+"$");0==d.length||null==d[e]?d=d.slice(0,e).concat(this.defval[index][e]).concat(d.slice(e)):null==d[e].match(f)&&(d=null!=d[e].match(new RegExp("^"+
b[e+1]+"$"))?d.slice(0,e).concat(this.defval[index][e]).concat(d.slice(e)):d.slice(0,e).concat(this.defval[index][e]).concat(d.slice(e+1)))}d=d.slice(0,b.length);this.input[index].value=d}}};

9
js/lib/page-manager-min.js vendored Normal file
View File

@ -0,0 +1,9 @@
function pageManagerClass(){}var ptrPageManagerClass;
pageManagerClass.prototype={depJS:null,depCSS:null,xhr:[],activeXHR:null,page:null,vars:[],path:"",jsPath:"js",cssPath:"css",pagelist:null,container:null,ajax:function(b,c,f,a){for(var d=0;d<this.xhr.length;d++)this.xhr=this.xhr.slice(0,d-1).concat(this.xhr.slice(d,this.xhr.length-1));var e;e=window.XMLHttpRequest?this.xhr.push(new XMLHttpRequest)-1:this.xhr.push(new ActiveXObject("Microsoft.XMLHttpRequest"))-1;this.activeXHR=this.xhr[e];var g=this;this.xhr[e].onreadystatechange=function(){4==g.xhr[e].readyState&&
(-1<[0,200].indexOf(g.xhr[e].status)?c(g.xhr[e].responseText):c())};f="string"==typeof f&&/^POST|GET$/i.test(f)?f.toUpperCase():"POST";a="POST"==f&&"object"==typeof a&&a instanceof FormData?a:null;this.xhr[e].open(f,b,!0);this.xhr[e].send(a);return this},explodeURL:function(b){b=1<=arguments.length?b:document.URL;if(null!=this.pagelist&&/^(?:(?:https?:\/\/)?[^\/]+)\/([a-z0-9_]+)\/?(?:\/((?:.+\/)+)\/?)?$/i.test(b)){for(var c=RegExp.$2.split("/");""==c[c.length-1];)c.pop();return-1<this.pagelist.indexOf(RegExp.$1)?
{page:RegExp.$1,"var":c}:null}return null},loadDependencies:function(){"object"==typeof this.depCSS&&this.depCSS instanceof Element&&this.depCSS.parentNode==document.head&&document.head.removeChild(this.depCSS);"object"==typeof this.depJS&&this.depJS instanceof Element&&this.depJS.parentNode==document.head&&document.head.removeChild(this.depJS);ptrPageManagerClass=this;this.ajax(this.path+"/"+this.cssPath+"/"+this.page+".css",function(b){null!=b?(ptrPageManagerClass.depCSS=document.createElement("link"),
ptrPageManagerClass.depCSS.rel="stylesheet",ptrPageManagerClass.depCSS.type="text/css",ptrPageManagerClass.depCSS.href=ptrPageManagerClass.path+"/"+ptrPageManagerClass.cssPath+"/"+ptrPageManagerClass.page+".css",document.head.appendChild(ptrPageManagerClass.depCSS)):console.warn("[loadDependencies_Error] - ("+ptrPageManagerClass.path+"/"+ptrPageManagerClass.cssPath+"/"+ptrPageManagerClass.page+".css)")});this.ajax(this.path+"/"+this.jsPath+"/"+this.page+".js",function(b){null!=b?(ptrPageManagerClass.depJS=
document.createElement("script"),ptrPageManagerClass.depJS.type="text/javascript",ptrPageManagerClass.depJS.src=ptrPageManagerClass.path+"/"+ptrPageManagerClass.jsPath+"/"+ptrPageManagerClass.page+".js",document.head.appendChild(ptrPageManagerClass.depJS)):console.warn("[loadDependencies_Error] - ("+ptrPageManagerClass.path+"/"+ptrPageManagerClass.jsPath+"/"+ptrPageManagerClass.page+".js)")})},updateURL:function(){0<this.vars.length?window.history.pushState(this.page,this.page,"/"+this.page+"/"+this.vars.join("/")+
"/"):window.history.pushState(this.page,this.page,"/"+this.page+"/")},setPage:function(b,c,f,a){var d="object"==typeof a&&a instanceof Array?a:null;if(null!=d)for(a=0;a<d.length&&(d="string"==typeof d[a]&&/^[a-z0-9_]+$/i.test(d[a])?d:null,null!=d);a++);this.pagelist=null!=d?d:this.pagelist;this.page=this.pagelist[0];this.path="string"==typeof c?c:this.path;this.container="object"==typeof f&&f instanceof Element?f:this.container;if(null!=this.pagelist&&null!=this.container)if("string"==typeof b&&-1<
this.pagelist.indexOf(b)){this.page=b;var e=this;b=new FormData;for(a=0;a<this.vars.length;a++)b.append(this.vars[a],null);this.ajax(this.path+"/"+this.page+".php",function(a){e.container.innerHTML=a;e.loadDependencies()},"POST",b);this.updateURL()}else if(c=this.explodeURL(),null!=c){this.page=c.page;var g=this;b=new FormData;for(a=this.vars.length=0;a<c["var"].length;a++)this.vars[a]=c["var"][a],b.append(this.vars[a],null);this.ajax(this.path+"/"+this.page+".php",function(a){g.container.innerHTML=
a;g.loadDependencies()},"POST",b);this.updateURL()}else this.setPage(this.pagelist[0]);else console.warn("pagelist et container manquant");return this},refresh:function(){this.setPage(this.page);return this}};

View File

@ -101,7 +101,7 @@ pageManagerClass.prototype = {
explodeURL: function(url_data){ explodeURL: function(url_data){
url_data = (arguments.length >= 1) ? url_data : document.URL; url_data = (arguments.length >= 1) ? url_data : document.URL;
// si pageList est correct et que l'URL correspond à un schéma de page => continue [sinon] return null // si pageList est correct et que l'URL correspond à un schéma de page => continue [sinon] return null
if( this.pagelist != null && /^(?:(?:http:\/\/)?[^\/]+)\/([a-z0-9_]+)\/?(?:\/((?:.+\/)+)\/?)?$/i.test(url_data) ){ if( this.pagelist != null && /^(?:(?:https?:\/\/)?[^\/]+)\/([a-z0-9_]+)\/?(?:\/((?:.+\/)+)\/?)?$/i.test(url_data) ){
// si la page récupérée dans l'url est dans la liste => renvoi de l'objet [sinon] null // si la page récupérée dans l'url est dans la liste => renvoi de l'objet [sinon] null
var vars = RegExp.$2.split('/'); var vars = RegExp.$2.split('/');
while( vars[vars.length-1] == '' ) // on supprime les dernières entrées vides while( vars[vars.length-1] == '' ) // on supprime les dernières entrées vides
@ -177,13 +177,13 @@ pageManagerClass.prototype = {
- pContainer<Element> l'élément du DOM qui contiendra la page chargée (**) - pContainer<Element> l'élément du DOM qui contiendra la page chargée (**)
- pPageList<Array<string>> tableau contenant la liste des pages sous forme de chaînes de caractères (**) (***) - pPageList<Array<string>> tableau contenant la liste des pages sous forme de chaînes de caractères (**) (***)
* Le chemin du dossier sans le '/' final si c'est le dossier actuel le chemin est une chaîne vide * Le chemin du dossier sans le '/' final si c'est le dossier actuel le chemin est une chaîne vide
Si le dossier est 'page' et que l'on cherche la page 'accUe1l', la requête sera vers 'page/accUe1l.php' Si le dossier est 'page' et que l'on cherche la page 'accUe1l', la requête sera vers 'page/accUe1l.php'
le nom de la page est sensible à la casse le nom de la page est sensible à la casse
** 1. pPageList et pContainer doivent être mis en paramètres uniquement à la première utilisation ** 1. pPageList et pContainer doivent être mis en paramètres uniquement à la première utilisation
et la première utilisation doit se faire au chargement de la page car elle permetra et la première utilisation doit se faire au chargement de la page car elle permetra
de mettre l'URL à jour et/ou charger la page de l'URL de mettre l'URL à jour et/ou charger la page de l'URL
*** la première page du tableau est la page par défaut (qui est chargée si l'URL ne contient *** la première page du tableau est la page par défaut (qui est chargée si l'URL ne contient
pas la page ou si la page de l'URL ne correspond à aucune page de la liste) pas la page ou si la page de l'URL ne correspond à aucune page de la liste)
========================================================================== */ ========================================================================== */
setPage: function(pName, pPath, pContainer, pPageList){ setPage: function(pName, pPath, pContainer, pPageList){

2
js/lib/reset-min.js vendored Normal file
View File

@ -0,0 +1,2 @@
function $(a){var b=document.querySelectorAll("#"+a);a=document.querySelectorAll("."+a);return 0<b.length?b[0]:a[0]}Element.prototype.getData=function(a){return"undefined"==typeof this.dataset?!1:this.dataset.hasOwnProperty(a)?this.dataset[a]:!1};Element.prototype.addClass=function(a){var b=this.className.split(" ");-1<b.indexOf(a)||(b.push(a),this.className=b.join(" ").trim())};
Element.prototype.remClass=function(a){var b=this.className.split(" ");a=b.indexOf(a);-1!=a&&(b=b.slice(0,a).concat(b.slice(a+1)),this.className=b.join(" ").trim())};NodeList.prototype.indexOf=HTMLCollection.prototype.indexOf=function(a){for(var b=0;b<this.length;b++)if(this[b]==a)return b;return-1};Element.prototype.anim=function(a,b){var c=this;c.addClass(a);setTimeout(function(){c.remClass(a)},b)};var format_code=new formatChecker(null,"HH-HH-HH-HH",{H:"[0-9A-F]"});

View File

@ -48,7 +48,7 @@
if( self::$instance == null || self::$error != ManagerError::Success ){ // Si aucune instance existante OU erreur de connection if( self::$instance == null || self::$error != ManagerError::Success ){ // Si aucune instance existante OU erreur de connection
// chargement de la configuration du server SQL // chargement de la configuration du server SQL
if( !isset($_SERVER['HTTP_HOST']) || isset($_SERVER['HTTP_HOST']) && $_SERVER['HTTP_HOST'] == 'stefproject' ) if( !checkdnsrr($_SERVER['SERVER_NAME'], 'NS') )
$conf = json_decode( ResourceDispatcher::getResource(self::$config_path['local']), true ); $conf = json_decode( ResourceDispatcher::getResource(self::$config_path['local']), true );
else else
$conf = json_decode( ResourceDispatcher::getResource(self::$config_path['remote']), true ); $conf = json_decode( ResourceDispatcher::getResource(self::$config_path['remote']), true );
@ -122,7 +122,7 @@
for( $i = 0 ; $i < count($fetchData) ; $i++ ) // pour tout les utilisateurs for( $i = 0 ; $i < count($fetchData) ; $i++ ) // pour tout les utilisateurs
foreach($fetchData[$i] as $col => $val){ // pour toutes les entrées foreach($fetchData[$i] as $col => $val){ // pour toutes les entrées
if( !mb_detect_encoding($val, 'UTF-8') ) if( !\mb_detect_encoding($val, 'UTF-8') )
$fetchData[$i][$col] = utf8_encode($val); $fetchData[$i][$col] = utf8_encode($val);
if( is_int($col) ){ // Si indice numerique if( is_int($col) ){ // Si indice numerique
@ -143,7 +143,7 @@
// on supprime les doublons des entrées (indice numérique) // on supprime les doublons des entrées (indice numérique)
foreach($fetchData as $i=>$val){ // pour toutes les entrées foreach($fetchData as $i=>$val){ // pour toutes les entrées
if( !mb_detect_encoding($val, 'UTF-8') ) if( !\mb_detect_encoding($val, 'UTF-8') )
$fetchData[$i] = utf8_encode($val); $fetchData[$i] = utf8_encode($val);
if( is_int($i) ){ // Si indice numerique if( is_int($i) ){ // Si indice numerique
@ -165,12 +165,12 @@
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// _ __ _ _ _ // _ __ _ _ _
// __ _____ _ __(_)/ _(_) ___ __ _| |_(_) ___ _ __ ___ // __ _____ _ __(_)/ _(_) ___ __ _| |_(_) ___ _ __ ___
// \ \ / / _ \ '__| | |_| |/ __/ _` | __| |/ _ \| '_ \/ __| // \ \ / / _ \ '__| | |_| |/ __/ _` | __| |/ _ \| '_ \/ __|
// \ V / __/ | | | _| | (_| (_| | |_| | (_) | | | \__ \ // \ V / __/ | | | _| | (_| (_| | |_| | (_) | | | \__ \
// \_/ \___|_| |_|_| |_|\___\__,_|\__|_|\___/|_| |_|___/ // \_/ \___|_| |_|_| |_|\___\__,_|\__|_|\___/|_| |_|___/
// //
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
@ -183,43 +183,104 @@
* *
*/ */
public static function check($type, $value){ public static function check($type, $value){
$checker = !is_null($value); $checker = true;
/* [0] On verifie que $value n'est pas nul
=========================================================*/
if( is_null($value) ) return false;
/* [1] Si de type VARCHAR(min, max)
=========================================================*/
if( preg_match('/^varchar\((\d+), ?(\d+)\)$/', $type, $match) ){
// On recupere la taille min
$min = (int) $match[1];
// On recupere la taille max
$max = (int) $match[2];
// On effectue la verification
return $checker && is_string($value) && strlen($value) <= $max && strlen($value) >= $min;
}
/* [2] Si de type ARRAY(type_elements)
=========================================================*/
if( preg_match('/^array<(.+)>$/', $type, $match) ){
// Si c'est pas un tableau on retourne une erreur
if( !is_array($value) )
return false;
$elements_type = $match[1];
// On verifie le type pour chaque element
foreach($value as $element)
// Si erreur dans au moins 1 element, on retourne que c'est incorrect
if( !self::check($elements_type, $element) )
return false;
// Si aucune erreur, on retourne que tout est bon
return true;
}
/* [n] Sinon, tous les autres types definis
=========================================================*/
switch($type){ switch($type){
/* (1) Global */ // Quoi que ce soit
case 'auto_increment_id': case 'mixed':
return $checker && is_numeric($value) && $value <= 2147483647 && $value >= -2147483647; return $checker && !is_null($value);
break; break;
/* (2) Utilisateur */ // Entier positif (id dans BDD)
case 'user.code': case 'id':
case 'machine.code': return $checker && is_numeric($value) && $value <= 2147483647 && $value >= 0;
return $checker && is_string($value) && preg_match('/^[\dA-F]{2}(\-[\dA-F]{2}){3,5}$/i', $value);
break; break;
case 'user.username': // String quelconque (peut etre vide)
case 'machine.name': case 'text':
case 'group.name': return $checker && is_string($value);
return $checker && is_string($value) && preg_match('/^[\w-]{1,30}$/i', $value);
break;
case 'user.firstname': // Adresse mail (255 caracteres max)
case 'user.lastname': case 'mail':
return $checker && is_string($value) && preg_match('/^[a-z -]{3,30}$/i', $value);
break;
case 'user.mail':
return $checker && is_string($value) && strlen($value) <= 50 && preg_match('/^[\w\.-]+@[\w\.-]+\.[a-z]{2,4}$/i', $value); return $checker && is_string($value) && strlen($value) <= 50 && preg_match('/^[\w\.-]+@[\w\.-]+\.[a-z]{2,4}$/i', $value);
break; break;
case 'user.password': // Hash sha1
case 'sha1':
return $checker && is_string($value) && preg_match('/^[\da-f]{40}$/i', $value); return $checker && is_string($value) && preg_match('/^[\da-f]{40}$/i', $value);
break; break;
case 'user.status': // Numéro de téléphone
return $checker && is_numeric($value) && floor($value) == $value && $value >= 0 && $value <= 100; case 'number':
return $checker && is_string($value) && preg_match('/^(?:0|\+33 ?|0?0?33 ?|)([1-9] ?(?:[0-9] ?){8})$/i', $value);
break; break;
// Tableau non vide
case 'array':
return $checker && is_array($value) && count($value) > 0;
break;
// Boolean
case 'boolean':
return $checker && is_bool($value);
break;
// Objet non vide
case 'object':
return $checker && is_object($value) && count((array) $value) > 0;
break;
// Chaine JSON (on vérifie via le parser)
case 'json':
return $checker && is_string($value) && json_decode($value, true) !== NULL;
break;
default:
return false;
break;
} }
return $checker; return $checker;
@ -227,5 +288,80 @@
} }
/* FONCTION QUI FORMATTE UN NUMÉRO DE TÉLÉPHONE
*
* @number<String> Numéro de téléphone en +336/336/06/0336/00336
*
* @return formatted<String> Numéro formatté (06), on FALSE si erreur
*
*/
public static function formatNumber($number){
// On met en <string> quel que soit le type
$number = (string) $number;
// On supprime tous les espaces
$number = str_replace(' ', '', $number);
// On formatte le numéro
if( preg_match("/^(?:\+33|0?0?33|0)(.+)/", $number, $m) )
$number = '0'.$m[1];
// On retourne le numéro formatté
return $number;
}
public static function readableNumber($number){
/* (1) On formatte le numéro si c'est pas fait */
$formatted = self::formatNumber($number);
for( $i = 1 ; $i < strlen($formatted) ; $i++ )
if( ($i-2) % 3 == 0 )
$formatted = substr($formatted, 0, $i).' '.substr($formatted, $i);
return $formatted;
}
////////////////////////////////////
// _ _
// __| | __ _| |_ ___ ___
// / _` |/ _` | __/ _ \/ __|
// | (_| | (_| | || __/\__ \
// \__,_|\__,_|\__\___||___/
//
////////////////////////////////////
// 1) Convertis une date en en francais explicite
public static function frDate($date){
/* [1] On definit les traductions
=========================================================*/
// Jours de la semaine
$days = array("Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche");
// Mois de l'annee
$months = array("Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre");
/* [2] On recupere le timestamp et les indices
=========================================================*/
$time = strtotime($date); // timestamp
$daynum = intval( date('N', $time)-1 ); // jour dans la semaine
$monthnum = intval( date('n', $time)-1 ); // numero du mois dans l'annee
/* [3] On recupere les infos independemment
=========================================================*/
$result = array(
$days[$daynum], // nom de jour
date('j', $time), // jour du mois
$months[$monthnum], // nom du mois
date('Y', $time), // annee
);
return implode(" ", $result);
}
} }
?> ?>

View File

@ -60,6 +60,21 @@
// Erreur lors de la creation d'un objet PDO (connection) // Erreur lors de la creation d'un objet PDO (connection)
const PDOConnection = 14; const PDOConnection = 14;
/* API token */
// Token inexistant ou faux
const TokenError = 15;
const PermissionError = 16;
/* Erreur d'UPLOAD */
const UploadError = 17;
// Mauvais format de fichier
const FormatError = 18;
/* Erreur au niveau javascript */
//const JavascriptError = 19; // -> géré en js
/* EXPLICITE UN CODE D'ERREUR /* EXPLICITE UN CODE D'ERREUR
* *
@ -70,33 +85,43 @@
*/ */
public static function explicit($error){ public static function explicit($error){
switch($error){ switch($error){
case self::Success: return "Tout s'est bien deroule"; break; case self::Success: return "Tout s'est bien deroulé."; break;
case self::ParsingFailed: return "La lecture du fichier JSON a echoue"; break; case self::ParsingFailed: return "La lecture du fichier JSON ou XML a echouée."; break;
case self::InvalidFlags: return "Les specifications (drapeaux) sont incorrects"; break; case self::InvalidFlags: return "Les spécifications (drapeaux) sont incorrects."; break;
case self::UnreachableResource: return "La ressource n'existe pas (404)"; break; case self::UnreachableResource: return "La ressource n'existe pas (404)."; break;
case self::MissingPath: return "Le chemin de delegation n'a pas ete renseigne"; break; case self::MissingPath: return "Le chemin de délégation n'a pas été renseigné."; break;
case self::WrongPathModule: return "Le chemin de delegation est incorrect ('nomModule/nomMethode')"; break; case self::WrongPathModule: return "Le chemin de délégation est incorrect ('nomModule/nomMethode')."; break;
case self::WrongPathRepo: return "Le chemin de delegation est incorrect ('nomRepo/nomMethode')"; break; case self::WrongPathRepo: return "Le chemin de délégation est incorrect ('nomRepo/nomMethode')."; break;
case self::UnknownModule: return "Le module n'existe pas"; break; case self::UnknownModule: return "Le module n'existe pas."; break;
case self::UnknownRepo: return "Le repo n'existe pas"; break; case self::UnknownRepo: return "Le repo n'existe pas."; break;
case self::UnknownMethod: return "Le methode n'existe pas"; break; case self::UnknownMethod: return "Le methode n'existe pas."; break;
case self::UncallableMethod: return "Le methode n'est pas amorcable"; break; case self::UncallableMethod: return "Le methode n'est pas amorçable."; break;
case self::ParamError: return "Un ou plusieurs parametres sont manquants ou incorrects"; break; case self::ParamError: return "Un ou plusieurs paramètres sont manquants ou incorrects."; break;
case self::ModuleError: return "Erreur lors du traitement du module"; break; case self::ModuleError: return "Erreur lors du traitement du module."; break;
case self::RepoError: return "Erreur lors du traitement du repo"; break; case self::RepoError: return "Erreur lors du traitement du repo."; break;
case self::PDOConnection: return "La connexion avec la base de donnees a echoue"; break; case self::PDOConnection: return "La connexion avec la base de données a echouée."; break;
// default: return "Erreur inconnue..."; break; case self::TokenError: return "Le token de connection est absent, érroné ou expiré."; break;
case self::PermissionError: return "Vous n'avez pas la permission d'effectuer cette action."; break;
case self::UploadError: return "Une erreur d'upload est survenue."; break;
case self::FormatError: return "Le fichier n'est pas au bon format."; break;
default: return "Description d'erreur inconnue..."; break;
} }
// Erreur inconnue // Erreur inconnue
return null; return null;
} }
public static function setHttpCode($error){
http_response_code( $error == self::Success ? 200 : 417 );
}
} }
?> ?>

View File

@ -1,28 +1,22 @@
<?php <?php
namespace manager; namespace manager;
use \manager\Database;
// FORMAT:
//
// path: "nomModule/nomMethode"
// data1: {donnee1}
// data2: {donnee2}
// ...
//
//
//
//
class ModuleRequest{ class ModuleRequest{
// Constantes // Constantes
public static $config_path = 'f/json/modules/conf'; public static $config_path = 'f/json/modules/conf';
public static $default_options = array(
'download' => false
);
// Attributs prives utiles (initialisation) // Attributs prives utiles (initialisation)
private $path; private $path;
private $data; private $params;
private $modules; private $modules;
private $options;
// Contiendra la reponse a la requete // Contiendra la reponse a la requete
public $answer; public $answer;
@ -37,12 +31,13 @@
/* CONSTRUCTEUR D'UNE REQUETE DE MODULE /* CONSTRUCTEUR D'UNE REQUETE DE MODULE
* *
* @path<String> Chemin de delegation ("module/methode") * @path<String> Chemin de delegation ("module/methode")
* @data<Array> Tableau contenant les parametres utiles au traitement * @param<Array> Tableau associatif contenant les parametres utiles au traitement
* @token<String> Token d'acces a l'api (OPTIONNEL)
* *
* @return status<Boolean> Retourne si oui ou non tout s'est bien passe * @return status<Boolean> Retourne si oui ou non tout s'est bien passe
* *
*/ */
public function __construct($path=null, $data=null){ public function __construct($path=null, $params=null, $token=null){
// Si pas parametre manquant, on quitte // Si pas parametre manquant, on quitte
if( $path == null ){ if( $path == null ){
$this->error = ManagerError::MissingPath; $this->error = ManagerError::MissingPath;
@ -71,19 +66,37 @@
} }
// Type de @data (optionnel) // Type de @data (optionnel)
$data = (is_array($data)) ? $data : array(); $params = (is_array($params)) ? $params : array();
/* [2] Verification du chemin (existence module+methode) /* [2] Verification du chemin (existence module+methode)
=========================================================*/ =========================================================*/
if( !$this->checkPath($path) ) // Verification de la coherence du chemin + attribution if( !$this->checkPath($path) ) // Verification de la coherence du chemin + attribution
return false; return false;
// Gestion d'erreur interne
/* [3] Construction de l'objet
/* [3] Verification des droits
=========================================================*/ =========================================================*/
$this->data = $data; if( !$this->checkPermission($token) ) // Si on a pas les droits
return false;
/* [4] Verification des parametres (si @type est defini)
=========================================================*/
if( !$this->checkParams($params) ){ // Verification de tous les types
$this->error = ManagerError::ParamError;
return false;
}
/* [5] Récupèration des options
=========================================================*/
$this->buildOptions();
/* [6] Construction de l'objet
=========================================================*/
$this->params = $params;
$this->error = ManagerError::Success; $this->error = ManagerError::Success;
return true; // On retourne que tout s'est bien passe return true; // On retourne que tout s'est bien passe
@ -94,35 +107,40 @@
/* EXECUTE LE TRAITEMENT ASSOCIE ET REMPLIE LA REPONSE /* EXECUTE LE TRAITEMENT ASSOCIE ET REMPLIE LA REPONSE
* *
* @return answer<ModuleAnswer> Retourne une reponse de type <ModuleAnswer> si tout s'est bien passe * @return answer<ModuleResponse> Retourne une reponse de type <ModuleResponse> si tout s'est bien passe
* *
*/ */
public function dispatch(){ public function dispatch(){
/* [0] Si c'est un download, on lance la methode `download()`
=========================================================*/
if( $this->options['download'] === true )
return $this->download();
/* [1] On verifie qu'aucune erreur n'a ete signalee /* [1] On verifie qu'aucune erreur n'a ete signalee
=========================================================*/ =========================================================*/
if( $this->error != ManagerError::Success ) // si il y a une erreur if( $this->error != ManagerError::Success ) // si il y a une erreur
return new ModuleAnswer($this->error); // on la passe a la reponse return new ModuleResponse($this->error); // on la passe a la reponse
/* [2] On verifie que la methode est amorcable /* [2] On verifie que la methode est amorcable
=========================================================*/ =========================================================*/
if( !is_callable($this->getFunctionCaller()) ){ if( !is_callable($this->getFunctionCaller()) ){
$this->error = ManagerError::UncallableMethod; $this->error = ManagerError::UncallableMethod;
return new ModuleAnswer($this->error); return new ModuleResponse($this->error);
} }
/* [3] On amorce la methode /* [3] On amorce la methode
=========================================================*/ =========================================================*/
$returned = call_user_func_array( $this->getFunctionCaller(), $this->data ); $returned = call_user_func( $this->getFunctionCaller(), $this->params );
/* [4] Gestion de la reponse /* [4] Gestion de la reponse
=========================================================*/ =========================================================*/
$answer = new ModuleAnswer($this->error); $response = new ModuleResponse($this->error);
$answer->appendAll($returned); $response->appendAll($returned);
return $answer; return $response;
} }
@ -130,71 +148,168 @@
/* DESERIALISATION ET CREATION D'UN OBJET
*
* @jsonString<String> Json au format string contenant les donnees
* /* EXECUTE LE TRAITEMENT ASSOCIE ET RENVOIE UN FICHIER AVEC LE HEADER ET LE BODY SPECIFIE
* @return instance<ModuleRequest> Retourne un objet de type <ModuleRequest>
* *
*/ */
public static function fromString($jsonString){ public function download(){
$json = json_decode( $jsonString, true ); /* [1] On verifie qu'aucune erreur n'a ete signalee
=========================================================*/
if( $this->error != ManagerError::Success ) // si il y a une erreur
return new ModuleResponse($this->error); // on la passe a la reponse
// Verification du parsage
if( $json == null )
return new ModuleRequest();
// Verification des parametres /* [2] On verifie que la methode est amorcable
if( !isset($json['path']) ) =========================================================*/
return new ModuleRequest(); if( !is_callable($this->getFunctionCaller()) ){
$this->error = ManagerError::UncallableMethod;
return new ModuleResponse($this->error);
}
// On definit $data au cas ou il soit vide
$data = (isset($json['data'])) ? $json['data'] : array();
return new ModuleRequest($json['path'], $data); /* [3] On amorce la methode
=========================================================*/
$returned = call_user_func( $this->getFunctionCaller(), $this->params );
/* [4] Vérification des erreurs et paramètres
=========================================================*/
/* (1) Vérification de l'erreur retournée, si pas Success, on retourne l'erreur */
if( isset($returned['ModuleError']) && $returned['ModuleError'] != ManagerError::Success ){
$this->error = $returned['ModuleError'];
return new ModuleResponse($this->error);
}
/* (2) Vérification du contenu, si pas défini */
if( !isset($returned['body']) ){
$this->error = ManagerError::ParamError;
return new ModuleResponse($this->error);
}
/* (3) Si @headers n'est pas défini on met par défaut */
if( !isset($returned['headers']) || !is_array($returned['headers']) )
$returned['headers'] = array();
$fromAjax = isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest';
/* [5] Si la requête vient d'ajax on crée un fichier temporaire et on renvoie son URL
=========================================================*/
if( $fromAjax ){
$tmpfname = '/tmp/download_'.uniqid().'.php';
$bodyfname = __ROOT__.'/tmp/content_'.uniqid().'.php';
/* (1) On crée le fichier temporaire */
$tmpfnameroot = __ROOT__.$tmpfname;
$tmpfile = fopen($tmpfnameroot, 'w');
fwrite($tmpfile, '<?php'.PHP_EOL);
/* (2) Script qui écrira les headers */
foreach($returned['headers'] as $header=>$value)
fwrite($tmpfile, "header(\"$header: $value\");".PHP_EOL);
/* (3) Script qui écrira le contenu */
// 1) On écrit le contenu dans un fichier temporaire (et oui encore)
$bodyfile = fopen($bodyfname, 'w');
fwrite($bodyfile, $returned['body']);
fclose($bodyfile);
chmod($bodyfname, 0775);
fwrite($tmpfile, "readfile('$bodyfname');".PHP_EOL);
/* (4) Script qui supprimera les fichiers temporaires */
fwrite($tmpfile, "unlink('$bodyfname');".PHP_EOL);
fwrite($tmpfile, "unlink(__FILE__);".PHP_EOL);
fwrite($tmpfile, '?>'.PHP_EOL);
/* (5) On ferme le fichier */
fclose($tmpfile);
chmod($tmpfnameroot, 0775);
$response = new ModuleResponse(ManagerError::Success);
$response->append('link', $tmpfname);
return $response;
/* [6] Gestion du download direct si pas AJAX
=========================================================*/
}else{
/* (1) On définit les headers */
foreach($returned['headers'] as $header=>$value)
header($header.': '.$value);
/* (2) On affiche le contenu */
echo $returned['body'];
return true;
}
} }
/* DESERIALISATION A PARTIR DES DONNEES POST /* DESERIALISATION A PARTIR DES DONNEES POST
* *
* @url<String> Contenu de l'url après api/ (si existe)
* @post<Array> Tableau des donnes $_POST => @path + @data (opt) * @post<Array> Tableau des donnes $_POST => @path + @data (opt)
* *
* @return instance<ModuleRequest> Retourne un objet de type <ModuleRequest> * @return instance<ModuleRequest> Retourne un objet de type <ModuleRequest>
* *
*/ */
public static function fromPost($post){ public static function fromPost($url, $post){
/* [0] Verification de l'authentification
=========================================================*/
// On definit le token
$token = isset($_SERVER['PHP_AUTH_DIGEST']) ? $_SERVER['PHP_AUTH_DIGEST'] : null;
/* [1] On verifie que le @path est renseigne /* [1] On verifie que le @path est renseigne
=========================================================*/ =========================================================*/
/* (1) Si le path est dans @url */
$pathInUrl = is_string($url[0]) && strlen($url[0]) > 0 && preg_match('#^([\w_-]+)/([\w_-]+)/?$#', $url[0], $urlMatches);
// On l'utilise pour le chemin
if( $pathInUrl )
$post['path'] = $urlMatches[1].'/'.$urlMatches[2];
/* (2) On vérifie dans tous les cas si le path existe */
if( !isset($post['path']) ) if( !isset($post['path']) )
return new ModuleRequest(); return new ModuleRequest();
/* [2] On verifie que @data est renseigne /* [2] On verifie que @data est renseigne
=========================================================*/ =========================================================*/
// Si variable n'existe pas, on cree un tableau vide // Si variable n'existe pas, on cree un tableau vide
$data = (isset($post['data'])) ? $post['data'] : array(); $params = $post;
// Si c'est toujours pas un tableau, on essaie de voir si c'est un json // On retire le @path de @params
$data = (!is_array($data)) ? json_decode($data, true) : $data; unset($params['path']);
// Si toujours pas de tableau, on cree un tableau vide
$data = (!is_array($data)) ? array() : $data;
/* [3] On retourne une instance de <ModuleRequest>
/* [3] On met les paramètres JSON en JSON (si ils décodent sans erreur)
=========================================================*/ =========================================================*/
return new ModuleRequest($post['path'], $data); foreach($params as $name=>$value){
$json = json_decode( $value, true );
// Si aucune erreur, on affecte la valeur
if( !is_null($json) )
$params[$name] = $json;
}
/* [4] On retourne une instance de <ModuleRequest>
=========================================================*/
// On cree notre requete avec le token
return new ModuleRequest($post['path'], $params, $token);
} }
/* VERIFICATION DU FORMAT ET DE LA COHERENCE DU CHEMIN SPECIFIE /* VERIFICATION DU FORMAT ET DE LA COHERENCE DU CHEMIN SPECIFIE
* *
* @path<String> String correspondant au chemin de delegation ("module/methode") * @path<String> String correspondant au chemin de delegation ("module/methode")
@ -214,6 +329,7 @@
$module = $matches[1]; $module = $matches[1];
$method = $matches[2]; $method = $matches[2];
/* [2] Verification de l'existence du module (conf) /* [2] Verification de l'existence du module (conf)
=========================================================*/ =========================================================*/
if( !array_key_exists($module, $this->modules) ){ // Si le module n'est pas specifie dans la conf if( !array_key_exists($module, $this->modules) ){ // Si le module n'est pas specifie dans la conf
@ -223,7 +339,7 @@
/* [3] Verification de l'existence de la methode (conf) /* [3] Verification de l'existence de la methode (conf)
=========================================================*/ =========================================================*/
if( array_search($method, $this->modules[$module]) === false ){ // Si la methode n'est pas specifie dans la conf if( array_key_exists($method, $this->modules[$module]) === false ){ // Si la methode n'est pas specifie dans la conf
$this->error = ManagerError::UnknownMethod; $this->error = ManagerError::UnknownMethod;
return false; // On retourne FALSE, si erreur return false; // On retourne FALSE, si erreur
} }
@ -244,6 +360,180 @@
/* RETOURNE SI ON A LA PERMISSION D'EXECUTER CETTE METHODE
*
* @token<String> Token d'acces a l'API (OPTIONNEL)
*
* @return permission<bool> Retourne si on a les droits ou pas pour executer cette methode
*
*/
private function checkPermission($token=null){
/* [1] On recupere les informations utiles
=========================================================*/
// On recupere le nom de la methode
$method = $this->modules[$this->path['module']][$this->path['method']];
// Si aucune permission n'est definie
if( !isset($method['permissions']) ) return true;
/* [2] Gestion si un @token est defini
=========================================================*/
if( Database::check('sha1', $token) ){
/* (1) On verifie que le token est valide */
$checkToken = new Repo('token/check', array($token) );
$token_permissions = $checkToken->answer();
// Si le token est invalide, on retourne une erreur -> FAUX
if( $token_permissions === false ){
$this->error = ManagerError::TokenError;
return false;
}
$local_permissions = $token_permissions;
/* [3] Gestion si aucun token, avec utilisateur connecté
=========================================================*/
}else if( isset($_SESSION['permission']) )
$local_permissions = $_SESSION['permission'];
// Si ni token, ni SESSION, erreur
else{
$this->error = ManagerError::PermissionError;
return false;
}
/* [4] Verification des droits parmi les permissions donnees
=========================================================*/
/* (1) On recupere la liste des permissions possibles */
$permissions = $method['permissions'];
/* (2) Si aucune permission n'est definie, on laisse l'acces */
if( count($permissions) == 0 ) return true;
/* (3) On verifie qu'il y a au moins une permission ok */
foreach($permissions as $permission)
if( in_array($permission, $local_permissions) ) return true;
/* [5] On retourne FAUX si aucun droit n'a ete trouve
=========================================================*/
$this->error = ManagerError::PermissionError;
return false;
}
/* VERIFICATION DU TYPE DES PARAMETRES ENVOYES
*
* @params<Array> Tableau associatif contenant les parametres
* @params peut se voir rajouter les paramètres optionnels s'ils ne sont pas renseignés (initialisés à NULL)
*
* @return correct<bool> Retourne si oui ou non les parametres ont le bon type
*
*/
private function checkParams(&$params){
/* [1] On verifie qu'il ne manque aucun parametre
=========================================================*/
// Si @params n'est pas un tableau
if( !is_array($params) ) return false;
$method = $this->modules[$this->path['module']][$this->path['method']];
/* [2] Si le type est defini, pour chaque param, on teste
=========================================================*/
foreach($method['parameters'] as $name=>$paramsdata){
/* (1) On récupère si le paramètre est optionnel ou pas */
$optional = isset($paramsdata['optional']) && $paramsdata['optional'] === true;
/* (2) Récupère si le paramètre est un fichier et définit comme de type 'FILE' */
$isFile = isset($paramsdata['type']) && $paramsdata['type'] == 'FILE' && isset($_FILES[$name]);
/* (3) Si le paramètre est obligatoire et qu'il n'est pas donné -> erreur */
if( !isset($params[$name]) && !$optional && !$isFile )
return false;
/* (4) Si le type n'est pas defini, on a pas besoin de le vérifier */
if( !isset($paramsdata['type']) )
continue;
/* (5) Si le paramètre est optionnel et n'est pas donné */
if( $isFile || $optional && (!isset($params[$name]) || is_null($params[$name])) ){
// On le crée le param optionnel avec la valeur NULL
$params[$name] = null;
// On donne une référence vers le fichier, si c'en est un
if( $isFile )
$params[$name] = &$_FILES[$name];
continue; // On passe au paramètre suivant
/* (6) Si le paramètre est renseigné */
}else
// Si la verification est fausse, on retourne faux
if( !Database::check($paramsdata['type'], $params[$name]) )
return false;
}
/* [3] Gestion du retour, si tout s'est bien passe
=========================================================*/
return true;
}
/* AJOUT DES OPTIONS A PARTIR DE LA CONFIGURATION
*
*/
private function buildOptions(){
/* [0] On récupère les options de la méthode en cours
=========================================================*/
$method = $this->modules[$this->path['module']][$this->path['method']];
/* (1) Si 'option' n'est pas défini (ou incorrect), on met les valeurs par défaut */
if( !isset($method['options']) || !is_array($method['options']) )
return true;
/* (2) Par défaut on définit les options par défaut */
$this->options = self::$default_options;
/* (3) On récupère les options données */
$options = $method['options'];
/* [1] Gestion des différentes options
=========================================================*/
foreach($options as $option=>$value){
/* (1) On ne prend en compte l'option que si elle est dans les options par défaut */
if( !isset(self::$default_options[$option]) )
continue;
/* (2) Le type de la valeur doit être le même que celui de la valeur par défaut */
if( gettype($value) != gettype(self::$default_options[$option]) )
continue;
/* (3) Si tout est bon, on définit la valeur */
$this->options[$option] = $value;
}
return true;
}
/* RENVOI LE CHEMIN D'AMORCAGE DE LA METHODE /* RENVOI LE CHEMIN D'AMORCAGE DE LA METHODE
* *
* @return path<Array> Retourne le chemin d'amorcage de la requete * @return path<Array> Retourne le chemin d'amorcage de la requete

View File

@ -14,7 +14,7 @@
// //
// //
class ModuleAnswer{ class ModuleResponse{
// Attributs prives utiles (initialisation) // Attributs prives utiles (initialisation)
private $data; private $data;
@ -136,8 +136,20 @@
*/ */
public function serialize(){ public function serialize(){
// Code Http
ManagerError::setHttpCode($this->error);
// Type de contenu
// header('Content-Type: application/json');
// On rajoute l'erreur au message // On rajoute l'erreur au message
$returnData = array_merge( array('ModuleError' => $this->error), $this->data ); $returnData = array_merge(
array(
'ModuleError' => $this->error,
'ErrorDescription' => ManagerError::explicit($this->error)
),
$this->data
);
return json_encode($returnData); return json_encode($returnData);

View File

@ -1,11 +1,33 @@
<?php <?php
// On definit la racine __ROOT__ si c'est pas deja fait /* [0] On definit la racine __ROOT__ si c'est pas deja fait
=========================================================*/
if( !defined('__ROOT__') ) define('__ROOT__', dirname(dirname(__FILE__)) ); if( !defined('__ROOT__') ) define('__ROOT__', dirname(dirname(__FILE__)) );
/* [1] On définit __SERVER_HOST__ et __SERVER_ROOT__ si c'est pas déja fait
=========================================================*/
if( !defined('__SERVER_HOST__') || !defined('__SERVER_ROOT') ){
/* (1) On charge le fichier de configuration */
$json = json_decode( file_get_contents(__ROOT__.'/config/server.json'), true );
// Si pas d'erreur, on définit
if( !is_null($json) ){
/* (2) Gestion de la config si server local ou remote */
if( !isset($_SERVER['SERVER_NAME']) || !checkdnsrr($_SERVER['SERVER_NAME'], 'NS') )
$config = $json['local'];
else
$config = $json['remote'];
/* (3) Création des constantes */
define('__SERVER_HOST__', $config['host']);
define('__SERVER_ROOT__', $config['root']);
}
}
@ -22,28 +44,6 @@
/* APPEL DYNAMIQUE DES CLASSES PASSEES EN PARAMETRE
*
* @classes<Array> Tableau contenant le nom des classes
*
*/
function autoload($classes){
foreach($classes as $class){
$name_only = substr(strrchr($class, '\\'), 1);
var_dump('use '.$class.' as '.$name_only.';');
eval('use '.$class.' as '.$name_only.';');
}
}
/* AUTOLOADER /* AUTOLOADER
* *
* @className<String> Nom de la classe appelee * @className<String> Nom de la classe appelee
@ -73,4 +73,15 @@
/* On demarre la session securisee PHP /* On demarre la session securisee PHP
=========================================================*/ =========================================================*/
\manager\sessionManager::session_start(); \manager\sessionManager::session_start();
/* [3] Gestion des droits des utilisateurs
=========================================================*/
/* (1) Retourne si l'utilisateur est connecte ou non */
function connected(){ return isset($_SESSION['permission']) && count($_SESSION['permission']) > 0; }
/* (2) Retourne si l'utilisateur a le status en question */
function permission($type){ return connected() && in_array($type, $_SESSION['permission']); }
?> ?>

116
manager/repo/parentRepo.php Normal file
View File

@ -0,0 +1,116 @@
<?php
namespace manager\repo;
use \manager\Database;
class parentRepo{
// mise à jour du nom de la table (pour les enfants)
protected static function table_name(){ static $table_name = null; return $table_name; }
/* GESTION DES GETTERS dynamiques
*
* @method<String> Nom du getter du type 'getAll' ou 'getX' avec 'X' une colonne de la table en question
* @args<Array> Liste des arguments, $args[0] est la valeur du getter (sauf pour 'getAll')
*
* @return lines<Array> Retourne le résultat du fetchAll()
*
*/
public static function __callStatic($method, $args){
// Si static::table_name() NULL
if( is_null(static::table_name()) ) return false;
/* [1] On vérifie que la méthode est 'getX', avec X une chaine
=========================================================*/
// Si c'est pas le bon format, on retourne une erreur
if( !preg_match('/^get(?:By(\w+)|(All))$/', $method, $matches) ) return false;
/* [2] On charge la liste des colonnes de la table
=========================================================*/
$getColumns = Database::getPDO()->query('SHOW COLUMNS FROM '.static::table_name());
$cols = Database::delNumeric( $getColumns->fetchAll() );
$table_columns = array(
'_PRIMARY_' => array() // Contiendra les champs de la clé primaire
);
// On ajoute la liste des colonnes
foreach($cols as $column){
// On enregistre la clé primaire (si elle l'est)
if( $column['Key'] == 'PRI' ) array_push($table_columns['_PRIMARY_'], $column['Field']);
array_push($table_columns, $column['Field']);
}
/* [3] On vérifie que la valeur après 'get' est dans $table_columns
=========================================================*/
$columnName = strtolower($matches[1]);
$getAll = count($matches) > 2; // Si 'getAll'
$getById = $columnName == 'id';
$getSomething = count($args) > 0 && in_array($columnName, $table_columns); // Si 'getX', et 'X' dans la liste des colonnes
// Si ni 'getAll' ni 'getSomething' -> erreur
if( !$getById && !$getAll && !$getSomething ) return false;
/* [4] On rédige la requête
=========================================================*/
$getRequestString = 'SELECT * FROM '.static::table_name();
// Si c'est 'getById', on ajoute une condition (clé primaire)
if( $getById ){
// S'il manque un paramètre, on retourne une erreur
if( count($args) < count($table_columns['_PRIMARY_']) )
return false;
// Pour chaque clé primaire (si elle est composée)
foreach($table_columns['_PRIMARY_'] as $i=>$primary_column)
// Première ligne
if( $i == 0 ) $getRequestString .= ' WHERE '.$table_columns['_PRIMARY_'][$i].' = :primary'.$i;
// Lignes suivantes
else $getRequestString .= ' AND '.$table_columns['_PRIMARY_'][$i].' = :primary'.$i;
// Si c'est 'getSomething', on ajoute une condition
}else if( $getSomething )
$getRequestString .= ' WHERE '.$columnName.' = :value';
$getRequestString .= ' ORDER BY 1 ASC';
// On prépare la requête
$getRequest = Database::getPDO()->prepare($getRequestString);
/* [5] On exécute la requête
=========================================================*/
// Si 'getById', on compose la clé primaire
if( $getById ){
$pdo_vars = array();
foreach($table_columns['_PRIMARY_'] as $i=>$primary_column)
$pdo_vars[':primary'.$i] = $args[$i];
$getRequest->execute( $pdo_vars );
// Si 'getSomething', on ajoute le champ
}else
$getRequest->execute(array(
':value' => ($getSomething||$getById) ? $args[0] : null
));
/* [6] On récupère le résultat
=========================================================*/
return Database::delNumeric( $getRequest->fetchAll() );
}
}
?>

View File

@ -58,6 +58,12 @@
/* AMORCEUR */ /* AMORCEUR */
/************/ /************/
public static function session_start(){ public static function session_start(){
// \session_start();
// return;
/* [1] Génération et Gestion des donnees a utiliser /* [1] Génération et Gestion des donnees a utiliser
==============================================================*/ ==============================================================*/
// On genere le hash a partir des donnees personnelles // On genere le hash a partir des donnees personnelles

12
test/ajaxTest.php Normal file
View File

@ -0,0 +1,12 @@
<?php define('__ROOT__', dirname(dirname(__FILE__)) );
require_once __ROOT__.'/manager/autoloader.php';
debug();
// DEFAULT SESSION CREDENTIALS
echo '{"data1": "'.session_id().'",';
echo '"data2": "'. ( $_SESSION['session_token']==$_COOKIE['session_token'] ? 'YES' : 'NO' ). '"}';
?>

View File

@ -1,4 +1,4 @@
<?php define('__ROOT__', dirname(__FILE__) ); <?php define('__ROOT__', dirname(dirname(__FILE__)) );
require_once __ROOT__.'/manager/autoloader.php'; require_once __ROOT__.'/manager/autoloader.php';
use \manager\ModuleRequest; use \manager\ModuleRequest;

53
test/sessionTest.php Normal file
View File

@ -0,0 +1,53 @@
<?php define('__ROOT__', dirname(dirname(__FILE__)) );
require_once __ROOT__.'/manager/autoloader.php';
debug();
// DEFAULT SESSION CREDENTIALS
var_dump( 'SESSID---'.session_id() );
var_dump( 'TOKEN----'.( $_SESSION['session_token']==$_COOKIE['session_token'] ? 'YES' : 'NO' ) );
?>
<div id=ajax1>NO VALUE</div><br>
<div id=ajax2>NO VALUE</div>
<br><br><br><br>
<button id=testAjax>LOAD AJAX</button>
<script type='text/javascript'>
function pHandler(data){
var parsedData = JSON.parse(data);
document.getElementById('ajax1').innerHTML = parsedData.data1;
document.getElementById('ajax2').innerHTML = parsedData.data2;
}
function testAjax(){
var xhr; // object ajax
if(window.XMLHttpRequest) // IE7+, Firefox, Chrome, Opera, Safari
xhr = new XMLHttpRequest();
else // IE5, IE6
xhr = new ActiveXObject('Microsoft.XMLHttpRequest');
xhr.onreadystatechange = function(){
if( xhr.readyState == 4 ) // si la requête est terminée
if( [0,200].indexOf(xhr.status) > -1 ) // si fichier existe et reçu
pHandler(xhr.responseText);
else // si code d'erreur retourne null
pHandler();
}
xhr.open( 'POST', '/test/ajaxTest.php', true );
xhr.send();
}
document.getElementById('testAjax').onclick = testAjax;
</script>

10
todo.md
View File

@ -135,7 +135,7 @@
- [x] [view/][view] Ajout de "use CLASS;" - [x] [view/][view] Ajout de "use CLASS;"
- [x] Ajout de "use CLASS;" dans les fichiers pour simplifier la lisibilite - [x] Ajout de "use CLASS;" dans les fichiers pour simplifier la lisibilite
- [x] [phpunit/sessionManager] test unitaires du manager de session php - [x] [phpunit/sessionManager] test unitaires du manager de session php
- [x] [ModuleAnswer] Gestion des erreurs au niveau interne des Modules - [x] [ModuleResponse] Gestion des erreurs au niveau interne des Modules
- [x] [autoloader][phpunit/bootstrap.php] Correction des bugs de $_SERVER avec PHPUnit -> autoloader + bootstrap personnalise - [x] [autoloader][phpunit/bootstrap.php] Correction des bugs de $_SERVER avec PHPUnit -> autoloader + bootstrap personnalise
- [x] [sessionManager] Import de sessionManager - [x] [sessionManager] Import de sessionManager
- [x] [phpunit/tests/Database_*] Tests unitaire de delNumeric() - [x] [phpunit/tests/Database_*] Tests unitaire de delNumeric()
@ -156,8 +156,8 @@
- [x] [view/*.php] Modification des views - [x] [view/*.php] Modification des views
- [x] Mise a jour / Modification / Correction des images du menu-side - [x] Mise a jour / Modification / Correction des images du menu-side
- [x] [ModuleRequest->dispatch] Passage de l'erreur a la reponse - [x] [ModuleRequest->dispatch] Passage de l'erreur a la reponse
- [x] [ModuleAnswer->serialize] Integration de l'erreur dans la serialisation - [x] [ModuleResponse->serialize] Integration de l'erreur dans la serialisation
- [x] [ModuleAnswer->get+getAll] Accesseurs aux donnees de la reponse - [x] [ModuleResponse->get+getAll] Accesseurs aux donnees de la reponse
- [x] Gestion des erreurs - [x] Gestion des erreurs
- [x] [ModuleError::explicit] Explicitation - [x] [ModuleError::explicit] Explicitation
- [x] Conception du systeme de delegation des managers - [x] Conception du systeme de delegation des managers
@ -165,8 +165,8 @@
- [x] [ModuleRequest->__construct] Inline (en php) - [x] [ModuleRequest->__construct] Inline (en php)
- [x] [ModuleRequest::fromString] Serialise (en json <String>) - [x] [ModuleRequest::fromString] Serialise (en json <String>)
- [x] [ModuleRequest::FromURL] Par url (POST) - [x] [ModuleRequest::FromURL] Par url (POST)
- [x] [ModuleAnswer] Module Answer - [x] [ModuleResponse] Module Answer
- [x] [ModuleAnswer->serialize] Serialisation pour renvoi - [x] [ModuleResponse->serialize] Serialisation pour renvoi
- [x] [index.php] Gestion de url/api avec donnees POST - [x] [index.php] Gestion de url/api avec donnees POST
- [x] [ModuleRequest->getFunctionCaller] Correction semantique du chemin d'amorcage, utilisation de tableau - [x] [ModuleRequest->getFunctionCaller] Correction semantique du chemin d'amorcage, utilisation de tableau
- [x] Gestion des erreurs - [x] Gestion des erreurs