8792 sujets

Développement web côté serveur, CMS

Bonjour à tous,

Je suis actuellement en train de développer un site en utilisant PHP.

J'ai commencé à utiliser les "include" en PHP, mais j'ai lu pas mal de choses diverses et variées (plusieurs tutoriaux et pas mal d'articles sur le sujet) et tout se mélange. Je suis vraiment confuse donc j'ose poster ici... 2 problèmes se posent :

- celui de la sécurisation de mes pages (je vous mets le code ci-dessous et vous verrez qu'il est vraiment très basique)



<?php include('haut.php');  ?>

<div id="contenu">

<?php include('menu.php');  ?>
		
<? if (!isset($_GET["page"])){
				include('accueil.php');
				}else{
				if ($_GET["page"]=="accueil"){
				include('accueil.php');
				}
				elseif ($_GET["page"]=="mettre-son-bien-en-vente"){
				include('mettre-son-bien-en-vente.php');
				}
				elseif ($_GET["page"]=="faire-estimer-son-bien"){
				include('faire-estimer-son-bien.php');
				}
				elseif ($_GET["page"]=="programmes-neufs"){
				include('programmes-neufs.php');
				}
				elseif ($_GET["page"]=="agences"){
				include('agences.php');
				}
				elseif ($_GET["page"]=="contact"){
				include('contact.php');
				}
				elseif ($_GET["page"]=="chercher-un-bien"){
				include('chercher-un-bien.php');
				}
				elseif ($_GET["page"]=="mentions-legales"){
				include('mentions-legales.php');
				}
				elseif ($_GET["page"]=="fiche"){
				include('fiche.php');
				}
				elseif ($_GET["page"]=="questions-reponses"){
				include('questions-reponses.php');
				}
				elseif ($_GET["page"]=="terrains"){
				include('terrains.php');
				}
				elseif ($_GET["page"]=="commerces"){
				include('commerces.php');
				}
				elseif ($_GET["page"]=="maisons"){
				include('maisons.php');
				}
				elseif ($_GET["page"]=="appartements"){
				include('appartements.php');
				}

			}
?>
</div>


- celui du dynamisme du site : la méthode de tests que j'ai trouvée me paraît très lourde : j'ai une bonne centaine de pages (résultats de requêtes paginés automatiquement) et ce nombre de pages augmentera encore par la suite.

Je ne peux pas aller rajouter chacune des pages dans le test de ma page d'index, ça prendrait trop de temps et de ressources, et surtout la personne qui tiendra à jour le site ne saurait pas le faire.

Ma question est donc : Comment utiliser les include de façon assez sécurisée, tout en pouvant rajouter autant de pages que je le souhaite sans devoir remodifier du code PHP à chaque fois ?

Se tourner vers un CMS me paraît tellement plus simple, mais n'est pas adapté à la structure du site que je dois développer. Je ne peux donc pas envisager de CMS pour cette fois !

Merci d'avance pour votre aide.
Modifié par camelie (20 Apr 2007 - 12:58)
Bonjour camelie,

Je commence en toute logique par ton premier problème qui (finalement) n'en est pas un. Il existe en effet un problème de sécurité avec l'include mais ton code (celui que tu postes en tout cas) n'est pas affecté par ce problème (explication de ce problème : utilisation directe d'une valeur d'un paramètre transmis par get dans un include ; ce qui permet à un être malfaisant d'inclure ce qu'il veut sans aucun problème). Dans ton cas, tu testes la valeur de $_GET['page'] donc pas de problème (à ma connaissance).

Pour le deuxième problème, tout dépend de comment tu as géré ton site dès le départ (organisation des pages, base de données ? ... etc.) ...

Une solution toutefois pour ton système de test : utiliser un tableau :

if (!empty($_GET['page']))
{
           $pages = array('page1','page2','page3');
           if (in_array($_GET['page'],$pages))
           {
                  include($_GET['page'].".php");
           }
           else
           {
                  include("accueil.php");
           }
}
else
{
           include("accueil.php");
}


<edit>En effet, isset($_GET['page']) est inutile ici (je l'ai viré du code précédent). Préférez la solution proposée au post suivant (qui passe par le test de l'existence de la page à inclure).</edit>

Bonne continuation.
Romain
Modifié par yodaswii (20 Apr 2007 - 12:08)
Salut,

Pour compléter les dires de maître yoda, tu peux également procéder comme cela (voir le code) pour tester l'existance de la page web qui est incluse en fonction du paramètre get :

if (!empty($_GET['page']) && file_exists('repertoire_contenant_tes_pages_php/' . $_GET['page'] . '.php') {
    include('repertoire' . / $_GET['page'] . '.php');
}
else {
  include('repertoire/accueil.php');
}


Rmq : je n'ai pas remis le test isset($_GET['page']) car le test !empty($_GET['page']) permet de vérifier l'existance de la variable (isset) et également que cette dernière n'est pas vide.

Cela te permet de rajouter autant de page web que tu souhaites sans avoir à toucher le code source ci-dessus.

Juste pour finir, il existe également une autre fonction pour inclure un fichier dans un fichier php qui est require. Personnelement, je préfère utiliser require car si le fichier que je tente d'inclure n'existe pas, le script php est automatiquement arrêté contrairement à include. A part ca, ils fonctionnent tout les deux de la même facon.

Voici un petit site qui compare les deux méthodes afin de te faire une idée Smiley cligne
Modifié par ymhotepa (19 Apr 2007 - 23:12)
Administrateur
avec le script ci-dessus il faudrait également tester la syntaxe du nom, pour ne pas y placer de . ou de / par exemple, avec un petit preg_match('/$[a-z0-9\-]+^/i',$page) (à l'arrache)
ymhotepa a écrit :
Salut,

Juste pour finir, il existe également une autre fonction pour inclure un fichier dans un fichier php qui est require. Personnelement, je préfère utiliser require car si le fichier que je tente d'inclure n'existe pas, le script php est automatiquement arrêté contrairement à include. A part ca, ils fonctionnent tout les deux de la même facon.

Voici un petit site qui compare les deux méthodes afin de te faire une idée Smiley cligne


Je dirais encore mieux Smiley lol require_once permet d'inclure une seule et unique fois ce fichier.
Bonjour,

Merci beaucoup d'avoir pris le temps de me donner ces infos, je vais tester vos solutions Smiley cligne

Et effectivement, le require (ou require_once, même) semble plus "brut" mais au moins, en stoppant tout s'il manque le fichier à inclure, tout est limpide. Et puis la solution proposée sur l'article est pas mal non plus.

Bon bon, je vais me replonger dans le code pour mettre tout ça en place et vous tenir au courant...

*plouf !*
Alors... ça marche ! Je vais donc mettre le sujet en [Résolu] et vous montrer le code adopté finalement (ça peut servir à quelqu'un, qui sait.).



if (!empty($_GET['page']) && file_exists($_GET['page'] . '.php') ) {

    require_once($_GET['page'] . '.php');

}
else {

  require_once('accueil.php');

}



Dios mios ça a l'air si simple comme ça... Merci beaucoup à vous !


Une question subsiste : Dew, tu proposais un contrôle supplémentaire sur le nom du fichier inclus. Je suis certaine qu'il faudrait l'intégrer au code, mais je ne connais pas parfaitement les expressions régulières et après des recherches voilà ce que je peux dire :

Tu proposes :
 && preg_match('[#red]/$[a-z0-9\-]+^/i[/#]',$_GET['page'])) 


Je traduis littéralement :
Chaîne qui après le "/", se termine par une chaîne de caractères pouvant contenir des lettres (a-z), ou des chiffres (0-9), ou les symboles "\" et "-"... et il me manque la fin ! Smiley murf

A bientôt.
Modifié par camelie (20 Apr 2007 - 11:14)
dew a écrit :
preg_match('/$[a-z0-9\-]+^/i',$page)

Cette expression régulière vérifie que le nom de fichier contient uniquement des lettres (a à z), des chiffres (0 a 9), ou bien un \, ou encore un -. Le + indique que le nom doit contenir au moins 1 caractère.

Par contre, notre cher Dew a inverser les caractères $ et ^. En effet, ^ indique le début de la chaîne (il indique également le/les caractères ne devant pas apparaitre dans la chaine lorsque celui-ci est placé dans une classe. Par exemple [^1] indique que la chaine doit contenir n'importe quel caractère sauf le 1). Quant au $, il indique la fin de la chaîne.

Ensuite, les / permettent des délimiter l'expression régulière.

Enfin, le i après le délimiteur de l'expression régulière indique que la recherche ne sera pas sensible à la casse

J'éspère que cela t'aidera Smiley cligne
Bonjour,

Pour donner suite à ce post bien intéressant, voici un essai de formalisation d'une fonction correspondante. Merci de m'indiquer votre avis.
<?php

/**
 @ param  string 	: résultat d'un $_GET['page] inséré ici dans $prm_getatester   
  - On doit ici fournir nom du fichier composé : des lettres a-z ou A-Z, des chiffres, de - ou de _
 @ param  string	: chemin absolu à la page à inclure inséré ici dans $prm_chemin
  - On doit ici fournir chemin composé : des lettres a-z et A-Z, des chiffres, de - ou de _, de \ ou de /
  - Chemin doit se terminer par un \ ou / pour pouvoir y  accoler ensuite le nom du fichier
 @ param  string : type d'inclusion inséré ici dans $prm_inclusion
  - valeurs attendues :   'r1' pour require_once ; 'r2' pour require ; 'i1' pour include_once ; 'i2' pour include
 @ return  string  : résultat de la demande d'inclusion. Messages possibles : 
  - 'pbp1' pour indiquer que le premier paramètre reçu n\'est pas un nom de fichier valide
  - 'pbp2' pour indiquer que le deuxième paramètre reçu - n\'est pas un chemin de fichier valide
  - 'pbp3' pour indiquer que le troisième paramètre reçu n'est pas l'une des 4 valeurs pour un type d\'inclusion
  - 'okr1' pour indiquer qu'une inclusion via require_once a été effectuée
  - 'okr2' pour indiquer qu'une inclusion via require a été effectuée
  - 'oki1' pour indiquer qu'une inclusion via include_once a été effectuée
  - 'oki2' pour indiquer qu'une inclusion via include a été effectuée
  - 'pbge' pour indiquer un problème général 
**/

function F_IncludeRequireByGet ($prm_getatester, $prm_chemin, $prm_inclusion) 
{
// Créer une variable drapeau
  $flag =0 ;
// Tester le premier paramètre
  if (preg_match('/^[a-z0-9_-]+$/i',$prm_getatester))
      /**
      Présentation de cette expression régulière : autorise les lettres a-z et A-Z, les chiffres, -, _
       /      : ouvre l'expression
       ^      : indique le début de la chaîne sujet à l'extérieur des crochets (sinon, indiquerait une négation)   
       [      : ouvre une classe
       a-z0-9 : RAS caractère alphanumérique minuscules
       -      : repère un tiret
       _      : repère un underscore
       ]      : ferme la classe
       +      : indique qu'il doit y avoir au moins un caractère
       $      : indique la fin de la chaîne sujet 
       /      : délimite la fin de l'expression régulière
       i      : indique que la recherche effectuée via l'expression rationnelle est insensible à la casse
      **/
  { $flag +=1 ;   // on met flag à 1 pour indiquer OK
  }
  else 
  { return 'pbp1';
  } 

// Tester le 2è paramètre $prm_chemin
  if (preg_match('/^[a-z0-9\/\\_-]*$/i',$prm_getatester))
      /**
      Présentation de cette expression régulière : Idem à celle du dessus !!! sauf rajout : 
       \\     : repère le caractère \  (Rq : le premier \ sert de caractère d'échappement)
       \/     : repère le caractère /  (Rq : le \ sert de caractère d'échappement)
       .      : repère le point        (Rq : pour cas d'un chemin provenant d'une autre adresse web)
      Modif par ailleurs du + en étoile pour indiquer qu'il peut y avoir 0 caractères ou plus
      **/
  { $flag +=1 ;   // on met flag à 1 pour indiquer OK
  }
  else 
  { return 'pbp2'; //problème sur le 2è paramètre
  } 

// Tester le paramètre $prm_inclusion
  //Cf. test au fil de l'eau via traitement ci-après (r1, i1, r2, i2)

// Procéder à l'inclusion si le paramètre $prm_inclusion convient, sinon retourner
  /** 
  * Note préalable : "it is important to realize that switch statements evaluate each case with 
  * the "==" operator by default. This can lead to unexpected results when comparing strings to integers, 
  * because PHP will convert the string to an integer. In many cases this means a string can be equivalent 
  * to the integer 0. (...) The easiest way to combat this issue is to force type comparison by using 
  * the "===" operator. This makes PHP forego the string to integer conversion. "
  * source : remarque de "scott at firefallpro dot com" sur  http://www.php.net/switch  (200705)
  **/

  if ($flag === 2 && !empty($prm_getatester) && file_exists($prm_chemin . $prm_getatester . '.php') 
  { $temp = $prm_chemin . $prm_getatester . '.php' ;
    switch ($prm_inclusion)
    { case ($prm_inclusion === 'r1') :
        require_once($temp);
        $temp_msg = 'okr1' ;  
        break ;                           
      case ($prm_inclusion === 'i1') :
        include_once($temp);
        $temp_msg = 'oki1' ;  
        break ;
      case ($prm_inclusion === 'r2') :
        require($temp);
        $temp_msg = 'okr2' ;  
        break ;
      case ($prm_inclusion === 'i2') :
        include($temp);
        $temp_msg = 'oki2' ;  
        break ;
      default : 
        return 'pbp3' ; // problème sur le 3è paramètre relatif au type d'inclusion
    }
    return $temp_msg ;
  }
  else {
    return 'pbge' ;
  }
}
?>

Encore mieux, si le paramètre page n'est pas vide, et n'est pas dans le tableau de pages valides, envoyer une erreur 404.


Après l'HTML, le protocole HTTP est la norme la moins respectée Smiley decu