ビシっと色を決める! 錯覚の画像をリメイク

pic0
アップロードの設定などとは関係ないのだが、画像系で気になったので。

小飼弾さんの記事で、最近良く見る目の錯覚の一つが言及されていた。

404 SPAM Not Found #13 絵に描いた餅の頂き方
http://ch.nicovideo.jp/dankogai/blomaga/ar303790

小飼弾さんは以前 tips – GIMPでJPEGの蚊を退治して”PNG”化する みたいな記事を書いていらしたので、「ああ、結構細かい所気にされているな」と思っておりました。で、記事中で

上も有名な錯視で、黄緑に見えるところと水色に見えるところは、実は同じ色。嘘だと思ったらPhotoshopなどで色比較をしてみて下さい。しかし、「これは錯視」だと知らなければ、そんなことをしてみる気も起きないでしょう。

というので荒い画像で薄々気づきながらも、bmpPNG画像だからもしかしてと思い、念のためPhotoshopで色を確認する。

pic1

R:0 G:255 B:140

pic2

R:0 G:251 B:172

まあ言いたいことはわかるが 「嘘だと思ったらPhotoshopなどで色比較をしてみて下さい。」 という程同じ色とは言いがたい。
近いと言えば違く、探せば同じ色が見つかるかもしれないが、めんどくさい。

そもそも↓(一部拡大したもの)ではスポイドで色を試すまでもない。

pic3

この手の画像はアンチエイリアスされていると驚きが半減する。
錯覚系の画像は、実際拡大してみると近いけど全く同じとは納得出来ない画像が多い。
前々から気になっていたので、男は黙って4色PNG。

pic4

こんなベクトルデータをIllustratorで作って4色PNGで保存。

pic5

アンチエイリアスしていないのでギザギザ感がありますが、

pic6

R:0 G:248 B:132

pic7

R:0 G:248 B:132

当然バッチリ合います。
自分で作ったので驚きはありません。
イラレのデータは汚いので公開はやめときます。

[追記]
作った後に元ネタはどこだろうと調べたら立命館大学の北岡明佳教授の作品のようです。
北岡教授の作品はGIFで、色も R:0 G:255 B:150 と美しいです。
http://www.psy.ritsumei.ac.jp/~akitaoka/shikisai2005.html

phpのアップロードで必ずチェックする設定値 (php.ini , httpd.conf)

phpでアップロードする際に気をつけるべき項目があります。
現在の設定値は下記コードで取得できます。

<?php
echo 'memory_limit = ' . ini_get('memory_limit') . "<br />";
echo 'post_max_size = ' . ini_get('post_max_size') . "<br />";
echo 'upload_max_filesize = ' . ini_get('upload_max_filesize') . "<br />";
echo 'max_execution_time = ' . ini_get('max_execution_time') . "<br />";
echo 'max_input_time = ' . ini_get('max_input_time') . "<br />";
?>

php.ini の設定

ファイルサイズの設定について

大きいファイルサイズのアップロードをする場合、必ず設定がいる項目です。

memory_limit = 500M
post_max_size = 400M
upload_max_filesize = 300M

基本的に下記の範囲の値にするので間違いないのですが、マニュアルでは、memory_limitに”一般的に”という条件がつきます。

memory_limit >= post_max_size >= upload_max_filesize

post_max_size >= upload_max_filesizeは絶対です。
ファイルのアップロードという行為がpost値に内包されるので。

memory_limitは必ずしも他の値よりも大きくなければならないということはありません。
memory_limitが他の値よりも小さい場合、それより大きサイズのファイルの処理速度が遅くなるなど弊害がありますが、空きメモリー状況によって調節してもよいです。
大きいサイズのファイルは、通常回線速度やHDD(またはSSD)のアクセス速度のほうがボトルネックになるはずです。
ただし、余りにも小さいmemory_limitは急激なレスポンス低下になります。
テストしながら適正な値に調整します。

実行時間の設定について

max_execution_time = 120

忘れがちですがPHPスクリプトの実行時間の変更も必要です。
大きいファイルサイズの場合、[ move_uploaded_file() ]などの実行時間でタイムアウトする可能性があります。
実行時間はHDD(SSD)のアクセス速度に影響されます。

php.iniで設定すると全てのファイルに影響がでますので、特定のファイル( upload.php など)だけ設定するなら下記のコードで設定できます。
ただし、レンタルサーバーなどではこのコードを書いても設定できないことがあります。

<?php
set_time_limit(120);
?>

実行時間の設定について (念のため)

max_input_time = 60

ユーザーがアップロードにかかる時間と勘違いすることが多いですが、マニュアルによると「すべてのデータを受け取ってから~」なので関係ありません。
ディフォルトのままでネックになることは、余程混んでいないと少ないと思いますが、念のためこういう設定項目があるということを覚えておく。

Apacheの設定 httpd.conf

LimitRequestBody 0

ディフォルトで無制限に設定されているが、サーバーによっては制限されている場合があります。
32ビットのapacheでは基本2GBが最大サイズ。

phpのフォームでファイルのアップロードをする2

phpでファイルをアップロードするときのやり方の続きです。
前回はアップロードする際の、送り出すHTMLを説明しましたが、今回は受け取る方のphpの説明です。

upload.php
HTMLのヘッダ、bodyは省略してます。

<?php
if(!isset($_FILES['my_file'])){
	echo 'ページ遷移が不正です。';
}else{
	if($_FILES['my_file']['error'] !== UPLOAD_ERR_OK){
		
		//エラーが発生している
		if($_FILES['my_file']['error'] == UPLOAD_ERR_FORM_SIZE){
			echo 'ファイルサイズがHTMLで指定した MAX_FILE_SIZE を超えています。';
		}elseif($_FILES['my_file']['error'] == UPLOAD_ERR_NO_FILE){
			echo 'ファイルが選択されていません。';
		}else{
			echo 'その他のエラーが発生しています。';
		}
		
	}else{
		
		//ここから通常の処理

		//ユーザーが指定したファイル名
		$myfile_name = $_FILES['my_file']['name'];
		//ファイルのMIME型
		$myfile_type = $_FILES['my_file']['type'];
		//ファイルサイズ
		$myfile_size = $_FILES['my_file']['size'];
		//アップロードしたファイルが保存されている一時保存場所
		$myfile_tmp_path = $_FILES['my_file']['tmp_name'];
		
		//SQLインジェクション対策用
		$safesql_myfile_name = mysql_real_escape_string($myfile_name);
		$safesql_myfile_type = mysql_real_escape_string($myfile_type);
	
		//HTML表示用
		$safehtml_myfile_name = htmlspecialchars($myfile_name);
		$safehtml_myfile_type = htmlspecialchars($myfile_type);
		
		
		//拡張子の取得
		$tmp_ary = explode('.',$myfile_name);
		if(count($tmp_ary)>1){
		    $extension = $tmp_ary[count($tmp_ary)-1];
			
			//拡張子が半角英数字以外なら拡張子がないものとする。
			if( !preg_match("/^[0-9a-zA-Z]+$/",$extension) ) $extension='';
		}else{
			//拡張子がない場合はそのまま。Macなど。
			$extension='';
		}
		
		//SQLインジェクション対策用
		$safesql_extension = mysql_real_escape_string($extension);
		//HTML表示用
		$safehtml_extension = htmlspecialchars($extension);
			
		
		//新しいファイル名を作成する
		$new_file_name = date("Ymd-His").'-'.mt_rand().'.'.$safehtml_extension;
		
		//php側でもファイルサイズのチェックを行う。
		if($myfile_size>10485760 or $myfile_size==0)die('エラー ファイルサイズが不正です。');		

		//ファイルの保存場所
		$myfile_new_path = '/uploads';
		if(!move_uploaded_file($myfile_tmp_path,"$myfile_new_path/$new_file_name")){
			die('エラー ファイルを保存できませんでした。');
		}
		
		echo 'アップロードは成功しました。<br /><br />';
		
		echo 'ファイル名 : '.$safehtml_myfile_name.'<br />';
		echo 'MIME型 : '.$safehtml_myfile_type.'<br />';
		echo 'ファイルサイズ : '.number_format($myfile_size).' bytes<br />';
		echo '新しいファイル名 : '.$new_file_name.'<br />';

	}
}
?>

サンプル

パーツの説明

1.POSTの存在確認

if(!isset($_FILES['my_file'])){
	echo 'ページ遷移が不正です。';
}

ファイルの存在の確認をしています。HTTP POST で渡された$_FILESの存在を確認します。
連想配列の名前は前回 input で指定した名前になります。

<input type="file" name="my_file" />

今回のサンプルの場合、POSTされずに来るページではないので、die()しても構わないと思います。

2.エラーの確認

大まかなエラーの確認からしていきます。

if($_FILES['my_file']['error'] !== UPLOAD_ERR_OK){

$_FILES[‘my_file’][‘error’] で自動的にエラーを確認してくれるので楽チンです。
エラーがない場合は UPLOAD_ERR_OK もしくは 0 。ある場合はエラーコードを返します。

if($_FILES['my_file']['error'] == UPLOAD_ERR_FORM_SIZE){

UPLOAD_ERR_FORM_SIZE 。もしくは 2 。そのままですが、ファイルサイズがHTMLで指定した MAX_FILE_SIZEを超えた場合の値。MAX_FILE_SIZEはユーザーが自由に変更できるので、あくまでも目安に。

}elseif($_FILES['my_file']['error'] == UPLOAD_ERR_NO_FILE){

同じくそのまま。値は 4 。ファイルが指定されていないです。
【1.存在確認】と違い、間違って押してしまう場合があるので、明示してあげるのが親切。

}else{
    echo 'その他のエラーが発生しています。';
}

上記2つ以外にもエラーコードがありますが、頻度が少ないので一括で処理。
その他のエラーコードはマニュアルを見て下さい。

3.$_FILESで取得できる値

$myfile_name = $_FILES['my_file']['name'];
$myfile_type = $_FILES['my_file']['type'];
$myfile_size = $_FILES['my_file']['size'];
$myfile_tmp_path = $_FILES['my_file']['tmp_name'];

それぞれファイル名、MIMEタイプ、サイズ、一時保存場所です。

$safesql_myfile_name = mysql_real_escape_string($myfile_name);
$safesql_myfile_type = mysql_real_escape_string($myfile_type);
$safehtml_myfile_name = htmlspecialchars($myfile_name);
$safehtml_myfile_type = htmlspecialchars($myfile_type);

SQLインジェクションやXSS対策のために汚染されていない値を作っておく。
ファイル名、MIMEタイプは汚染されている可能性があります。
サイズ、一時保存場所の値は安全ですが、念のため同様にサニタイズした方がいいと思います。
→一時保存場所は /var/phptmp など。サイズは整数値。
またSQLに関しては必ずプリペアドステートメントをするべきです。

4.拡張子の取得

いろいろな方法があると思いますが、ここでは[ . ](ピリオド)で分割し、配列の最後の値(-1)を取得しています。

$tmp_ary = explode('.',$myfile_name);
if(count($tmp_ary)>1){
    $extension = $tmp_ary[count($tmp_ary)-1];
}else{
    $extension='';
}

MACなどで拡張子がない場合もありますので、ピリオドがない場合は拡張子なしとしています。

if( !preg_match("/^[0-9a-zA-Z]+$/",$extension) ) $extension='';

拡張子が半角英数字以外は拡張子をないものとしてます。
MACで拡張子がなく、[ プレゼン資料.2013.04.02修正バージョン ]のようなファイル名も考えられ、これに対応します。ここで拡張子の桁数を確認してもいいですが、拡張子はシビアになる項目でもないです。
(そもそもユーザー指定なので信用せず単なる目安と考える)

$safesql_extension = mysql_real_escape_string($extension);
$safehtml_extension = htmlspecialchars($extension);

ユーザーから送信された拡張子は安全ではないのでサニタイズしています。

5.新しいファイル名の作成

ユーザー指定のファイル名だと何かと不都合が多いので、サーバー側で指定します。
ユーザー指定だと保存フォルダがカオスになり、当然重複も発生します。

$new_file_name = date("Ymd-His").'-'.mt_rand().'.'.$safehtml_extension;

ファイル名には時間を指定していますが、全く同時にアップロードも考えられますので、ランダムな値を付加しています。マイクロ秒などでもほとんど問題ないと思いますが、ランダムな値のほうがお勧めです。
拡張子は$safehtml_extensionを利用しました。

※マイクロ秒などでは操作によって同時が考えられる。

6.ファイルサイズのチェック

if($myfile_size>10485760 or $myfile_size==0)die('エラー ファイルサイズが不正です。');

php側でもファイルサイズのチェックは必須です。
MAX_FILE_SIZEの値は信用出来ません。
また、念のためファイルサイズが0の場合もチェックしています。

7.ファイルの移動

if(!move_uploaded_file($myfile_tmp_path,"$myfile_new_path/$new_file_name")){
	die('エラー ファイルを保存できませんでした。');
}

move_uploaded_fileで一時保存場所からファイルを移動します。
アップロードするファイルの場所はフルパスで指定したほうがいいです。