SQLの窓

2017年06月27日


ファイルを一つアップロード : FORM の target を IFRAME にして、PHP に JavaScript を書き出させて元のページにメッセージを表示させる

昨今、ファイルをアップロードするならば、JavsScript を駆使して UI を作成し、 $.ajax で送信したほうが簡潔になりますが、ベタな FORM の記述のみで送信してそれなりのレスポンスを得ようという処理です。

デモページ


画像をクリックするとデモページへ移動します

当然ですが、デモページで実際のアップロードはできません。しかし、結果を表示するにチェックを入れて送信すると、上の画像のように実際と同じ状態で情報をシミュレートします。

UI の構築を気楽に工夫できるように、twitter-bootstrap の 4.0.0-alpha.6 を組み込んでいます

IFRAME は本来非表示で、ここに JavaScript で右上のメッセージ(toastr.js)を表示するようにしていますが、デバッグ用としても使えるようにしており、その場合は PHP 側の $_FILES の中身が見れるようになっています。

type="file" の name 属性は target で固定して php 側で使用しています。
送信データの制限 データの制限はサーバに対する無意味なアクセスを遮断するアプローチと、アプリから見たデータの制限という二つのアプローチがあります。前者がもっとも重要で、それがなければ php.ini の upload_max_filesize 内であれば結果的にそのサイズまでは送信を許してしまいます。 ※ upload_max_filesize を超えると $_FILES そのものが空になるようです。 後者は、FORM 内の name="MAX_FILE_SIZE" の値で指定できますが、完全な対策ではありません。そこで、対象ページのあるディレクトリの .htaccess 内に 『LimitRequestBody 102400』のように制限値を設定し、さらに『ErrorDocument 413』 を設定してそのページの中でエラー処理の対応をしています ▼ 413.html
<!DOCTYPE html>
<html lang="ja">
<style>
* {
	font-size: 32px;
}
</style>
<script>

	try {
		parent.$("iframe").show();
		parent.toastr.info( "ファイル のアップロードに失敗しました");
		parent.toastr.info( "エラー内容 : Request Entity Too Large" );
	}
	catch (e) {}

</script>
</head>
<body>

JavaScript の処理用に IFRAME を定義している場合で、
413 Request Entity Too Large が発生した場合にこのページが IFRAME 内に表示されます。

</body>
</html>


file_upload_html.php

$debug 変数で、実際のアップロードの可否を切り替えています。if ( !$_FILES ) { の部分は、upload_max_filesize を超えてしまった状態の対処ですが、ここでは LimitRequestBody 102400 を設定しているので発生する事はありません。
<?php
session_cache_limiter('nocache');
session_start();

header( "Content-Type: text/html; charset=utf-8" );

// *************************************
// 変数初期値
// *************************************
$debug = 0;
$upload_dir = "./upload";
if ( !$_FILES ) {
	// php.ini の upload_max_filesize を超えて、
	// Apache に制限が無いと $_FILE が空になる
	$_FILES['target']['error'] = 5;	// ユーザエラーメッセージ
}

// *************************************
// アップロード処理
// フィールド名 : target で固定
// *************************************
if ( $_SERVER['REQUEST_METHOD'] == "POST" ) {

	// 公開状態では実行しない
	if ( $debug == 1 ) {

		$upload = realpath ( $upload_dir );
		$upload .= ( DIRECTORY_SEPARATOR . $_FILES['target']['name'] );
		if ( move_uploaded_file(
			$_FILES['target']['tmp_name'], $upload ) ) {
			$_POST['result']  = "アップロードに成功しました";
		}
		else {
			if ( !$_FILES ) {
				$_FILES['target']['error'] = 5;	// ユーザエラーメッセージ
			}
			$_POST['result']  = "アップロードに失敗しました";
		}

	}
	else {
		if ( $_FILES['target']['error'] == 0 ) {
			$_POST['result']  = "アップロードに成功しました";
		}
		else {
			$_POST['result']  = "アップロードに失敗しました";
		}
	}

}
else {
	$_POST['result']  = "POST メソッドを使用して下さい";
}

$_POST['files'] = $_FILES;

// *************************************
// この JSON 文字列を HTML 内の json
// オブジェクト定義として埋め込みます
// *************************************
$json = json_encode($_POST, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE );


// *************************************
// 画面定義
// *************************************
?>
<!DOCTYPE html>
<html lang="ja">
<script>
var message = <?php require("error.json.php") ?>
var json = <?= $json ?>;

if ( json.files.target.error == 0 ) {
	parent.toastr.info(json.files.target.name + " がアップロードされました");
	parent.toastr.info("ファイルサイズ : " + json.files.target.size);
}
else {
	parent.toastr.info(json.files.target.name + " のアップロードに失敗しました");
	parent.toastr.info("エラー内容 : " + message.error[json.files.target.error]);
}

<?php if( $_POST["disp_result"] == "1" ) { ?>

	parent.$("iframe[name='upload']")
		.css("border", "1px solid #c0c0c0")
		.show();

<?php } else { ?>

	parent.$("iframe[name='upload']").hide();

<?php } ?>

</script>
</head>
<body>
<?php if( $_POST["disp_result"] == "1" ) { ?>
<textarea style='width:90%;height:350px;'><?= $json ?></textarea>

<?php } ?>
</body>
</html>


error.json.php は、PHP のエラーメッセージです。ここでは部品として埋め込んでいますが、$.ajax バージョンでも使用(error.json.php?type=json)しています。

error.json.php
<?php
if ( $_GET["type"] == "json" ) {
	session_cache_limiter('nocache');
	session_start();
	header( "Content-Type: application/json; charset=utf-8" );
}

?>
{
	"error": [
		"0 - 正常終了",
		"1 - アップロードされたファイルは、php.ini の upload_max_filesize ディレクティブの値を超えています",
		"2 - アップロードされたファイルは、HTML フォームで指定された MAX_FILE_SIZE を超えています",
		"3 - アップロードされたファイルは一部のみしかアップロードされていません",
		"4 - ファイルはアップロードされませんでした",
		"5 - 『アップロードに失敗しました』",
		"6 - テンポラリフォルダがありません。PHP 5.0.3 で導入されました",
		"7 - ディスクへの書き込みに失敗しました。PHP 5.1.0 で導入されました",
		"8 - PHP の拡張モジュールがファイルのアップロードを中止しました"
	]
}


upload.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta content="width=device-width initial-scale=1.0 minimum-scale=1.0 maximum-scale=1.0 user-scalable=no" name="viewport">
<title>HTML の FORM のみでファイルを一つアップロードする</title>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<link id="link" rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.10.1/themes/base/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/css/bootstrap.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/js/bootstrap.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/2.1.3/toastr.min.css">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/2.1.3/toastr.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.qrcode/1.0/jquery.qrcode.min.js"></script>

<!-- 共通の表示 -->
<link rel="stylesheet" href="common.css">

<!-- CSS の指定 -->
<style>
/* PC 用の表示 */
@media screen and ( min-width:480px ) {
	#content {
		margin: 20px;
	}
}
/* スマホ用の表示 */
@media screen and ( max-width:479px ) {
	#content {
		margin: 0px;
	}
	body {
		width: 100%!important;
		margin: 0px;
	}
	.unit {
		width: 100%;
	}
}
</style>
<script>
// 簡易的なスマホチェックを jQuery のプロパティとして登録
jQuery.isMobile = (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase()));
if ( $.isMobile ) {
	// スマホの場合は表示画面下の中央
	toastr.options.positionClass = "toast-bottom-center";
}

$(function(){

	// このページ自身の QRコードの表示
	$('#qrcode')
		.css({ "margin" : "20px" })
		.qrcode({width: 160,height: 160,text: location.href });
		

});
</script>
</head>
<body>
<div id="head">
	<div id="title">
		<a href="./">One File アップロード</a>
	</div>
</div>

<div id="content">

	<form target="upload" enctype="multipart/form-data" action="../../php_upload/file_upload_html.php" method="POST">
		<input type="hidden" name="MAX_FILE_SIZE" value="40000">
		<input name="target" type="file" class="btn btn-info">
		<input type="submit" value="ファイルを送信" class="btn btn-success ">

		<br>
		<label for="disp_result">結果を表示する</label> <input id="disp_result" type="checkbox" name="disp_result" value="1" class="mt-5">
	</form>

</div>

<div id="qrcode"></div>

<iframe src="about:blank" name="upload" style="display:none;border:0px solid #c0c0c0;margin-left:20px;width:90%;height:400px;"></iframe>



</body>
</html>


HTML 側のダウンロード



PHP 側のダウンロード





【PHP + 通信の最新記事】
posted by lightbox at 2017-06-27 12:55 | Comment(0) | PHP + 通信 | このブログの読者になる | 更新情報をチェックする
バッチ処理

Microsoft Office
container 終わり

フリーフォントで簡単ロゴ作成
フリーフォントでボタン素材作成
フリーフォントで吹き出し画像作成
フリーフォントではんこ画像作成
ほぼ自由に利用できるフリーフォント
フリーフォントの書体見本とサンプル
画像を大きく見る為のウインドウを開くボタンの作成

Android SDK ポケットリファレンス
改訂版 Webデザイナーのための jQuery入門
今すぐ使えるかんたん ホームページ HTML&CSS入門
CSS ドロップシャドウの参考デモ
PHP正規表現チェッカー
Google Hosted Libraries
cdnjs
BUTTONS (CSS でボタン)
イラストAC
ぱくたそ
写真素材 足成
フリーフォント一覧
utf8 文字ツール
右サイド 終わり
base 終わり