以前、JavaScriptで15パズルをつくりましたが、今回はユーザーが好きな画像をアップロードできるように15パズルを改良します。

画像をアップロードできるようにする

まず画像をアップロードできるようにしなければなりません。

HTML部分を示します。といってもここではアップロード用のフォームを表示させているだけです。

upload.html

アップロードボタンがクリックされたらupload.phpで処理がおこなわれます。

upload.php

PHPで画像ファイルかどうかを調べるには?

一応、これでアップロードはできるのですが、これだと問題があります。

それは画像以外のファイルでもアップロードできてしまうということです。画像ファイル以外のものをアップロードした場合(とくに有害スクリプト)は削除してしまいたいです。

exif_imagetype関数は危険かも?

exif_imagetype関数を使う方法がよく紹介されています。ただこの方法はあまりよくありません。

なぜexif_imagetype関数を使う方法がよくないかというと、この関数は画像の先頭バイトを読んで そのサインを調べているだけだからです。

たとえばテキストファイルをつくって以下を書き込みます。そしてファイル名をGIF画像っぽい名前にしてアップロードしてみると画像ファイルではないのに削除されません。GIFファイルの先頭部分は「GIF89a」なのでここだけ見てGIF画像であると判断しているようです。もしここに有害な作用をするスクリプトが仕込まれていたらゾッとします。

dangerous.gif(悪意があるファイル)

imagecreatefromstring関数で解決

ではどうすればいいのか? imagecreatefromstring関数を使います。

これだと上記の偽装したGIFファイルや壊れた画像ファイルをアップロードすると削除されます。

ユーザーが画像をアップロードできる15パズルをつくる

ではユーザーが画像をアップできるようにしてみましょう。

同じ名前でファイルをアップロードすると上書きされてしまうので、元ファイル名の先頭にアップロード日時を加えることで名前がバッティングすることを防ぎします。また15パズルの本体があるディレクトリに大量の画像ファイルを置きたくないのでimagesというディレクトリ内に配置します。

upload.php

JavaScript側でアップロードされているファイルを取得できるようにします。そのためにクライアントサイドからディレクトリ内のファイルパスを取得できるように以下のようなphpファイルを用意します。

get-files.php

JavaScript部分の変更箇所

15パズル本体の処理が書かれているindex.js(JavaScriptで15パズルをつくるを参照)の以下の部分を変更します。

ページが読み込まれたときにおこなう処理をまるっと変更します。

get-files.phpにアクセスするとファイルパスが改行区切りで出力されるので、これを改行で分解してファイルのパスを取得します。そしてグローバル変数に格納します。

ゲームを開始する処理でランダムで画像を取得してpiecesの配列をクリアします。