Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
126 views
in Technique[技术] by (71.8m points)

mysql - How do you echo a SQL SELECT statement from a PHP file called by AJAX?

There's a lot of code in each file, too much to post, so I'm giving you a general idea of what's happening in each file.

index.php [html dropdown menu code etc.]

scripts.js [AJAX detects user selection from dropdown, grabs fetch.php which pulls database to generate html code for secondary dropdown selections to put in index.php]

fetch.php [Generates secondary dropdown code based on user selection and query of the database]

I need to see what exactly is being queried to debug, so I'd like to echo the sql select statement:

$query = "SELECT * FROM databasename WHERE.."

That is in fetch.php when user makes a selection from index.php - How do I do this?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

When I deal with AJAX, that I return as JSON, one trick I use is to take advantage of output buffering. You can't just echo or output anything you want because it will mess up the JSON data so for an example,

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.

What this does, is wrap any output from you script into your JSON data so that it's format is not messed up.

Then on the javascript side you can use console.log

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

If you are not used to debugging with console.log(), you can usually hit F12 and open the debugger in most browsers. Then in there the output will be sent to the "console". IE9 had a bit of an issue with console.log() if I recall, but I don't want to go to far off track.

NOTE: Just make sure to not leave this stuff in the code when you move it to production, its very simple to just comment this line out,

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

And then your debug information wont be exposed in production. There are other ways to automatically do this, but it depends on if you do development local then publish to the server. For example you can switch it on the $_SERVER['SERVER_ADDR']; which will be ::1 or 127.0.0.1 when it's local. This has a few drawbacks, mainly the server address is not available from the Command Line Interface (CLI). So typically I will tie it into a global constant that says what "mode" the site is in (included in the common entry point, typically 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);

Then it is a simple matter to check it:

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

If you know how to use error reporting you can even tie into that using

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

Which will only show the debug when display errors is on.

Hope that helps.

UPDATE

Because I mentioned it in the comments, here is an example of it wrapped in a class (this is a simplified version, so I didn't test this)

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;
   }

}

Then when you make a AJAX response you just wrap it like this (note $result is pass by reference, this way we don't have to do return, and in the case of an exception we update $result in "real time" instead of on completion)

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

If you need to pass additional data into the closure don't forget you can use the use statement, like this.

$otherdata = 'bar';

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

Sandbox

This handles catching any output and puts it in debug, if the environment is correct (commented out). Please pleas make sure to implement some kind of protection so that the output is not sent to clients on production, I cant stress that enough. It also catches any exceptions puts it in error. And it also handles the header and encoding.

One big benefit to this is consistent structure to your JSON, you will know (on the client side) that if if(data.userdata.error) then you have an exception on the back end. It gives you one place to tweak your headers, JSON encoding etc...

One note in PHP7 you'll have to or should add the Throwable interface (instead of Exception). If you want to catch Error and Exception classes Or do two catch blocks.

Let's just say I do a lot of AJAX and got sick of re-writing this all the time, my actual class is more extensive then this, but that's the gist of it.

Cheers.

UPDATE1

One thing I had to do for things to display was to parse the data variable before I console.log() it

This is typically because you are not passing the correct header back to the browser. If you send (just before calling json_encode)

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

This just lets the browser know what type of data it is getting back. One thing most people forget is that on the web all responses are done in text. Even images or file download and web pages. It's all just text, what makes that text into something special is the Content-Type that the browser thinks it is.

One thing to note about header is you cannot output anything before sending the headers. However this plays well with the code I posted because that code will capture all the output and send it after the header is sent.

I updated the original code to have the header, I had it in the more complex class one I posted later. But if you add that in it should get rid of the need to manually parse the JSON.

One last thing I should mention I do is check if I got JSON back or text, you could still get text in the event that some error occurs before the output buffering is started.

There are 2 ways to do this.

If Data is a string that needs to be parsed

$.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.
          }
    }
    //....
}

Or if you have the header and its always JSON, then its a bit simpler

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

Hope that helps!

UPDATE2

Because this topic comes up a lot, I put a modified version of the above code on my GitHub you can find it here.

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...