[PHP, JS]jQueryのAjaxによるPHP、Javascript間の送受信(JSON)

Ajax(非同期通信)を用いれば画面遷移なしでデータのやり取りができるため、最近では定番の技術として頻繁に用いられています。

今回は Javascript を使ってホストにデータを送信し、処理結果を受け取るというプログラムを JSON、JSONP を使うケース、同一ドメイン、クロスドメイン環境のケースに分けて説明します。

同一ドメイン間で JSON を使ったサンプル

クライアント

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Ajax</title>
        <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
        <script>
        $(function(){
            $("#button1").on('click', function(event){
                event.preventDefault();
                var param = { "text": "Hello" };

                $.ajax({
                    type: "GET",
                    url: "get.php",
                    data: param,
                    crossDomain: false,
                    dataType : "json",
                    scriptCharset: 'utf-8'
                }).done(function(data){
                    alert(data.text);
                }).fail(function(XMLHttpRequest, textStatus, errorThrown){
                    alert(errorThrown);
                });
            });
        });
        </script>
    </head>
    <body>
        <button id="button1">submit</button>
    </body>
</html>

ホスト

<?php
// Ajax以外からのアクセスを遮断
$request = isset($_SERVER['HTTP_X_REQUESTED_WITH'])
     ? strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) : '';
if($request !== 'xmlhttprequest') exit;

$text = filter_input(INPUT_GET, 'text');
header('Content-type: application/json; charset=utf-8');
echo json_encode(['text' => $text . ', World!']);

出力結果

Hello, World!

「Hello」と書かれたボタンを押すと、JavaScript から PHP に「Hello」という文字列が送信されます。
PHP はそれに「, World!」という文字列を加えて返します。
Javascript は結果を受け取り「Hello, World!」と表示する流れです。

非クロスドメイン環境で ajax を使うと HTTP_X_REQUESTED_WITH というヘッダー情報が送信されます。これをもとに Ajax 以外の方法をブロックしています。

「type: "POST"」とした場合は POST メソッドで送信されるのでホスト側も「$text = filter_input(INPUT_POST, "text");」のようにして受け取ることになります。

JSONP を使ったクロスドメイン Ajax

JSONP(JSON with padding)を使うとクロスドメイン環境での Ajax が可能です。
クライアントの dataType に jsonp を指定し、type を GET に変更します。

クライアント

<script>
$(function(){
    $("#button1").on('click', function(event){
        event.preventDefault();
        var param = { "text": "Hello" };

        $.ajax({
            type: "GET",
            url: "get-jsonp.php",
            data: param,
            crossDomain: true,
            dataType : "jsonp",
            scriptCharset: 'utf-8'
        }).done(function(data){
            alert(data.text);
        }).fail(function(XMLHttpRequest, textStatus, errorThrown){
            alert(errorThrown);
        });
    });
});
</script>

ホスト

<?php
text = filter_input(INPUT_GET, 'text');
$callback = filter_input(INPUT_GET, 'callback');
$callback = htmlspecialchars(strip_tags($callback));
 
$param = ['text' => $text . ", World!"];

header('Content-type: text/javascript; charset=utf-8');
printf("{$callback}(%s)", json_encode( $param ));

JSONP ではクライアントから callback というデータが送信されます。これを javascript の関数を呼び出すような形にして出力するとデータの受け渡しができるようになります。

JSON を使ったクロスドメイン Ajax

JSON を使ってクロスドメイン通信を行う場合は次のヘッダーをサーバー側で出力しておく必要があります。

header("Access-Control-Allow-Origin: *");

「*」はすべてのサイトからの通信を許可するということを意味します。特定のサイトからのみリソースの利用を許可する場合は次のようにして URL を指定します。

header("Access-Control-Allow-Origin: http://foo.com http://bar.com");

不特定多数のクライアントにリソースシェアリングを行う場合は認証機能をつけることについても検討して下さい。

参考:
http://www.learningjquery.com/2010/03/detecting-ajax-events-on-the-server/

[PHP]中心から角度を指定して線を引く(座標の回転)

360

ある座標から角度を指定して線を引くサンプルです。
線の長さを同じにして角度をすこしずつ変えていくと円のようになります。
時計の針のようなものをイメージするとわかりやすいと思います。

サンプルとして中心から 80 ピクセルの線を 45 度で描画してみます。

45

<?php
//線分の長さ
$r = 80;

//角度
$angle = 45;

//キャンバスサイズ
$width	 = 200;
$height	 = 200;

//キャンバスの中心を原点とする
$origin = array( round($width / 2), round($height / 2) );

$image = imagecreatetruecolor($width, $height);

//線の色
$color = imagecolorallocate( $image, 255, 255, 255 );

list($x, $y) = point_rotate($r, $angle);
imageline($image, $origin[0], $origin[1], $origin[0] + $x, $origin[1] + $y, $color);

header('Content-Type: image/jpeg');
imagejpeg($image);
imagedestroy($image);

function point_rotate($r, $angle){
	$angle = deg2rad($angle);
	$x = round($r * cos($angle));
	$y = round($r * sin($angle));
	return array($x, $y);
}

0 度の時は水平線で、角度が増えるごとに時計回りに回転します。
時計のように 12 時から始める場合は 90 度引いて計算します。

[PHP]マスク画像で写真を好きな形に切り抜く(クリッピングマスク)

result

写真と図形などのマスク画像を組み合わせて写真を自由な形にくり抜くサンプルです。
例ではアルファベットの「A」の形の透過 PNG に合わせて森の写真をはめ込み合成しています。
合成する写真よりもマスク画像が大きくならないように気をつけて下さい。

mask.png
mask

sample.jpg
sample

<?php
$canvas	 = new stdClass();
$image	 = new stdClass();
$mask	 = new stdClass();

$image->image	 = imagecreatefromjpeg('sample.jpg');
$mask->image	 = imagecreatefrompng('mask.png');

$image->width	 = imagesx($image->image);
$image->height	 = imagesy($image->image);

$mask->width	 = imagesx($mask->image);
$mask->height	 = imagesy($mask->image);

$canvas->width	 = $mask->width;
$canvas->height	 = $mask->height;
$canvas->image = imagecreatetruecolor($canvas->width, $canvas->height);

imagealphablending($canvas->image, false);
imagesavealpha($canvas->image, true);
$transparent = imagecolorallocatealpha( $canvas->image, 0, 0, 0, 127 );
imagefill( $canvas->image, 0, 0, $transparent );

//中心から切り抜くための調整
$top	 = round(($image->width - $mask->width) / 2);
$left	 = round(($image->height - $mask->height) / 2);

for($y=0;$y<$canvas->height;$y++){
	for($x=0;$x<$canvas->width;$x++){
		$rgb	 = imagecolorat($mask->image, $x, $y);
		$index	 = imagecolorsforindex($mask->image, $rgb);
		
		$alpha	 = $index['alpha'];
		//$alpha	 = ($index['red'] + $index['green'] + $index['blue']) / 765 * 127 ;

		$current = imagecolorat($image->image, $x + $top, $y + $left);
		$index	 = imagecolorsforindex($image->image, $current);
		$color	 = imagecolorallocatealpha($canvas->image, $index['red'], $index['green'], $index['blue'], $alpha);
		imagesetpixel($canvas->image, $x, $y, $color);
	}
}
header("Content-type: image/png");
imagepng($canvas->image);

imagedestroy($canvas->image);
imagedestroy($image->image);
imagedestroy($mask->image);

今回画像データの管理に stdClass() を用いましたが、PHP のバージョンが古い場合は連想配列を使って書きなおして下さい。
マスクの透明部分をもとに画像を切り抜くので、透明度を徐々に変化させてグラデーション状にすると切り抜かれる画像にもグラデーションがかかります。

・透明度のグラデーションを利用したマスク
gradient

grad_result

例では透過 PNG の不透明な部分に写真を合成していますが、色の黒い部分に画像を合成する場合は下記のように変更します。

//PNGの透明度を利用する方法
//$alpha	 = $index['alpha'];

//色の黒さを利用する方法
$alpha	 = ($index['red'] + $index['green'] + $index['blue']) / 765 * 127 ;

最初のサンプルでは文字の形に背景を切り出しましたが、逆に背景から文字部分を透明にするには、「$alpha = 127 – $alpha;」を付け足して反転させます。

$alpha	 = $index['alpha'];
$alpha   = 127 - $alpha;

result2


写真素材 足成
http://www.ashinari.com/