Date check in PHP while importing hand typed CSV

32 Views Asked by At

I am having a CSV to be prone to errors (typed by hand) to import to Oracle.

I want to check if the field in it is a valid (dd/mm/yyyy) date.

I wrote the following code

function check_date($a1,$a2,$a3,$a4)
{
    global $error;
    if ( DateTime::createFromFormat('d/m/Y', $a1)->format('d/m/Y') !== $a1 )
    {
        echo "ERROR - Row ($a2) - Column ($a4) - Invalid $a3</br>";
        $error = 1 ;
    }
}

This failed if the field was empty so I added to be

function check_date($a1,$a2,$a3,$a4)
{
    global $error;
    if ( $a1 == "" )
    {
        echo "ERROR - Row ($a2) - Column ($a4) - Empty $a3</br>";
        $error = 1 ;
        goto end_function ;
    }
    if ( DateTime::createFromFormat('d/m/Y', $a1)->format('d/m/Y') !== $a1 )
    {
        echo "ERROR - Row ($a2) - Column ($a4) - Invalid $a3</br>";
        $error = 1 ;
    }
    end_function:
}

Now the problem is if the field is any character like 'a' the script fails.

I call the function

check_date($CSVData[2], $row_count, "ISSUE_DATE" , $alphabet[2] ) ;

How can I solve it.

Thanks.

1

There are 1 best solutions below

2
Nick On BEST ANSWER

You just need to check if the result of DateTime::createFromFormat is a DateTime object before attempting to use it. Since it's now (as of PHP8.0.21, 8.1.8 and 8.2.0) possible for this function to throw an error, this can be implemented with a try/catch block, throwing an exception if the conversion fails or doesn't match the input:

function check_date($a1,$a2,$a3,$a4)
{
    global $error;
    try {
        $date = DateTime::createFromFormat('d/m/Y', $a1);
        if ($date === false || $date->format('d/m/Y') !== $a1) throw new Exception('Invalid date');
    }
    catch (Throwable $e) {
        echo "ERROR - Row ($a2) - Column ($a4) - {$e->getMessage()} $a3: \"$a1\"</br>" . PHP_EOL;
        $error = 1 ;
    }
}

check_date("\0", 1, "ISSUE_DATE", 'Start date');
check_date('20/01/2023', 2, "ISSUE_DATE", 'Start date');
check_date('3/4/2023', 3, "ISSUE_DATE", 'Start date');
check_date('2023-01-20', 4, "ISSUE_DATE", 'Start date');
check_date('', 5, "ISSUE_DATE", 'Start date');
check_date('a', 6, "ISSUE_DATE", 'Start date');

Output:

ERROR - Row (1) - Column (Start date) - DateTime::createFromFormat(): Argument #2 ($datetime) must not contain any null bytes ISSUE_DATE: ""</br>
ERROR - Row (3) - Column (Start date) - Invalid date ISSUE_DATE: "3/4/2023"</br>
ERROR - Row (4) - Column (Start date) - Invalid date ISSUE_DATE: "2023-01-20"</br>
ERROR - Row (5) - Column (Start date) - Invalid date ISSUE_DATE: ""</br>
ERROR - Row (6) - Column (Start date) - Invalid date ISSUE_DATE: "a"</br>

Demo on 3v4l.org