配列をカンマ区切り連結文字に変換(IN句,CSV用に) | implode

	$ary=array('neko','yagi','kani','same');
	$ids_str = "'" . implode("','", $ary) . "'";

	//出力→ $ids_str = 'neko','yagi','kani','same'
	

URLをサニタイズ | 要素属性へのXSS攻撃

説明

a要素のhrefへ、自由にURLを指定できるようなシステムの場合、XSSの危険性がある。
また、aタグ以外でも、要素の属性を指定できる場合、XSSを起きる。
該当する属性は、href,srcだけでなく、すべてに注意。

悪意のあるXSS攻撃にはセッションハイジャックがある。
クッキーからセッションIDを表示させるJSコードが埋め込まれてしまい、セッションIDを盗まれる。
セッションIDを盗まれるとなりすましも可能になる。

対策
URLに含まれる次の記号、「<>"'」をサニタイズすれば良い。
また、記号「:;」も除去しておいた方が良い。

XSSを引き起こすコードの例

典型的な危険コード
a要素のhrefに以下のコードが指定されていると、画面を開いただけでJSが実行される。
http://example.com/?<script>alert(document.domain);</script>


クリックするとJavaScriptが実行される。
<a href="javascript:alert('XSS')" >テスト</a>
テスト

以下のような特殊環境で起こるケースも。
javascript:alert%28location%29
リンクに触るだけで、XSSを引き起こす特に注が必要な危険コード。
以前、TwitterにXSS脆弱性の問題があったが、以下と同様なものである。
http://example.com/"onmouseover="alert(1)"
a要素以外も注意
<IMG SRC="jav ascript:alert('XSS');">
<IMG SRC="javascript:alert('XSS')"+
IE7以前では、CSS内でJSコードを実行することも
<div style="color:expression(alert('XSS'));">a</div>
<div style='behavior:url(test.sct)'>a</div>

サンプル

ソースコード
	<?php
		$xssList=array(
			"http://example.com/\"onmouseover=\"alert(1)\"",
			"http://example.com/?<script>alert(document.domain);</script>",
			"https://example.com/?neko=1&yagi=2\"onmouseover=\"alert(1)\"",
			"javascript:alert('XSS')",
			"jav	ascript:alert('XSS');",
			"color:expression(alert('XSS'));",
			"behavior:url(test.sct)",
		);


		foreach($xssList as $xss){

			$s=htmlspecialchars_url($xss);


			echo htmlspecialchars($xss);
			echo " → ";
			echo htmlspecialchars($s);
			echo "<br>";
		}

		/**
		 * URL用のサニタイズ
		 * 記号「<>"'」をエンコードし、記号「:;」を除去する。
		 * ただし「http:」「https:」に付いている「:」は除去しない。
		 * @param  $xss	サニタイズ対象文字
		 * @return サニタイズ後の文字
		 */
		function htmlspecialchars_url($xss){
			$s=htmlspecialchars($xss, ENT_QUOTES, 'UTF-8');
			$s=str_replace('http:','http<',$s);
			$s=str_replace('https:','https<',$s);
			$s=str_replace(':','',$s);
			$s=str_replace(';','',$s);
			$s=str_replace('http<','http:',$s);
			$s=str_replace('https<','https:',$s);
			return $s;
		}

	?>
		

実行結果
http://example.com/"onmouseover="alert(1)" → http://example.com/&quotonmouseover=&quotalert(1)&quot
http://example.com/?<;script>;alert(document.domain);<;/script>; → http://example.com/?&ltscript&gtalert(document.domain)&lt/script&gt
https://example.com/?neko=1&yagi=2"onmouseover="alert(1)" → https://example.com/?neko=1&ampyagi=2&quotonmouseover=&quotalert(1)&quot
javascript:alert('XSS') → javascriptalert(&#039XSS&#039)
jav&#x09;ascript:alert('XSS'); → jav&amp#x09ascriptalert(&#039XSS&#039)
color:expression(alert('XSS')); → colorexpression(alert(&#039XSS&#039))
behavior:url(test.sct) → behaviorurl(test.sct)

文字化け対策した日本語ファイル名のファイルコピー | move_uploaded_file

日本語ファイル名をコピーする場合、ファイル名の文字コードをShift-JISに変換せねばならない。
$file_name = mb_convert_encoding($_FILES['files']['name'][$i], "SJIS", "auto");


例(複数ファイルアップロードの場合)
	if(!empty($_FILES)){

		$lenth=count($_FILES["files"]["name"]);
		for($i=0;$i<$lenth;$i++){

			//日本語ファイル名の文字化け対策
			$file_name = mb_convert_encoding($_FILES['files']['name'][$i], "SJIS", "auto");

			//一時ファイルをtestフォルダにコピー
			move_uploaded_file($_FILES["files"]["tmp_name"][$i], "test/" . $file_name);
		}

	}
	

日本語ディレクトリの存在チェック | 日本語フォルダに対応したis_dir


関数
	/**
	 * 日本語ディレクトリの存在チェック
	 * @param  $dn	ディレクトリ名
	 * @return boolean	true:存在	false:未存在
	 */
	function is_dir_ex($dn){
		$dn=mb_convert_encoding($dn,'SJIS','UTF-8');
		if (is_dir($dn)){
			return true;
		}else{
			return false;
		}
	}
	

指定したパスから中間ディレクトリも含めてディレクトリを作成

    $destinationPath = 'app/public/uploads/rich_menu';
    
    // ディレクトリが存在しない場合に作成
    if (!file_exists($destinationPath)) {
        // ディレクトリを作成する。(中間のディレクトリも作成)
        if (!mkdir($destinationPath, 0777, true)) {
            die('ディレクトリの作成に失敗しました。');
        }
    }
	

ディレクトリを作成しながらファイルコピー(日本語名ファイル対応)

copy関数はディレクトリごとファイルコピーできない。また日本語名のファイルだと文字化けする。
下記のcopyEx関数は、ディレクトリごとのコピーと、日本語名ファイルコピーに対応する。

関数

	/**
	 * 拡張コピー 存在しないディテクトリも自動生成
	 * 日本語ファイルに対応
	 * @param コピー元ファイル名 $sourceFn
	 * @param コピー先ファイル名 $copyFn
	 */
	function copyEx($sourceFn,$copyFn){

		//フルファイル名からパスを取得する。
		$di=dirname($copyFn);

		//コピー先ファイル名とコピー元ファイル名が同名であれば、Nullを返して処理を終了
		if($sourceFn==$copyFn){
			return null;
		}

		//ディレクトリが存在するかチェック。
		if (is_dir_ex($di)){

			//存在するならそのままコピー処理
			$sourceFn=mb_convert_encoding($sourceFn,'SJIS','UTF-8');
			$copyFn=mb_convert_encoding($copyFn,'SJIS','UTF-8');
			copy($sourceFn,$copyFn);
		}else{

			//存在しない場合。
			//パスを各ディレクトリに分解し、ディレクトリ配列をして取得する。
			$ary=explode('/', $di);
			//ディレクトリ配列の件数分以下の処理を繰り返す。
			$iniFlg=true;
			foreach ($ary as $key => $val){

				//作成したディレクトリが存在しない場合、ディレクトリを作成
				if ($iniFlg==true){
					$iniFlg=false;
					$dd=$val;
				}else{
					$dd.='/'.$val;
				}

				if (!(is_dir_ex($dd))){
					mkdir($dd);//ディレクトリを作成
				}

			}

			$sourceFn=mb_convert_encoding($sourceFn,'SJIS','UTF-8');
			$copyFn=mb_convert_encoding($copyFn,'SJIS','UTF-8');
			copy($sourceFn,$copyFn);//ファイルをコピーする。

		}
	}


	/**
	 * 日本語ディレクトリの存在チェック
	 * @param  $dn	ディレクトリ名
	 * @return boolean	true:存在	false:未存在
	 */
	function is_dir_ex($dn){
		$dn=mb_convert_encoding($dn,'SJIS','UTF-8');
		if (is_dir($dn)){
			return true;
		}else{
			return false;
		}
	}
	




使用例
	$fn="日本語.pdf";
	$ffn="tmp2/".$fn;

	$ffn2 ='dummy2/'. $fn;//コピー先。dummy2は未作成でも良い。

	//拡張コピー。存在しないディレクトリも自動生成し、日本語ファイル名にも対応。
	copyEx($ffn,$ffn2);

	

ディレクトリ内のファイルを列挙 | ファイル一覧を取得


	

旧式

	/**
	 * scandir関数の拡張関数。
	 * 
	 * @note
	 * 「.」「..」となっているファイル名は除外する。
	 * 日本語ファイル名に対応するためUTF-8に変換している。
	 * そのため、当関数で取得したファイル名でWindows上のファイルを扱う場合、Shift-JISに戻す必要がある。
	 * WindowsのファイルはShift-JISで扱わねばならないためである。
	 *
	 * @param  $dir_name	ディレクトリ名
	 * @return ファイル名の配列
	 */
	function scandir2($dir_name){
		$files = scandir($dir_name);
		
		// 「.」,「..」名のファイルを除去、および日本語ファイルに対応。
		$files2 = array();
		foreach($files as $file){
			if($file=='.' || $file=='..'){
				continue;
			}
			$file = mb_convert_encoding($file, 'UTF-8', 'SJIS');
			$files2[] = $file;
		}

	
		return $files2;
	}
	

使用例
	$dir_name="tmp2";
	$files = scandir2($dir_name);
	echo var_dump($files);
	

ディレクトリ階層化の全ファイルを列挙


	$fileNames = getAllFileNamesInDir('tmp');
	var_dump($fileNames);
	
	/**
	 * ディレクトリ階層化の全ファイル名を取得する
	 * @param string $dir ディレクトリ
	 * @param array $list ファイル名リスト(内部処理用なのでセット不要)
	 * @return ファイル名リスト
	 */
	function getAllFileNamesInDir($dir,$list=array()) {
		if ($handle = opendir("$dir")) {
			while (false !== ($item = readdir($handle))) {
				if ($item != "." && $item != "..") {
					if (is_dir("$dir/$item")) {
						$list = getAllFileNamesInDir("$dir/$item",$list);
					} else {
						//unlink("$dir/$item");
						$list[] = "$dir/$item";
					}
				}
			}
			closedir($handle);
			
		}
		return $list;
	}
	

出力例
	array (size=11)
	  0 => string 'tmp/xxx/icon_kabuto.jpg' (length=23)
	  1 => string 'tmp/xxx/icon_tilapia.jpg' (length=24)
	  2 => string 'tmp/xxx/imori.jpg' (length=17)
	  3 => string 'tmp/xxx/imori_md.jpg' (length=20)
	  4 => string 'tmp/xxx/imori_md.png' (length=20)
	  5 => string 'tmp/xxx/inago.jpg' (length=17)
	  6 => string 'tmp/xxx/sasigame.jpg' (length=20)
	  7 => string 'tmp/xxx/smp1.png' (length=16)
	  8 => string 'tmp/xxx/test1.jpg' (length=17)
	  9 => string 'tmp/xxx/test3.jpg' (length=17)
	


パスを削除する | 内部にファイルを含むディレクトリの削除、ファイル削除、失敗リストも返す


    /**
     * パスを削除します。
     * @note 
     * ディレクトリごとファイルを削除できます。
     * 階層化のファイルまで削除可能。
     * もちろん通常のファイルも削除可能。
     * パスの指定先にファイルやディレクトリが無くてもエラーになりません。
     * 
     * @param string $path 削除対象ディレクトリ(絶対パスで指定する。セパレータはスラッシュ、バックスラッシュが混在しても良い)
     * @return [] 削除に失敗したパス名のリスト
     */
    public function removePath($path){
        $falseData = [];
        $this->removePath0($path, $falseData);
        return $falseData;
    }
    
    /**
     * パスを削除します。 このメソッドは再帰呼び出し処理がなされています。
     * @note 
     * ディレクトリごとファイルを削除できます。
     * 階層化のファイルまで削除可能。
     * もちろん通常のファイルも削除可能。
     * パスの指定先にファイルやディレクトリが無くてもエラーになりません。
     * 
     * @param string $path 削除対象ディレクトリ(絶対パスで指定する。セパレータはスラッシュ、バックスラッシュが混在しても良い)
     * @param [] $falseData 失敗ファイルリスト     削除に失敗したパスの情報
     * @return [] 削除に失敗したパス名のリスト
     */
    private function removePath0($path, &$falseData) {
        
        
        // ディレクトリでないなら即削除
        if (!is_dir($path)) {
            
            if(@unlink($path) == false) $falseData[] = $path; // 「@」を付けることにより、ディレクトリやファイルが存在しなくてもWarningがでないようにする。

            return $falseData;
        }
        if ($handle = opendir($path)) {
            while (false !== ($item = readdir($handle))) {
                if ($item != "." && $item != "..") {
                    $dp = $path . '/' . $item;
                    if (is_dir($dp)) {
                        $this->removePath0($dp, $falseData);
                    } else {
                        if(@unlink($dp) == false) $falseData[] = $path; // ファイルを削除。失敗した場合は失敗リストにパス名を追加する。
                    }
                }
            }
            closedir($handle);
            if(rmdir($path) == false) $falseData[] = $path; // ディレクトリを削除。失敗した場合は失敗リストにパス名を追加する。
        }
        
        return $falseData;
    }
    

ディレクトリ内のファイルをまとめて削除


関数
	/**
	 * ディレクトリ内のファイルをまとめて削除する。
	 * @param  $dir_name ファイル削除対象のディレクト名
	 * @return
	 */
	function dirClear($dir_name){
		//フォルダ内のファイルを列挙
		$files = scandir($dir_name);
		$files = array_filter($files, function ($file) {
			return !in_array($file, array('.', '..'));
		});

		foreach($files as $fn){
			$ffn=$dir_name.'/'.$fn;
			try {
				unlink($ffn);//削除
			} catch (Exception $e) {
				throw e;
			}
		}

		return true;
	}
	

使用例
	$dir_name="tmp3";
	dirClear($dir_name);
	echo 'フォルダ内のファイルを削除しました。';
	

ディレクトリごとファイルを削除する


	/**
	 * ディレクトリごとファイルを削除する。(階層化のファイルまで削除可能)
	 * @param string $dir 削除対象ディレクトリ(絶対パスで指定する。セパレータはスラッシュ、バックスラッシュが混在しても良い)
	 */
	public function removeDirectory($dir) {
		// ディレクトリでないなら即削除
 		if (!is_dir($dir)) {
			@unlink($dir); // 「@」を付けることにより、ディレクトリやファイルが存在しなくてもWarningがでないようにする。
			return;
		}
		if ($handle = opendir($dir)) {
			while (false !== ($item = readdir($handle))) {
				if ($item != "." && $item != "..") {
					$dp = $dir . '/' . $item;
					if (is_dir($dp)) {
						$this->removeDirectory($dp);
					} else {
						@unlink($dp);
					}
				}
			}
			closedir($handle);
			rmdir($dir);
		}
	}
	
参考サイト



ディレクトリ内のファイルとフォルダをすべて除去する


	/**
	 * ディレクトリ内のファイルとフォルダをまとめて削除する。
	 * @param  string $dir_name ファイル削除対象のディレクト名
	 */
	private function dirClearEx($dir_name){
		//フォルダ内のファイルを列挙
		$files = scandir($dir_name);
		$files = array_filter($files, function ($file) {
			return !in_array($file, array('.', '..'));
		});
			
			foreach($files as $fn){
				$ffn=$dir_name.'/'.$fn;
				try {
					//unlink($ffn);//削除
					$this->removeDirectory($ffn);
				} catch (Exception $e) {
					throw e;
				}
			}
			
			return true;
	}
	
	/**
	 * ディレクトリごとファイルを削除する。(階層化のファイルまで削除可能)
	 * @param string $dir 削除対象ディレクトリ
	 */
	private function removeDirectory($dir) {
		if ($handle = opendir($dir)) {
			while (false !== ($item = readdir($handle))) {
				if ($item != "." && $item != "..") {
					$dp = $dir . '/' . $item;
					if (is_dir($dp)) {
						removeDirectory($dp);
					} else {
						unlink($dp);
					}
				}
			}
			closedir($handle);
			rmdir($dir);
		}
	}
	

ディレクトリ内のファイル削除 | 指定日数より古い更新日のファイルをすべて削除する


<?php 

$sample = new Sample();
$sample->removeFileByOldDay('sample', 2);

class Sample{
	
    /**
     * 危険処理
     * 指定日数より古い更新日のファイルをすべて削除する
     *
     * @note
     *指定日数に2を指定した場合、二日以上前のファイルをすべて削除。
     *0を指定すると、すべてのファイルを削除
     *
     * @param string $dp ディレクトリパス
     * @param number $day_num 指定日数
     * @param string $ext 削除ファイルの拡張子(小文字) null:すべてのファイルが対象
     */
    public function removeFileByOldDay($dp, $day_num = 1, $ext = null){
        
        $fps = $this->scandir3($dp); // ディレクトリ内にあるすべてのファイルのファイルパスを取得する
        $today = date("Y-m-d");
        
        foreach($fps as $fp){
            $dt = date("Y-m-d", filemtime($fp));
            $diff_day = $this->diffDay($today, $dt); // 2つの日付の日数差を算出する

            // 日付差が指定日数以上なら、ファイル削除とする。
            if($day_num <= $diff_day){
                
                // ファイルパスから拡張子(小文字)を取得
                $pi = pathinfo($fp);
                $ext2 = mb_strtolower($pi['extension']); 
                
                // 拡張子が一致するなら、このファイルを削除する
                if($ext == $ext2){
                    unlink($fp);
                }
            }
        }
    }
	
	
	/**
	 * 2つの日付の日数差を算出する
	 *
	 * diff = d2 - d1
	 *
	 * @param date or string $d2
	 * @param date or string $d1
	 * @return int 日数差
	 */
	private function diffDay($d2,$d1){
		
		$u1=strtotime($d1);
		$u2=strtotime($d2);
		
		//日数を算出
		$diff=$u2-$u1;
		$d_cnt=$diff/86400;
		
		return $d_cnt;
	}
	
	
	/**
	 * scandir関数の拡張関数。
	 *
	 * @note
	 * 「.」「..」となっているファイル名は除外する。
	 *
	 * @param  string $dp ディレクトリ名
	 * @param string $sep セパレータ(省略可)
	 * @return array ファイルパスリスト
	 */
	private function scandir3($dp, $sep = '/'){
		$files = scandir($dp);
		
		// ディレクトリパスの末尾にセパレータを付け足す
		$dp2 = $dp;
		if(mb_substr($dp2, -1) != $sep){
			$dp2 .= $sep;
		}
		
		// 「.」,「..」名のファイルを除去、および日本語ファイルに対応。
		$fps = [];
		foreach($files as $file){
			if($file=='.' || $file=='..'){
				continue;
			}
			$fps[] = $dp2 . $file;
		}
		
		return $fps;
	}
}


function debug($var){
	echo '<pre>';
	var_dump($var);
	echo '</pre>';
}

?>

ファイル名からディレクトリ、ファイル名、拡張子を取得する | pathinfo()

	$pi = pathinfo('/okinawa/kunigami/oku/habu.jpg');

	echo $pi['dirname'],	//→ '/okinawa/kunigami/oku',
	echo $pi['basename'];	//→ 'habu.jpg',
	echo $pi['extension'];	//→ 'jpg'
	echo $pi['filename'];	//→ 'habu'

	

ディレクトリが存在しないならディレクトリを作成する


	$dirName = "C:\xampp\htdocs\xample\test";
	makeDirEx($dirName);
	


mkdirの拡張メソッド

パスに新しく作成せねばならないディレクトリ情報が複数含まれている場合でも、順次ディレクトリを作成する。


	/**
	 * ディレクトリを作成する
	 *
	 * @note
	 * ディレクトリが既に存在しているならディレクトリを作成しない。
	 * パスに新しく作成せねばならないディレクトリ情報が複数含まれている場合でも、順次ディレクトリを作成する。
	 * 日本語ディレクトリ名にも対応。
	 * パスセパレータは「/」と「¥」に対応。
	 * ディレクトリのパーミッションの変更をを行う。(既にディレクトリが存在する場合も)
	 * セパレータから始まるディレクトリはホームルートパスからの始まりとみなす。
	 *
	 * @version 1.3
	 * @date 2014-4-13 | 2018-8-18
	 *
	 * @param string $dir_path ディレクトリパス
	 */
	private function makeDirEx($dir_path,$permission = 0705){

 		if(empty($dir_path)){return;}

 		$home_flg = false; // ホームディレクトリパス  1:ホーム(htdocsより以降)からのパス
 		$s1 = mb_substr($dir_path,0,1);
 		if($s1 == '/' || $s1 == DIRECTORY_SEPARATOR){
 			$home_flg = 1;
 		}
		
		// 日本語名を含むパスに対応する
		$dir_path=mb_convert_encoding($dir_path,'SJIS','UTF-8');
		
		// ディレクトリが既に存在する場合、書込み可能にする。
		if (is_dir($dir_path)){
			chmod($dir_path,$permission);// 書込み可能なディレクトリとする
			return;
		}
		
		// パスセパレータを取得する
		$sep = DIRECTORY_SEPARATOR;
		if(strpos($dir_path,"/")!==false){
			$sep = "/";
		}
		
		//パスを各ディレクトリに分解し、ディレクトリ配列をして取得する。
		$ary=explode($sep, $dir_path);
		
		//ディレクトリ配列の件数分以下の処理を繰り返す。
		$dd = '';
		foreach ($ary as $i => $val){
			
			if($i==0){
				$dd=$val;
				if($home_flg == 1){
					$dd = $_SERVER['DOCUMENT_ROOT'] . $sep . $dd;
				}
			}else{
				$dd .= $sep.$val;
			}
			
			//作成したディレクトリが存在しない場合、ディレクトリを作成
			if (!is_dir($dd)){
				mkdir($dd,$permission);//ディレクトリを作成
				chmod($dd,$permission);// 書込み可能なディレクトリとする
			}
		}
	}
	



ファイル削除を日本語名ファイルで行う方法 | unlink


	$ffn='/sample/xxx/日本語.pdf';

	$ffn=mb_convert_encoding($ffn,'SJIS','UTF-8');//日本語ファイル名に対応
	if(file_exists($ffn)){//ファイルが存在するか?
		unlink($ffn);//ファイルを削除
	}
	

ディレクトリを深く探り、ファイル群のファイルパス配列を取得する

	/**
	 * ディレクトリを深く探り、ファイル群のファイルパス配列を取得する
	 * @param string $path ディレクトリパス
	 * @param array $data 内部処理用・ファイルパスリスト
	 * @return array ファイルパスリスト
	 */
	function getFilePathFromDeep($path, &$data=array()){
		
		if(is_file($path)){
			$data[] = $path;
		}else{
			foreach(glob($path . '/*') as $path2){
				$data = getFilePathFromDeep($path2, $data);
			}
		}
		
		return $data;
	}
	

IPアドレスを取得する

	$ipAddr=$_SERVER["REMOTE_ADDR"];//IPアドレス取得

	$ipVal = ip2long($ipAddr);// IPアドレスを数値変換
	
	$ipAddr=$this->request->clientIp(false);//CakePHPでのIPアドレス取得
	
サンプル