JSONとして返すAJAXを扱うとき、私が使用する1つのトリックは、出力バッファリングを利用することです。 JSONデータを台無しにするため、必要なものをエコーしたり出力したりすることはできません。たとえば、
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.
これは、スクリプトからの出力をJSONデータにラップして、形式が乱れないようにすることです。
次に、JavaScript側でconsole.logを使用できます
$.post(url, input, function(data){
if(data.debug) console.log(data.debug);
});
console.log()
を使用したデバッグに慣れていない場合 、通常はF12
を押すことができます ほとんどのブラウザでデバッガを開きます。次に、そこで出力が「コンソール」に送信されます。 IE9には、console.log()
に少し問題がありました。 思い出したとしても、遠くに行きたくないのです。
注: 本番環境に移行するときは、コードにこのようなものを残さないように注意してください。この行をコメントアウトするのは非常に簡単です。
//$data['debug'] = $debug;
そして、デバッグ情報は本番環境では公開されません。これを自動的に行う方法は他にもありますが、ローカルで開発してからサーバーに公開するかどうかによって異なります。たとえば、$_SERVER['SERVER_ADDR'];
で切り替えることができます これは::1
になります または127.0.0.1
それがローカルであるとき。これにはいくつかの欠点があります。主に、サーバーアドレスはコマンドラインインターフェイス(CLI)から利用できません。したがって、通常は、サイトがどの「モード」にあるかを示すグローバル定数に関連付けます(共通のエントリポイント、通常は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);
次に、それを確認するのは簡単なことです:
if(ENVIRONMENT == ENV_PRODUCTION ) $data['debug'] = $debug;
エラー報告の使用方法を知っている場合は、
を使用してそれに結び付けることもできます。 if(ini_get('display_errors') == 1) $data['debug'] = $debug;
表示エラーがオンの場合にのみデバッグが表示されます。
お役に立てば幸いです。
更新
コメントで言及したので、これはクラスにラップされた例です(これは簡略化されたバージョンなので、これをテストしませんでした)
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;
}
}
次に、AJAX応答を作成するときは、次のようにラップします($ resultは参照によって渡されるため、returnを実行する必要はありません。例外の場合は、代わりに$resultを「リアルタイム」で更新します。完了時の)
LibAjax::respond( function(&$result){
$result['data'] = 'foo';
});
クロージャーに追加のデータを渡す必要がある場合は、use
を使用できることを忘れないでください このようなステートメント。
$otherdata = 'bar';
LibAjax::respond( function(&$result) use($otherdata){
$result['data'][] = 'foo';
$result['data'][] = $otherdata;
});
これは、出力のキャッチを処理し、環境が正しい(コメントアウトされている)場合はデバッグに入れます。出力が本番環境でクライアントに送信されないように、何らかの保護を実装するようにしてください。十分に強調することはできません。また、例外をキャッチしてエラーを発生させます。また、ヘッダーとエンコーディングも処理します。
これの大きな利点の1つは、JSONの構造が一貫していることです。これにより、(クライアント側で)if(data.userdata.error)
次に、バックエンドに例外があります。ヘッダー、JSONエンコーディングなどを微調整するための1つの場所を提供します...
PHP7の1つの注意点は、(例外の代わりに)Throwableインターフェースを追加する必要があるか追加する必要があることです。 ErrorクラスとExceptionクラスをキャッチする場合、または2つのキャッチブロックを実行する場合。
私がAJAXをたくさんやっていて、これをいつも書き直すことにうんざりしているとしましょう。私の実際のクラスはこれよりも広範囲ですが、それがその要点です。
乾杯。
UPDATE1
これは通常、正しいヘッダーをブラウザに返さないためです。送信する場合(json_encodeを呼び出す直前)
header('Content-Type: application/json');
これにより、ブラウザはどのタイプのデータを取得しているかを知ることができます。ほとんどの人が忘れていることの1つは、Webではすべての応答がテキストで行われることです。画像やファイルのダウンロードやウェブページですら。それはすべて単なるテキストであり、そのテキストを特別なものにするのはContent-Type
です。 ブラウザがそれを認識していること。
header
について注意すべきことが1つあります ヘッダーを送信する前に何も出力できないということです。ただし、これは私が投稿したコードでうまく機能します。そのコードはすべての出力をキャプチャし、ヘッダーが送信された後に送信するからです。
元のコードを更新してヘッダーを作成しました。後で投稿した、より複雑なクラスに追加しました。ただし、これを追加すると、JSONを手動で解析する必要がなくなります。
最後に言及しなければならないのは、JSONが返されるかテキストが返されるかどうかを確認することです。出力バッファリングが開始される前にエラーが発生した場合でも、テキストを取得できます。
これを行うには2つの方法があります。
データが解析する必要のある文字列の場合
$.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.
}
}
//....
}
または、ヘッダーとその常にJSONがある場合は、少し単純です
$.post(url, {}, function(data){
if( typeof data == 'string'){
data = {userdata : {error : data}};
}
if(data.userdata){
if( data.userdata.error){
//...etc.
}
}
//....
}
お役に立てば幸いです。
UPDATE2
このトピックは頻繁に取り上げられるため、上記のコードの修正バージョンをGitHubに配置しました。ここで見つけることができます。
https://github.com/ArtisticPhoenix/MISC/blob/master /AjaxWrapper/AjaxWrapper.php