From ea59bcf150bd5f59986906ea858555c94396f6ae Mon Sep 17 00:00:00 2001 From: shibafu Date: Sun, 16 Feb 2020 14:28:30 +0900 Subject: [PATCH] =?UTF-8?q?=E6=97=A5=E4=BB=98=E5=BD=A2=E5=BC=8F=E3=81=A8?= =?UTF-8?q?=E7=AF=84=E5=9B=B2=E3=81=AE=E3=83=81=E3=82=A7=E3=83=83=E3=82=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Io/CheckinCsvImporter.php | 5 ++-- app/Rules/CsvDateTime.php | 21 ++++++++++++++-- tests/Unit/Io/CheckinCsvImporterTest.php | 31 ++++++++++++++++++++++++ tests/fixture/Csv/invalid-date.utf8.csv | 17 +++++++++++++ 4 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 tests/fixture/Csv/invalid-date.utf8.csv diff --git a/app/Io/CheckinCsvImporter.php b/app/Io/CheckinCsvImporter.php index 2a7bb91..92a9ac6 100644 --- a/app/Io/CheckinCsvImporter.php +++ b/app/Io/CheckinCsvImporter.php @@ -51,6 +51,7 @@ class CheckinCsvImporter } foreach ($csv->getRecords() as $offset => $record) { + $line = $offset + 1; $ejaculation = new Ejaculation(['user_id' => $this->user->id]); $validator = Validator::make($record, [ @@ -61,7 +62,7 @@ class CheckinCsvImporter if ($validator->fails()) { foreach ($validator->errors()->all() as $message) { - $errors[] = "{$offset} 行 : {$message}"; + $errors[] = "{$line} 行 : {$message}"; } continue; } @@ -82,7 +83,7 @@ class CheckinCsvImporter break; } if (mb_strlen($tag) > 255) { - $errors[] = "{$offset} 行 : {$column}列は255文字以内にしてください。"; + $errors[] = "{$line} 行 : {$column}列は255文字以内にしてください。"; continue 2; } diff --git a/app/Rules/CsvDateTime.php b/app/Rules/CsvDateTime.php index 118c5ba..76159ef 100644 --- a/app/Rules/CsvDateTime.php +++ b/app/Rules/CsvDateTime.php @@ -17,6 +17,12 @@ class CsvDateTime implements Rule 'Y/n/j G:i', ]; + const MINIMUM_TIMESTAMP = 946652400; // 2000-01-01 00:00:00 JST + const MAXIMUM_TIMESTAMP = 4102412399; // 2099-12-31 23:59:59 JST + + /** @var string Validation error message */ + private $message = ':attribute の形式は "年/月/日 時:分" にしてください。'; + /** * Create a new rule instance. * @@ -44,8 +50,19 @@ class CsvDateTime implements Rule foreach (self::VALID_FORMATS as $format) { $date = \DateTime::createFromFormat('!' . $format, $value); + if (!$date) { + continue; + } - if ($date && $date->format($format) === $value) { + $timestamp = (int) $date->format('U'); + if ($timestamp < self::MINIMUM_TIMESTAMP || self::MAXIMUM_TIMESTAMP < $timestamp) { + $this->message = ':attribute は 2000/01/01 00:00 〜 2099/12/31 23:59 の間のみ対応しています。'; + + return false; + } + + $formatted = $date->format($format); + if ($formatted === $value) { return true; } } @@ -60,6 +77,6 @@ class CsvDateTime implements Rule */ public function message() { - return ':attribute の形式は "年/月/日 時:分" にしてください。'; + return $this->message; } } diff --git a/tests/Unit/Io/CheckinCsvImporterTest.php b/tests/Unit/Io/CheckinCsvImporterTest.php index 5776838..71256d0 100644 --- a/tests/Unit/Io/CheckinCsvImporterTest.php +++ b/tests/Unit/Io/CheckinCsvImporterTest.php @@ -70,4 +70,35 @@ class CheckinCsvImporterTest extends TestCase 'NoZero, NoSecond, UTF8' => [$date, __DIR__ . '/../../fixture/Csv/date-nozero-nosecond.utf8.csv'], ]; } + + public function testInvalidDate() + { + $user = factory(User::class)->create(); + + try { + $importer = new CheckinCsvImporter($user, __DIR__ . '/../../fixture/Csv/invalid-date.utf8.csv'); + $importer->execute(); + } catch (CsvImportException $e) { + $this->assertSame('2 行 : 日時 は 2000/01/01 00:00 〜 2099/12/31 23:59 の間のみ対応しています。', $e->getErrors()[0]); + $this->assertSame('3 行 : 日時 は 2000/01/01 00:00 〜 2099/12/31 23:59 の間のみ対応しています。', $e->getErrors()[1]); + $this->assertSame('4 行 : 日時 の形式は "年/月/日 時:分" にしてください。', $e->getErrors()[2]); + $this->assertSame('5 行 : 日時 の形式は "年/月/日 時:分" にしてください。', $e->getErrors()[3]); + $this->assertSame('6 行 : 日時 の形式は "年/月/日 時:分" にしてください。', $e->getErrors()[4]); + $this->assertSame('7 行 : 日時 の形式は "年/月/日 時:分" にしてください。', $e->getErrors()[5]); + $this->assertSame('8 行 : 日時 の形式は "年/月/日 時:分" にしてください。', $e->getErrors()[6]); + $this->assertSame('9 行 : 日時 の形式は "年/月/日 時:分" にしてください。', $e->getErrors()[7]); + $this->assertSame('10 行 : 日時 の形式は "年/月/日 時:分" にしてください。', $e->getErrors()[8]); + $this->assertSame('11 行 : 日時 の形式は "年/月/日 時:分" にしてください。', $e->getErrors()[9]); + $this->assertSame('12 行 : 日時 の形式は "年/月/日 時:分" にしてください。', $e->getErrors()[10]); + $this->assertSame('13 行 : 日時 の形式は "年/月/日 時:分" にしてください。', $e->getErrors()[11]); + $this->assertSame('14 行 : 日時 の形式は "年/月/日 時:分" にしてください。', $e->getErrors()[12]); + $this->assertSame('15 行 : 日時 の形式は "年/月/日 時:分" にしてください。', $e->getErrors()[13]); + $this->assertSame('16 行 : 日時 の形式は "年/月/日 時:分" にしてください。', $e->getErrors()[14]); + $this->assertSame('17 行 : 日時 の形式は "年/月/日 時:分" にしてください。', $e->getErrors()[15]); + + return; + } + + $this->fail('期待する例外が発生していません'); + } } diff --git a/tests/fixture/Csv/invalid-date.utf8.csv b/tests/fixture/Csv/invalid-date.utf8.csv new file mode 100644 index 0000000..3c60935 --- /dev/null +++ b/tests/fixture/Csv/invalid-date.utf8.csv @@ -0,0 +1,17 @@ +日時,ノート +1999/12/31 23:59:59,最小境界 +2100/01/01 00:00:00,最大境界 +-1/01/01 00:00:00,存在しない日付 +2019/-1/01 00:00:00,存在しない日付 +2019/01/-1 00:00:00,存在しない日付 +2019/02/29 00:00:00,存在しない日付 +2019/00/01 00:00:00,存在しない日付 +2019/01/00 00:00:00,存在しない日付 +2019/01/32 00:00:00,存在しない日付 +2019/13/01 00:00:00,存在しない日付 +2019/01/01 00:60:00,存在しない時刻 +2019/01/01 24:00:00,存在しない時刻 +2019/01/01 00:00:60,存在しない時刻 +2019/01/01 -1:00:00,存在しない時刻 +2019/01/01 00:-1:00,存在しない時刻 +2019/01/01 00:00:-1,存在しない時刻