PHPのプログラミングについての質問です。
日付を入力するフォームがあり、送信された文字列が日付として有効かどうかをチェックしています。
年月日を別々に入力させてcheckdate
関数でチェックする方法が無難だと思いますが今回はできません。
現状はこんな感じで書いています
PHP
1//送信された日付文字列 2$date = $_POST('date'); 3//日付かどうかチェック 4if(strtotime($date) === false){ 5 //ダメなときの処理 6 $date = null; 7}else{ 8 //下記フォーマットに統一する 9 $date = date('Y-m-d',strtotime($date)); 10}
同じ様なチェックをDateTime
オブジェクトを使ってシンプルに書くことはできるでしょうか?
ユーザーからの入力は、YYYY-MM-DD、YYYY/MM/DD、YYYYMMDDを想定しています。
よろしくお願いします。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答6件
0
ユーザーからの入力は、YYYY-MM-DD、YYYY/MM/DD、YYYYMMDDを想定
であればパターンを設定して正規表現でチェックしてください
そうでない場合他の想定していないパターンにもマッチします
またフォーマットがあっていればstrtotimeは無理やり日付として
解釈するので、極端な値を設定したり0月や20月とか0日とか99日などを
チェックしてもそれなりに解釈します。
PHP
1$a=["2017-02-14","2017/02/15","20170216",//問題なくマッチ 2 "2017/2/17","2017020180","2017/02-19","xxxx-yy-zz",//エラー 3 "0000-00-00","9999-99-99" //極端な数字でもマッチ 4 ]; 5/* $pattern="#^\d{4}[/-]{0,1}\d{2}[/-]{0,1}\d{2}$#"; */ 6/* おかしなパターンを拾うのでいかに修正 */ 7$pattern="#^\d{4}([/-]?)\d{2}\\1\d{2}$#"; 8foreach ($a as $val){ 9 print $val." is "; 10 if(preg_match($pattern,$val,$match)){ 11 print date("Y-m-d",strtotime($val))."<br>"; 12 }else{ 13 print "ng<br>"; 14 } 15}
おまけ
POSTで受けたデータを前提とするのであれば、filter_inputで先に
バリデートするとか、日付形式の文字かどうかをcheckdate()するとか
色々やりようはあります
HTML
1<form method="post"><input type="text" name="a" value="2017-02-14"><input type="submit" value="go"></form> 2<form method="post"><input type="text" name="a" value="2017/02/15"><input type="submit" value="go"></form> 3<form method="post"><input type="text" name="a" value="20170216"><input type="submit" value="go"></form> 4<form method="post"><input type="text" name="a" value="2017/2/17"><input type="submit" value="go"></form> 5<form method="post"><input type="text" name="a" value="2017020180"><input type="submit" value="go"></form> 6<form method="post"><input type="text" name="a" value="2017/02-19"><input type="submit" value="go"></form> 7<form method="post"><input type="text" name="a" value="xxxx-yy-zz"><input type="submit" value="go"></form> 8<form method="post"><input type="text" name="a" value="0000-00-00"><input type="submit" value="go"></form> 9<form method="post"><input type="text" name="a" value="0001-01-01"><input type="submit" value="go"></form> 10<form method="post"><input type="text" name="a" value="9999-12-31"><input type="submit" value="go"></form> 11<form method="post"><input type="text" name="a" value="2017-00-01"><input type="submit" value="go"></form> 12<form method="post"><input type="text" name="a" value="2017-01-40"><input type="submit" value="go"></form>
PHP
1$pattern='#^(\d{4})([/-]?)(\d{2})\2(\d{2})$#'; 2$a=!isset($_POST["a"])?NULL:filter_input(INPUT_POST,'a',FILTER_VALIDATE_REGEXP,[ 3 'options'=>[ 4 'default'=> "", 5 'regexp'=> $pattern 6 ], 7 ]); 8if(!is_null($a)){ 9 if(preg_match($pattern,$a,$m) and checkdate($m[3],$m[4],$m[1])){ 10 print date("Y-m-d",strtotime($a))."<br>"; 11 }else{ 12 print "bad data!"; 13 } 14}
投稿2017/02/14 02:58
編集2017/02/14 07:52総合スコア117669
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/02/14 04:08
2017/02/14 04:26

退会済みユーザー
2017/02/16 06:49

退会済みユーザー
2017/02/16 09:34

0
$d = DateTime::createFromFormat('Y-m-d', $date) or DateTime::createFromFormat('Y/m/d', $date) or DateTime::createFromFormat('Ymd', $date); if ($d === false) { $date = null; } else { $date = $d -> format('Y-m-d'); }
投稿2017/02/14 07:03
総合スコア5570
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/02/14 07:22
2017/02/14 08:05
2017/02/14 08:53

0
終わった後の検証作業
dについて
01 から 31 あるいは 1 から 31 とあるので最後の日付だけ通るてしまうのではないでしょうか
print_r(date_parse_from_format ( $format ,$date ));
php
1<?php 2 3$dates = [ 4 '2017028', 5 '2017208' 6]; 7function chk_date($date) { 8 $formats = [ 9 'Ymd' 10 ]; 11 foreach ( $formats as $format ) { 12 DateTime::createFromFormat ( $format, $date ); 13 echo "<pre>"; 14 print_r(date_parse_from_format ( $format ,$date )); 15 echo "</pre>"; 16 $result = DateTime::getLastErrors (); 17 18 if (! $result ['warning_count'] && ! $result ['error_count']) { 19 return TRUE; 20 } 21 } 22 return FALSE; 23} 24 25foreach ( $dates as $date ) { 26 echo $date . ':'; 27 echo chk_date ( $date ) ? 'OK' : 'NG'; 28 echo PHP_EOL; 29}
Array ( [year] => 2017 [month] => 2 [day] => 8 [hour] => [minute] => [second] => [fraction] => [warning_count] => 0 [warnings] => Array ( ) [error_count] => 0 [errors] => Array ( ) [is_localtime] => ) OK 2017208: Array ( [year] => 2017 [month] => 20 [day] => 8 [hour] => [minute] => [second] => [fraction] => [warning_count] => 1 [warnings] => Array ( [7] => The parsed date was invalid ) [error_count] => 0 [errors] => Array ( ) [is_localtime] => )
投稿2017/02/16 02:12
総合スコア1820
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

退会済みユーザー
2017/02/16 02:17

退会済みユーザー
2017/02/16 23:57 編集

退会済みユーザー
2017/02/17 06:11

0
PHP DateTime
DateTimeクラスで、不正な日付フォーマットの場合にException投げるようですよ。
投稿2017/02/14 02:49
総合スコア5405
0
ベストアンサー
せっかくなんで、備忘録兼ねて回答します。
php
1<?php 2$dates = [ 3'2017-02-28', 4'2017/02/28', 5'20170228', 6'2016-02-29', 7'1800-02-28', 8'2017-02-31', 9'17-02-29', 10'hogehoge', 11]; 12 13function chk_date($date) 14{ 15 $formats = [ 16 'Y-m-d', 17 'Y/m/d', 18 'Ymd', 19 ]; 20 foreach ($formats as $format){ 21 DateTime::createFromFormat($format, $date); 22 $result = DateTime::getLastErrors(); 23 if(!$result['warning_count'] && !$result['error_count']) 24 { 25 return TRUE; 26 } 27 } 28 return FALSE; 29} 30 31foreach ($dates as $date){ 32 echo $date . ':'; 33 echo chk_date($date)?'OK':'NG'; 34 echo PHP_EOL; 35}
勉強になりました。
投稿2017/02/14 11:15

退会済みユーザー
総合スコア0
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

退会済みユーザー
2017/02/15 05:12

退会済みユーザー
2017/02/16 01:24

退会済みユーザー
2017/02/16 02:22

0
日付の正当性以前に $date = $_POST('date');
が気になりますが、それは置いておいて、kunai さんの提案のように、DateTimeクラスで良くないですか?
exit しなければ、やりたいことは実現できる気がするのですが。
投稿2017/02/14 07:13

退会済みユーザー
総合スコア0
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/02/14 09:35

退会済みユーザー
2017/02/14 09:51

退会済みユーザー
2017/02/14 10:12

退会済みユーザー
2017/02/14 10:52

退会済みユーザー
2017/02/14 11:17

あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。