Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Como você ecoa uma instrução SQL SELECT de um arquivo PHP chamado por AJAX?


Quando lido com AJAX, que retorno como JSON, um truque que uso é aproveitar o buffer de saída. Você não pode simplesmente ecoar ou produzir o que quiser, porque isso atrapalhará os dados JSON, por exemplo,
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.

O que isso faz é envolver qualquer saída do seu script em seus dados JSON para que seu formato não seja confuso.

Então, no lado do javascript, você pode usar console.log
$.post(url, input, function(data){
   if(data.debug) console.log(data.debug);
});

Se você não está acostumado a depurar com console.log() , normalmente você pode pressionar F12 e abra o depurador na maioria dos navegadores. Então lá a saída será enviada para o "console". O IE9 teve um pequeno problema com console.log() se bem me lembro, mas não quero ir muito longe.

OBSERVAÇÃO: Apenas certifique-se de não deixar essas coisas no código quando você movê-lo para produção, é muito simples apenas comentar esta linha,
//$data['debug'] = $debug;

E então suas informações de depuração não serão expostas na produção. Existem outras maneiras de fazer isso automaticamente, mas depende se você faz o desenvolvimento local e depois publica no servidor. Por exemplo, você pode ativá-lo no $_SERVER['SERVER_ADDR']; que será ::1 ou 127.0.0.1 quando é local. Isso tem algumas desvantagens, principalmente o endereço do servidor não está disponível na interface de linha de comando (CLI). Então, normalmente eu vou amarrá-lo em uma constante global que diz em que "modo" o site está (incluído no ponto de entrada comum, normalmente 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);

Então é uma questão simples de verificar:
if(ENVIRONMENT == ENV_PRODUCTION ) $data['debug'] = $debug;

Se você sabe como usar o relatório de erros, pode até vincular isso usando
 if(ini_get('display_errors') == 1) $data['debug'] = $debug;

Que só mostrará a depuração quando os erros de exibição estiverem ativados.

Espero que ajude.

ATUALIZAÇÃO

Porque eu mencionei isso nos comentários, aqui está um exemplo dele envolto em uma classe (esta é uma versão simplificada, então não testei isso)
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;
   }

}

Então, quando você faz uma resposta AJAX, basta envolvê-la assim (observe que $ resultado é passado por referência, dessa forma não precisamos retornar e, no caso de uma exceção, atualizamos $ resultado em "tempo real" de na conclusão)
LibAjax::respond( function(&$result){
     $result['data'] = 'foo';
});

Se você precisar passar dados adicionais para o encerramento, não esqueça que você pode usar o use declaração, assim.
$otherdata = 'bar';

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

Sandbox

Isso lida com a captura de qualquer saída e a coloca em depuração, se o ambiente estiver correto (comentado). Por favor, certifique-se de implementar algum tipo de proteção para que a saída não seja enviada aos clientes em produção, não posso enfatizar isso o suficiente. Ele também captura todas as exceções que o colocam em erro. E também lida com o cabeçalho e a codificação.

Um grande benefício para isso é uma estrutura consistente para seu JSON, você saberá (no lado do cliente) que se if(data.userdata.error) então você tem uma exceção no back-end. Dá-lhe um lugar para ajustar seus cabeçalhos, codificação JSON etc ...

Uma nota no PHP7 você terá que ou deve adicionar a interface Throwable (em vez de Exception). Se você quiser pegar as classes Error e Exception Ou faça dois blocos catch.

Vamos apenas dizer que eu faço muito AJAX e fiquei cansado de reescrever isso o tempo todo, minha aula real é mais extensa do que isso, mas essa é a essência.

Felicidades.

ATUALIZAÇÃO1

Isso geralmente ocorre porque você não está passando o cabeçalho correto de volta para o navegador. Se você enviar (logo antes de chamar json_encode)
header('Content-Type: application/json');

Isso apenas permite que o navegador saiba que tipo de dados está recebendo de volta. Uma coisa que a maioria das pessoas esquece é que na web todas as respostas são feitas em texto. Mesmo imagens ou download de arquivos e páginas da web. É tudo apenas texto, o que torna esse texto em algo especial é o Content-Type que o navegador pensa que é.

Uma coisa a ser observada sobre header é que você não pode produzir nada antes de enviar os cabeçalhos. No entanto, isso funciona bem com o código que postei porque esse código capturará toda a saída e a enviará após o envio do cabeçalho.

Atualizei o código original para ter o cabeçalho, tinha na classe mais complexa que postei depois. Mas se você adicionar isso, deve se livrar da necessidade de analisar manualmente o JSON.

Uma última coisa que devo mencionar que faço é verificar se recebi JSON de volta ou texto, você ainda pode obter texto no caso de ocorrer algum erro antes que o buffer de saída seja iniciado.

Existem 2 maneiras de fazer isso.

Se Data for uma string que precisa ser analisada
$.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 se você tem o cabeçalho e é sempre JSON, é um pouco mais simples
$.post(url, {}, function(data){
    if( typeof data == 'string'){
        data = {userdata : {error : data}};
    }
    if(data.userdata){
          if( data.userdata.error){
               //...etc.
          }
    }
    //....
}

Espero que ajude!

ATUALIZAÇÃO2

Como esse tópico aparece muito, coloquei uma versão modificada do código acima no meu GitHub, você encontra aqui.

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