TinyMCE5とPHPで画像アップロード機能実装【ロリポップ】
TinyMCE5で画像アップロード機能を追加するのに躓いたので、その解決策メモを残します。こちらのnoteはすでにTinyMCE5を導入済みで、更に画像アップロード機能を実装したい人向けです。
僕が作りたかったのは、まさにWordPressのようなWYSIWYG(見たままに編集)エディタです。単純なTinyMCEだけでも、pタグやaタグを含んだHTMLの生成が可能ですが、やはりそこまでできると画像のアップロード/挿入機能も欲しくなるところです。標準では画像のリンクを入力することで、画像を表示させることができます。しかし、ローカルにある画像をアップロードするには、画像ファイルを実際にサーバーにアップロードするプロセスを必要とするため、PHPなどのサーバーサイドと連携させなければなりません。こちらのnoteでは、実装までの手順をまとめていきます。
TinyMCEでローカル画像アップロードをオンにする
英語ですが、公式ドキュメントに画像アップロード機能をオンにするやり方が記載されています。TinyMCEをinitする際に、下のコードを任意の位置に追加します。
tinymce.init({
selector: '#textareaId', // TinyMCEを有効にするテキストエリアのid
images_upload_handler: function (blobInfo, success, failure) {
var xhr, formData;
xhr = new XMLHttpRequest();
xhr.withCredentials = false;
xhr.open('POST', '<accept_php_file_path>'); // ココに画像をアップロードするPHPファイルへのパスを入力する
xhr.onload = function() {
var json;
if (xhr.status != 200) {
failure('HTTP Error: ' + xhr.status);
return;
}
json = JSON.parse(xhr.responseText);
if (!json || typeof json.location != 'string') {
failure('Invalid JSON: ' + xhr.responseText);
return;
}
success(json.location);
};
formData = new FormData();
formData.append('file', blobInfo.blob(), blobInfo.filename());
xhr.send(formData);
}
});
これだけでクライアント側の設定は終了です。これにより、TinyMCEの画像アイコンをクリックすると、アップロード部分が表示されます。
POSTされるPHPファイルを作成
次にTinyMCEから画像ファイルを受け取るPHPファイルを作成していきます。下のようなサンプルコードで受け取り側のPHPファイルを作りましょう。
<?php
reset($_FILES);
$temp = current($_FILES);
if (is_uploaded_file($temp['tmp_name'])) {
// 許可するファイル形式を設定
if (! in_array(strtolower(pathinfo($temp['name'], PATHINFO_EXTENSION)), array(
"gif",
"jpg",
"png"
))) {
header("HTTP/1.1 400 Not an Image");
return;
}
$fileName = "uploads/" . $temp['name'];
move_uploaded_file($temp['tmp_name'], $fileName);
// JSON形式で画像ファイルの位置をレスポンス
echo json_encode(array(
'file_path' => $fileName
));
}
?>
PHPファイルでやることは下の2つです。
<PHP側でやるコト>
・POSTされた画像ファイルをテンポラリディレクトリから、uploadsなどの任意のディレクトリ移動する
・レスポンスとして、JSON形式で"file_path"をキーとして、移動させた画像ファイルのパスまたはURLを返す
レスポンスを返すと、TinyMCE側に画像のソースと画像の幅・高さが表示されます。
「画像のソースは表示されるけど幅と高さが表示されない...」という場合は、PHPのレスポンスは返ってきているけど実際にそのパスに従った画像ファイルが存在しないということになります。開発者ツールにも404 Not Foundが表示されているかと思います。レスポンス部分のfile_pathが正しいかを確認してください。
レンタルサーバー使用時の注意点
僕はロリポップレンタルサーバーを使用していますが、この画像アップロード機能により生成されたimgタグを含んだHTMLをデータベースに保存する際にエラーが出ました。WAF設定により、POSTするテキストに'../'が含まれていると、403エラーが出るのです。
よって、実際にこちらの画像アップロード機能で生成したimgタグを含むHTMLをPOSTするときは、'src="../uploads'などの部分を'src="https://example.com/uploads/'などに置換する必要があります。これはまあPOSTする前にJavaScriptでなんとかすれば良いので、そこまでハマることもないかと思います。