Lancer un script PHP dans un article

All contributions published for previous SPIP versions

Pouvoir lancer un script personnel dans un article spécifique et créer ainsi des articles à contenu « dynamique ».

Introduction :

La philosophie de SPIP est de pouvoir publier des articles.
Donc on ne peut pas faire un <?php include( "script.php"); ?> dans un article, ca n’est pas fait pour ca.

Pourtant dans certains cas précis, vous pouvez avoir besoin d’afficher dans un article des informations que vous avez calculé et surtout qui peuvent évoluer.

Exemple

Je dois gérer sur mon site une liste des membres d’un club.

Cette liste est modifiée régulièrement, et je l’ai donc mise dans une table de ma base de données.

J’aurai pu créer une page spécifique pour afficher cette liste, et pourtant j’aurai aimé qu’elle s’intègre parfaitement dans l’environnement SPIP, déjà niveau design, mais aussi qu’on puisse faire une recherche SPIP sur la partie fixe de l’article (autour de la liste), qu’elle apparaisse dans les rubriques, etc.

J’aurai également pu utiliser la fonction de redirection d’article, mais elle ne me plait pas non plus parce que j’ai envie d’utiliser une fonctionnalité importante de SPIP qui est le cache des pages !

Je vais donc vous montrer comment j’ai fait !

Avantages :

Par rapport au développement d’un partie spéciale d’un site, cette solution permet :
-  de garder une arborescence homogène avec les rubriques de SPIP, et compatible avec le moteur de recherche.
-  de pouvoir habiller un script dans un article et donc de le modifier facilement.
-  de bénéficier du moteur de cache de SPIP.

Sécurité :

Pour une question de sécurité, chaque script proposé dans les articles DOIT être inscrit dans une liste de scripts autorisés, pour ne pas que chaque rédacteur puisse faire n’importe quoi avec n’importe quel script !

Concrètement :

Ce que nous allons pouvoir faire c’est inclure à n’importe quel endroit de l’article la commande suivante :

#INCLURE (mon_script.php3)

Ceci plusieurs fois, et avec plusieurs scripts différents.

Le filtre qui va bien

J’ai créé un filtre appelé “autoriser_php” à appliquer sur le champs voulu (en particulier #TEXTE)

Voici ce filtre, à ajouter au fichier «mes_fonctions.php3»

/*****************************************************************************/
/**  Cette fonction permet de lancer un script PHP dans un article
/**
/**  La syntaxe est la suivante :
/**    #INCLURE ( nom_fichier )
/**
/**  Auteur  : F. Quointeau
/**  Version : 0.0.2
/**  Date    : 16 Mai 2004
/*****************************************************************************/
function autoriser_php( $texte) {
 
    // Dossier où sont stockés les scripts
    $dossier_inclus = './';
 
    // Liste des scripts autorisés
    $scripts_autorises = Array( 
        'mon_premier_script.php3',
        'mon_second_script.php3'
    );
 
 
    // Les fichiers inclus autorises sont : *.php, *.php3, *.php4, *.phtml, *.htm, *.html, *.inc
    $chaine_recherche = '/#INCLU[R|D]E( *)\(( *)([^\)]*\.(php|php3|php4|phtml|htm|html|inc))( *)\)/i';
 
    // Recherche la chaine #INCLUDE(script)
    while( preg_match( $chaine_recherche, $texte, $resultats)) {
        // Verifie le droit d'inclure ce fichier script !
        $autorise = false;
        reset( $scripts_autorises);
        while( $script = each( $scripts_autorises)) {
            if( strcasecmp( $script[value], $resultats[3]) == 0) $autorise = true;
        }
        if( $autorise == true) {
            // Verifie que le fichier existe
            if( file_exists ( $dossier_inclus . $resultats[3])) {
                // Vide le buffer de sortie
                $affichage_php = '';
                // Et lance le fichier inclu !!!
                include( $dossier_inclus . $resultats[3]);
            } else {
                $affichage_php = "<b>#INCLURE: Le fichier de script n'existe pas !</b>";
            }
        } else {
            $affichage_php = "<b>#INCLURE: Script NON autoris&eacute; !</b>";
        }
        // Attention, n'effectue qu'un seul remplacement à la fois !
        $texte = preg_replace( $chaine_recherche, $affichage_php, $texte, 1);
    }
 
    return( $texte);
}

Attention :
Au début de la fonction, il y a un tableau php qui décrit la liste des scripts qui ont le droit d’être lancé à partir d’un article. Pensez à le mettre à jour avec vos scripts.

Dossier des scripts

Si vous souhaitez mettre vos scripts dans un dossier spécial, mettez également le chemin des scripts dans la variable
$dossier_inclus au début de la fonction filtre. Par exemple :

    $dossier_inclus = 'mes_scripts/';

Notez le ’/’ obligatoire à la fin du dossier.

Mais vous pouvez aussi «cacher» vos scripts (non disponibles par une requête HTTP dessus) en les placant en amont du dossier racine du site web :

    $dossier_inclus = '../mes_scripts_caches/';

Attention, en fonction de votre hébergeur, vous n’aurez pas forcément la possibilité de le faire !

Le script des familles :

Voici le script que vous voulez promouvoir :

<?php
    echo( "Hello World !");
?>

Puissant, mais vous allez devoir l’écrire sous cette forme :

<?php
    $affichage_php = "Hello World !";
?>

Vous suivez ?

Vous ne pouvez pas vous permettre d’afficher sauvagement vos informations directement par un echo( ), celles-ci ne seraient pas prises en compte dans le cache de SPIP, et souvenez-vous que votre script travaille à l’intérieur d’un filtre, et qu’il y a peut être d’autres filtres qui attendent derrière :-)

Et maintenant, comment relier le tout ?

Créez un article comme celui-ci par exemple :

Bonjour,
voici le résultat de ma fonction :
#INCLURE (mon_premier_script.php3)

Hop

Créez ensuite un fichier mon_premier_script.php3 qui contient le script énoncé plus haut; mettez le dans le dossier de SPIP si vous n’avez pas spécifié de dossier dans la variable $dossier_inclus (par défaut elle contient le dossier courant).

Dans votre squelette, vous devez avoir quelque chose du genre :

<BOUCLE_1 (ARTICLES) {id_article}>
  [(#TEXTE|autoriser_php)]
</BOUCLE_1>

J’ai appliqué le filtre “autoriser_php” à l’affichage de #TEXTE.

Et votre article affiche désormais :

Bonjour,
voici le résultat de ma fonction :
Hello World !

Hop

Pour aller un peu plus loin...

Imaginons que vous ayez besoin de récupérer une variable de l’url dans votre script. Les variables globales de SPIP sont accessibles depuis votre script, puisqu’il fonctionne à l’intérieur d’un filtre SPIP.

Regardez le script suivant

<?php
  // Ma variable
  $id_machin = $GLOBALS['id_machin'];
 
  $affichage_php = "Hello machin n°$id_machin";
?>

Je récupère la variable globale $id_machin et je l’affiche dans mon script. Cette variable globale est tout simplement une des variables passées en paramètres.

Si j’essaye l’url :
article.php3?id_article=x{{&id_machin=11}}

J’aurai alors l’affichage :

Bonjour,
voici le résultat de ma fonction :
Hello machin n°11

Hop

C’est d’autant plus pratique que SPIP va générer un cache pour TOUTES les url différentes.

Fort heureusement, sinon l’affichage de
article.php3?id_article=x&id_machin=1
serait le même que l’affichage de
article.php3?id_article=x&id_machin=2

puisque la page article.php3?id_article=x est à priori déjà dans le cache.

Attention toutefois à ne pas remplir votre cache de millions de fichiers si votre script peut comporter des millions de combinaisons de paramètres dans l’url !

Récupérer des variables globales de SPIP

En plus de pouvoir récupérer des variables de l’url, vous pouvez récupérer des variables de l’environnement SPIP, comme celle-ci :

$GLOBALS['spip_lang']

qui vous permet de récupérer la langue courante (si vous utilisez SPIP multilingue).
Ca peut en effet être très pratique si vous avez besoin de générer un affichage «localisé» avec votre script. [1]

Mise en garde avec MySQL

SPIP utilise par défaut la connexion courante à la base de données MySQL. Autrement dit, si dans votre script, vous ouvrez une base MySQL autre que celle utilisée par SPIP, celui-ci n’aura plus accès à sa base une fois le filtre exécuté.

Pour remédier à ca, il y a deux solutions :

-  Utiliser la base de SPIP. Pour avoir la base toujours ouverte au début de votre script, utilisez
include_ecrire( “inc_connect.php3”);
En effet ce sript ouvre la base seulement si elle n’est pas déjà ouverte, et l’avantage c’est que vous n’avez pas besoin de gérer vous même les paramètres d’ouverture.

-  Demander à SPIP de faire des accès complets à la base (avec sélection de la base à chaque requête). Pour ca, renseignez la variable
$mysql_rappel_connexion = true;
dans mes_options.php3 [2].

Exemple d’utilisation :

<?php
include_ecrire( "inc_connect.php3"); 
 
$ma_requete = mysql_query( "SELECT id, nom, prenom, DATE_FORMAT(naissance, '%d/%m/%Y') as naissance, FROM utilisateur ORDER BY nom,prenom");
if( $ma_requete) {
    if( mysql_num_rows($ma_requete) > 0) {
        $affichage_php .= "<table cellpadding=\"2\" align=\"center\" border=\"0\" class=\"spip\">\n";
        $affichage_php .= "<tr align=\"center\" class=\"row_first\"> <td><b>Nom</b></td> <td><b>Date de naissance</b></td> </tr>\n";
        while ($mon_resultat = mysql_fetch_array($ma_requete)) {
            $affichage_php .= "<tr class=\"row_" . ($ncr_numero_ligne++ % 2 ? 'odd' : 'even') . "\">";
            $affichage_php .= "<td>" . $mon_resultat["nom"] . " " . $mon_resultat["prenom"] . "</a></td> <td align=\"right\">" . $mon_resultat["naissance"] . "</td>";
            $affichage_php .= "</tr>\n";
        }
        $affichage_php .= "</table>\n";
    }
}
?>

Conclusion

Attention, ceci ne fonctionne que dans la partie publique évidemment !

J’utilise actuellement ce script sur mon site, et ca fonctionne plutôt bien ! Et ce qui est génial, c’est que le cache est géré correctement par SPIP.

Notez: la page est regénérée quand elle a expirée, et pas quand le résultat de votre script a changé !

Footnotes

[1Merci à Paolo pour l’info

[2Je l’indique pour information puisque je ne l’ai pas testé

updated on 30 November 2012

Discussion

46 discussions

  • 2

    Bonjour,
    Après avoir suivi à la lettre les instructions pour intégrer du PHP dans un article, j’obtiens systématiquement une erreur PHP sur la fonction autoriser_php à l’instruction finale : $texte = preg_replace( $chaine_recherche, $affichage_php, $texte, 1);
    Le code erreur est : Warning: Wrong parameter count for preg_replace() in your script on line 53

    Je ne vois pas de solution, merci d’avance de vos réponses.

    Jeff.

    • Quelle version de PHP utilises-tu ?

      -  pour le savoir, fais un script PHP qui comporte la fonction phpinfo()

      <?php
          phpinfo();
      ?>
    • j’avais le meme probleme alors j’ai viré le dernier parametre ,1 de cette fonction et ça marche

    Reply to this message

  • 7
    marrock

    j’ai une erreur sur ma page avec ce message d’erreur :

    Erreur : filtre « autoriser_php » non défini

    de l’aide serait la bienvenue

    • marrock

      je précise qu’au dessus de ma page s’affiche le script :’(

    • Tu dois impérativement ajouter la fonction :

      function autoriser_php( $texte) {
      [...]
      }

      dans le fichier “mes_fonctions.php3” à la racine de ton site SPIP comme décrit dans l’article.

      Ensuite tu peux faire un “vider le cache” à partir de l’interface d’admin pour être sûr de recalculer toutes les pages.

    • marrock

      pourtant c’est ce que je fais
      en fait on a crée une nouvelle couche de spip, un extranet ou il faut être connecté, mais je pense pas que ça soit ça

      en fait je fais appelle à une page php qui affiche une revue de presse mise à jour dynamiquement
      et mon fichier php appelle un template

      est ce que mon code html doit etre mis dans le fichier php ?
      est ce que ça retourne plusieurs variables php ? (j’ai 8)
      ou il faut que je mette tout dans une seule variable

      merci de tes réponses.

    • marrock

      hum je crois comprendre j’avais pas bien lu le script

      il faut utiliser $affichage_php
      (je pensais que c’était un exemple)

    • Et finalement tu as réussit à t’en sortir ?

    • fracasss

      Salut !
      j’ai exactement le meme probleme que marrock
      une erreur “filtre non defini”
      et ca le fait avec n’importe quel filtre “maison” (ca marche avec les filtres intégrés, mais pas avec les filtres créés dans mes_fonctions).
      Y a-t-il quelque chose a programmer dans article.php ???
      j’avoue que je suis perdu !!!

    • j’avais le meme probleme; car j’avais oublié d’encadrer le code du fichier mes_fonctions.php3 par <?php et ?>

    Reply to this message

  • bonjour,

    à mon tour :

    Dans un article, j’inclus l’appel à un fichier annees.php3 ( <?php $fond "annees"$delais 3600; include ("inc-public.php3"); ?> ).

    ll appelle donc un fichier annees.html qui peut aussi contenir du php selon les tests mais d’abord des boucles.

    Malheureusement, si le résultat s’affiche, c’est par-dessous la page (en tête, mais sous les div). Je suis même reparti du squelette article par défaut. Les inclusions ne rentrent pas dans la mise en page. Elles fonctionnaient très bien en dur, mais ici ça semble coincer.

    Pour le “$affichage_php” avec ou sans, c’est pareil mais je ne crois pas avoir trouvé la bonne syntaxe dans ce cas. Donc ça plus les boucles...

    Sinon, mon plan ne dois pas être très bon puisqu’en plus le résultat ne reste pas en cache. J’aurais tenté.

    Claude

    Reply to this message

  • Bonjour,

    Le script fonctionne parfaitement bien mais j’ai un soucis de cache. Si dans la plupart des cas le fait que SPIP cache les données issues des scripts me réjouit dans certain cas je ne veux pas qu’il les cachent.

    Alors comment faire ?

    J’avais pensé à 2 solutions mais je les trouve peu élégantes :

    -  dans mon fichier articles.php3 modifier dynamiquement la durée du cache suivant l’Id de l’article. Un tableau de gestion des exceptions qui en gros suivant l’id d’article change la durée du cache.

    -  rerouter mon article vers un squelette sans cache du style article_sans_cache.php3

    A la limite je préfére la 1er mais je me demande s’il n’y a pas une solution plus élégante qui demanderai moins de bidouille et qui reposerai sur des variables ou des trucs comme ça ?

    Reply to this message

  • 1

    Bonjour encore moi!
    Bien après trois jours d’essais je n’arrive même pas à faire le premier exercice (Je suis vraiment nul)
    Comme Nounette, J’ai créé :
    Un fichier HTML et un fichier php3 “mon_premier_script”, J’ai tout copié dans le fichier racine ou se trouve les fichiers: article.html etc..., inclus le fichier mes_fonctions.php3. J’ai tout copié/collé (en principe pas d’erreurs)
    Puis dans mon article j’ai inclu #INCLURE (mon_premier_script.php3)
    Problème, quand j’édite l’article Je retrouve:
    Bonjour, voici le résultat de ma fonction:#INCLURE (mon_premier_script.php3) Hop?
    Je ne comprend vraiment pas? merci de votre aide.

    • As-tu pensé à modifier ton fichier article.html pour ajouter le filtre au texte de l’article ?

      Comme ceci :

      [(#TEXTE|autoriser_php)]

      Fred.

    Reply to this message

  • Bonjour,
    débutant, je viende découvrir SPIP. D’après ce que j’ai compris, l’on peut afficher une requête dans un article. J’ai une base de donnée pour un club de hockey. J’aimerai afficher les équipes qui sont sélectionnée sous forme de requêtes. Est-ce possible et comment faire. Je travaille avec:Données: MySQL 4.0.17 log phpMyAdmin 2.5.7. pl1.
    Mercide votre réponse.

    christian

    Reply to this message

  • 1) Tu n’utilises pas une variable qui commence par “var_” ?
    Parce que le cache n’est pas recréé pour :
    article.php3?id_article=1&var_id=1
    et
    article.php3?id_article=1&var_id=2

    2) Oui c’est possible, il suffit de retrouver la fonction PHP qui gère ca, et l’appeler à la fin du script. Après j’ai peur qu’elle change en fonction des versions...

    J’ai regardé, la fonction n’est pas dans inc_filtres.

    Reply to this message

  • Bonjour!

    1) Tu écris: “C’est d’autant plus pratique que SPIP va générer un cache pour TOUTES les url différentes.
    Fort heureusement, sinon l’affichage de
    article.php3 ?id_article=x&id_machin=1
    serait le même que l’affichage de
    article.php3 ?id_article=x&id_machin=2”

    Malheureusement, c’est justement ça qui se passe chez moi (Spip 1.7.2). J’ai dû régler le cache à 0 pour avoir les bons résultats chaque fois que l’URL change.

    2) J’aimerais faire passer le résultat $affichage_php par le même traitement typo que subit un texte tapé normalement dans un champ Spip (insérer espace devant :!? etc.) Vois-tu comment faire cela?

    merci, Paolo

    Reply to this message

  • Ok cela fonctionne, mais j’aimerais arriver à la même chose sans stocker le résultat du script dans le cache

    A chaque affichage je souhaiterais executer le code
    Comment faire ??

    Reply to this message

  • 1
    Nounette

    Bonjour,

    Je trouve cette contrib très utile et j’essaie de l’utiliser.

    Sauf que j’ai :
    “Erreur : filtre « autoriser_php » non défini”

    J’avoue etre débutante avec php et spip... je sais, ca aide pas ;)

    -  J’ai crée un fichier mes_fonctions.php3 à la racine du site (il se trouve au milieu de article.html, rubrique.html et autres).
    -  J’ai crée un premier script comme expliqué dans la contrib : mon_premier_script.php3.
    -  j’ai ensuite créé un article avec le contenu suivant :
    Résultat de la recherche :
    #INCLURE(mon_premier_script.php3)

    -  Et sur la page d’accueil (en fond, derrière) j’ai le script de mes_fonctions.php3 qui apparait ! (j’ai pourtant fait un copier/collé à partir de la contrib)

    -  Je travaille en local : easyphp1.7 et windows xp

    Il me semble avoir suivi les instructions à la lettre. Quelque chose a pourtant du m’échapper !

    Merci de toute aide :-)

    • Nounette

      Désolée pour le dérangement...
      J’avais juste un problème de placement du filtre.
      #TEXTE|autoriser_php.
      Je l’avais placé dans une nouvelle boucle, alors qu’il suffisait simplement de l’ajouter au #TEXTE existant.

      Ca marche...
      Merci, merci :-))

    Reply to this message

Comment on this article

Who are you?
  • [Log in]

To show your avatar with your message, register it first on gravatar.com (free et painless) and don’t forget to indicate your Email addresse here.

Enter your comment here

This form accepts SPIP shortcuts {{bold}} {italic} -*list [text->url] <quote> <code> and HTML code <q> <del> <ins>. To create paragraphs, just leave empty lines.

Add a document

Follow the comments: RSS 2.0 | Atom