[SPIP][PLUGINS] v3.0-->v3.2
[lhc/web/www.git] / www / ecrire / public / sandbox.php
index d0cbd39..f877c08 100644 (file)
@@ -3,44 +3,61 @@
 /***************************************************************************\
  *  SPIP, Systeme de publication pour l'internet                           *
  *                                                                         *
- *  Copyright (c) 2001-2016                                                *
+ *  Copyright (c) 2001-2017                                                *
  *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
  *                                                                         *
  *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
  *  Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne.   *
 \***************************************************************************/
 
+/**
+ * Gestion d'une sécurisation des squelettes
+ *
+ * Une surcharge de ce fichier pourrait permettre :
+ *
+ * - de limiter l'utilisation des filtres à l'aide d'une liste blanche ou liste noire,
+ * - de rendre inactif le PHP écrit dans les squelettes
+ * - de refuser l'inclusion de fichier PHP dans les squelettes
+ *
+ * @package SPIP\Core\Compilateur\Sandbox
+ **/
 
-if (!defined('_ECRIRE_INC_VERSION')) return;
+if (!defined('_ECRIRE_INC_VERSION')) {
+       return;
+}
 
 /**
- * Composer le code d'execution d'un texte
- * en principe juste un echappement de guillemets
+ * Composer le code d'exécution d'un texte
+ *
+ * En principe juste un echappement de guillemets
  * sauf si on veut aussi echapper et interdire les scripts serveurs
- * dans les squelette
+ * dans les squelettes
  *
  * @param string $texte
- * @param string $code
- * @param string $arglist
- * @param Object $p
+ *     Texte à composer
+ * @param Champ $p
+ *     Balise qui appelle ce texte
  * @return string
+ *     Texte
  */
-function sandbox_composer_texte($texte, &$p){
-       $code = "'".str_replace(array("\\","'"),array("\\\\","\\'"), $texte)."'";
+function sandbox_composer_texte($texte, &$p) {
+       $code = "'" . str_replace(array("\\", "'"), array("\\\\", "\\'"), $texte) . "'";
+
        return $code;
 }
 
 
 /**
- * Composer le code d'execution d'un filtre
+ * Composer le code d'exécution d'un filtre
  *
  * @param string $fonc
  * @param string $code
  * @param string $arglist
- * @param Object $p
+ * @param Champ $p
+ *     Balise qui appelle ce filtre
  * @return string
  */
-function sandbox_composer_filtre($fonc, $code, $arglist, &$p){
+function sandbox_composer_filtre($fonc, $code, $arglist, &$p) {
        if (isset($GLOBALS['spip_matrice'][$fonc])) {
                $code = "filtrer('$fonc',$code$arglist)";
        }
@@ -48,6 +65,7 @@ function sandbox_composer_filtre($fonc, $code, $arglist, &$p){
        // le filtre est defini sous forme de fonction ou de methode
        // par ex. dans inc_texte, inc_filtres ou mes_fonctions
        elseif ($f = chercher_filtre($fonc)) {
+
                // cas particulier : le filtre |set doit acceder a la $Pile
                // proto: filtre_set(&$Pile, $val, $args...)
                if (strpbrk($f, ':')) { // Class::method
@@ -56,16 +74,17 @@ function sandbox_composer_filtre($fonc, $code, $arglist, &$p){
                        $refl = new ReflectionFunction($f);
                }
                $refs = $refl->getParameters();
-               if (isset($refs[0]) AND $refs[0]->name == 'Pile') {
+               if (isset($refs[0]) and $refs[0]->name == 'Pile') {
                        $code = "$f(\$Pile,$code$arglist)";
-               }
-               else {
+               } else {
                        $code = "$f($code$arglist)";
                }
        }
        // le filtre n'existe pas,
        // on le notifie
-       else erreur_squelette(array('zbug_erreur_filtre', array('filtre'=>  texte_script($fonc))), $p);
+       else {
+               erreur_squelette(array('zbug_erreur_filtre', array('filtre' => texte_script($fonc))), $p);
+       }
 
        return $code;
 }
@@ -85,80 +104,105 @@ else {
  * Composer le code d'inclusion PHP
  *
  * @param string $fichier
- * @param Object $p
+ * @param Champ $p
+ *     Balise créant l'inclusion
  * @param array $_contexte
  * @return string
  */
-function sandbox_composer_inclure_php($fichier, &$p, $_contexte){
+function sandbox_composer_inclure_php($fichier, &$p, $_contexte) {
        $compil = texte_script(memoriser_contexte_compil($p));
        // si inexistant, on essaiera a l'execution
-       if ($path = find_in_path($fichier))
+       if ($path = find_in_path($fichier)) {
                $path = "\"$path\"";
-       else $path = "find_in_path(\"$fichier\")";
+       } else {
+               $path = "find_in_path(\"$fichier\")";
+       }
 
        return sprintf(CODE_INCLURE_SCRIPT, $path, $fichier, $compil, $_contexte);
 }
 
 /**
- * Composer le code se securisation anti script
+ * Composer le code de sécurisation anti script
  *
  * @param string $code
- * @param Object $p
+ * @param Champ $p
+ *     Balise sur laquelle s'applique le filtre
  * @return string
  */
-function sandbox_composer_interdire_scripts($code, &$p){
+function sandbox_composer_interdire_scripts($code, &$p) {
        // Securite
        if ($p->interdire_scripts
-       AND $p->etoile != '**') {
-               if (!preg_match("/^sinon[(](.*),'([^']*)'[)]$/", $code, $r))
+               and $p->etoile != '**'
+       ) {
+               if (!preg_match("/^sinon[(](.*),'([^']*)'[)]$/", $code, $r)) {
                        $code = "interdire_scripts($code)";
-               else {
+               else {
                        $code = interdire_scripts($r[2]);
                        $code = "sinon(interdire_scripts($r[1]),'$code')";
                }
        }
+
        return $code;
 }
 
 
 /**
  * Appliquer des filtres sur un squelette complet
- * la fonction peut plusieurs tableaux de filtres a partir du 3eme argument
- * qui seront appliques dans l'ordre
+ *
+ * La fonction accèpte plusieurs tableaux de filtres à partir du 3ème argument
+ * qui seront appliqués dans l'ordre
+ *
+ * @uses echapper_php_callback()
  *
  * @param array $skel
  * @param string $corps
  * @param array $filtres
- * @param array ...
+ *     Tableau de filtres à appliquer.
  * @return mixed|string
  */
-function sandbox_filtrer_squelette($skel, $corps, $filtres){
+function sandbox_filtrer_squelette($skel, $corps, $filtres) {
        $series_filtres = func_get_args();
        array_shift($series_filtres);// skel
        array_shift($series_filtres);// corps
 
        // proteger les <INCLUDE> et tous les morceaux de php licites
-       if ($skel['process_ins'] == 'php')
-               $corps = preg_replace_callback(',<[?](\s|php|=).*[?]>,UimsS','echapper_php_callback', $corps);
+       if ($skel['process_ins'] == 'php') {
+               $corps = preg_replace_callback(',<[?](\s|php|=).*[?]>,UimsS', 'echapper_php_callback', $corps);
+       }
 
        // recuperer les couples de remplacement
        $replace = echapper_php_callback();
 
-       foreach($series_filtres as $filtres){
-               if (count($filtres))
+       foreach ($series_filtres as $filtres) {
+               if (count($filtres)) {
                        foreach ($filtres as $filtre) {
-                               if ($filtre AND $f = chercher_filtre($filtre))
+                               if ($filtre and $f = chercher_filtre($filtre)) {
                                        $corps = $f($corps);
+                               }
                        }
+               }
        }
 
        // restaurer les echappements
-       return str_replace($replace[0],$replace[1],$corps);
+       return str_replace($replace[0], $replace[1], $corps);
 }
 
 
-// http://doc.spip.org/@echapper_php_callback
-function echapper_php_callback($r=null) {
+/**
+ * Callback pour échapper du code PHP (les séquences `<?php ... ?>`)
+ *
+ * Rappeler la fonction sans paramètre pour obtenir les substitutions réalisées.
+ *
+ * @see sandbox_filtrer_squelette()
+ *
+ * @param array|null $r
+ *     - array : ce sont les captures de la regex à échapper
+ *     - NULL : demande à dépiler tous les échappements réalisés
+ * @return string|array
+ *     - string : hash de substitution du code php lorsque `$r` est un array
+ *     - array : Liste( liste des codes PHP, liste des substitutions )
+ **/
+function echapper_php_callback($r = null) {
        static $src = array();
        static $dst = array();
 
@@ -166,12 +210,14 @@ function echapper_php_callback($r=null) {
        // on enregistre le code a echapper dans dst, et le code echappe dans src
        if (is_array($r)) {
                $dst[] = $r[0];
-               return $src[] = '___'.md5($r[0]).'___';
+
+               return $src[] = '___' . md5($r[0]) . '___';
        }
 
        // si on recoit pas un tableau, on renvoit les couples de substitution
        // et on RAZ les remplacements
-       $r = array($src,$dst);
+       $r = array($src, $dst);
        $src = $dst = array();
+
        return $r;
 }