JSONP をサーバサイドも含めて実装。 php -S 8080 とかで簡単に試せる
<?php
if (PHP_SAPI === 'cli') {
echo 'Usage:' . PHP_EOL;
echo " run: php -S localhost:8080 {$argv[0]}" . PHP_EOL;
echo ' browse http://localhost:8080/' . PHP_EOL;
exit;
}
const JSONP_URL_PATH = '/jsonp';
// routing
if (parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) === JSONP_URL_PATH){
render_js();
return;
}
render_html();
// more info
// http://www.atmarkit.co.jp/ait/articles/0908/10/news087.html
// https://mathiasbynens.be/notes/javascript-identifiers
// http://stackoverflow.com/questions/1661197/what-characters-are-valid-for-javascript-variable-names
//
// 間違えるとXSSの原因になる
// そういう意味で、関数名を固定にするメリットもある
function is_js_var_valid($js_var){
return preg_match('#\A[_$a-zA-z][_$a-zA-z0-9]*\z#', $js_var);
}
function render_js(){
$callback_js_function_name = filter_input(INPUT_GET, 'callback');
if (! $callback_js_function_name ||
is_js_var_valid($callback_js_function_name) !== 1) {
exit();
}
// 本当は、この部分で条件によってデータを変える必用がある
$data = array('temperature' => 23, 'location' => '北海道');
// 以下のコードがブラウザ側で実行される
$js_snippet = $callback_js_function_name . '(' . json_encode($data) . ');';
// コードを渡すので
// データを送る場合より自由度が高くて危険性が高い
// http://d.hatena.ne.jp/kanonji/20110406/1302065168
// IE7,8 だと application/javascript だとエラーになるらしい
header('Content-Type: application/javascript;charset=UTF-8');
echo $js_snippet;
}
function render_html(){
?>
<html>
<head>
<script>
// JSONP で呼んでもらう関数
// サーバからデータが帰ってきた後の継続になる
function local_temperature(data){
var box = document.getElementById('temperature');
box.textContent = '今日の' + data.location + 'の気温: ' + data.temperature + '度';
}
window.onload = function(){
var script = document.createElement('script');
// callback= の部分で呼んでもらう関数名を指定している
// FB, Twitter の投稿表示だと固定の関数名を使っていた
script.src = '<?php echo JSONP_URL_PATH; ?>' + '?callback=' + 'local_temperature';
// 可変だと重複を回避できるけど、
// 使う人は名前を指定する手間が増える。
// 非プログラマも使うと考えれば、名前を長くして固定にするのが無難かもしれない
document.body.appendChild(script);
script.parentNode.removeChild(script);
};
</script>
</head>
<body>
<div id="temperature"></div>
</body>
</html>
<?php } ?>