<?php
/****************************************************************************************
 * SMI (Services Maintenance Interventions) est une gestion libre de maintenance et de SAV
 *
 * Version 1.0.4
 *
 * Copyright (C) 2006-2016  Sylvain FATOME
 * This program is free software; you can redistribute it and/or modify it under the terms
 * of the GNU General Public License as published by the Free Software Foundation;
 * either version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this program
 * (in the directory docs);
 * if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA  02110-1301, USA.
 *
 * Contact : galawa@free.fr
 *
 * Web : http://smi.no-ip.org
 ****************************************************************************************/


// Vérification des tentatives de hack
$pos = strpos($_SERVER['PHP_SELF'], 'inc.php');
if ($pos !== FALSE) {
    header('Location: ../index.php');
}

/** Fonctions de gestion des dates et heures **/

/*********************/
/* Gestion des dates */
/*********************/

/*
if (!function_exists('date_parse_from_format')) {
    function date_parse_from_format($format, $date) {
        $i=0;
        $pos=0;
        $output=array();
        while ($i< strlen($format)) {
            $pat = substr($format, $i, 1);
            $i++;
            switch ($pat) {
                case 'd': //    Day of the month, 2 digits with leading zeros    01 to 31
                    $output['day'] = substr($date, $pos, 2);
                    $pos+=2;
                    break;
                case 'D': // A textual representation of a day: three letters    Mon through Sun
                    //TODO
                    break;
                case 'j': //    Day of the month without leading zeros    1 to 31
                    $output['day'] = substr($date, $pos, 2);
                    if (!is_numeric($output['day']) || ($output['day']>31)) {
                        $output['day'] = substr($date, $pos, 1);
                        $pos--;
                    }
                    $pos+=2;
                    break;
                case 'm': //    Numeric representation of a month: with leading zeros    01 through 12
                    $output['month'] = (int)substr($date, $pos, 2);
                    $pos+=2;
                    break;
                case 'n': //    Numeric representation of a month: without leading zeros    1 through 12
                    $output['month'] = substr($date, $pos, 2);
                    if (!is_numeric($output['month']) || ($output['month']>12)) {
                        $output['month'] = substr($date, $pos, 1);
                        $pos--;
                    }
                    $pos+=2;
                    break;
                case 'Y': //    A full numeric representation of a year: 4 digits    Examples: 1999 or 2003
                    $output['year'] = (int)substr($date, $pos, 4);
                    $pos+=4;
                    break;
                case 'y': //    A two digit representation of a year    Examples: 99 or 03
                    $output['year'] = (int)substr($date, $pos, 2);
                    $pos+=2;
                    break;
                case 'g': //    12-hour format of an hour without leading zeros    1 through 12
                    $output['hour'] = substr($date, $pos, 2);
                    if (!is_numeric($output['day']) || ($output['hour']>12)) {
                        $output['hour'] = substr($date, $pos, 1);
                        $pos--;
                    }
                    $pos+=2;
                    break;
                case 'G': //    24-hour format of an hour without leading zeros    0 through 23
                    $output['hour'] = substr($date, $pos, 2);
                    if (!is_numeric($output['day']) || ($output['hour']>23)) {
                        $output['hour'] = substr($date, $pos, 1);
                        $pos--;
                    }
                    $pos+=2;
                    break;
                case 'h': //    12-hour format of an hour with leading zeros    01 through 12
                    $output['hour'] = (int)substr($date, $pos, 2);
                    $pos+=2;
                    break;
                case 'H': //    24-hour format of an hour with leading zeros    00 through 23
                    $output['hour'] = (int)substr($date, $pos, 2);
                    $pos+=2;
                    break;
                case 'i': //    Minutes with leading zeros    00 to 59
                    $output['minute'] = (int)substr($date, $pos, 2);
                    $pos+=2;
                    break;
                case 's': //    Seconds: with leading zeros    00 through 59
                    $output['second'] = (int)substr($date, $pos, 2);
                    $pos+=2;
                    break;
                case 'l': // (lowercase 'L')    A full textual representation of the day of the week    Sunday through Saturday
                case 'N': //    ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0)    1 (for Monday) through 7 (for Sunday)
                case 'S': //    English ordinal suffix for the day of the month: 2 characters    st: nd: rd or th. Works well with j
                case 'w': //    Numeric representation of the day of the week    0 (for Sunday) through 6 (for Saturday)
                case 'z': //    The day of the year (starting from 0)    0 through 365
                case 'W': //    ISO-8601 week number of year: weeks starting on Monday (added in PHP 4.1.0)    Example: 42 (the 42nd week in the year)
                case 'F': //    A full textual representation of a month: such as January or March    January through December
                case 'u': //    Microseconds (added in PHP 5.2.2)    Example: 654321
                case 't': //    Number of days in the given month    28 through 31
                case 'L': //    Whether it's a leap year    1 if it is a leap year: 0 otherwise.
                case 'o': //    ISO-8601 year number. This has the same value as Y: except that if the ISO week number (W) belongs to the previous or next year: that year is used instead. (added in PHP 5.1.0)    Examples: 1999 or 2003
                case 'e': //    Timezone identifier (added in PHP 5.1.0)    Examples: UTC: GMT: Atlantic/Azores
                case 'I': // (capital i)    Whether or not the date is in daylight saving time    1 if Daylight Saving Time: 0 otherwise.
                case 'O': //    Difference to Greenwich time (GMT) in hours    Example: +0200
                case 'P': //    Difference to Greenwich time (GMT) with colon between hours and minutes (added in PHP 5.1.3)    Example: +02:00
                case 'T': //    Timezone abbreviation    Examples: EST: MDT ...
                case 'Z': //    Timezone offset in seconds. The offset for timezones west of UTC is always negative: and for those east of UTC is always positive.    -43200 through 50400
                case 'a': //    Lowercase Ante meridiem and Post meridiem    am or pm
                case 'A': //    Uppercase Ante meridiem and Post meridiem    AM or PM
                case 'B': //    Swatch Internet time    000 through 999
                case 'M': //    A short textual representation of a month: three letters    Jan through Dec
                default:
                    $pos++;
            }
        }
        return  $output;
    }
}
*/
if (!function_exists('date_parse_from_format')) {

    /**
     * @param $format
     * @param $date
     * @return array
     */
    function date_parse_from_format($format, $date)
    {
        // reverse engineer date formats
        $keys = [
            'Y' => ['year', '\d{4}'],
            'y' => ['year', '\d{2}'],
            'm' => ['month', '\d{2}'],
            'n' => ['month', '\d{1,2}'],
            'M' => ['month', '[A-Z][a-z]{3}'],
            'F' => ['month', '[A-Z][a-z]{2,8}'],
            'd' => ['day', '\d{2}'],
            'j' => ['day', '\d{1,2}'],
            'D' => ['day', '[A-Z][a-z]{2}'],
            'l' => ['day', '[A-Z][a-z]{6,9}'],
            'u' => ['hour', '\d{1,6}'],
            'h' => ['hour', '\d{2}'],
            'H' => ['hour', '\d{2}'],
            'g' => ['hour', '\d{1,2}'],
            'G' => ['hour', '\d{1,2}'],
            'i' => ['minute', '\d{2}'],
            's' => ['second', '\d{2}']
        ];

        // convert format string to regex
        $regex = '';
        $chars = str_split($format);
        foreach ($chars AS $n => $char) {
            $lastChar = isset($chars[$n - 1]) ? $chars[$n - 1] : '';
            $skipCurrent = '\\' == $lastChar;
            if (!$skipCurrent && isset($keys[$char])) {
                $regex .= '(?P<' . $keys[$char][0] . '>' . $keys[$char][1] . ')';
            } else if ('\\' == $char) {
                $regex .= $char;
            } else {
                $regex .= preg_quote($char);
            }
        }

        $dt = [];
        $dt['error_count'] = 0;
        // now try to match it
        if (preg_match('#^' . $regex . '$#', $date, $dt)) {
            foreach ($dt AS $k => $v) {
                if (is_int($k)) {
                    unset($dt[$k]);
                }
            }
            if (!checkdate($dt['month'], $dt['day'], $dt['year'])) {
                $dt['error_count'] = 1;
            }
        } else {
            $dt['error_count'] = 1;
        }
        $dt['errors'] = [];
        $dt['fraction'] = '';
        $dt['warning_count'] = 0;
        $dt['warnings'] = [];
        $dt['is_localtime'] = 0;
        $dt['zone_type'] = 0;
        $dt['zone'] = 0;
        $dt['is_dst'] = '';
        return $dt;
    }

}

/**
 * Vérifie si une date est correcte en fonction du pays choisi
 *
 * @param $dte
 *
 * @return bool
 */
function chkdate($dte)
{
    $date_ok = FALSE;

    if ($dte <> '') {
        $dte_parse = date_parse_from_format($_SESSION['date_fmt'], $dte);
        if ((int)$dte_parse['warning_count'] == 0) {
            $date_ok = checkdate($dte_parse['month'], $dte_parse['day'], $dte_parse['year']);
        }
    }

    return $date_ok;
}

/**
 * Convertion d'une date locale vers date MySQL
 *
 * @param $dte
 *
 * @return bool|string
 */
function datetomysql($dte)
{
    global
    $_SESSION;

    $date = '0000-00-00';

    if ($dte <> '') {
        $dte_parse = date_parse_from_format($_SESSION['date_fmt'], $dte);
        if ((int)$dte_parse['warning_count'] == 0) {
            $dte_utime = strtotime($dte_parse['year'] . '-' . $dte_parse['month'] . '-' . $dte_parse['day']);
            $date = date('Y-m-d', $dte_utime);
        }
    }

    return $date;
}

/**
 * Comparaison de 2 dates (vrai si $dte1 <= $dte2)
 * $tolocal : si TRUE, on utilise le format d'affichage du pays choisi
 *
 * @param $dte1
 * @param $dte2
 * @param $tolocal
 *
 * @return bool
 */
function comp_date($dte1, $dte2, $tolocal = FALSE)
{
    $fmt = 'Y-m-d';

    if ($tolocal == TRUE) {
        $fmt = $_SESSION['date_fmt'];
    }

    $result = FALSE;

    if (($dte1 <> '') AND ($dte2 <> '')) {
        $dte1_parse = date_parse_from_format($fmt, $dte1);
        if ((int)$dte1_parse['warning_count'] == 0) {
            $dte1_utime = strtotime($dte1_parse['year'] . '-' . $dte1_parse['month'] . '-' . $dte1_parse['day']);
            $dte2_parse = date_parse_from_format($fmt, $dte2);
            if ((int)$dte2_parse['warning_count'] == 0) {
                $dte2_utime = strtotime($dte2_parse['year'] . '-' . $dte2_parse['month'] . '-' . $dte2_parse['day']);
                if ($dte1_utime <= $dte2_utime) {
                    $result = TRUE;
                }
            }
        }
    }

    return $result;
}

/**
 * Formate une date Anglaise vers le format du pays choisi
 *
 * @param $dte
 *
 * @return bool|string
 */
//
function datetolocal($dte)
{
    global
    $_SESSION;

    $date = '';
    if (($dte <> '') AND ($dte <> '0000-00-00')) {
        $dte_parse = date_parse_from_format('Y-m-d', $dte);
        if ((int)$dte_parse['warning_count'] == 0) {
            $dte_utime = strtotime($dte_parse['year'] . '-' . $dte_parse['month'] . '-' . $dte_parse['day']);
            $date = date($_SESSION['date_fmt'], $dte_utime);
            chkdate($date);
        }
    }

    return $date;
}


/**
 * Différence (en secondes) entre 2 dates
 * $tolocal : si TRUE, on utilise le format d'affichage du pays choisi
 *
 * @param $dte1
 * @param $dte2
 * @param bool $tolocal
 *
 * @return bool|int
 */
function diff_date_sec($dte1, $dte2, $tolocal = FALSE)
{
    global
    $_SESSION;

    $fmt = 'Y-m-d';

    if ($tolocal == TRUE) {
        $fmt = $_SESSION['date_fmt'];
    }

    $diff = 0;

    if (($dte1 <> '') AND ($dte2 <> '')) {
        $dte1_parse = date_parse_from_format($fmt, $dte1);
        if ((int)$dte1_parse['warning_count'] == 0) {
            $dte1_utime = strtotime($dte1_parse['year'] . '-' . $dte1_parse['month'] . '-' . $dte1_parse['day']);
            $dte2_parse = date_parse_from_format($fmt, $dte2);
            if ((int)$dte2_parse['warning_count'] == 0) {
                $dte2_utime = strtotime($dte2_parse['year'] . '-' . $dte2_parse['month'] . '-' . $dte2_parse['day']);
                $diff = $dte2_utime - $dte1_utime;
            }
        }
    }

    return $diff;
}

/**
 * Différence (en jours) entre 2 dates
 * $arrondir : si TRUE on arrondi au plus proche
 * $tolocal : si TRUE, on utilise le format d'affichage du pays choisi
 *
 * @param $dte1
 * @param $dte2
 * @param bool $arrondir
 * @param bool $tolocal
 * @return bool|float|int
 */
function diff_date_jours($dte1, $dte2, $arrondir = FALSE, $tolocal = FALSE)
{
    $diff_sec = diff_date_sec($dte1, $dte2, $tolocal);

    if ($diff_sec >= 0) {
        if ($arrondir == TRUE) {
            $diff_sec = ceil($diff_sec / 86400);
        } else {
            $diff_sec /= 86400;
        }
    }

    return $diff_sec;
}

/**
 * Donne le Timestamp d'une chaîne de type "jj-mm-aaaa hh:mm:ss"
 *
 * @param $chaine
 *
 * @return int
 */
function getTimeStamp($chaine)
{
    list($date, $temps) = explode(' ', $chaine); // Séparation date et heure
    list($jour, $mois, $annee) = explode('-', $date); // Explosion date
    list($heure, $minute, $seconde) = explode(':', $temps); // Explosion heure

    return mktime($heure, $minute, $seconde, $mois, $jour, $annee);
}

/**
 * Différence (en secondes) entre 2 dates + heures (format français)
 *
 * @param $datedebut
 * @param $datefin
 *
 * @return int
 */
function diff_dateheure_sec($datedebut, $datefin)
{
    $debut = getTimeStamp($datedebut);
    $fin = getTimeStamp($datefin);
    return $fin - $debut;
}

/**
 * Différence (en secondes) entre 2 Timestamp
 *
 * @param $ts1
 * @param $ts2
 *
 * @return mixed
 */
function diff_timestamp_sec($ts1, $ts2)
{
    return $ts2 - $ts1;
}

/**
 * Vérifie si la date $dte2 est dépassée par la date $dte1
 * $tolocal : si TRUE, on utilise le format d'affichage du pays choisi
 *
 * @param $dte1
 * @param $dte2
 * @param bool $tolocal
 *
 * @return bool
 */
function echeance_depassee_date($dte1, $dte2, $tolocal = FALSE)
{
    $depasse = FALSE;

    if (diff_date_sec($dte2, $dte1, $tolocal) > 0) {
        $depasse = TRUE;
    }

    return $depasse;

}

/**
 * Ajoute un jour à une date (format anglais)
 *
 * @param $dte
 *
 * @return bool|string
 */
function ajoute_un_jour_date($dte)
{

    $tDte = explode('-', $dte);

    $DteTime = mktime(0, 0, 0, $tDte[1], $tDte[2], $tDte[0]);
    $DteTime += 86400;

    return date('Y-m-d', $DteTime);

}

/**
 * Calcule une date (format anglais) 'x' jours avant une date donnée (Anglaise)
 *
 * @param $date
 * @param $jours
 *
 * @return bool|string
 */
function nouv_date_moins_jours($date, $jours)
{
    $tDate = explode('-', $date);

    return date('Y-m-d', mktime(0, 0, 0, $tDate[1], $tDate[2] - $jours, $tDate[0]));

}

/**
 * Calcule une date (format anglais) 'x' jours après une date donnée (Anglaise)
 *
 * @param $date
 * @param $jours
 *
 * @return bool|string
 */
function nouv_date_plus_jours($date, $jours)
{
    $tDate = explode('-', $date);

    return date('Y-m-d', mktime(0, 0, 0, $tDate[1], $tDate[2] + $jours, $tDate[0]));

}

/**
 * Calcule une date (format anglais) 'x' mois avant une date donnée (Anglaise)
 *
 * @param $date
 * @param $mois
 *
 * @return bool|string
 */
function nouv_date_moins_mois($date, $mois)
{
    $tDate = explode('-', $date);

    return date('Y-m-d', mktime(0, 0, 0, $tDate[1] - $mois, $tDate[2], $tDate[0]));

}

/**
 * Calcule une date (format anglais) 'x' mois après une date donnée (Anglaise)
 *
 * @param $date
 * @param $mois
 *
 * @return bool|string
 */
function nouv_date_plus_mois($date, $mois)
{
    $tDate = explode('-', $date);

    return date('Y-m-d', mktime(0, 0, 0, $tDate[1] + $mois, $tDate[2], $tDate[0]));

}

/**
 * Calcule une date (format anglais) 'x' années avant une date donnée (Anglaise)
 *
 * @param $date
 * @param $annees
 *
 * @return bool|string
 */
function nouv_date_moins_annees($date, $annees)
{
    $tDate = explode('-', $date);

    return date('Y-m-d', mktime(0, 0, 0, $tDate[1], $tDate[2], $tDate[0] - $annees));

}

/**
 * Calcule une date (format anglais) 'x' annees après une date donnée (Anglaise)
 *
 * @param $date
 * @param $annees
 *
 * @return bool|string
 */
function nouv_date_plus_annees($date, $annees)
{
    $tDate = explode('-', $date);

    return date('Y-m-d', mktime(0, 0, 0, $tDate[1] + $annees, $tDate[2], $tDate[0]));

}

/**
 * Retourne le numéro de jour de la semaine (date anglaise)
 *
 * @param $date
 *
 * @return bool|string
 */
function njour_semaine($date)
{
    $tDate = explode('-', $date);
    return date('w', mktime(0, 0, 0, $tDate[1], $tDate[2], $tDate[0]));
}

/**
 * Retourne la date du lundi de la semaine d'une date donnée
 *
 * @param null $date
 *
 * @return bool|string
 */
function date_lundi($date = null)
{

    if (null === $date) {
        $date = date('Y-m-d');
    }
    $daynum = njour_semaine($date);
    $diff = $daynum - 1;
    return nouv_date_moins_jours($date, $diff);
}

/**
 * Retourne la date du dimanche de la semaine d'une date donnée
 *
 * @param null $date
 *
 * @return bool|string
 */
function date_dimanche($date = null)
{

    if (null === $date) {
        $date = date('Y-m-d');
    }
    $daynum = njour_semaine($date);
    return nouv_date_moins_jours($date, $daynum);

}


/**
 * Retourne le dernier jour du mois pour un mois et une année donnés
 *
 * @param $mois
 * @param $annee
 *
 * @return int
 */
function lastday_month_year($mois, $annee)
{
    $lastday = 28;
    while (checkdate($mois, $lastday, $annee)) :
        $lastday++;
    endwhile;
    --$lastday;
    return $lastday;
}

/**
 * Donne le jour du premier jour d'un mois
 *
 * @param $mois
 * @return bool|string
 */
function first_day_month($mois)
{
    return date('w', mktime(0, 0, 0, $mois, 1, date('Y')));
}

/*********************/
/* Gestion des heures */
/*********************/

/**
 * Génère un tableau des heures
 *
 * @param $from
 * @param $to
 * @param $step
 * @param bool $blank
 * @return array
 */
function give_tab_heures($from, $to, $step, $blank = TRUE)
{
    $tab_heures = [];

    if ($blank) {
        $tab_heures[''] = '';
    }
    for ($i = $from; $i <= $to; $i += $step) {
        $heure = heure_to_hhmm(sec_heure($i));
        $tab_heures[$heure] = $heure;
    }

    return $tab_heures;
}


/**
 * Génère un tableau des durées minimums
 *
 * @param $from
 * @param $to
 * @param $step
 * @param bool $blank
 * @return array
 */
function give_tab_dureemin($from, $to, $step, $blank = TRUE)
{
    $tab_dureemin = [];

    if ($blank) {
        $tab_dureemin[''] = '';
    }
    for ($i = $from; $i < $to; $i += $step) {
        $tab_dureemin[$i] = substr(sec_heure($i * 60), 0, 5);
    }

    return $tab_dureemin;
}
