Lancer un script PHP dans un article

Ceci est une ARCHIVE, peut-être périmée. Vérifiez bien les compatibilités !

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é !

Notes

[1Merci à Paolo pour l’info

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

Dernière modification de cette page le 30 novembre 2012

Discussion

46 discussions

  • 1
    Seb-esperanto

    bonjour,

    je n’ai pas testé, mais vous devriez pouvoir utiliser les fonctions ob_start() et ob_get_contents() pour récupérer dans une chaînes les outputs générés par des echo-s faits par des scripts déjà existants...

    helpeme,
    sébastien

    • Ouais :-)
      Je n’y avais pas pensé.

      A vérifier toutefois si SPIP n’utilise pas déjà du buffering...

    Répondre à ce message

  • 2
    RItalMan

    C’est génial comme idée. Ca serait bien de proposer un script php qui puisse utiliser la fonction highlight de PHP ?

    Quelqu’un à une idée ?

    • RItalMan

      Bon j’ai trouvé comment faire pour afficher la source de mes fichiers PHP.

      Il y a juste un problème, la source du fichier PHP n’est pas bien formattée dans l’article, elle apparaît en arrière plan,c’est pas ce que je voulais ;)

      J’ai pourtant utilisé une variable :

      $source = show_source(’fichier.php’) ;
      $affichage_php = $source ;

      Une idée ?

    • RItalMan

      Bon ben j’ai encore trouvé, cc’est encore une histoire d’affichage brute donc, si vous voulez afficher la source d’un programme il faut créer un script php contenant :

      <?
      $affichage_php = highlight_file('fichier.php',TRUE');
      ?>

      Et voilà le travail :D

    Répondre à ce message

  • 5

    Bonjour,
    Très novice en php, je me suis cassé la tête bien longtemps pour insérer du php dans un article, avant de tomber avec bonheur sur cette contrib. Je l’ai adaptée à mon site dans plusieurs article et cela marche à merveille. Bon,trêve de flatterie (!), j’ai encore un souci. En lisant les réponses à cet article j’ai l’impression de ne pas être loin, mais ça bloque.

    Voici : je souhaiterais rajouter dans la commande "$ma_requete = mysql_query( « SELECT id, nom, etc... » une clause WHERE ... LIKE ... où la valeur associée à LIKE proviendrait de la saisie de l’utilisateur dans un formulaire inclus dans l’article. J’arrive à afficher la boite de saisie du formulaire, dont le code commence par « $affichage_php . » avec « $self-php » comme valeur pour ACTION et (POST) comme valeur pour METHOD. Mais la saisie de l’utilisateur n’est pas prise en compte.

    Le script débute par :

    Les paramètres de connexion ;

    un test if : $REQUEST_METHOD == post (entre guillemets simples)

    $ma_requete = mysql_query( "SELECT id, nom, etc...

    Puis viennent les commandes d’affichage des résultats puis les commandes d’affichage du formulaire.

    Merci d’avance pour le dépannage !

    • Essayes de ne pas utiliser de POST. Utilise plutôt un GET puisque c’est ce qu’utilise SPIP. Je ne sais pas (pour ne l’avoir pas testé) si SPIP récupère correctement les variables issues d’un POST.

      Sinon ton cas me paraît relativement simple :

      Tu as un formulaire sous la forme

      <form method="GET" action="article.php3">
        <input type="hidden" name="id_article" value="x">
        <input type="text" name="ma_saisie">
      </form>

      Une fois le formulaire envoyé vers l’article « x » tu as une variable globale $GLOBALS[« ma_saisie »] (dans le PHP de l’article x)

      Hop !

    • Ca coince toujours...

      J’ai remplacé ’post’ par ’get’, j’ai modifié le formulaire de façon à inclure la référence au numéro de l’article qui appelle le script php, j’ai également essayé de mettre le formulaire dans l’article même qui appelle le script php. J’ai utilisé « ma_saisie » dans le formulaire, puis « $ma_saisie » pour la valeur de LIKE, et j’ai testé aussi « $GLOBALS[ »ma_saisie« ] » pour LIKE... Rien. Au mieux le formulaire se réaffiche sans afficher les résultats, au pire j’ai une belle page blanche sans message d’erreur... Pour « ACTION », j’ai mis « article.php3 » et aussi « $self-php », mais sans succès non plus.

      Il doit y avoir une évidence que je ne vois pas...

    • Vérifies-tu l’existence de $GLOBALS[« ma_saisie »] avec un isset() ou tu le balances directement dans la chaîne SQL ?

      Ne serais-ce alors pas un problème de syntaxe du LIKE ?

    • Pas Hop !!

      La syntaxe du LIKE fonctionne avec une constante. Acceptes-tu de jeter un oeil sur mon script ? Il n’a que 40 lignes, commentaires compris... Bon, si tu as le temps... Et dans ce cas, comment l’intégrer dans un message ?

      A+
       :-))#

    • Ca marche !!

      Ben oui, c’était simple ! La lumière vient de jaillir ce matin aux aurores : il suffit de mettre le formulaire de recherche dans un article, formulaire qui fait appel au second article dans lequel est inclus le script de recherche dans la table. Je suppose que cela était implicite dans ta première réponse...
      Merci encore
       ;-))#

    Répondre à ce message

  • 2

    J’essaye, pour la première fois de mettre les scripts dans un sous-dossier.

    Pour que cela marche, il me semble que la ligne dans le code :

    // Et lance le fichier inclu !!!
    include( $resultats[3]) ;

    doit être modifiée à :

    include( $dossier_inclus . $resultats[3]) ;

    Paolo

    • Un peu que tu as raison !!!

      Ca se voit tant que ca que j’utilise mes scripts dans le dossier général de SPIP ? :-D

      Merci pour la correction !

    • Ca a été corrigé dans l’article !

      Tout est rentré dans l’ordre :-)

    Répondre à ce message

  • 6

    Merci c’est génial !!!

    Néophyte en php, (j’y viens doucement, tout doucement ...).

    J’ai a gérer une petite videotheque perso.

    je souhaite intégrer dans une page une recherche basée sur plusieurs critères

    1er >2000 ou <2000 (via des boutons radio)
    2éme Le type de film (via liste deroulante, 4 ou 5 choix possible pour le moment).
    3éme Le nom d’un acteur (le principal pourquoi pas ?).

    Et pour lancer cette requete un bouton de validation.

    Pour facilter la recherche, j’ai imaginé la chose suivante :

    J’ai crée 4/5 pages (une par choix de type de film)
    Dans chaqu’une de ces pages, qui porte en titre un type de film (action, western, polar, ...), le champ texte contient un tableau à la spip avec des « | » comme séparateur, chaque « cellule » de ce tableau (5 par ligne) contient des infos (Acteur, titre du film, durée, vo/vn, Réalisateur).

    Lorsque le choix est effectué en utilisant les boutons et les menus déroulants, on lance la recherche.
    Toujours pour faciliter, ces 4/5 pages sont bien présentes sur le site mais restent en cours de rédaction, pour ne pas être accessible aux visiteurs mais avec des infos présentent dans la base spip, (rusé ???), de plus pour extraire plus facilement les infos qu’elles contiennent, le titre de ces pages est « AA-letitredelapage ».

    Maintenant
    Je dois récupérer le titre de ces 4/5 pages (qui pourront dans le temps éventuellement augmenter) pour remplir le premier menu déroulant.
    Ensuite, je dois récupérer le contenu de la premier « cellule » de toutes les lignes du tableau présent dans le champ « texte » (Acteur) pour remplir le deuxième menu déroulant.

    Toujours avec la complicité de mon neurone, je valide le tout en cliquant sur le bouton prévu à cet effet, et là par le plus heureux des hasards .... Sous le tableau vient s’inscrire :
    L’acteur, le titre du film, la durée, VN ou VO et le nom du réalisateur.

    -  1 Suis je dans un délire total ?
    -  2 Ma façon de voir et d’imaginer n’est elle pas trop compliqué, voir ... ?
    -  3 A la reflexion, il doit y avoir plus simple ! N’est ce pas Doc ?

    En utilisant les scripts et boucles que j’ai pu lire dans l’article, puis je imaginer un jour, arriver à réaliser ceci ?

    N’y a t il pas un spipeur plus sobre que moi qui aurait pensé quelque chose de ce genre ?

    A toutes et à tous mes salutations et félicitations pour vos squelettes, boucles, fonctions, et vos nuits blanches ...

    Eric

    • Oui oui tu délires un peu.

      Tu ne peux pas faire ca en SPIP. C’est pas magique le SPIP ! C’est génial pour gérer des rubriques et des articles, mais ca ne fait pas le café ;-)

      Il faut que tu fasses une table de vidéos dans ta base de données SPIP (avec phpMyAdmin) et que tu fasses une recherche comme l’exemple que j’ai donné avec une table « utilisateur »...

      Bon courage !

    • merci doc ; je le savais que le neurone n’était pas bien .. Je vais faire ce qu’il faut de ce coté et suivre ta méthode.

      Bravos et remerciements amicaux

      Eric

    • Bonjour !

      Novice mais tenace ...

      J’ai suivi au plus près les explications données.

      J’approche du résultat, sauf que :
      -  Le résultat de mon script s’affiche dans tous les articles du site et non seulement sur celui voulu. (Article id 14)
      -  dans cet article lors de l’affichage, je vois apparaitre sur la page :
      #INCLURE (mon_premier.php)
      des textes parasites (des infos provenant de la partie texte d’autres rubriques et d’autres articles).
      et enfin le résultat de mon script.

      Quand je demande l’affichage d’autres articles, j’obtiens :

      le contenu de l’aricle en question, suivi des textes parasites
      et du résultat de mon script.

      J’ai bien introduit dans le squelette :


      (#TEXTE

      (14) étant l’id de l’article en question.

      je suppose que je n’ai pas placé cela correctement dans le squelette.

      Peut on savoir précisément à quel endroit du squelette il faut donc le placer.

      Remerciements amicaux

      Eric

    • Erratum

      dans mon précdent message, il faut lire :

      BOUCLE_1 (ARTICLES) 14>

      (#TEXTE

      /BOUCLE_1>

      et non ce qu’il y a d’inscrit

      Eric

    • Normal que ca déconne !

      Ce bout de code oblige SPIP à afficher le contenu de l’article 14, quel que soit l’article demandé !

      Nulle part dans tes squelettes tu ne dois faire référence à ce fameux article 14.

      Si tu mets des spécifications dans tes squelettes, c’est inhiber le principe même de cette contrib, qui te permet d’afficher un bout de code PHP sans avoir besoin de l’ajouter dans le squelette !

      Le PHP est lié à l’article, et le squelette affiche n’importe quel article.

      Tu me suis ?

    • ok doc, je test cela demain vu l’heure, ce soir ...

      Merci des tuyaux.

      Amities

      eric

    Répondre à ce message

  • 2

    Est-il possible d’envisager sur le même principe de passer des paramètres a la fonction depuis l’article de la meme maniere que lorsqu’on fait un <INCLURE("template.php3") {lang} {id_rubrique}> ?

    • Ca n’est à priori pas prévu pour l’instant. Tout simplement parce que l’utilité est relativement restreinte. Tu as à ta disposition TOUTES les variables globales, y compris $GLOBALS[’id_rubrique’] si tu en as besoin.

    • oui mais dans mon cas il y aurait des parametres à passer autres que les variables globales
      je vais essayer de voir si je peux adapter ton script ou si qqun s’en sent capable.

    Répondre à ce message

Ajouter un commentaire

Qui êtes-vous ?

Pour afficher votre trombine avec votre message, enregistrez-la d’abord sur gravatar.com (gratuit et indolore) et n’oubliez pas d’indiquer votre adresse e-mail ici.

Ajoutez votre commentaire ici

Ce champ accepte les raccourcis SPIP {{gras}} {italique} -*liste [texte->url] <quote> <code> et le code HTML <q> <del> <ins>. Pour créer des paragraphes, laissez simplement des lignes vides.

Ajouter un document

Suivre les commentaires : RSS 2.0 | Atom