khaled-alshamaa / ar-php

Set of functionalities enable Arabic website developers to serve professional search, present and process Arabic content in PHP

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[bug] Undefined behavior when the correction value causes the gregorian day to be <=0 or >31

Socotoly opened this issue · comments

ar-php/src/Arabic.php

Lines 1143 to 1149 in 58046cd

if ($hj_d <= 0) {
$hj_d = $hj_d == 0 ? 30 : 29;
list($hj_y, $hj_m, $temp) = $this->arDateGregToIslamic((int)$y, (int)$m, (int)$d + $correction);
} elseif ($hj_d > 30) {
$hj_d = $hj_d == 31 ? 1 : 2;
list($hj_y, $hj_m, $temp) = $this->arDateGregToIslamic((int)$y, (int)$m, (int)$d + $correction);
}

In lines 1145 and 1148, specifically, the $d + $correction portion. If the gregorian day is 1 and the $correction value is -1 or the day is 31 and the $correction value is 1, this causes the day to be an invalid value 0 and 32 respectively. In this case the gregoriantojd() function will return 0 as the passed day is invalid

Dear @Socotoly,

Thanks for passing by our library and reviewing its code. We highly appreciate your time, but first of all, I can't reproduce the extreme case you describe in your static analysis and demonstrate it in an example script. In fact, the $correction values have been calculated in a way to avoid such scenarios.

On the other hand, your suggested fix is changing the $d value for the given Gregorian date, which is not correct! We added that correction value to the 3rd parameter of the arDateGregToIslamic method to get the $y and $m of the previous or next Hijri month.

Rather than that, I advise you to replace the original block from lines 1143 to 1149 (i.e., the if statement) with the following block of code as a compromise, which will serve your original purpose and fit well with that method logic.

if ($hj_d <= 0) {
    $hj_d = $hj_d == 0 ? 30 : 29;
    // alter the $hj_m and $hj_y to refer to the previous month
    $hj_m = $hj_m == 1 ? 12 : $hj_m - 1;
    $hj_y = $hj_m == 12 ? $hj_y - 1 : $hj_y;
} elseif ($hj_d > 30) {
    $hj_d = $hj_d == 31 ? 1 : 2;
    // alter the $hj_m and $hj_y to refer to the next month
    $hj_m = $hj_m == 12 ? 1 : $hj_m + 1;
    $hj_y = $hj_m == 1 ? $hj_y + 1 : $hj_y;
}

Dear Yaqoob Khalid, I will highly appreciate it if you could update your PR code snippet to reflect the advise I mentioned in my previous comment as soon as possible because I am going to publish the next release 6.3 within a week from now and I would like to have your contribution in it.

Hi @khaled-alshamaa, Thanks for the feedback.

You can reproduce the issue using this code:

$ar = new \ArPHP\I18N\Arabic();

$date1 = $ar->date("Y m d", strtotime("2022-06-01"), -2);
$date2 = $ar->date("Y m d", strtotime("2022-05-31"), 2);

var_dump($date1, $date2);

Output:

"-5504 248 29"
"-5504 248 01"

I'll incorporate your code in the PR.

Your modifications have been merged, thanks for your valuable contribution my dear friend @Socotoly