PHPの覚書

時分チェック関数

	//時分チェック(h:i形式)
	function is_time_hi($v){

		$v=trim($v);


		if(empty($v)){
			return true;
		}


		$ary=explode(':',$v);

		if(count($ary) != 2){
			return false;
		}

		$h=trim($ary[0]);
		$m=trim($ary[1]);

		if(!preg_match('/^[0-9]+$/', $h)){
			return false;
		}

		if(!preg_match('/^[0-9]+$/', $m)){
			return false;
		}

		if($h < 0 || $h > 23){
			return false;
		}

		if($m < 0 || $m > 59){
			return false;
		}

		return true;
	}
	
サンプル

期間月分割 | 開始日から終了日までの期間を月ごとに分割する関数

2012/12/25から2015/5/12の期間を下記のように指定月毎に分割する関数。
	0:  2012-12-25 ~ 2012-12-31
	1:  2013-01-01 ~ 2013-03-31
	2:  2013-04-01 ~ 2013-06-30
	3:  2013-07-01 ~ 2013-09-30
	4:  2013-10-01 ~ 2013-12-31
	5:  2014-01-01 ~ 2014-03-31
	6:  2014-04-01 ~ 2014-06-30
	7:  2014-07-01 ~ 2014-09-30
	8:  2014-10-01 ~ 2014-12-31
	9:  2015-01-01 ~ 2015-03-31
	10:  2015-04-01 ~ 2015-05-12
	


関数
	/**
	 * 開始日から終了日までの期間を月ごとに分割する。
	 * 月間隔を指定するなら季節ごとの分割も再現できる。(1月を基準とし、月間隔値の倍数で分割)
	 * @param $start 開始日
	 * @param $end 終了日
	 * @param $interval 月間隔
	 * @return 期間分割リスト
	 */
	function termMonthSplit($start,$end,$interval){

		//Y-m-d形式にする。
		$start=date('Y-m-d',strtotime($start));
		$end=date('Y-m-d',strtotime($end));

		// 開始日を年月日に分割
		$start_y=date('Y', strtotime($start));
		$start_m=date('m', strtotime($start));


		// 終了日を年月日に分割
		$end_y=date('Y', strtotime($end));
		$end_m=date('m', strtotime($end));


		$m1=0;	// 月値1
		$m2=0;	// 月値2
		$list=array();
		// 開始年から終了年までの年ループ
		for($y=$start_y ; $y <= $end_y ; $y++){

			// 年ループは初周回であるか?
			if($y == $start_y){
				$m1 = $start_m; // 月ループの月値1に開始月をセット

			}else{
				$m1 = 1;	// 月ループの月値1に1をセット
			}

			// 年ループは最周回であるか?
			if($y == $end_y){
				$m2 = $end_m;// 月ループの月値2に終了月をセット

			}else{
				$m2 = 12; // 月ループの月値2に12
			}

			// 月ループ	月値1から月値2までループ
			for($m=$m1 ; $m <= $m2 ; $m++){


				// 年ループの初周回且つ、月ループの初周回であるか?
				if($y == $start_y && $m == $m1){
					$list[]=$start; // リストに開始日を追加
				}

				// 年ループの最周回且つ、月ループの最周回であるか?
				if($y == $end_y && $m == $m2 ){
					$list[]=$end;// リストに最終日を追加
				}

				// 月値は月間隔の倍数であるか?
				if(($m % $interval) == 0){

 					$str_ym1=$y.'-'.$m.'-1';

					// 月値の月末を取得し、リストに追加
					$yml = date('Y-m-t',strtotime($str_ym1));

 					$list[]=$yml;

					// 次月の月初を取得し、リストに追加
					if($m == 12){
						$str_ym2=($y + 1).'-1-1';
					}else{
						$str_ym2=$y.'-'.($m + 1).'-1';
					}
					$ym1=date('Y-m-d',strtotime($str_ym2));
					$list[]=$ym1;

				}

			}
		}

		$list2=array_chunk($list,2);//開始年と終了年のリストになるよう構造変換

		return $list2;
	}



	
サンプル

XSSサニタイズ

XSSサニタイズ


	/**
	 * XSSサニタイズ
	 *
	 * @note
	 * XSSサニタイズ
	 * 記号「<>」を「&lt;&gt;」にエスケープする。
	 *
	 * @param mixied $data 対象データ | 値および配列を指定
	 * @return void
	 */
	public function xssSanitizeW(&$data){
		$this->xss_sanitize($data);
		return $data;
	}
	
	/**
	 * XSSエスケープ(XSSサニタイズ)
	 *
	 * @note
	 * XSSサニタイズ
	 * 記号「<>」を「&lt;&gt;」にエスケープする。
	 * 高速化のため、引数は参照(ポインタ)にしており、返値もかねている。
	 *
	 * @param mixied $data 対象データ | 値および配列を指定
	 * @return void
	 */
	private function xss_sanitize(&$data){
		
		if(is_array($data)){
			foreach($data as &$val){
				$this->xss_sanitize($val);
			}
			unset($val);
		}elseif(gettype($data)=='string'){
			$data = str_replace(array('<','>'),array('&lt;','&gt;'),$data);
		}else{
			// 何もしない
		}
	}
	

XSSアンエスケープ


	/**
	 * XSSアンエスケープ(XSSサニタイズデコード)
	 *
	 * @note
	 * XSSエスケープされたデータを元に戻す。
	 * 高速化のため、引数は参照(ポインタ)にしており、返値もかねている。
	 *
	 * @param any $data 対象データ | 値および配列を指定
	 * @return void
	 */
	function xss_unescape(&$data){
		
		if(is_array($data)){
			foreach($data as &$val){
				xss_unescape($val);
			}
			unset($val);
		}elseif(gettype($data)=='string'){
			$data = str_replace(array('&lt;','&gt;'),array('<','>'),$data);
		}else{
			// 何もしない
		}
	}
	


改行やXSSの危険可能性がある文字列を出力する場合、以下の1行コードが便利。
echo nl2br (h($str));

簡易版のXSSサニタイズ関数


	/**
	 * XSSサニタイズ
	 * @param string $str 対象文字列
	 * @return XSSサニタイズ後の文字列
	 */
	function xss_sanitize($str){
		return str_replace(array('<','>'),array('&lt;','&gt;'),$str);
	}
	


SQLインジェクション用のサニタイズ

addslashes関数は「'」記号を「\'」にサニタイズされることを確認ずみ。
その他の記号についてのサニタイズは確認できていない。「,」だけか?

SQLインジェクションサニタイズ


	/**
	 * SQLインジェクションサニタイズ
	 * @param mixed $data 文字列および配列に対応
	 * @return mixed サニタイズ後のデータ
	 */
	private function sqlSanitizeW(&$data){
		$this->sql_sanitize($data);
		return $data;
	}
	
	
	/**
	 * SQLインジェクションサニタイズ(配列用)
	 *
	 * @note
	 * SQLインジェクション対策のためデータをサニタイズする。
	 * 高速化のため、引数は参照(ポインタ)にしている。
	 *
	 * @param array サニタイズデコード対象のデータ
	 * @return void
	 */
	protected function sql_sanitize(&$data){
	
		if(is_array($data)){
			foreach($data as &$val){
				$this->sql_sanitize($val);
			}
			unset($val);
		}elseif(gettype($data)=='string'){
			$data = addslashes($data);// SQLインジェクション のサニタイズ
		}else{
			// 何もしない
		}
	}
	

SQLサニタイズデコード


	/**
	 * SQLサニタイズデコード(配列用)
	 *
	 * @note
	 * SQLインジェクションでサニタイズしたデータを元に戻す。
	 * 高速化のため、引数は参照(ポインタ)にしている。
	 *
	 * @param array サニタイズデコード対象のデータ
	 * @return void
	 */
	protected function sql_sanitize_decode(&$data){
	
		if(is_array($data)){
			foreach($data as &$val){
				$this->sql_sanitize_decode($val);
			}
			unset($val);
		}elseif(gettype($data)=='string'){
			$data = stripslashes($data);
		}else{
			// 何もしない
		}
	}
	

下記は旧記述 2017-5-22


	/**
	 * SQLインジェクションのサイニタイズ
	 *
	 * @note
	 * 高速化のため参照型の引数としている。(返値をかねた引数)
	 * 引数には文字列と多重配列を指定できる。
	 * addslashes関数を使用しているため文字コードShift_JISやGBKでは不安要素あり。
	 *
	 * @param string/array $any 対象文字列または配列
	 * @return void
	 */
	private function sql_sanitize(&$any){
		if (is_array($any)){
			foreach ($any as $i =< &$val){
				$this-<sql_sanitize($val);
			}
			unset($val);
		}else{
	
			if(gettype($any)=='string'){
				//SQLインジェクション のサニタイズ
				$any=addslashes($any);
	
			}
		}
	
	}
	

補足
addslashes関数でサニタイズした文字列はstripslashes関数で戻せる。

SQLインジェクション対策にはmysql_real_escape_string関数を使うと便利である。
mysql_real_escape_string関数はシングルクォートにバックスラッシュを付加する。


	$v = " || a=''";
	$v = mysql_real_escape_string($v);
	echo $v;
	

出力
	|| a=\'\'

mysql_real_escape_stringが使えない場合
	$str = str_replace("'","\'",$str);
	
※不完全である。他にも注意しておいた方がよい記号た多数存在する。

注意

mysql_real_escape_stringはPHP5.5から非推奨になり、PHP7からは削除された。
以下が代替手段とのこと。しかい、DB接続設定が必要になるので使いにくい。



XML出力用のエスケープ

XMLエスケープ


	/**
	 * XMLエスケープ
	 *
	 * @note
	 * XMLに出力データをエスケープする。
	 * 記号「<>"'&」を「&lt;&gt;&amp;&quot;&apos;」にエスケープする。
	 * 高速化のため、引数は参照(ポインタ)にしており、返値もかねている。
	 *
	 * @param any $data 対象データ | 値および配列を指定 
	 * @return void
	 */
	function xml_escape(&$data){
		
		if(is_array($data)){
			foreach($data as &$val){
				xml_escape($val);
			}
			unset($val);
		}elseif(gettype($data)=='string'){
			$data = str_replace(array('&','<','>','"',"'"),array('&amp;','&lt;','&gt;','&quot;','&apos;'),$data);
		}else{
			// 何もしない
		}
	}
	
検証

XMLアンエスケープ


	/**
	 * XMLアンエスケープ
	 *
	 * @note
	 * XMLエスケープされたデータを元に戻す。
	 * 高速化のため、引数は参照(ポインタ)にしており、返値もかねている。
	 *
	 * @param any $data 対象データ | 値および配列を指定
	 * @return void
	 */
	function xml_unescape(&$data){
		
		if(is_array($data)){
			foreach($data as &$val){
				xml_unescape($val);
			}
			unset($val);
		}elseif(gettype($data)=='string'){
			$data = str_replace(array('&lt;','&gt;','&quot;','&apos;','&amp;'),array('<','>','"',"'",'&'),$data);
		}else{
			// 何もしない
		}
	}
	


PHPの注意:PHPの関数と同じ名前でオリジナル関数を作ってはいけない。

環境により、呼び出す関数が変化する。
開発環境では正常に動いても、本番環境(サーバー上)では正常に動かない可能性がある。

関数「getSize()」で確認。

2次元配列から列を抜き出す

array_column関数は2次元配列から縦区切りで、データを抽出できます。
	require_once 'array_column.php';//PHP5.5未満の環境でもarray_column関数を使えるようにする。

	//1列目だけを抽出例。
	$dd=array(
		array(1,'nezumi','a'),
		array(2,'usi','b'),
		array(3,'tora','c'));
	$ary=array_column($dd, 1);
	echo var_dump($ary);
	
出力
	array (size=3)
	  0 => string 'nezumi' (length=6)
	  1 => string 'usi' (length=3)
	  2 => string 'tora' (length=4)
	
; サンプル
もちろんインデックスだけでなくキー名を指定して列を抽出することも可能。
列は1つだけなく複数取得できる。
ドキュメント

array_columnはPHP5.5からの関数である。 PHP5.5未満の対応方法はここから

数値を2桁表記にする(例 2→02)

	$m=2;
	$m2=sprintf('%02d', $m);
	//$m2='02'
	

小数点以下の0(ゼロ)埋めて桁数をそろえる | number_format

	$num1 = 123.456;
	$num2 = 123.45678;
	$num3 = 123;
	$num4 = 123.45674;
	$num5 = 123.45675;

	echo number_format($num1, 4); // → 123.4560
	echo number_format($num2, 4); // → 123.4568
	echo number_format($num3, 4); // → 123.0000
	echo number_format($num4, 4); // → 123.4567 (切り捨て部分は四捨五入される)
	echo number_format($num5, 4); // → 123.4568 (切り捨て部分は四捨五入される)

	

科学記法を10進数表記にする(例 1.23E+14 → 123000000000000)

巨大な整数を出力する科学記法になってしまう。

科学記法になってしまう例
	$a=123000000000000;// ←巨大な整数
	echo $a;// → (float) 1.23E+14
	

科学記法でなく10進数で表記したい場合、以下のようにする。
	$a=number_format($a, 0, '.', '');
	echo $a;// → 123000000000000
	

※ただ小数点以下の数値には対応していない。小数点以下は無視されてしまう。

出す | array_keys
array_keys関数でキーのリストを取り出すことができる。

ソースコード
	$ary=array('neko'=>'猫','hituji'=>'羊','kani'=>'蟹','same'=>'鮫',);
	$keys=array_keys($ary);
	Debugger::dump($keys);
	

ダンプ
	array(
		(int) 0 => 'neko',
		(int) 1 => 'hituji',
		(int) 2 => 'kani',
		(int) 3 => 'same'
	)
	
※配列が空であれば、空のキーリストを返す。エラーにはならない。

文字列を指定文字数ごとに区切って配列にする | str_split

str_split関数は文字列を指定文字数ごとに区切ることができる。

ソースコード
	$str="20120229";
	$ary=str_split($str,2);
	Debugger::dump($ary);
	
ダンプ
	array(
		(int) 0 => '20',
		(int) 1 => '12',
		(int) 2 => '02',
		(int) 3 => '29'
	)
	



区切り文字数を省略すると一文字ごとの配列になる
	$str="20120229";
	$ary=str_split($str);
	Debugger::dump($ary);
	
ダンプ
	array(
		(int) 0 => '2',
		(int) 1 => '0',
		(int) 2 => '1',
		(int) 3 => '2',
		(int) 4 => '0',
		(int) 5 => '2',
		(int) 6 => '2',
		(int) 7 => '9'
	)
	



空文字($str=null)である場合、データ1件の配列になる。nullにはならないので注意。
	$str=null;
	$ary=str_split($str);
	Debugger::dump($ary);
	
ダンプ
	array(
		(int) 0 => ''
	)