Mysql
 sql >> Base de données >  >> RDS >> Mysql

Comment faites-vous écho d'une instruction SQL SELECT à partir d'un fichier PHP appelé par AJAX ?

Lorsque je traite avec AJAX, que je renvoie en tant que JSON, une astuce que j'utilise consiste à tirer parti de la mise en mémoire tampon de sortie. Vous ne pouvez pas simplement faire écho ou afficher tout ce que vous voulez, car cela gâcherait les données JSON. Par exemple,

ob_start(); //turn on buffering at beginning of script.

.... other code ...

print_r($somevar);

.... other code ...

$debug = ob_get_clean();  //put output in a var
$data['debug'] = $debug;

header('Content-Type: application/json');
echo json_encode($data); //echo JSON data.

Ce que cela fait, c'est encapsuler toute sortie de votre script dans vos données JSON afin que son format ne soit pas foiré.

Ensuite, côté javascript, vous pouvez utiliser console.log

$.post(url, input, function(data){
   if(data.debug) console.log(data.debug);
});

Si vous n'êtes pas habitué à déboguer avec console.log() , vous pouvez généralement appuyer sur F12 et ouvrez le débogueur dans la plupart des navigateurs. Ensuite, la sortie sera envoyée à la "console". IE9 avait un petit problème avec console.log() si je me souviens, mais je ne veux pas aller trop loin.

REMARQUE : Assurez-vous simplement de ne pas laisser ces éléments dans le code lorsque vous le déplacez en production, c'est très simple de simplement commenter cette ligne,

//$data['debug'] = $debug;

Et puis vos informations de débogage ne seront pas exposées en production. Il existe d'autres moyens de le faire automatiquement, mais cela dépend si vous faites du développement local puis publiez sur le serveur. Par exemple, vous pouvez le basculer sur le $_SERVER['SERVER_ADDR']; qui sera ::1 ou 127.0.0.1 quand c'est local. Cela présente quelques inconvénients, principalement l'adresse du serveur n'est pas disponible à partir de l'interface de ligne de commande (CLI). Donc, généralement, je vais le lier à une constante globale qui indique dans quel "mode" se trouve le site (inclus dans le point d'entrée commun, généralement index.php).

if(!defined('ENV_DEVELOPMENT')) define('ENV_DEVELOPMENT','DEVELOPMENT');

if(!defined('ENV_PRODUCTION')) define('ENV_PRODUCTION','PRODUCTION');

if(!defined('ENVIRONMENT')) define('ENVIRONMENT',ENV_DEVELOPMENT);
//site is in Development mode, uncomment for production
//if(!defined('ENVIRONMENT')) define('ENVIRONMENT',ENV_DEVELOPMENT);

Il suffit ensuite de le vérifier :

if(ENVIRONMENT == ENV_PRODUCTION ) $data['debug'] = $debug;

Si vous savez comment utiliser les rapports d'erreurs, vous pouvez même vous y connecter en utilisant

 if(ini_get('display_errors') == 1) $data['debug'] = $debug;

Ce qui n'affichera le débogage que lorsque les erreurs d'affichage sont activées.

J'espère que ça aide.

MISE À JOUR

Parce que je l'ai mentionné dans les commentaires, en voici un exemple enveloppé dans une classe (c'est une version simplifiée, donc je n'ai pas testé cela)

class LibAjax{
    public static function respond($callback, $options=0, $depth=32){
        $result = ['userdata' => [
              'debug' => false,
              'error' => false
        ]];

        ob_start();

         try{

             if(!is_callable($callback)){
                //I have better exception in mine, this is just more portable
                throw new Exception('Callback is not callable');
             }

             $callback($result);
         }catch(\Exception $e){
              //example 'Exception[code:401]'
             $result['userdata']['error'] = get_class($e).'[code:'.$e->getCode().']';
            //if(ENVIRONMENT == ENV_DEVELOPMENT){
            //prevents leaking data in production
                $result['userdata']['error'] .= ' '.$e->getMessage();
                $result['userdata']['error'] .= PHP_EOL.$e->getTraceAsString();
            //}
         }

         $debug = '';
         for($i=0; $i < ob_get_level(); $i++){
             //clear any nested output buffers
             $debug .= ob_get_clean();
         }
         //if(ENVIRONMENT == ENV_DEVELPMENT){
             //prevents leaking data in production
              $result['userdata']['debug'] = $debug;
        //}
         header('Content-Type: application/json');
         echo self::jsonEncode($result, $options, $depth);
   }

   public static function jsonEncode($result, $options=0, $depth=32){
       $json = json_encode($result, $options, $depth);
       if(JSON_ERROR_NONE !== json_last_error()){
           //debug is not passed in this case, because you cannot be sure that, that was not what caused the error.  Such as non-valid UTF-8 in the debug string, depth limit, etc...
           $json = json_encode(['userdata' => [
              'debug' => false,
              'error' => json_last_error_msg()
           ]],$options);
       }
       return $json;
   }

}

Ensuite, lorsque vous faites une réponse AJAX, vous l'enveloppez simplement comme ceci (notez que $result est passé par référence, de cette façon, nous n'avons pas à faire de retour, et dans le cas d'une exception, nous mettons à jour $result en "temps réel" à la place à la fin)

LibAjax::respond( function(&$result){
     $result['data'] = 'foo';
});

Si vous avez besoin de transmettre des données supplémentaires dans la fermeture, n'oubliez pas que vous pouvez utiliser le use déclaration, comme celle-ci.

$otherdata = 'bar';

LibAjax::respond( function(&$result) use($otherdata){
     $result['data'][] = 'foo';
     $result['data'][] = $otherdata;
});

Sandbox

Cela gère la capture de toute sortie et la met en débogage, si l'environnement est correct (commenté). S'il vous plaît, assurez-vous de mettre en place une sorte de protection afin que la sortie ne soit pas envoyée aux clients en production, je ne saurais trop insister là-dessus. Il attrape également toutes les exceptions le met en erreur. Et il gère également l'en-tête et l'encodage.

Un gros avantage à cela est la structure cohérente de votre JSON, vous saurez (côté client) que si if(data.userdata.error) alors vous avez une exception sur le back-end. Il vous donne un endroit pour modifier vos en-têtes, encodage JSON etc...

Une note dans PHP7, vous devrez ou devriez ajouter l'interface Throwable (au lieu d'Exception). Si vous voulez attraper les classes d'erreur et d'exception ou faire deux blocs catch.

Disons simplement que je fais beaucoup d'AJAX et que j'en ai marre de réécrire tout le temps, ma classe réelle est plus étendue que celle-ci, mais c'est l'essentiel.

Bravo.

MISE À JOUR1

Cela est généralement dû au fait que vous ne retransmettez pas l'en-tête correct au navigateur. Si vous envoyez (juste avant d'appeler json_encode)

header('Content-Type: application/json');

Cela permet simplement au navigateur de savoir quel type de données il récupère. Une chose que la plupart des gens oublient, c'est que sur le Web, toutes les réponses se font sous forme de texte. Même des images ou des téléchargements de fichiers et des pages Web. Ce n'est que du texte, ce qui fait de ce texte quelque chose de spécial est le Content-Type que le navigateur pense qu'il est.

Une chose à noter à propos de header est que vous ne pouvez rien produire avant d'envoyer les en-têtes. Cependant, cela fonctionne bien avec le code que j'ai posté car ce code capturera toute la sortie et l'enverra après l'envoi de l'en-tête.

J'ai mis à jour le code d'origine pour avoir l'en-tête, je l'avais dans la classe plus complexe que j'ai posté plus tard. Mais si vous ajoutez cela, vous devriez vous débarrasser de la nécessité d'analyser manuellement le JSON.

Une dernière chose que je dois mentionner est de vérifier si j'ai récupéré JSON ou du texte, vous pouvez toujours obtenir du texte au cas où une erreur se produirait avant le démarrage de la mise en mémoire tampon de sortie.

Il y a 2 façons de procéder.

Si Data est une chaîne qui doit être analysée

$.post(url, {}, function(data){
    if( typeof data == 'string'){
        try{
            data = $.parseJSON(data);
        }catch(err){
            data = {userdata : {error : data}};
        }
    }
    if(data.userdata){
          if( data.userdata.error){
               //...etc.
          }
    }
    //....
}

Ou si vous avez l'en-tête et c'est toujours JSON, alors c'est un peu plus simple

$.post(url, {}, function(data){
    if( typeof data == 'string'){
        data = {userdata : {error : data}};
    }
    if(data.userdata){
          if( data.userdata.error){
               //...etc.
          }
    }
    //....
}

J'espère que ça aide !

MISE À JOUR2

Parce que ce sujet revient souvent, j'ai mis une version modifiée du code ci-dessus sur mon GitHub, vous pouvez le trouver ici.

https://github.com/ArtisticPhoenix/MISC/blob/master /AjaxWrapper/AjaxWrapper.php