0

I have a script that allows me to automatically generate slots on a calendar according to the different opening hours of my users.

Today, I would like to improve the execution of my script to make it much faster than today (it takes a few seconds to make the calendar appear).

You have to know that I have a table OPENING_TIMES which contains 7 rows (1 per day) for each user.

I tried some improvements but without success (with joins for example).

Do you have any ideas?

Thanks in advance !

$Sch_Link_User  = $_GET['psy'];
$Data_query = mysqli_query($_Db_Con, 'SELECT ID_UNIQUE, CONSULTATION_TIME, CONSULTATION_TIME_BEFORE, TIMEZONE FROM USERS WHERE PROFILE_URL LIKE "' . $Sch_Link_User . '"');
$Data       = mysqli_fetch_assoc($Data_query);
$Sch_Id_User    = $Data['ID_UNIQUE'];

$Difference = '0';

switch ($Data['CONSULTATION_TIME']) {
    case 1:
        $Sch_Time_Consultation = 30;
        break;
    case 2:
        $Sch_Time_Consultation = 45;
        break;
    case 3:
        $Sch_Time_Consultation = 60;
        break;
    default:
        $Sch_Time_Consultation = 60;
}

$Calendar = array();

$weekslots = array_map(function($dow) {return array('dow' => $dow, 'hour' => 00);}, range(0, 6));

$date = time();
$end_date = $date + (6 * 7 * 24 * 60 * 60);

$open_hours_cache = array();

while($date <= $end_date) {
    $date_dow = date('w', $date);

    foreach($weekslots as $timeslot) {
        if($date_dow == $timeslot['dow']) {
            $timeofday = $date + (3600 * $timeslot['hour']);

            for($nd = 1; $nd <= 7; $nd++) {
                if(date('N', $timeofday) == $nd) {
                    if (!isset($open_hours_cache[$nd])) {
                        $Data_Openhours_query = mysqli_query($_Db_Con, 'SELECT START_HOUR_M, END_HOUR_M, START_HOUR_A, END_HOUR_A FROM OPENING_TIMES WHERE ID_USER = "' . $Sch_Id_User . '" AND WEEKDAY = "' . $nd . '" AND CLOSED = 0');
                        $open_hours_cache[$nd] = mysqli_fetch_assoc($Data_Openhours_query);
                    }

                    $Data_Openhours = $open_hours_cache[$nd];

                    if(isset($Data_Openhours['START_HOUR_M']) && $Data_Openhours['END_HOUR_M'] == NULL && $Data_Openhours['START_HOUR_A'] == NULL && isset($Data_Openhours['END_HOUR_A'])) {
                        $shm = strtotime($Data_Openhours['START_HOUR_M'] . $Difference . ' hour');
                        $eha = strtotime($Data_Openhours['END_HOUR_A'] . $Difference . ' hour');
                        
                        $timeslots = array();
                        $interval = new DateInterval("PT{$Sch_Time_Consultation}M");
                        $timeRange = new DatePeriod(new DateTime(date('Y-m-d H:i', $shm)), $interval, new DateTime(date('Y-m-d H:i', $eha)));

                        foreach ($timeRange as $time) {
                            $timeslots[] = $time->format("H:i");
                        }

                        foreach ($timeslots as $slot) {
                            $datefinal = date('Y-m-d', $timeofday) . ' ' . $slot . ':00';
                            $timestamp = strtotime($datefinal . $Difference . ' hour');
                        
                            $Check_Slot = mysqli_query($_Db_Con, 'SELECT ID, ID_USER, STATUS FROM APPOINTMENTS WHERE ID_USER = "' . $Sch_Id_User . '" AND DATE_START = "' . $timestamp . '" AND (STATUS = 1 OR STATUS = 2 OR STATUS = 9 OR STATUS = 10) AND DATE_START > "' . $Time . '"');
                            $Data_Slot = mysqli_fetch_assoc($Check_Slot);
                            $status = isset($Data_Slot['STATUS']) && $Data_Slot['STATUS'] == 9 && $Data_Slot['ID_USER'] == $_SESSION['uid'];
                            $check_slot = mysqli_num_rows($Check_Slot) == 0;
                            $time_before = ($Time + (60 * 60 * $Data['CONSULTATION_TIME_BEFORE'])) < $timestamp;
                        
                            if ($status) {
                                $class = 'blocked';
                            } elseif ($check_slot && $time_before) {
                                $class = 'available';
                            } else {
                                $class = 'unavailable';
                            }
                        
                            $Calendar[] = array(
                                'id' => date('Y-m-d', $timeofday) . '/' . $slot,
                                'title' => $slot,
                                'class' => $class,
                                'psy' => $Sch_Id_User,
                                'start' => $timestamp . '000',
                            );
                        }
                    } else if(isset($Data_Openhours['START_HOUR_M']) && isset($Data_Openhours['END_HOUR_M']) && isset($Data_Openhours['START_HOUR_A']) && isset($Data_Openhours['END_HOUR_A'])) {
                        $shm = strtotime($Data_Openhours['START_HOUR_M'] . $Difference . ' hour');
                        $ehm = strtotime($Data_Openhours['END_HOUR_M'] . $Difference . ' hour');
                        
                        $sha = strtotime($Data_Openhours['START_HOUR_A'] . $Difference . ' hour');
                        $eha = strtotime($Data_Openhours['END_HOUR_A'] . $Difference . ' hour');
                        
                        $timeslots = array();
                        $interval = new DateInterval("PT{$Sch_Time_Consultation}M");
                        
                        $timeRange = new DatePeriod(new DateTime(date('Y-m-d H:i', $shm)), $interval, new DateTime(date('Y-m-d H:i', $ehm)));
                        foreach ($timeRange as $time) {
                            $timeslots[] = $time->format("H:i");
                        }

                        $timeRange = new DatePeriod(new DateTime(date('Y-m-d H:i', $sha)), $interval, new DateTime(date('Y-m-d H:i', $eha)));
                        foreach ($timeRange as $time) {
                            $timeslots[] = $time->format("H:i");
                        }

                        foreach ($timeslots as $slot) {
                            $datefinal = date('Y-m-d', $timeofday) . ' ' . $slot . ':00';

                            $Check_Slot = mysqli_query($_Db_Con, 'SELECT ID, ID_USER, STATUS FROM APPOINTMENTS WHERE ID_USER = "' . $Sch_Id_User . '" AND DATE_START = "' . strtotime($datefinal) . '" AND (STATUS = 1 OR STATUS = 2 OR STATUS = 9 OR STATUS = 10) AND DATE_START > "' . $Time . '"');
                            $Data_Slot = mysqli_fetch_assoc($Check_Slot);
                            
                            // * 24 le temps avant possibilité de prende rendez-vous
                            $status = isset($Data_Slot['STATUS']) && $Data_Slot['STATUS'] == 9 && $Data_Slot['ID_USER'] == $_SESSION['uid'];
                            $check_slot = mysqli_num_rows($Check_Slot) == 0;
                            $time_before = ($Time + (60 * 60 * $Data['CONSULTATION_TIME_BEFORE'])) < strtotime($datefinal . $Difference . ' hour');

                            if ($status) {
                                $class = 'blocked';
                            } elseif ($check_slot && $time_before) {
                                $class = 'available';
                            } else {
                                $class = 'unavailable';
                            }

                            $Calendar[] = array(
                                'id' => date('Y-m-d', $timeofday) . '/' . $slot,
                                'title' => $slot,
                                'class' => $class,
                                'psy' => $Sch_Id_User,
                                'start' => strtotime($datefinal . $Difference . ' hour') . '000',
                            );
                        }
                    }
                }
            }
        }
    }
    
    $date += 86400;
}

$Calendar_Data = array(
    'success'   => 1,
    'result'    => $Calendar);

echo json_encode($Calendar_Data);

So I try to have a much faster loading with joins or a cache system to limit the number of requests.

Moreover, wouldn't it be more efficient if I also put everything in one column of my user table, the schedules?

  • 3
    **Warning:** You are wide open to [SQL Injections](https://php.net/manual/en/security.database.sql-injection.php) and should use parameterized **prepared statements** instead of manually building your queries. They are provided by [PDO](https://php.net/manual/pdo.prepared-statements.php) or by [MySQLi](https://php.net/manual/mysqli.quickstart.prepared-statements.php). Never trust any kind of input! Even when your queries are executed only by trusted users, [you are still in risk of corrupting your data](http://bobby-tables.com/). [Escaping is not enough!](https://stackoverflow.com/q/32391315) – Dharman Jan 20 '23 at 14:35

0 Answers0