htmlspecialchars($image_top_no_preview) . '">
' . $premiereCategorie . '

' . htmlspecialchars($name_nearest_places) . '

' . $display_distance . '
'; } else { $display_top_places_screen .= '
' . $premiereCategorie . '

' . htmlspecialchars($name_nearest_places) . '

' . $display_distance . '
'; $display_top_places_small_screen .= '
' . $premiereCategorie . '

' . htmlspecialchars($name_nearest_places) . '

' . $display_distance . '
'; } } } $display_places_list = '
'.$display_top_places_screen.'
'.$display_top_places_large_screen.'
'.$display_top_places_small_screen.'
'; //if($c == 0) { $display_places_list .= '
Voir plus
'; } //$latLngEncrypted = encrypt_latlng($lat,$lng); //$log .= '
latLngEncrypted : '.$latLngEncrypted.'
'; if (isset($query_nearest_places) && !empty($query_nearest_places)) { $log .= '
query_nearest_places :
'.substr($query_nearest_places,0,300).'...
'; } //$log .= '
query_nearest_places :
'.$query_nearest_places.'
'; $log .= '
Google Maps ('.$lat.' - '.$lng.')
'; // Temps de chargement (fin) $endTime = microtime(true); //$loadTime = $endTime - $startTime; $loadTime = round($endTime - $startTime, 3); $log .= "
Load time: " . number_format($loadTime, 3) . " seconds
"; if($test == 1) echo '
[function.php]
'.$log.'
'; mysqli_close($c1); return $display_places_list; } // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- // DISPLAY PLACE CONTENT // ---------------------------------------------------------------------------- // Filter les "fermé définitivement" et et attention aux "fermés temporairement" function gen_place_content_new($p, $country_code) { global $c1; global $c2; global $test; $test = 0; // 1: général - 2: hours (+ test = 1 pour completerPlagesHoraires() / clean_and_order_hours()) $content = ''; $log = ''; $langue = 'fr'; $today = date('Y-m-d H:i:s'); $places_table = 'places_min_2025'; // Déterminer la table en fonction du code pays $places_table_country = 'places_' . strtolower($country_code); // Ex: places_fr, places_us // Validation des paramètres if (empty($p) || empty($country_code)) { return '
Erreur : ID de la place ou code pays manquant.
'; } $p = mysqli_real_escape_string($c1, $p); // Sécurisation de l'ID $country_code = mysqli_real_escape_string($c1, strtoupper($country_code)); // Sécurisation du code pays // Requête SQL pour récupérer les données de la table correspondante $query = "SELECT * FROM `$places_table_country` WHERE `unique_id` = '$p'"; $result = @mysqli_query($c1, $query); if (!$result || mysqli_num_rows($result) == 0) { return '
Aucune place trouvée pour cet ID et ce pays.
'; } $row_places = mysqli_fetch_assoc($result); // --- Votre code original à partir d'ici --- $Name = @$row_places['Name']; $Name = corrigerCaracteresLatin($Name); $escapedName = mysqli_real_escape_string($c1, @$row_places['Name']); $Keyword = @$row_places['Keyword']; $Full_Address = @$row_places['Full_Address']; //$Full_Address = @mb_convert_encoding($Full_Address, 'ISO-8859-1', 'UTF-8'); $Plus_Code = @$row_places['Plus_Code']; $Website = @$row_places['Website']; if ($Website == 'facebook.com') $Website = ''; if (!@preg_match("/^(http:\/\/|https:\/\/)/", $Website) && $Website != '') { $Website = "https://" . $Website; } $WebsiteDisplay = websiteDisplay($Website); $Phone = @$row_places['Phone'] ?: @$row_places['Phone_1']; $Phonelink = convertirTelephone($Phone); $Email = @$row_places['Email']; $Facebook = @$row_places['Facebook']; $Twitter = @$row_places['Twitter']; $Instagram = @$row_places['Instagram']; $Youtube = @$row_places['Youtube']; $LinkedIn = @$row_places['LinkedIn']; $Tiktok = @$row_places['Tiktok']; $Pinterest = @$row_places['Pinterest']; // Fonction pour nettoyer les valeurs (supprime 'Lat ' ou 'Lng ') function clean_coordinate($value) { if (strpos($value, 'Lat ') === 0) { return substr($value, 4); // Supprime 'Lat ' } elseif (strpos($value, 'Lng ') === 0) { return substr($value, 4); // Supprime 'Lng ' } return $value; // Retourne inchangé si pas de préfixe } // Nettoyage et traitement des variables Lat et Lng $Lat = isset($row_places['Lat']) ? round(floatval(clean_coordinate($row_places['Lat'])), 6) : (isset($row_places['Latitude']) ? round(floatval(clean_coordinate($row_places['Latitude'])), 6) : null); $Lng = isset($row_places['Lng']) ? round(floatval(clean_coordinate($row_places['Lng'])), 6) : (isset($row_places['Longitude']) ? round(floatval(clean_coordinate($row_places['Longitude'])), 6) : null); $Rating = @$row_places['Rating'] ?: @$row_places['Average_rating']; $Reviews = @$row_places['Reviews'] ?: @$row_places['Reviews_count']; $Top_Image_URL = @$row_places['Top_Image_URL'] ?: @$row_places['Image_Top']; $Sub_Title = @$row_places['Sub_Title']; $Pricing = @$row_places['Pricing'] ?: @$row_places['Price']; $Summary = @$row_places['Summary']; function nl2br_limit($text, $maxConsecutiveNewlines = 3) { if ($text === null) { return ''; } $text = nl2br($text); $pattern = '/(\s*){' . ($maxConsecutiveNewlines + 1) . ',}/'; $replacement = str_repeat('
', $maxConsecutiveNewlines) . "\n"; return preg_replace($pattern, $replacement, $text); } function nl2br_single($text) { if ($text === null) { return ''; } $text = nl2br($text); return preg_replace('/(\s*){2,}/', '
', $text); } $query_IA = "SELECT * FROM `gemini2` WHERE `unique_id` LIKE '$p'"; $result_IA = @mysqli_query($c2, $query_IA); $row_IA = mysqli_fetch_array($result_IA); $Summary_IA = @$row_IA['Summary_IA']; $Summary_IA = nl2br_single($Summary_IA); $Description_IA = @$row_IA['Description_IA']; $Description_IA = nl2br_limit($Description_IA); $Amenities = @$row_places['Amenities']; $hours = isset($row_places['Hours']) ? $row_places['Hours'] : ''; if (is_string($hours) && trim($hours) !== '') { $hours_encoded = hours_encodeRawHoursToHex($hours); } else { $hours_encoded = ''; } $External_Urls = @$row_places['External_Urls']; $Photo_Tags = @$row_places['Photo_Tags']; $Services = @$row_places['Services']; $Located_in = @$row_places['Located_in']; $Attributes = @$row_places['Attributes']; $URL = @$row_places['URL'] ?: @$row_places['GMB_URL']; $URL = str_replace('hl=en', 'hl=' . $langue, $URL ?? ''); preg_match('/place_id:([^\/]+)/', $URL, $matches); if (isset($matches[1])) { $Place_id = $matches[1]; $URL = 'https://www.google.com/maps/search/?api=1&query=' . urlencode($Full_Address) . '&query_place_id=' . $Place_id; } else { $Place_id = ''; } $Category = @$row_places['Category']; $Category_all = @$row_places['Category_all']; $id_cat_all = @$row_places['id_cat_all']; $id_cat_all_array = explode(',', $id_cat_all); if (!empty($id_cat_all_array) && $id_cat_all_array[0] == 3660) { $deuxieme_valeur = count($id_cat_all_array) > 1 ? $id_cat_all_array[1] : 3660; $id_cat = $deuxieme_valeur; } else { $id_cat = reset($id_cat_all_array); } $nomsCategories = array(); $identifiantSpecial = 3660; $idsArray = explode(',', $id_cat_all); foreach ($idsArray as $id) { $nomCategorie = obtenirTexte($id, $langue); if ($id == $identifiantSpecial) { $nomsCategories[] = $nomCategorie; } else { array_unshift($nomsCategories, $nomCategorie); } } $unique_id = @$row_places['unique_id']; $parent_cat = obtenirParentcat($id_cat, $langue); if ($test == 1) { $log .= '
Category_all : ' . $Category_all . '
id_cat_all : ' . $id_cat_all . '
id_cat : ' . $id_cat . '
parent_cat : ' . $parent_cat . '
'; } $Category_all = idCatAllToTexte($id_cat_all, 'fr'); if (strpos($Category_all, ',') !== false) { $categoriesArray = explode(',', $Category_all); $premiereCategorie = reset($categoriesArray); $premiereCategorie = mb_strtoupper(mb_substr($premiereCategorie, 0, 1)) . mb_substr($premiereCategorie, 1); $premiereCategorie = @mb_convert_encoding($premiereCategorie, 'ISO-8859-1', 'UTF-8'); } else { $premiereCategorie = $Category_all; } $Category_all_links = idCatAllToTexteAndLinks($id_cat_all, 'fr', $Lat, $Lng); if (strpos($Category_all_links, ',') !== false) { $categoriesArray = explode(',', $Category_all_links); $premiereCategorie_link = reset($categoriesArray); $premiereCategorie_link = mb_strtoupper(mb_substr($premiereCategorie_link, 0, 1)) . mb_substr($premiereCategorie_link, 1); $premiereCategorie_link = @mb_convert_encoding($premiereCategorie_link, 'ISO-8859-1', 'UTF-8'); } else { $premiereCategorie_link = $Category_all_links; } $image_top = 'cache/places/top_images_webp/' . unique_id_to_imagepath($unique_id) . '.webp'; //image_top = unique_id_to_imagepath($unique_id).'.webp'; $no_preview = 'images/no-preview/svg/' . no_preview($parent_cat ?? $c ?? null); $exists = is_file($image_top) || is_file('../../' . $image_top); if(!$exists) { //if(file_exists($image_top) === false) { //echo 'cache/places/top_images_webp/'.$image_top; if(!@$c) $image_top = no_preview($parent_cat); else $image_top = no_preview($c); $image_top = 'images/no-preview/svg/'.$image_top; } /* if (file_exists('../../' . $image_top) === false) { if (file_exists($image_top) === false) { if (!@$c) $image_top = no_preview($parent_cat); else $image_top = no_preview($c); $image_top = 'images/no-preview/svg/' . $image_top; } } */ $date = @$row_places['date']; $date_maj = @$row_places['date_maj']; function displayHours($hours_encoded, $timeNow) { $displayHours = ''; if ($hours_encoded != '') { $displayHours .= '
' . hours_isOpenNowMinimalist($hours_encoded['hex']) . ' ' . hours_delayOpenClose($hours_encoded['hex']) . '
'; $displayHours .= '
' . hours_hoursTextualDisplay($hours_encoded['hex'], date('Y-m-d H:i:s')) . '
'; $isOpenNow = hours_displayOpeningHours($hours_encoded['hex'], null); $displayHours .= $isOpenNow; } return $displayHours; } $timeNow = date('Y-m-d H:i:s', time()); if ($hours_encoded != '') $displayHours = displayHours($hours_encoded, $timeNow); else $displayHours = ''; $display_en_savoir_plus = ''; if ($Description_IA != '') { $display_en_savoir_plus = ''; $display_en_savoir_plus .= '
' . $Description_IA . '
'; $display_en_savoir_plus .= '
'; } $display_suggestions_similaires = ' '; $log .= $query_suggestions_similaires; $display_suggestions_proximite = ' '; $log .= $query_suggestions; // Places > "En savoir plus..." // --------------------------------------------------------------------------------------------------------------------------------------------- $display_en_savoir_plus = ''; if($Description_IA != '') { $display_en_savoir_plus = ''; $display_en_savoir_plus .= '
'.$Description_IA.'
'; $display_en_savoir_plus .= ''; } // Display GetYourGuide // --------------------------------------------------------------------------------------------------- // Manual //$widget_getyourguide = '
Powered by GetYourGuide
'; // Auto //$widget_getyourguide = '
'; // Manuel $widget_getyourguide = '
Powered by GetYourGuide
'; $display_getyourguide = ''; $place_home_title = latlng_to_location($Lat,$Lng); if($place_home_title == '') $place_home_title = 'Accueil'; $content .= '
'.$place_home_title.''; $nameDisplay = $Name; $content .= '

'.$nameDisplay.' '.meteo($Lat,$Lng,2,$c1).'

Photo de '.$Name.' '; //echo 'Category_all_links:'.$Category_all_links; if($Category_all != '') { if(strlen($Category_all_links) >= 150) $Category_all_links_display = cutSentence($Category_all_links,150); else $Category_all_links_display = $Category_all_links; $content .= '
' . $Category_all_links . '
'; } else $content .= '
' . $premiereCategorie_link . '
'; $content .= '
Crédit photo : @Google Places API
'; if($displayHours != '') $content .= '
'.$displayHours.'
'; $content .= '
'; if ($Full_Address != '') { $content .= '
'; $content .= ''; $content .= '

Adresse : '.$Full_Address.'

'; $content .= '
'; } if ($Phone != '') { $content .= '

Téléphone Des frais supplémentaires peuvent s\'appliquer en fonction de votre opérateur téléphonique et de l\'origine de votre appel. : '.$Phone.'

'; } if($Website != '') $content .= '

Site Internet : '.$WebsiteDisplay.'

'; if($Facebook != '') $Facebook .= '

Facebook : '.$Facebook.'

'; if($Twitter != '') $Twitter .= '

Twitter : '.$Twitter.'

'; if($Instagram != '') $Instagram .= '

Instagram : '.$Instagram.'

'; if($Youtube != '') $Youtube .= '

Youtube : '.$Youtube.'

'; if($LinkedIn != '') $LinkedIn .= '

LinkedIn : '.$LinkedIn.'

'; if($Tiktok != '') $Tiktok .= '

Tiktok : '.$Tiktok.'

'; if($Pinterest != '') $Pinterest .= '

Pinterest : '.$Pinterest.'

'; //if($Category != '') $content .= '

Categorie : '.$cat_name_fr.'

'; //if($Category_all != '') $content .= '

Categories : '.$Category_all.'

'; // A FAIRE : s ou pas s si unique //if($Summary_IA != '') $content .= '

L\'essentiel :
'.$Summary_IA.'

'; //if($Summary_IA != '') $content .= '
'; if($Summary_IA != '') { $content .= ''; $content .= '
'.$Summary_IA.'
'; //$content .= '
'; } $content .= '
'; $content .= ''; $content .= ''; $content .= '
'; $log .= '
Lat : '.$Lat.'
Lng : '.$Lng.'
image_top : '.$image_top.'
'; if($Email != '') $log .= '
Email : '.$Email.'
'; if($Facebook != '') $log .= '
Email : '.$Facebook.'
'; if($Twitter != '') $log .= '
Email : '.$Twitter.'
'; if($Instagram != '') $log .= '
Email : '.$Instagram.'
'; if($Youtube != '') $log .= '
Email : '.$Youtube.'
'; // Test : random place // ----------------------------------------------- if($test >= 1) { $query_random_place = "SELECT unique_id FROM $places_table ORDER BY RAND() LIMIT 0,1"; $result_random_place = mysqli_query($c1,$query_random_place); $row_random_place = mysqli_fetch_array($result_random_place); $random_place_id = $row_random_place['unique_id']; $random_place_country_code = $row_random_place['unique_id']; $log .= ''; } $log .= '
Rating : '.$Rating.'
Sub_Title : '.$Sub_Title.'
Pricing : '.$Pricing.'
Amenities : '.$Amenities.'
Summary : '.$Summary.'
Top_Image_URL : '.$Top_Image_URL.'/div>
Services : '.$Services.'
Located_in : '.$Located_in.'
Attributes : '.$Attributes.'
unique_id : '.$unique_id.'
id_cat : '.$id_cat.'
parent_cat : '.$parent_cat.'
classement : '.@$classement.'
source : '.@$source.'
'.$Name.'
Ouvert actuellementFerme à 20:00 (dans ~1:15)
'; $content .= '
'; if($display_en_savoir_plus != '') $content .= $display_en_savoir_plus; // Lieux similaires if($display_suggestions_similaires != '') $content .= $display_suggestions_similaires; // Lieux proches if($display_suggestions_proximite != '') $content .= $display_suggestions_proximite; //if($display_getyourguide != '') $content .= $display_getyourguide; $content .= '
'; // Display Test if($test == 1 or $test == 2) { //$content .= '
'.$log.'
'; } $content .= ""; //mysqli_close($c1); return $content; } // gen_place_content_new():fin // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- // DISPLAY PLACE CONTENT // ---------------------------------------------------------------------------- // Filter les "fermé définitivement" et et attention aux "fermés temporairement" function gen_place_content($p) { global $c1; global $c2; global $test; $test = 0; // 1: général - 2: hours (+ test = 1 pour completerPlagesHoraires() / clean_and_order_hours() ) $content = ''; $log = ''; $langue = 'fr'; $today = date('Y-m-d H:i:s'); $places_table = 'places_min_2025'; // places - places_online - places_min //$p = '9a44060ef8f9af490d702b0bebc2e56c5d2774887b29e123a109c1d93b362ad9'; // Tour Eiffel //$p = '898f73ee3cc7acb1c6b221a3a0a22c5214522fd51e7e456400f07943a506e836'; // Casa Pairal if(isset($_GET['p'])) { $p = $_GET['p']; $p = htmlentities($p); } //$p = 'cd1340676787d0efb6a68a2818670c47'; // Table d'orientation Cabestany // Place > content : json // ----------------------------------------------------------------- $json_path = 'cache/places/content/'.unique_id_to_jsonpath($p); if(@file_exists($json_path) === true && filesize($json_path)>0) { $log .= '
[JSON : file_exists :'.file_exists($json_path === true).' - filesize:'.filesize($json_path).']
'; $json_content = file_get_contents($json_path); $row_places = json_decode($json_content, true); $Name = @$row_places['Name']; $Name = @$row_places['Name']; //$Name = @mb_convert_encoding($Name, 'ISO-8859-1', 'UTF-8'); $Name = corrigerCaracteresLatin($Name); $escapedName = mysqli_real_escape_string($c1, @$row_places['Name']); $Keyword = @$row_places['Keyword']; $Full_Address = @$row_places['Full_Address']; $Full_Address = @mb_convert_encoding($Full_Address, 'ISO-8859-1', 'UTF-8'); $Plus_Code = @$row_places['Plus_Code']; $Website = @$row_places['Website']; if($Website == 'facebook.com') $Website = ''; if (!@preg_match("/^(http:\/\/|https:\/\/)/", $Website) && $Website != '') { $Website = "https://" . $Website; } $WebsiteDisplay = websiteDisplay($Website); $Phone = @$row_places['Phone']; $Phonelink = convertirTelephone($Phone); $Email = @$row_places['Email']; $Facebook = @$row_places['Facebook']; $Twitter = @$row_places['Twitter']; $Instagram = @$row_places['Instagram']; $Youtube = @$row_places['Youtube']; $LinkedIn = @$row_places['LinkedIn']; $Tiktok = @$row_places['Tiktok']; $Pinterest = @$row_places['Pinterest']; $Lat = $row_places['Lat'] ?? $row_places['Latitude'] ?? null; $Lng = $row_places['Lng'] ?? $row_places['Longitude'] ?? null; $Lat = $Lat !== null ? round((float)$Lat, 6) : null; $Lng = $Lng !== null ? round((float)$Lng, 6) : null; /*$Lat = isset($row_places['Lat']) ? round(floatval($row_places['Lat']), 6) : null; $Lng = isset($row_places['Lng']) ? round(floatval($row_places['Lng']), 6) : null;*/ $Rating = @$row_places['Rating']; $Reviews = @$row_places['Reviews']; $Top_Image_URL = @$row_places['Top_Image_URL']; $Sub_Title = @$row_places['Sub_Title']; //$Sub_Title = @mb_convert_encoding($Sub_Title, 'ISO-8859-1', 'UTF-8'); $Pricing = @$row_places['Pricing']; //$Pricing = @mb_convert_encoding($Pricing, 'ISO-8859-1', 'UTF-8'); /* $Description = @$row_places['Description']; $Description = nl2br($Description); $Description = @mb_convert_encoding($Description, 'ISO-8859-1', 'UTF-8'); */ $Summary = @$row_places['Summary']; //$Summary = @mb_convert_encoding($Summary, 'ISO-8859-1', 'UTF-8'); // -------------------------------------------------------------------------------------------------------------------------- // SQL Description IA + Summary_IA // -------------------------------------------------------------------------------------------------------------------------- // Limite le nombre de retours à la ligne consécutifs à $maxConsecutiveNewlines function nl2br_limit($text, $maxConsecutiveNewlines = 3) { if ($text === null) { return ''; } $text = nl2br($text); $pattern = '/(\s*){' . ($maxConsecutiveNewlines + 1) . ',}/'; $replacement = str_repeat('
', $maxConsecutiveNewlines) . "\n"; return preg_replace($pattern, $replacement, $text); } // Supprime les doubles retours à la ligne ou plus function nl2br_single($text) { if ($text === null) { return ''; } $text = nl2br($text); return preg_replace('/(\s*){2,}/', '
', $text); } $query_IA = "SELECT * FROM `gemini2` WHERE `unique_id` LIKE '$p'"; $result_IA = @mysqli_query($c2,$query_IA); $row_IA = mysqli_fetch_array($result_IA); $Summary_IA = @$row_IA['Summary_IA']; $Summary_IA = nl2br_single($Summary_IA); $Description_IA = @$row_IA['Description_IA']; $Description_IA = nl2br_limit($Description_IA); // -------------------------------------------------------------------------------------------------------------------------- $Amenities = @$row_places['Amenities']; $hours = @$row_places['Hours']; if($hours != '') $hours_encoded = hours_encodeRawHoursToHex($hours); else $hours_encoded = ''; //$hours = @mb_convert_encoding($Hours, 'ISO-8859-1', 'UTF-8'); $External_Urls = @$row_places['External_Urls']; $Photo_Tags = @$row_places['Photo_Tags']; //$Photo_Tags = @mb_convert_encoding($Photo_Tags, 'ISO-8859-1', 'UTF-8'); $Services = @$row_places['Services']; //$Services = @mb_convert_encoding($Services, 'ISO-8859-1', 'UTF-8'); $Located_in = @$row_places['Located_in']; //$Located_in = @mb_convert_encoding($Located_in, 'ISO-8859-1', 'UTF-8'); $Attributes = @$row_places['Attributes']; $URL = @$row_places['URL']; $URL = str_replace('hl=en', 'hl=' . $langue, $URL ?? ''); // Google Maps link V2 - Extract place_id (ie : https:\/\/www.google.com\/maps\/place\/?q=place_id:ChIJlRPzKwbdfkcR-IJwGf5BJcU) /*preg_match('/place_id:([^\/]+)/', $URL, $matches); $Place_id = $matches[1]; $URL = 'https://www.google.com/maps/search/?api=1&query='.urlencode($Full_Address).'&query_place_id='.$Place_id; */ preg_match('/place_id:([^\/]+)/', $URL, $matches); // Vérifier si $matches contient la clé 1 if (isset($matches[1])) { $Place_id = $matches[1]; // Utiliser $Place_id dans votre URL $URL = 'https://www.google.com/maps/search/?api=1&query='.urlencode($Full_Address).'&query_place_id='.$Place_id; } else $Place_id = ''; $Category = @$row_places['Category']; $Category_all = @$row_places['Category_all']; $id_cat_all = @$row_places['id_cat_all']; $id_cat_all_array = explode(',', $id_cat_all); if (!empty($id_cat_all_array) && $id_cat_all_array[0] == 3660) { // Si le tableau a plus d'un élément, afficher la deuxième valeur, sinon, laisser 3660 $deuxieme_valeur = count($id_cat_all_array) > 1 ? $id_cat_all_array[1] : 3660; $id_cat = $deuxieme_valeur; } else $id_cat = reset($id_cat_all_array);; /*echo 'next(id_cat_array) : '.next($id_cat_array); if($id_cat == 3660 && next($id_cat_array) != '') $id_cat = next($id_cat_array); // On prend le suivant */ // Initialiser un tableau pour stocker les noms de catégories $nomsCategories = array(); // Identifiant spécial à mettre en dernier (trop généraliste) $identifiantSpecial = 3660; $idsArray = explode(',', $id_cat_all); $nomsCategories = array(); foreach ($idsArray as $id) { $nomCategorie = obtenirTexte($id, $langue); if ($id == $identifiantSpecial) { // Mettre cet élément en dernier dans le tableau $nomsCategories[] = $nomCategorie; } else { // Mettre cet élément avant l'identifiant spécial dans le tableau array_unshift($nomsCategories, $nomCategorie); } } $unique_id = @$row_places['unique_id']; $parent_cat = obtenirParentcat($id_cat, $langue); // A FAIRE : utiliser fichier json des cat_fr /* $query_cat = "SELECT * FROM categories_google_maps WHERE id_cat=$id_cat"; $result_cat = @mysqli_query($c1,$query_cat); $row_cat = @mysqli_fetch_array($result_cat); $parent_cat = $row_cat['parent_cat']; $cat_name = $row_cat['parent_cat']; $cat_name_fr = $row_cat['cat_name_fr']; $cat_name_fr = ucfirst($cat_name_fr); if($cat_name_fr == "") { if($parent_cat == 1) $cat_name_fr = 'Site naturel'; elseif($parent_cat == 2) $cat_name_fr = 'Monument'; elseif($parent_cat == 3) $cat_name_fr = 'Musée'; elseif($parent_cat == 4) $cat_name_fr = 'Activités & Loisirs'; elseif($parent_cat == 6) $cat_name_fr = 'Sport'; else $cat_name_fr = ''; } */ if($test == 1) $log .= '
Category_all : '.$Category_all.'
id_cat_all : '.$id_cat_all.'
id_cat : '.$id_cat.'
parent_cat : '.$parent_cat.'
'; $Category_all = idCatAllToTexte($id_cat_all,'fr'); // Vérifier si $Category_all contient des virgules if (strpos($Category_all, ',') !== false) { $categoriesArray = explode(',', $Category_all); $premiereCategorie = reset($categoriesArray); $premiereCategorie = mb_strtoupper( mb_substr( $premiereCategorie, 0, 1 )) . mb_substr( $premiereCategorie, 1 ); $premiereCategorie = @mb_convert_encoding($premiereCategorie, 'ISO-8859-1', 'UTF-8'); } else { $premiereCategorie = $Category_all; } // Pour Places : link(s) sur image $Category_all_links = idCatAllToTexteAndLinks($id_cat_all,'fr',$Lat,$Lng); if (strpos($Category_all_links, ',') !== false) { $categoriesArray = explode(',', $Category_all_links); $premiereCategorie_link = reset($categoriesArray); $premiereCategorie_link = mb_strtoupper( mb_substr( $premiereCategorie_link, 0, 1 )) . mb_substr( $premiereCategorie_link, 1 ); $premiereCategorie_link = @mb_convert_encoding($premiereCategorie_link, 'ISO-8859-1', 'UTF-8'); } else { $premiereCategorie_link = $Category_all_links; } // A FAIRE : display si catégorie vide ? $classement = @$row_places['classement']; $image_top = 'cache/places/top_images_webp/'.unique_id_to_imagepath($unique_id).'.webp'; $exists = is_file($image_top) || is_file('../../' . $image_top); if(!$exists) { //if(file_exists('../../'.$image_top) === false) { if(!@$c) $image_top = no_preview($parent_cat); else $image_top = no_preview($c); $image_top = 'images/no-preview/svg/'.$image_top; } /* if(file_exists('../../'.$image_top) === false) { if(file_exists($image_top) === false) { if(!@$c) $image_top = no_preview($parent_cat); else $image_top = no_preview($c); $image_top = 'images/no-preview/svg/'.$image_top; } } */ $source = @$row_places['source']; // 1 = robots : botsol / Leadsniper - 2 = datatourisme $date = @$row_places['date']; $date_maj = @$row_places['date_maj']; function displayHours($hours_encoded,$timeNow) { $displayHours = ''; //$displayHours .= '
'; if($hours_encoded != '') { /* echo 'hours_encoded:*'.$hours_encoded.'*'; print_r($hours_encoded); */ // A FAIRE : delete deprecated function hours_nextOpeningDayAndTime $displayHours .= '
'.hours_isOpenNowMinimalist($hours_encoded['hex']).' '.hours_delayOpenClose($hours_encoded['hex']).'
'; // TEST. Bug a faire : eea64b12fa9dbeed8ec927afadddfce2 //$displayHours .= '
'.hours_isOpenNowMinimalist($hours_encoded['hex']).' '.hours_delayOpenClose($hours_encoded['hex'],'2025-03-09 1:15:00').'
'; $displayHours .= '
'.hours_hoursTextualDisplay($hours_encoded['hex'], date('Y-m-d H:i:s')).'
'; $isOpenNow = hours_displayOpeningHours($hours_encoded['hex'], null); $displayHours .= $isOpenNow; } /* //$displayHours .= '
'.isOpen($openingHoursExample, $timeNow).' '.delayOpenClose($openingHoursExample, $timeNow).'
'; $displayHours .= '
'. hoursTextualDisplay($openingHoursExample, $timeNow).'
'; $isOpenNow = displayOpeningHours($openingHoursExample, $timeNow); $displayHours .= $isOpenNow; */ return $displayHours; } $timeNow = date('Y-m-d H:i:s', time()); if($hours_encoded != '') $displayHours = displayHours($hours_encoded,$timeNow); else $displayHours = ''; //echo '
[JSON : file_exists:'.file_exists($json_path === true).' - filesize:'.filesize($json_path).' - '.$json_path.' don\'t exists.]
'; // A FAIRE : fichier n'existe pas / alerte ?. } // Places > "En savoir plus..." // --------------------------------------------------------------------------------------------------------------------------------------------- $display_en_savoir_plus = ''; if($Description_IA != '') { $display_en_savoir_plus = ''; $display_en_savoir_plus .= '
'.$Description_IA.'
'; $display_en_savoir_plus .= '
'; } // Places > Suggestions > Lieux similaires dans les environs // --------------------------------------------------------------------------------------------------------------------------------------------- $timeNow = date('Y-m-d H:i:s', time()); //$randomStart = mt_rand(0, 20); $display_suggestions_similaires = ' '; $log .= $query_suggestions_similaires; // Places > Suggestions > à proximité // --------------------------------------------------------------------------------------------------------------------------------------------- $timeNow = date('Y-m-d H:i:s', time()); //$randomStart = mt_rand(0, 20); $display_suggestions_proximite = ' '; $log .= $query_suggestions; // Places > "En savoir plus..." // --------------------------------------------------------------------------------------------------------------------------------------------- $display_en_savoir_plus = ''; if($Description_IA != '') { $display_en_savoir_plus = ''; $display_en_savoir_plus .= '
'.$Description_IA.'
'; $display_en_savoir_plus .= ''; } // Display GetYourGuide // --------------------------------------------------------------------------------------------------- // Manual //$widget_getyourguide = '
Powered by GetYourGuide
'; // Auto //$widget_getyourguide = '
'; // Manuel $widget_getyourguide = '
Powered by GetYourGuide
'; $display_getyourguide = ''; $place_home_title = latlng_to_location($Lat,$Lng); if($place_home_title == '') $place_home_title = 'Accueil'; $content .= '
'.$place_home_title.''; $nameDisplay = $Name; $content .= '

'.$nameDisplay.' '.meteo($Lat,$Lng,2,$c1).'

Photo de '.$Name.' '; if($Category_all != '') { if(strlen($Category_all_links) >= 150) $Category_all_links_display = cutSentence($Category_all_links,150); else $Category_all_links_display = $Category_all_links; $content .= '
' . $Category_all_links . '
'; } else $content .= '
' . $premiereCategorie_link . '
'; $content .= '
Crédit photo : @Google Places API
'; if($displayHours != '') $content .= '
'.$displayHours.'
'; $content .= '
'; if ($Full_Address != '') { $content .= '
'; $content .= ''; $content .= '

Adresse : '.$Full_Address.'

'; $content .= '
'; } if ($Phone != '') { $content .= '

Téléphone Des frais supplémentaires peuvent s\'appliquer en fonction de votre opérateur téléphonique et de l\'origine de votre appel. : '.$Phone.'

'; } if($Website != '') $content .= '

Site Internet : '.$WebsiteDisplay.'

'; if($Facebook != '') $Facebook .= '

Facebook : '.$Facebook.'

'; if($Twitter != '') $Twitter .= '

Twitter : '.$Twitter.'

'; if($Instagram != '') $Instagram .= '

Instagram : '.$Instagram.'

'; if($Youtube != '') $Youtube .= '

Youtube : '.$Youtube.'

'; if($LinkedIn != '') $LinkedIn .= '

LinkedIn : '.$LinkedIn.'

'; if($Tiktok != '') $Tiktok .= '

Tiktok : '.$Tiktok.'

'; if($Pinterest != '') $Pinterest .= '

Pinterest : '.$Pinterest.'

'; //if($Category != '') $content .= '

Categorie : '.$cat_name_fr.'

'; //if($Category_all != '') $content .= '

Categories : '.$Category_all.'

'; // A FAIRE : s ou pas s si unique //if($Summary_IA != '') $content .= '

L\'essentiel :
'.$Summary_IA.'

'; //if($Summary_IA != '') $content .= '
'; if($Summary_IA != '') { $content .= ''; $content .= '
'.$Summary_IA.'
'; //$content .= '
'; } $content .= '
'; $content .= ''; $content .= ''; $content .= '
'; $log .= '
Lat : '.$Lat.'
Lng : '.$Lng.'
image_top : '.$image_top.'
'; if($Email != '') $log .= '
Email : '.$Email.'
'; if($Facebook != '') $log .= '
Email : '.$Facebook.'
'; if($Twitter != '') $log .= '
Email : '.$Twitter.'
'; if($Instagram != '') $log .= '
Email : '.$Instagram.'
'; if($Youtube != '') $log .= '
Email : '.$Youtube.'
'; // Test : random place // ----------------------------------------------- if($test >= 1) { $query_random_place = "SELECT unique_id FROM $places_table ORDER BY RAND() LIMIT 0,1"; $result_random_place = mysqli_query($c1,$query_random_place); $row_random_place = mysqli_fetch_array($result_random_place); $random_place_id = $row_random_place['unique_id']; $random_place_country_code = $row_random_place['country_code']; $log .= ''; } $log .= '
Rating : '.$Rating.'
Sub_Title : '.$Sub_Title.'
Pricing : '.$Pricing.'
Amenities : '.$Amenities.'
Summary : '.$Summary.'
Top_Image_URL : '.$Top_Image_URL.'/div>
Services : '.$Services.'
Located_in : '.$Located_in.'
Attributes : '.$Attributes.'
unique_id : '.$unique_id.'
id_cat : '.$id_cat.'
parent_cat : '.$parent_cat.'
classement : '.$classement.'
source : '.$source.'
'.$Name.'
Ouvert actuellementFerme à 20:00 (dans ~1:15)
'; $content .= '
'; if($display_en_savoir_plus != '') $content .= $display_en_savoir_plus; // Lieux similaires if($display_suggestions_similaires != '') $content .= $display_suggestions_similaires; // Lieux proches if($display_suggestions_proximite != '') $content .= $display_suggestions_proximite; //if($display_getyourguide != '') $content .= $display_getyourguide; $content .= '
'; // Display Test if($test == 1 or $test == 2) { //$content .= '
'.$log.'
'; } $content .= ""; mysqli_close($c1); return $content; } // gen_place_content():fin // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- function corrigerCaracteresLatin($string) { $replace_map = [ 'À' => 'À', 'Â' => 'Â', 'Ã' => 'Ã', 'Ä' => 'Ä', 'Ã…' => 'Å', 'Ç' => 'Ç', 'È' => 'È', 'É' => 'É', 'Ê' => 'Ê', 'Ë' => 'Ë', 'ÃŒ' => 'Ì', 'ÃŽ' => 'Î', 'Ñ' => 'Ñ', 'Ã’' => 'Ò', 'Ó' => 'Ó', 'Ô' => 'Ô', 'Ö' => 'Ö', 'Ø' => 'Ø', 'Ù' => 'Ù', 'Ú' => 'Ú', 'Û' => 'Û', 'Ü' => 'Ü', 'ß' => 'ß', 'à ' => 'à', 'á' => 'á', 'â' => 'â', 'ã' => 'ã', 'ä' => 'ä', 'Ã¥' => 'å', 'ç' => 'ç', 'è' => 'è', 'é' => 'é', 'ê' => 'ê', 'ë' => 'ë', 'ì' => 'ì', 'î' => 'î', 'ï' => 'ï', 'ñ' => 'ñ', 'ò' => 'ò', 'ó' => 'ó', 'ô' => 'ô', 'õ' => 'õ', 'ø' => 'ø', 'ù' => 'ù', 'ú' => 'ú', 'û' => 'û', 'ü' => 'ü', 'ý' => 'ý', 'ÿ' => 'ÿ', '’' => '\'', '®' => '®', 'à' => 'à', 'ó' => 'ó', ]; return strtr($string, $replace_map); } // Genere une IP aléatoire en Europe // https://chatgpt.com/c/6830a43c-f758-8002-af85-23431f136048 // V2 : https://chatgpt.com/c/6856c160-e3bc-8002-b56e-0d869016f65a?model=o3 // ============================================================================================== function generateRandomEuropeCoordinates() { $places = [ // ========================= FRANCE (villages & petites villes) ========================= [43.9475, 1.8850, 'Cordes-sur-Ciel', 'FR'], [44.8000, 1.6167, 'Rocamadour', 'FR'], [43.7417, 4.7956, 'Les Baux-de-Provence', 'FR'], [44.1231, 4.8369, 'Uzès', 'FR'], [43.6806, -0.9308, 'Saint-Jean-Pied-de-Port', 'FR'], [43.3833, -1.5667, 'Espelette', 'FR'], [43.8997, 6.6283, 'Moustiers-Sainte-Marie', 'FR'], [48.4468, -2.0409, 'Dinan', 'FR'], [44.0546, 4.8314, 'Vaison-la-Romaine', 'FR'], [48.7346, -3.4596, 'Tréguier', 'FR'], [46.4939, 4.2892, 'Cluny', 'FR'], [43.8367, 5.7867, 'Forcalquier', 'FR'], [43.3525, 3.2181, 'Pézenas', 'FR'], [48.2842, 7.4474, 'Riquewihr', 'FR'], [48.1919, 7.3064, 'Eguisheim', 'FR'], [48.1366, 7.2678, 'Kaysersberg', 'FR'], [46.1964, 6.7003, 'Yvoire', 'FR'], [45.2631, 5.9461, 'Pont-en-Royans', 'FR'], [43.9333, 3.5833, 'La Couvertoirade', 'FR'], [44.1000, 6.6333, 'Colmars-les-Alpes', 'FR'], [45.4091, 6.6340, 'Bonneval-sur-Arc', 'FR'], [44.8000, 6.8667, 'Saint-Véran', 'FR'], [43.9328, 2.1467, 'Monestiés', 'FR'], [44.3275, 3.5936, 'La Malène', 'FR'], [48.0000, 0.2000, 'Sainte-Suzanne', 'FR'], [45.0000, 0.2000, 'Aubeterre-sur-Dronne', 'FR'], [43.5667, 5.0833, 'Lourmarin', 'FR'], [42.5260, 3.0830, 'Collioure', 'FR'], [49.4194, 0.2329, 'Honfleur', 'FR'], [49.7061, 0.2042, 'Étretat', 'FR'], [43.9122, 5.2000, 'Gordes', 'FR'], [43.9030, 5.2930, 'Roussillon', 'FR'], [44.4660, 1.6670, 'Saint-Cirq-Lapopie', 'FR'], [44.6000, 2.4010, 'Conques', 'FR'], [43.2150, 5.5370, 'Cassis', 'FR'], [48.0800, 7.3550, 'Colmar', 'FR'], [49.2760, -0.7010, 'Bayeux', 'FR'], [44.8890, 1.2160, 'Sarlat-la-Canéda', 'FR'], [44.8950, -0.1550, 'Saint-Émilion', 'FR'], [45.0600, 1.6580, 'Collonges-la-Rouge', 'FR'], // ========================= BELGIQUE (communes de charme) ========================= [50.2667, 4.8833, 'Durbuy', 'BE'], [50.2531, 5.3292, 'La Roche-en-Ardenne', 'BE'], [50.4533, 5.9733, 'Malmedy', 'BE'], [50.0056, 4.6075, 'Bouillon', 'BE'], [50.3211, 4.6614, 'Dinant', 'BE'], [50.4308, 5.6842, 'Spa', 'BE'], [50.1500, 5.7167, 'Marche-en-Famenne', 'BE'], [51.2530, 3.2810, 'Damme', 'BE'], [51.2720, 3.0330, 'De Haan', 'BE'], [49.5270, 5.4930, 'Torgny', 'BE'], [50.1250, 5.1860, 'Han-sur-Lesse', 'BE'], [50.3490, 4.9510, 'Crupet', 'BE'], [50.1670, 5.2220, 'Rochefort', 'BE'], [51.0543, 3.7174, 'Bruges', 'BE'], // ========================= ITALIE (borghi / petites villes) ========================= [43.4670, 11.0430, 'San Gimignano', 'IT'], [40.6280, 14.4840, 'Positano', 'IT'], [40.6490, 14.6120, 'Ravello', 'IT'], [40.3560, 18.1760, 'Otranto', 'IT'], [40.9960, 17.2290, 'Alberobello', 'IT'], [40.9950, 17.2270, 'Locorotondo', 'IT'], [40.9956, 17.2170, 'Martina Franca', 'IT'], [40.9950, 17.2230, 'Polignano a Mare', 'IT'], [37.8510, 15.2850, 'Taormina', 'IT'], [38.0390, 12.5880, 'Erice', 'IT'], [45.8010, 8.4210, 'Orta San Giulio', 'IT'], [42.6270, 12.0930, 'Civita di Bagnoregio', 'IT'], [44.1430, 9.7060, 'Portovenere', 'IT'], [44.1350, 9.6830, 'Vernazza', 'IT'], [44.1070, 9.7270, 'Manarola', 'IT'], [39.4230, 9.6500, 'Bosa', 'IT'], // ========================= ROYAUME-UNI (villages & petites villes) ========================= [51.4910, -2.2280, 'Castle Combe', 'GB'], [51.7610, -1.8330, 'Bibury', 'GB'], [51.8850, -1.7010, 'Bourton-on-the-Water', 'GB'], [50.2110, -5.4820, 'St Ives (Cornwall)', 'GB'], [50.5770, -4.8310, 'Port Isaac', 'GB'], [50.3310, -4.5180, 'Polperro', 'GB'], [50.2860, -3.7780, 'Salcombe', 'GB'], [50.8840, -0.5430, 'Arundel', 'GB'], [50.5240, -3.7650, 'Dartmouth', 'GB'], [57.4120, -5.4730, 'Plockton', 'GB'], [56.6220, -6.0700, 'Tobermory (Mull)', 'GB'], [50.9510, 0.7340, 'Rye', 'GB'], [54.4870, -0.6140, 'Whitby', 'GB'], [52.2410, 0.7950, 'Lavenham', 'GB'], [57.4110, -6.1970, 'Portree (Isle of Skye)', 'GB'], // ========================= SUISSE (communes de charme) ========================= [46.5839, 7.0825, 'Gruyères', 'CH'], [46.0207, 7.7491, 'Zermatt', 'CH'], [46.6067, 7.9227, 'Wengen', 'CH'], [46.5589, 7.8920, 'Mürren', 'CH'], [46.1550, 8.7720, 'Ascona', 'CH'], [47.6550, 8.8580, 'Stein am Rhein', 'CH'], [47.3300, 9.4090, 'Appenzell', 'CH'], [46.3400, 9.5390, 'Soglio', 'CH'], [46.7750, 10.1500, 'Guarda', 'CH'], [47.3730, 7.1520, 'Saint-Ursanne', 'CH'], [45.9850, 8.9140, 'Morcote', 'CH'], // ========================= ESPAGNE (pueblos / petites villes) ========================= [36.7400, -5.1660, 'Ronda', 'ES'], [40.0730, -1.9990, 'Albarracín', 'ES'], [43.5630, -6.1450, 'Cudillero', 'ES'], [36.7920, -3.8970, 'Frigiliana', 'ES'], [42.2880, 3.2770, 'Cadaqués', 'ES'], [43.3890, -4.1060, 'Santillana del Mar', 'ES'], [42.1980, 2.7020, 'Besalú', 'ES'], [36.8400, -5.3920, 'Zahara de la Sierra', 'ES'], [36.8660, -5.1830, 'Setenil de las Bodegas', 'ES'], [39.7630, -0.0570, 'Peñíscola', 'ES'], [39.7050, 2.4240, 'Valldemossa (Majorque)', 'ES'], // ========================= AUTRICHE ========================= [47.5622, 13.6493, 'Hallstatt', 'AT'], [48.3965, 15.5193, 'Dürnstein (Wachau)', 'AT'], [47.3950, 11.9440, 'Alpbach', 'AT'], [47.7400, 13.4490, 'St. Wolfgang im Salzkammergut', 'AT'], [47.0460, 12.8440, 'Heiligenblut', 'AT'], [47.4030, 12.9080, 'Maria Alm', 'AT'], [47.1130, 13.1340, 'Bad Gastein', 'AT'], [47.3230, 12.7980, 'Zell am See', 'AT'], [47.5830, 12.1620, 'Kufstein', 'AT'], [47.4290, 13.5200, 'Filzmoos', 'AT'], // ========================= BÉNIN ========================= [6.3631, 2.0850, 'Ouidah', 'BJ'], [6.4710, 2.4220, 'Ganvié (Sô-Ava)', 'BJ'], [6.2880, 1.8220, 'Grand-Popo', 'BJ'], [7.1829, 1.9912, 'Abomey', 'BJ'], [10.3040, 1.3780, 'Natitingou', 'BJ'], [10.6200, 1.2670, 'Tanguiéta', 'BJ'], [7.3630, 2.6030, 'Kétou', 'BJ'], [6.6650, 2.1510, 'Allada', 'BJ'], // ========================= ALLEMAGNE ========================= [49.3780, 10.1860, 'Rothenburg ob der Tauber', 'DE'], [51.7870, 10.8130, 'Wernigerode', 'DE'], [51.7880, 11.1480, 'Quedlinburg', 'DE'], [50.2300, 6.2400, 'Monschau', 'DE'], [50.1460, 7.1670, 'Cochem', 'DE'], [50.0600, 7.7660, 'Bacharach', 'DE'], [47.6980, 9.2700, 'Meersburg', 'DE'], [47.4750, 10.9630, 'Füssen', 'DE'], [47.4420, 11.2630, 'Mittenwald', 'DE'], [47.5450, 9.6830, 'Lindau', 'DE'], [51.1510, 14.9880, 'Görlitz', 'DE'], [48.5210, 9.0550, 'Tübingen', 'DE'], // ========================= ÉGYPTE (villes/communes touristiques de charme) ========================= [28.5000, 34.5170, 'Dahab', 'EG'], [29.2040, 25.5190, 'Siwa (Oasis)', 'EG'], [25.0670, 34.8870, 'Marsa Alam', 'EG'], [27.3940, 33.6780, 'El Gouna', 'EG'], [29.0360, 34.6640, 'Nuweiba', 'EG'], [26.1060, 34.2770, 'Al-Quseir', 'EG'], [22.3370, 31.6250, 'Abu Simbel', 'EG'], [24.0880, 32.8990, 'Assouan', 'EG'], [25.6870, 32.6390, 'Louxor', 'EG'], [29.4650, 30.5040, 'Tunis (Fayoum)', 'EG'], // ========================= CROATIE ========================= [45.0812, 13.6400, 'Rovinj', 'HR'], [43.5170, 16.2516, 'Trogir', 'HR'], [43.1729, 16.4428, 'Hvar (ville)', 'HR'], [42.9612, 17.1354, 'Korčula (ville)', 'HR'], [42.5800, 18.2170, 'Cavtat', 'HR'], [45.3340, 13.8250, 'Motovun', 'HR'], [45.3310, 13.7440, 'Grožnjan', 'HR'], [43.7330, 15.8950, 'Šibenik', 'HR'], [42.8400, 17.7000, 'Ston', 'HR'], [43.5860, 15.9260, 'Primošten', 'HR'], // ========================= IRLANDE ========================= [51.7070, -8.5300, 'Kinsale', 'IE'], [52.1400, -10.2710, 'Dingle', 'IE'], [51.8830, -9.5830, 'Kenmare', 'IE'], [52.5620, -8.7950, 'Adare', 'IE'], [53.8000, -9.5170, 'Westport', 'IE'], [51.8490, -8.2940, 'Cobh', 'IE'], [53.0150, -9.3770, 'Doolin', 'IE'], [53.5420, -9.2840, 'Cong', 'IE'], [52.0590, -9.5060, 'Killarney', 'IE'], [52.6540, -7.2440, 'Kilkenny', 'IE'], // ========================= ISLANDE ========================= [63.4190, -19.0060, 'Vík í Mýrdal', 'IS'], [65.2640, -14.0100, 'Seyðisfjörður', 'IS'], [66.0440, -17.3380, 'Húsavík', 'IS'], [65.0750, -22.7330, 'Stykkishólmur', 'IS'], [66.1510, -18.9100, 'Siglufjörður', 'IS'], [64.9240, -23.2630, 'Grundarfjörður', 'IS'], [64.2530, -15.2120, 'Höfn', 'IS'], [64.0010, -21.1900, 'Hveragerði', 'IS'], // ========================= MAROC ========================= [35.1714, -5.2697, 'Chefchaouen', 'MA'], [35.4650, -6.0350, 'Asilah', 'MA'], [31.5085, -9.7595, 'Essaouira', 'MA'], [34.0540, -5.5240, 'Moulay Idriss Zerhoun', 'MA'], [33.5330, -5.1100, 'Ifrane', 'MA'], [30.4720, -8.8760, 'Tafraoute', 'MA'], [30.4700, -9.6000, 'Tiznit', 'MA'], [28.0000, -10.0000, 'Merzouga', 'MA'], [35.5710, -5.3720, 'Tétouan', 'MA'], [30.9189, -6.8934, 'Ouarzazate (Aït Ben Haddou)', 'MA'], // ========================= MONACO (quartiers/secteurs) ========================= [43.7314, 7.4204, 'Monaco-Ville', 'MC'], [43.7396, 7.4276, 'Monte-Carlo', 'MC'], [43.7360, 7.4200, 'La Condamine', 'MC'], [43.7310, 7.4150, 'Fontvieille', 'MC'], [43.7491, 7.4353, 'Larvotto', 'MC'], // ========================= MADAGASCAR ========================= [-13.4040, 48.2660, 'Andoany (Nosy Be)', 'MG'], [-20.2830, 44.3170, 'Morondava', 'MG'], [-21.8320, 46.9360, 'Ambalavao', 'MG'], [-20.5200, 47.2460, 'Ambositra', 'MG'], [-19.8650, 47.0330, 'Antsirabe', 'MG'], [-16.9820, 49.8500, 'Ambodifotatra (Sainte-Marie)', 'MG'], [-23.1330, 43.6160, 'Ifaty', 'MG'], [-25.0330, 46.9830, 'Tolagnaro (Fort-Dauphin)', 'MG'], // ========================= NIGÉRIA (villes/towns à intérêt culturel/nature) ========================= [6.4150, 2.8920, 'Badagry', 'NG'], [7.1120, 5.1100, 'Idanre', 'NG'], [7.7710, 4.5560, 'Osogbo', 'NG'], [6.6670, 9.1670, 'Obudu', 'NG'], [5.3900, 7.9300, 'Arochukwu', 'NG'], [7.5850, 5.0030, 'Ikogosi', 'NG'], [7.5800, 4.8170, 'Erin-Ijesha', 'NG'], [6.8180, 3.9170, 'Ijebu-Ode', 'NG'], // ========================= NORVÈGE ========================= [67.9330, 13.0890, 'Reine (Lofoten)', 'NO'], [68.1540, 14.2100, 'Henningsvær (Lofoten)', 'NO'], [60.9380, 6.5780, 'Undredal', 'NO'], [62.1015, 7.2058, 'Geiranger', 'NO'], [62.5680, 7.6880, 'Åndalsnes', 'NO'], [58.9860, 6.1900, 'Preikestolen (Jørpeland)', 'NO'], [60.8610, 7.1130, 'Flåm', 'NO'], [62.5740, 11.3840, 'Røros', 'NO'], [57.4110, 7.3440, 'Skudeneshavn', 'NO'], // ========================= PORTUGAL ========================= [39.3600, -9.1570, 'Óbidos', 'PT'], [38.7890, -9.3900, 'Sintra', 'PT'], [37.1270, -7.6480, 'Tavira', 'PT'], [38.4440, -7.3810, 'Monsaraz', 'PT'], [39.3940, -7.3760, 'Marvão', 'PT'], [38.9650, -9.4180, 'Ericeira', 'PT'], [39.6030, -9.0700, 'Nazaré', 'PT'], [40.0380, -7.1140, 'Monsanto (Idanha-a-Nova)', 'PT'], [40.3360, -7.2000, 'Sortelha', 'PT'], [39.4180, -7.4530, 'Castelo de Vide', 'PT'], [41.7670, -8.5830, 'Ponte de Lima', 'PT'], [41.2720, -8.0840, 'Amarante', 'PT'], // ========================= SUÈDE ========================= [57.5980, 11.2830, 'Fjällbacka', 'SE'], [55.4290, 13.8200, 'Ystad', 'SE'], [59.6170, 17.7170, 'Sigtuna', 'SE'], [57.8850, 11.5830, 'Marstrand', 'SE'], [57.6348, 18.2948, 'Visby (Gotland)', 'SE'], [58.8960, 17.5520, 'Trosa', 'SE'], [58.4500, 14.8910, 'Vadstena', 'SE'], [60.3330, 18.4330, 'Öregrund', 'SE'], [57.6670, 14.9670, 'Eksjö', 'SE'], [58.3000, 14.2830, 'Hjo', 'SE'], // ========================= TURQUIE ========================= [41.2500, 32.6900, 'Safranbolu', 'TR'], [37.9400, 27.4350, 'Şirince', 'TR'], [40.6530, 35.8330, 'Amasya', 'TR'], [38.2860, 26.3760, 'Alaçatı', 'TR'], [36.2010, 29.6370, 'Kaş', 'TR'], [37.0510, 28.3230, 'Akyaka', 'TR'], [39.8330, 26.0670, 'Bozcaada', 'TR'], [39.3250, 26.6410, 'Cunda (Ayvalık)', 'TR'], [37.9810, 38.7400, 'Mont Nemrut (Kahta)', 'TR'], [37.9210, 29.1187, 'Pamukkale (Denizli)', 'TR'], [38.6431, 34.8352, 'Göreme (Cappadoce)', 'TR'] ]; $random = $places[array_rand($places)]; return [ 'latitude' => $random[0], 'longitude' => $random[1], 'name' => $random[2], 'country_code' => $random[3] ]; } /* //------------------------------------------------------------------------- // 1) Choix des coordonnées de départ //------------------------------------------------------------------------- //$ip = '92.161.169.68'; // TEST Perpignan //$ip = '109.236.62.174'; // TEST Belgique //$ip = '45.11.80.5'; // TEST Italie //$ip = '109.236.63.10'; // TEST Belgique /* ---------------------------------------------------------------- // DEPRECATED – IP to location $ip = $_SERVER['REMOTE_ADDR']; $location = get_location_from_ip($ip); $lat = $location['latitude']; $lng = $location['longitude']; $bounding_distance = 0.5; ---------------------------------------------------------------- */ // DISPLAY HOME > QUELQUES IDEES // https://chatgpt.com/c/6830a43c-f758-8002-af85-23431f136048 // Gen listes villes taille moyennes populaires dans chaque pays : https://chatgpt.com/c/6856c160-e3bc-8002-b56e-0d869016f65a // ============================================================================================== /** * Génère la section « Quelques idées » de la page d'accueil. * • Titre dynamique – « Des lieux inspirants » ou « Des lieux inspirants : Perpignan (FR) » lorsqu’un lieu par défaut est utilisé. * • Bounding distance : 0 .5 km quand on tire un lieu par défaut, 0.2 km sinon. * • Lazy‑loading natif, sans accès disque : on tente l’image ; si elle n’existe pas le navigateur bascule sur loader17.gif grâce à onerror. * * Les blocs commentés (tests IP, méthode IP‑to‑location dépréciée, etc.) sont conservés pour mémoire. */ function gen_home_quelques_idees($lat, $lng) { global $c1; $places_table = 'places_min_2025'; $lat = 0; $lng = 0; $test = 0; // mode debug $location_label = ''; // affiché dans le titre si défini //-------------------------------------------------------------------- // 1) Choix des coordonnées de départ //-------------------------------------------------------------------- //$ip = '92.161.169.68'; // TEST Perpignan //$ip = '109.236.62.174'; // TEST Belgique //$ip = '45.11.80.5'; // TEST Italie //$ip = '109.236.63.10'; // TEST Belgique if ($lat == 0 && $lng == 0) { // → Pas de géoloc : on choisit un lieu touristique européen aléatoire $tmp = generateRandomEuropeCoordinates(); $lat = $tmp['latitude']; $lng = $tmp['longitude']; $location_label = $tmp['name'] . ' (' . $tmp['country_code'] . ')'; // ← ajouté $bounding_distance = 0.5; // 0.5 km pour cette toute première recherche } else { // Coords déjà fournies $bounding_distance = 0.2; } // Troncature simple (pas d’arrondi) $lat = floor($lat * 10000) / 10000; $lng = floor($lng * 10000) / 10000; $bd_lat = $bounding_distance; $bd_lng = $bounding_distance * cos(deg2rad($lat)); //-------------------------------------------------------------------- // 2) Générateur de requête SQL paramétrable //-------------------------------------------------------------------- $generate_query = function ($lat, $lng, $bd_lat, $bd_lng, $places_table) { return "SELECT p.unique_id, p.Name, p.truncated_lat, p.truncated_lng, p.Reviews, p.Country_Code FROM $places_table p JOIN categories_google_maps c ON FIND_IN_SET(c.id_cat, p.id_cat_all) WHERE p.truncated_lat BETWEEN ($lat - $bd_lat) AND ($lat + $bd_lat) AND p.truncated_lng BETWEEN ($lng - $bd_lng) AND ($lng + $bd_lng) AND p.Reviews > 1 AND c.yutugo_cat IN (3,4) AND c.id_cat <> 3661 GROUP BY p.unique_id ORDER BY p.Reviews DESC LIMIT 16;"; }; //-------------------------------------------------------------------- // 3) Première tentative //-------------------------------------------------------------------- $sql = $generate_query($lat, $lng, $bd_lat, $bd_lng, $places_table); $result = $c1->query($sql); //-------------------------------------------------------------------- // 4) Repli si aucun résultat //-------------------------------------------------------------------- if (!$result || $result->num_rows === 0) { $tmp = generateRandomEuropeCoordinates(); $lat = $tmp['latitude']; $lng = $tmp['longitude']; $location_label = $tmp['name'] . ' (' . $tmp['country_code'] . ')'; $bounding_distance = 0.5; // idem 0.5 km $bd_lat = $bounding_distance; $bd_lng = $bounding_distance * cos(deg2rad($lat)); $sql = $generate_query($lat, $lng, $bd_lat, $bd_lng, $places_table); $result = $c1->query($sql); } //-------------------------------------------------------------------- // 5) Construction du HTML //-------------------------------------------------------------------- $output_html = ''; if ($result && $result->num_rows > 0) { $output_html .= '
'; $output_html .= '

Des lieux inspirants' . ($location_label ? ' : ' . htmlspecialchars(preg_replace_callback('/\(([A-Z]{2})\)/', function($m){return '(' . iso2_to_country_fr($m[1]) . ')';}, $location_label)) . '' : '') . '

'; //$output_html .= '

Des lieux inspirants' . ($location_label ? ' : ' . htmlspecialchars($location_label) . '' : '') . '

'; $output_html .= '
'; $seen_lats = $seen_lngs = []; $count = 0; while ($row = $result->fetch_assoc()) { // — Éviter doublons sur 4 décimales — $lat_key = number_format(floor($row['truncated_lat'] * 10000) / 10000, 4, '.', ''); $lng_key = number_format(floor($row['truncated_lng'] * 10000) / 10000, 4, '.', ''); if (isset($seen_lats[$lat_key]) || isset($seen_lngs[$lng_key])) continue; $seen_lats[$lat_key] = $seen_lngs[$lng_key] = true; // — Chemin image (aucune vérif disque) — $img = 'cache/places/top_images_webp/' . unique_id_to_imagepath($row['unique_id']) . '.webp'; // — Nom formaté — $Name = ajusterMajuscules(mb_strtoupper(mb_substr($row['Name'],0,1)) . mb_substr($row['Name'],1)); $uid = $row['unique_id']; $country_code = $row['Country_Code']; // — Bloc HTML avec IMG lazy et onerror fallback — $output_html .= ''; if (++$count >= 12) break; // 12 vignettes max } $output_html .= '
'; // wrappers fermants } if ($output_html === '') $output_html = '

..

'; if ($result) $result->free(); echo $output_html; exit; } function iso2_to_country_fr($code) { static $countries = [ 'AF'=>'Afghanistan','ZA'=>'Afrique du Sud','AL'=>'Albanie','DZ'=>'Algérie','DE'=>'Allemagne', 'AD'=>'Andorre','AO'=>'Angola','AI'=>'Anguilla','AQ'=>'Antarctique','AG'=>'Antigua-et-Barbuda', 'SA'=>'Arabie saoudite','AR'=>'Argentine','AM'=>'Arménie','AW'=>'Aruba','AU'=>'Australie', 'AT'=>'Autriche','AZ'=>'Azerbaïdjan','BS'=>'Bahamas','BH'=>'Bahreïn','BD'=>'Bangladesh', 'BB'=>'Barbade','BE'=>'Belgique','BZ'=>'Belize','BJ'=>'Bénin','BM'=>'Bermudes','BT'=>'Bhoutan', 'BY'=>'Biélorussie','MM'=>'Birmanie','BO'=>'Bolivie','BA'=>'Bosnie-Herzégovine','BW'=>'Botswana', 'BR'=>'Brésil','BN'=>'Brunei','BG'=>'Bulgarie','BF'=>'Burkina Faso','BI'=>'Burundi', 'KH'=>'Cambodge','CM'=>'Cameroun','CA'=>'Canada','CV'=>'Cap-Vert','CL'=>'Chili','CN'=>'Chine', 'CY'=>'Chypre','CO'=>'Colombie','KM'=>'Comores','CG'=>'Congo','CD'=>'Congo (RDC)', 'KP'=>'Corée du Nord','KR'=>'Corée du Sud','CR'=>'Costa Rica','CI'=>'Côte d’Ivoire','HR'=>'Croatie', 'CU'=>'Cuba','DK'=>'Danemark','DJ'=>'Djibouti','DM'=>'Dominique','EG'=>'Égypte','AE'=>'Émirats arabes unis', 'EC'=>'Équateur','ER'=>'Érythrée','ES'=>'Espagne','EE'=>'Estonie','US'=>'États-Unis','ET'=>'Éthiopie', 'FJ'=>'Fidji','FI'=>'Finlande','FR'=>'France','GA'=>'Gabon','GM'=>'Gambie','GE'=>'Géorgie', 'GH'=>'Ghana','GI'=>'Gibraltar','GR'=>'Grèce','GD'=>'Grenade','GL'=>'Groenland','GP'=>'Guadeloupe', 'GU'=>'Guam','GT'=>'Guatemala','GN'=>'Guinée','GQ'=>'Guinée équatoriale','GW'=>'Guinée-Bissau', 'GY'=>'Guyana','GF'=>'Guyane','HT'=>'Haïti','HN'=>'Honduras','HU'=>'Hongrie','IN'=>'Inde', 'ID'=>'Indonésie','IQ'=>'Irak','IR'=>'Iran','IE'=>'Irlande','IS'=>'Islande','IL'=>'Israël','IT'=>'Italie', 'JM'=>'Jamaïque','JP'=>'Japon','JO'=>'Jordanie','KZ'=>'Kazakhstan','KE'=>'Kenya','KG'=>'Kirghizistan', 'KI'=>'Kiribati','KW'=>'Koweït','LA'=>'Laos','LS'=>'Lesotho','LV'=>'Lettonie','LB'=>'Liban', 'LR'=>'Liberia','LY'=>'Libye','LI'=>'Liechtenstein','LT'=>'Lituanie','LU'=>'Luxembourg', 'MK'=>'Macédoine du Nord','MG'=>'Madagascar','MY'=>'Malaisie','MW'=>'Malawi','MV'=>'Maldives', 'ML'=>'Mali','MT'=>'Malte','MA'=>'Maroc','MQ'=>'Martinique','MU'=>'Maurice','MR'=>'Mauritanie', 'MX'=>'Mexique','MD'=>'Moldavie','MC'=>'Monaco','MN'=>'Mongolie','ME'=>'Monténégro','MZ'=>'Mozambique', 'NA'=>'Namibie','NR'=>'Nauru','NP'=>'Népal','NI'=>'Nicaragua','NE'=>'Niger','NG'=>'Nigeria', 'NO'=>'Norvège','NZ'=>'Nouvelle-Zélande','OM'=>'Oman','UG'=>'Ouganda','UZ'=>'Ouzbékistan', 'PK'=>'Pakistan','PA'=>'Panama','PG'=>'Papouasie-Nouvelle-Guinée','PY'=>'Paraguay','NL'=>'Pays-Bas', 'PE'=>'Pérou','PH'=>'Philippines','PL'=>'Pologne','PF'=>'Polynésie française','PT'=>'Portugal', 'QA'=>'Qatar','CF'=>'République centrafricaine','CZ'=>'République tchèque','DO'=>'République dominicaine', 'RO'=>'Roumanie','GB'=>'Royaume-Uni','RU'=>'Russie','RW'=>'Rwanda','KN'=>'Saint-Christophe-et-Niévès', 'LC'=>'Sainte-Lucie','SM'=>'Saint-Marin','VC'=>'Saint-Vincent-et-les-Grenadines','SV'=>'Salvador', 'WS'=>'Samoa','ST'=>'Sao Tomé-et-Principe','SN'=>'Sénégal','RS'=>'Serbie','SC'=>'Seychelles', 'SL'=>'Sierra Leone','SG'=>'Singapour','SK'=>'Slovaquie','SI'=>'Slovénie','SO'=>'Somalie', 'SD'=>'Soudan','LK'=>'Sri Lanka','SE'=>'Suède','CH'=>'Suisse','SR'=>'Suriname','SY'=>'Syrie', 'TJ'=>'Tadjikistan','TW'=>'Taïwan','TZ'=>'Tanzanie','TD'=>'Tchad','TH'=>'Thaïlande','TG'=>'Togo', 'TT'=>'Trinité-et-Tobago','TN'=>'Tunisie','TM'=>'Turkménistan','TR'=>'Turquie','UA'=>'Ukraine', 'UY'=>'Uruguay','VU'=>'Vanuatu','VE'=>'Venezuela','VN'=>'Viêt Nam','YE'=>'Yémen','ZM'=>'Zambie','ZW'=>'Zimbabwe' ]; return $countries[strtoupper($code)] ?? $code; } /* function gen_home_quelques_idees($lat, $lng) { global $c1; $test = 0; //$ip = '92.161.169.68'; // TEST Perpignan //$ip = '109.236.62.174'; // TEST Belgique //$ip = '45.11.80.5'; // TEST Italie //$ip = '109.236.63.10'; // TEST Belgique // Si lat et lng sont 0, utiliser la localisation par IP if ($lat == 0 && $lng == 0) { $ip = $_SERVER['REMOTE_ADDR']; // IP en production $location = get_location_from_ip($ip); // Initialisation des variables $lat = $location['latitude']; $lng = $location['longitude']; $bounding_distance = 0.5; } else { $bounding_distance = 0.2; } function truncateToFourDecimals($number) { return floor($number * 10000) / 10000; } $lat = truncateToFourDecimals($lat); $lng = truncateToFourDecimals($lng); $bounding_distance_lat = $bounding_distance; $bounding_distance_lng = $bounding_distance * cos(deg2rad($lat)); // Fonction pour générer la requête SQL function generate_query($lat, $lng, $bounding_distance_lat, $bounding_distance_lng) { return "SELECT p.unique_id, p.Name, p.truncated_lat, p.truncated_lng, SUBSTRING_INDEX(p.id_cat_all, ',', 1) AS category_id, p.Reviews FROM places_min p JOIN categories_google_maps c ON FIND_IN_SET(c.id_cat, p.id_cat_all) WHERE p.truncated_lat BETWEEN ($lat - $bounding_distance_lat) AND ($lat + $bounding_distance_lat) AND p.truncated_lng BETWEEN ($lng - $bounding_distance_lng) AND ($lng + $bounding_distance_lng) AND p.`Reviews` > 0 AND c.yutugo_cat IN (3,4) AND c.id_cat != 3661 GROUP BY p.unique_id ORDER BY RAND() DESC LIMIT 16;"; // ORDER BY p.Reviews DESC // WHERE yutugo_cat >= 1 } /* function generate_query($lat, $lng, $bounding_distance_lat, $bounding_distance_lng) { return " SELECT unique_id, Name, truncated_lat, truncated_lng, SUBSTRING_INDEX(id_cat_all, ',', 1) AS category_id, `Reviews` * 1 AS `Reviews` FROM `places_min` WHERE ( `truncated_lat` BETWEEN ($lat - $bounding_distance_lat) AND ($lat + $bounding_distance_lat) AND `truncated_lng` BETWEEN ($lng - $bounding_distance_lng) AND ($lng + $bounding_distance_lng) AND SUBSTRING_INDEX(id_cat_all, ',', 1) IN ( SELECT id_cat FROM categories_google_maps WHERE yutugo_cat = 3 OR yutugo_cat = 4 ) ) GROUP BY `Name` ORDER BY `Reviews` DESC, RAND() LIMIT 16;"; // WHERE yutugo_cat >= 1 } */ /* // Exécuter la requête avec les coordonnées actuelles $query_nearest_places = generate_query($lat, $lng, $bounding_distance_lat, $bounding_distance_lng); $result = $c1->query($query_nearest_places); // Si aucun résultat n'est trouvé, utiliser une IP par défaut (Paris) if (!$result || $result->num_rows === 0) { // Coordonnées de Paris $lat = 48.8566; // Latitude de Paris $lng = 2.3522; // Longitude de Paris $bounding_distance_lat = $bounding_distance; $bounding_distance_lng = $bounding_distance * cos(deg2rad($lat)); // Requête pour Paris $query_nearest_places = generate_query($lat, $lng, $bounding_distance_lat, $bounding_distance_lng); $result = $c1->query($query_nearest_places); } // Vérification des résultats $output_html = ''; if ($result && $result->num_rows > 0) { $output_html = '

Quelques idées...

'; $count = 0; // Compteur pour limiter à 12 résultats avec photos while ($row = $result->fetch_assoc()) { $lat_quelques_idees = $row['truncated_lat']; $lng_quelques_idees = $row['truncated_lng']; // Troncature à 4 décimales sans arrondi $lat_key = number_format(floor((float)$lat_quelques_idees * 10000) / 10000, 4, '.', ''); $lng_key = number_format(floor((float)$lng_quelques_idees * 10000) / 10000, 4, '.', ''); // Vérifie si déjà vu (lat OU lng) if (isset($seen_lats[$lat_key]) || isset($seen_lngs[$lng_key])) { if($test == 1) echo "
Ignoré (doublon lat/lng) : $lat_key / $lng_key
"; continue; } // Stocker les valeurs tronquées comme déjà vues $seen_lats[$lat_key] = true; $seen_lngs[$lng_key] = true; // Récupération de l'image $image_top_nearest_places = unique_id_to_imagepath($row['unique_id']); $image_top_nearest_places = 'cache/places/top_images_webp/' . $image_top_nearest_places . '.webp'; // Vérification si l'image existe if (!file_exists('../../' . $image_top_nearest_places) && !file_exists($image_top_nearest_places)) { continue; // Ignorer les lieux sans image } $Name = $row['Name']; //$Name = @mb_convert_encoding($Name, 'ISO-8859-1', 'UTF-8'); //$Name = mb_convert_encoding($Name, 'UTF-8'); $Name = mb_strtoupper(mb_substr($Name, 0, 1)) . mb_substr($Name, 1); $Name = ajusterMajuscules($Name); $unique_id = @$row['unique_id']; // Générer le HTML pour chaque lieu $output_html .= ''; //
$count++; // Incrémenter le compteur // Arrêter après avoir trouvé 12 lieux avec photos if ($count >= 12) { break; } } $output_html .= '
'; } // Si aucun lieu valide n'a été trouvé if ($output_html === '') { $output_html = '

..

'; // Message personnalisé } // Libérer les résultats if ($result) $result->free(); // Afficher le HTML echo $output_html; exit; } */ // ============================================================================================== // DISPLAY HOME > Que faire, quoi faire : afficher les catégories les plus populaires en Reviews // https://chatgpt.com/c/684535f9-f0a8-8002-bf51-822133a53d9a // ============================================================================================== function gen_home_cat_suggestions($parent_cat = 0, $nb_suggestions = 10) { $parent_cat = intval($parent_cat); $json_path = "cache/places/content/cat_popular/cat_{$parent_cat}.json"; if (!file_exists($json_path)) return ''; $json_content = file_get_contents($json_path); $categories = json_decode($json_content, true); if (!$categories || !is_array($categories)) return ''; /*

*/ $output = ''; return $output; } // ============================================================================================== // Test page header : 200 / 404 / 500 ... // ============================================================================================== function get_http_response_code($url) { $headers = get_headers($url); return substr($headers[0], 9, 3); } // Generate unique_id i.e. (64 car.) : 57e1722b207c3ffe13c8cf0d0301ab042b8cc912f99fcb0cc2749ac2b451266a // ============================================================================================== function str_rand(int $length = 64){ // 64 = 32 $length = ($length < 4) ? 4 : $length; return bin2hex(random_bytes(($length-($length%2))/2)); } // Image > symétrie horizontale // ============================================================================================== function image_flip(&$filename) { $test = 0; // Activez avec $test = 1 pour débogage // Vérification si le fichier existe if (!file_exists($filename)) { if ($test == 1) echo '
Fichier introuvable : ' . $filename . '
'; return false; } // Vérification du format de l'image $image_info = @getimagesize($filename); if ($image_info === false) { if ($test == 1) echo '
[' . $filename . ' - ' . (filesize($filename) / 1024) . ' Kb] Impossible de lire les informations de l\'image.
'; return false; } if ($test == 1) { echo '
MIME infos : ' . $image_info['mime'] . ' | Dimensions : ' . $image_info[0] . 'x' . $image_info[1] . ' | Fichier : ' . $filename . '
'; } if ($image_info['mime'] === 'image/jpeg') { $source = @imagecreatefromjpeg($filename); } elseif ($image_info['mime'] === 'image/png') { if ($test == 1) echo '
Le fichier n\'est pas un JPEG valide mais un PNG
'; $image = imagecreatefrompng($filename); if ($image === false) { if ($test == 1) echo '
Erreur lors de la création de l\'image PNG.
'; return false; } imagejpeg($image, $filename, 90); imagedestroy($image); $source = imagecreatefromjpeg($filename); } elseif ($image_info['mime'] === 'image/gif') { if ($test == 1) echo '
Le fichier n\'est pas un JPEG valide mais un GIF
'; $image = imagecreatefromgif($filename); if ($image === false) { if ($test == 1) echo '
Erreur lors de la création de l\'image GIF.
'; return false; } imagejpeg($image, $filename, 90); imagedestroy($image); $source = imagecreatefromjpeg($filename); } elseif ($image_info['mime'] === 'image/webp') { if ($test == 1) echo '
Le fichier n\'est pas un JPEG valide mais un WebP
'; $image = imagecreatefromwebp($filename); if ($image === false) { if ($test == 1) echo '
Erreur lors de la création de l\'image WebP.
'; return false; } imagejpeg($image, $filename, 90); imagedestroy($image); $source = imagecreatefromjpeg($filename); } else { if ($test == 1) echo '
[' . $filename . ' - ' . (filesize($filename) / 1024) . ' Kb] Le fichier n\'est pas un format reconnu (jpeg,png,gif,webp). MIME type : ' . $image_info['mime'] . '
'; return false; } // Vérifier si la création de l'image a réussi if ($source === false) { if ($test == 1) echo '
Erreur lors de la création de l\'image à partir de ' . $filename . '
'; return false; } if ($test == 1) echo '
Image créée avec succès : ' . imagesx($source) . 'x' . imagesy($source) . '
'; // Effectuer le flip horizontal $rotate = @imageflip($source, IMG_FLIP_HORIZONTAL); if ($rotate === false) { if ($test == 1) echo '
Échec de imageflip pour ' . $filename . '. Dimensions : ' . imagesx($source) . 'x' . imagesy($source) . '
'; imagedestroy($source); return false; } if ($test == 1) echo '
Fliped OK !
'; // Sauvegarder l'image $saved = @imagejpeg($source, $filename, 80); @imagedestroy($source); if ($saved === false) { if ($test == 1) echo '
Erreur lors de la sauvegarde de l\'image.
'; return false; } return true; } // Image > Crop // ============================================================================================== function cropAlign($image, $cropWidth, $cropHeight, $horizontalAlign = 'center', $verticalAlign = 'middle') { $width = imagesx($image); $height = imagesy($image); $horizontalAlignPixels = calculatePixelsForAlign($width, $cropWidth, $horizontalAlign); $verticalAlignPixels = calculatePixelsForAlign($height, $cropHeight, $verticalAlign); return imageCrop($image, [ 'x' => $horizontalAlignPixels[0], 'y' => $verticalAlignPixels[0], 'width' => $horizontalAlignPixels[1], 'height' => $verticalAlignPixels[1] ]); } function calculatePixelsForAlign($imageSize, $cropSize, $align) { switch ($align) { case 'left': case 'top': return [0, min($cropSize, $imageSize)]; case 'right': case 'bottom': return [max(0, $imageSize - $cropSize), min($cropSize, $imageSize)]; case 'center': case 'middle': return [ max(0, floor(($imageSize / 2) - ($cropSize / 2))), min($cropSize, $imageSize), ]; default: return [0, $imageSize]; } } function image_crop_inside(&$filename) { list($width_orig, $height_orig) = getimagesize($filename); $new_width = 380; $new_height = ($height_orig/$width_orig)*$new_width; $im = imagecreatefromjpeg($filename); imagejpeg(cropAlign($im, $new_width, $new_height, 'center', 'middle'), $filename, 80); //imagejpeg($croppedImage, $filename); $im = imagecreatefromjpeg($filename); imagefilter($im, IMG_FILTER_CONTRAST, -10); imagefilter($im, IMG_FILTER_BRIGHTNESS, 30); //imagefilter($im, IMG_FILTER_BRIGHTNESS, +10); imagejpeg($im, $filename, 80); } // Watermarquer l'image // ============================================================================================== function cropImage($sourcePath, $destinationPath) { $test = 0; // Enable with $test = 1 for debugging // Vérification si le fichier existe if (!file_exists($sourcePath)) { if ($test == 1) echo '
Fichier source introuvable : ' . $sourcePath . '
'; return false; } // Ouvrir l'image $image = @imagecreatefromjpeg($sourcePath); // Vérifier si l'image a été chargée correctement if ($image === false) { if ($test == 1) echo '
[' . $sourcePath . ' - ' . (filesize($sourcePath) / 1024) . ' Kb] Impossible de charger l\'image JPEG.
'; return false; } // Obtenir les dimensions de l'image $originalWidth = (int)@imagesx($image); // Explicit cast to integer $originalHeight = (int)@imagesy($image); // Explicit cast to integer // Vérifier si les dimensions sont valides if ($originalWidth <= 0 || $originalHeight <= 0) { if ($test == 1) echo '
Dimensions invalides pour ' . $sourcePath . ': ' . $originalWidth . 'x' . $originalHeight . '
'; @imagedestroy($image); return false; } if ($test == 1) echo '
Dimensions originales : ' . $originalWidth . 'x' . $originalHeight . '
'; // Calculer les nouvelles dimensions après le recadrage $newWidth = (int)($originalWidth - ($originalWidth * 0.05 * 2)); // Explicit cast to integer $newHeight = (int)($originalHeight - ($originalHeight * 0.05 * 2)); // Explicit cast to integer if ($test == 1) echo '
Nouvelles dimensions calculées : ' . $newWidth . 'x' . $newHeight . '
'; // Vérifier si les nouvelles dimensions sont valides (positives) if ($newWidth <= 0 || $newHeight <= 0) { if ($test == 1) echo '
Dimensions trop petites pour recadrer ' . $sourcePath . '. Copie de l\'originale.
'; $copied = @copy($sourcePath, $destinationPath); @imagedestroy($image); return $copied !== false; } // Créer une nouvelle image recadrée $croppedImage = @imagecreatetruecolor($newWidth, $newHeight); // Vérifier si la création de l'image a réussi if ($croppedImage === false) { if ($test == 1) echo '
Échec de la création de l\'image recadrée pour ' . $sourcePath . '
'; @imagedestroy($image); return false; } // Copier la portion recadrée de l'image d'origine $success = @imagecopy($croppedImage, $image, 0, 0, (int)($originalWidth * 0.05), (int)($originalHeight * 0.05), $newWidth, $newHeight); if ($success === false) { if ($test == 1) echo '
Échec du recadrage pour ' . $sourcePath . '
'; @imagedestroy($image); @imagedestroy($croppedImage); return false; } // Sauvegarder l'image recadrée $saved = @imagejpeg($croppedImage, $destinationPath, 80); // Libérer la mémoire @imagedestroy($image); @imagedestroy($croppedImage); if ($saved === false) { if ($test == 1) echo '
Échec de la sauvegarde de l\'image recadrée pour ' . $destinationPath . '
'; return false; } if ($test == 1) echo '
Recadrage réussi pour ' . $destinationPath . '
'; return true; } // Watermarquer l'image // ============================================================================================== function watermarkImageNew ($SourceFile, $DestinationFile, $type) { //@unlink($DestinationFile); $type = strtolower($type); if($type == 'gif') $type = 1; elseif($type == 'jpg') $type = 2; elseif($type == 'jpeg') $type = 2; elseif($type == 'png') $type = 3; elseif($type == 'swf') $type = 4; elseif($type == 'psd') $type = 5; elseif($type == 'bmp') $type = 6; elseif($type == 'tiff') $type = 7; // 1 = GIF , 2 = JPG , 3 = PNG , 4 = SWF , 5 = PSD , 6 = BMP , 7 = TIFF $watermark = imagecreatefromgif('../images/ttf/watermark.gif'); $watermark_width = imagesx($watermark); $watermark_height = imagesy($watermark); $image = imagecreatetruecolor($watermark_width, $watermark_height); if($type==1) $image = imagecreatefromgif($SourceFile); elseif($type==2) { $image = @imagecreatefromjpeg($SourceFile); if (!$image) { $image= @imagecreatefromstring(file_get_contents($SourceFile)); $type = 3; } } elseif($type==3) $image = imagecreatefrompng($SourceFile); else $image = imagecreatefromjpeg($SourceFile); $size = @getimagesize($SourceFile); $dest_x = 0; $dest_y = $size[1]/2 - $watermark_height; //$dest_y = $size[1]/2; /* $dest_x = $size[0] - $watermark_width - 5; $dest_y = $size[1] - $watermark_height - 5; */ @imagecopymerge($image, $watermark, $dest_x, $dest_y, 0, 0, $watermark_width, $watermark_height, 10); //imagejpeg($image); if($type==1) @imagegif ($image, $DestinationFile, 80); /*elseif($type==2) { if ($image_test_jpg_png !== false) imagepng ($image, $DestinationFile, 9); else imagejpeg ($image, $DestinationFile, 100); }*/ elseif($type==2) @imagejpeg ($image, $DestinationFile, 80); elseif($type==3) @imagepng ($image, $DestinationFile, 8); else @imagejpeg($image, $DestinationFile, 80); copy($DestinationFile,$SourceFile); //unlink($DestinationFile); } // Image > .webp // ============================================================================================== function image_webp($source,$destination) { $im = @imagecreatefromjpeg($source); @imagewebp($im, $destination, 60); } // Image size Kb // ============================================================================================== function image_size($image_path) { $file_size = @filesize($image_path); // Get file size in bytes $file_size = $file_size / 1024; // Get file size in KB $file_size = @number_format($file_size,2); return $file_size; } // no_preview : imgage afficher par défaut et par catégorie // ============================================================================================== function no_preview($c) { // liste / place (couleur) $no_preview_suffixe = '-c'; if($c==1) $image_top_nearest_places = '1-nature.svg'; elseif($c==2) $image_top_nearest_places = '2-monument.svg'; elseif($c==3) $image_top_nearest_places = '3-museum.svg'; elseif($c==4) $image_top_nearest_places = '4-leisure.svg'; elseif($c==5) $image_top_nearest_places = '5-playground.svg'; elseif($c==6) $image_top_nearest_places = '6-sport.svg'; else $image_top_nearest_places = '0-no-preview.svg'; return $image_top_nearest_places; } // Formater la durée d'un script de ms > hh:mm:ss // ============================================================================================== function formatSeconds( $seconds ) { $seconds = $seconds * 1000; $hours = 0; $milliseconds = str_replace( "0.", '', $seconds - floor( $seconds ) ); if ( $seconds > 3600 ) { $hours = floor( $seconds / 3600 ); } $seconds = $seconds % 3600; return str_pad( $hours, 2, '0', STR_PAD_LEFT ) . gmdate( ':i:s', $seconds ) . ($milliseconds ? ".$milliseconds" : '') ; } // Delete first line of a file // ============================================================================================== function read_and_delete_first_line($filename) { global $test; $file = file($filename); $output = $file[0]; // "sep=" or "Full_Address" exist on first line ? if(strpos($output, 'sep=') === false && strpos($output, 'Full_Address') === false) { if($test == 1) echo '
[13.1] Line already cleaned
'; } else { unset($file[0]); $result_fpc = file_put_contents($filename, $file); if($result_fpc !== false) { if($test == 1) echo '
[13.1] file_put_contents = '.$result_fpc.'
'; if($test == 1) echo '
[13.2] Line deleted from .csv files
'; } else { if($test == 1) echo '
[13.1] Line not deleted from .csv files
'; } } if($test == 1) echo '
[13.1] ------------------------
'; return $output; } // Pourcentage de la requête effectuée // ============================================================================================== function percent_done($total,$total_done) { if(rand(0,20)==10) { $total_percent_done = round((100/$total)*$total_done,2); echo '
'.$total_percent_done.'%
'; } } // Encrypt/Decrypt // ============================================================================================== function encrypt_latlng($lat,$lng){ /* Algo : $e0 = 'z2o'; 0 = "z" comme "'z'éro" - 0+2='2' - zér'o', ce qui donne 0 = z2o(lettre "o") [lettre + chiffre+2 + lettre] 1 = "u" comme "'u'n" - 1+3='4' - u'n', ce qui donne 0 = u4n [lettre + chiffre+4 + lettre] ... chiffre + 2 ... chiffre + 4 */ $e0 = 'z2o'; $e1 = 'u5n'; $e2 = 'd4x'; $e3 = 't7s'; $e4 = 'q6e'; $e5 = 'c9q'; $e6 = 's8x'; $e7 = 's1t'; $e8 = 'h0t'; $e9 = 'n3f'; $e0 = 'd2x'; $ep = 'p5t'; // point $se = 'p7t'; // Séparation entre lat et lng // Encrypt Lat $output_str_lat = ""; $charachters_lat = str_split($lat); for($i = 0 ; $i < sizeof($charachters_lat) ; $i++){ if($charachters_lat[$i] == '.') $output_str_lat .= $ep; else $output_str_lat .= @${'e'.$charachters_lat[$i]}; } // Encrypt Lng $output_str_lng = ""; $charachters_lng = str_split($lng); for($i = 0 ; $i < sizeof($charachters_lng) ; $i++){ if($charachters_lng[$i] == '.') $output_str_lng .= $ep; else $output_str_lng .= @${'e'.$charachters_lng[$i]}; } return $output_str_lat.$se.$output_str_lng; } function decrypt_latlng($latLngEncrypted){ $output_str = ""; $charachters = str_split($input_str,3); for($i = 0 ; $i < sizeof($charachters) ; $i++){ $output_str .= chr($charachters[$i]); } return $output_str; } // ---------------------------------------------------------------------------- // A FAIRE : Mettre en cookie et si ordi fixe un point "lat,lng Home" durée longue de cookie. // Transforme Lat & Lng to place location function latlng_to_location($lat, $lng) { $test = 0; // Active le mode test pour afficher les logs $log = ''; global $base_path; global $is_local; // Déterminer le chemin du fichier de connexion if ($is_local) { $chemin_fichier = $base_path."/yutugo.com/yutugo.com/"; } else { $chemin_fichier = $base_path."/"; } include $chemin_fichier.'include/connexion/connexion.php'; // Réduction à 4 décimales $lat = number_format((float)$lat, 4, '.', ''); $lng = number_format((float)$lng, 4, '.', ''); if ($test == 1) { echo '
'; echo 'Logs de latlng_to_location

'; echo '[INFO] Fonction appelée avec lat: ' . $lat . ', lng: ' . $lng . '
'; } // Vérification des coordonnées invalides if ($lat == '0' && $lng == '0' || $lat == '' && $lng == '' || !$lat && !$lng || $lat <= -90 || $lat >= 90 || $lng <= -180 || $lng >= 180) { if ($test == 1) echo '[ERROR] Coordonnées invalides.
'; return null; } // Vérification de la connexion active if (!$c1) { if ($test == 1) echo '[ERROR] La connexion à la base de données est introuvable.
'; die("Erreur : Connexion à la base de données introuvable."); } // 1. Vérification dans la base de données $stmt = $c1->prepare("SELECT display_name FROM latlng_to_location WHERE lat = ? AND lng = ?"); $stmt->bind_param("dd", $lat, $lng); $stmt->execute(); $stmt->bind_result($display_name); if ($stmt->fetch()) { if ($test == 1) echo '[INFO] Donnée trouvée dans la base : ' . $display_name . '
'; $stmt->close(); if ($test == 1) echo '
'; // Ferme le cadre de log return $display_name; } $stmt->close(); // 2. Si non trouvé, utilisation des APIs $apiKey = 'pk.d679066b906e03040f288a93e79908da'; $url_locationiq = 'https://us1.locationiq.com/v1/reverse?key='.$apiKey.'&lat='.$lat.'&lon='.$lng.'&format=json'; $url_osm = 'https://nominatim.openstreetmap.org/reverse?format=json&lat='.$lat.'&lon='.$lng.'&zoom=15&addressdetails=1&limit=1&email=noisycity@yahoo.fr'; $opts = array('http' => array('header' => "User-Agent: MonApplication/1.0 (https://www.yutugo.com; noisycity@yahoo.fr)\r\n")); $context = stream_context_create($opts); // Essai avec LocationIQ $response = @file_get_contents($url_locationiq, false, $context); $source = 'LocationIQ'; if ($response === FALSE) { $response = @file_get_contents($url_osm, false, $context); $source = 'OpenStreetMap'; } // 3. Si toujours erreur, retourner lat,lng à 2 décimales if ($response === FALSE) { if ($test == 1) echo '[ERROR] Aucune réponse des API. Retour des coordonnées uniquement.
'; return number_format($lat, 2) . ',' . number_format($lng, 2); } // Décodage JSON et affichage des données brutes $json_extracted = json_decode($response, true); if ($test == 1) { echo 'Source : ' . $source . '
'; echo 'Données brutes reçues :
' . htmlspecialchars($response) . '
'; } if (!isset($json_extracted['address'])) { if ($test == 1) echo '[ERROR] Données d\'adresse manquantes.
'; return number_format($lat, 2) . ',' . number_format($lng, 2); } // Extraction et priorisation des champs $address = $json_extracted['address']; $neighbourhood = @$address['neighbourhood']; $road = @$address['road']; $suburb = @$address['suburb']; $city_district = @$address['city_district']; $city = @$address['city']; $town = @$address['town']; $village = @$address['village']; $country = @$address['country']; // Priorité définie : neighbourhood > road > suburb > city_district $selected_neighbourhood = $neighbourhood ?: $road ?: $suburb ?: $city_district; $selected_city = $city ?: $town ?: $village; // Construction du nom final $elements = []; if (!empty($selected_neighbourhood)) $elements[] = $selected_neighbourhood; if (!empty($selected_city)) $elements[] = $selected_city; if (!empty($country)) $elements[] = $country; $final_display_name = implode(', ', array_filter($elements)); $final_display_name = html_entity_decode($final_display_name, ENT_QUOTES | ENT_HTML5, 'UTF-8'); $final_display_name = str_replace("Metropolitan France", "France", $final_display_name ?? ''); //$final_display_name = mb_convert_encoding($final_display_name, 'UTF-8', 'auto'); // 4. Insertion dans la base $stmt_insert = $c1->prepare("INSERT INTO latlng_to_location (lat, lng, display_name) VALUES (?, ?, ?)"); $stmt_insert->bind_param("dds", $lat, $lng, $final_display_name); $stmt_insert->execute(); $stmt_insert->close(); // 5. Affichage du résultat final if ($test == 1) { echo 'Résultat final : ' . $final_display_name . '
'; echo ''; // Ferme le cadre des logs } return !empty($final_display_name) ? $final_display_name : number_format($lat, 2) . ',' . number_format($lng, 2); } // DEPRECATED ---------------------------------------------------------------------------- // A FAIRE : Mettre en cookie et si ordi fixe un point "lat,lng Home" durée longue de cookie. // Transforme Lat & Lng to place location
function latlng_to_location_openstreetmap($lat,$lng) { $test = 0; $today = date('Y-m-d H:i:s'); $log = ''; if($test == 1) $log .= '
[0] function latlng_to_location('.$lat.','.$lng.')
'; // SECU if ($lat == '0' && $lng == '0' or $lat == '' && $lng == '' or !$lat && !$lng or $lat<=-90 or $lat>=90 or $lng<=-180 or $lng>=180) exit; else { $url = 'https://nominatim.openstreetmap.org/reverse?format=json&lat='.$lat.'&lon='.$lng.'&zoom=15&addressdetails=1&limit=1&email=noisycity@yahoo.fr'; //echo $url; if(get_http_response_code($url) == 200) { // Create a stream //$opts = array('http'=>array('header'=>"User-Agent: StevesCleverAddressScript 3.7.6\r\n")); $opts = array('http' => array('header' => "User-Agent: MonApplication/1.0 (https://www.yutugo.com; noisycity@yahoo.fr)\r\n")); $context = stream_context_create($opts); // Open the file using the HTTP headers set above $file = file_get_contents($url, false, $context); $url_content = file_get_contents($url); $log .= '
[1.2] get_http_response_code:200 - ('.$url.')
'.$url_content.'
'; $json_extracted = json_decode($url_content, true); $json_suburb = @$json_extracted['address']['suburb']; if($json_suburb == '') $json_suburb = @$json_extracted['address']['neighbourhood']; $json_city = @$json_extracted['address']['city']; if($json_city == '') $json_city = @$json_extracted['address']['town']; $json_city_district = @$json_extracted['address']['city_district']; $json_locality = @$json_extracted['address']['locality']; $json_village = @$json_extracted['address']['village']; $json_municipality = @$json_extracted['address']['municipality']; $json_county = @$json_extracted['address']['county']; $json_state = @$json_extracted['address']['state']; $json_country = @$json_extracted['address']['country']; $json_postcode = @$json_extracted['address']['postcode']; $json_boundingbox_1 = @$json_extracted['boundingbox'][0]; $json_boundingbox_2 = @$json_extracted['boundingbox'][1]; $json_boundingbox_3 = @$json_extracted['boundingbox'][2]; $json_boundingbox_4 = @$json_extracted['boundingbox'][3]; $log .= '
[1.30] json_extracted (json_suburb) : '.$json_suburb.'
'; $log .= '
[1.31.1] json_extracted (json_extracted) : '.$json_city.'
'; $log .= '
[1.31.2] json_extracted (json_city_district) : '.$json_city_district.'
'; $log .= '
[1.31.3] json_extracted (json_locality) : '.$json_locality.'
'; $log .= '
[1.31.4] json_extracted (json_village) : '.$json_village.'
'; $log .= '
[1.31.5] json_extracted (json_municipality ) : '.$json_municipality.'
'; $log .= '
[1.32] json_extracted (json_county) : '.$json_county.'
'; $log .= '
[1.33] json_extracted (json_state) : '.$json_state.'
'; $log .= '
[1.34] json_extracted (json_country) : '.$json_country.'
'; $log .= '
[1.35] json_extracted (json_postcode) : '.$json_postcode.'
'; $log .= '
[1.36] json_extracted (json_boundingbox - lat 1) : '.$json_boundingbox_1.'
'; $log .= '
[1.37] json_extracted (json_boundingbox - lat 2) : '.$json_boundingbox_2.'
'; $log .= '
[1.38] json_extracted (json_boundingbox - lng 1) : '.$json_boundingbox_3.'
'; $log .= '
[1.39] json_extracted (json_boundingbox - lng 2) : '.$json_boundingbox_4.'
'; // id city place_id state country latitude longitude search_time $sql = "INSERT INTO search_autocomplete VALUES('','$json_city','','','$json_country','$lat','$lng','$today');"; // Cookie // A FAIRE : proposer : "[choisir un lieu]" if($test == 1) echo $log; $title_location = ''; $a = 2; while($a>1) { if($json_suburb != '' && $a>=1) { $a--; $title_location .= $json_suburb; if($a==1) $title_location .= ', '; } if($json_city != '' && $a>=1) { $a--; $title_location .= $json_city; if($a==1) $title_location .= ', '; } if($json_village != '' && $a>=1) { $a--; $title_location .= $json_village; if($a==1) $title_location .= ', '; } if($json_city_district != '' && $a>=1) { $a--; $title_location .= $json_city_district; if($a==1) $title_location .= ', '; } if($json_county != '' && $a>=1) { $a--; $title_location .= $json_county; if($a==1) $title_location .= ', '; } if($json_state != '' && $a>=1) { $a--; $title_location .= $json_state; if($a==1) $title_location .= ', '; } if($json_country != '' && $a>=1) { $a--; $title_location .= $json_country; if($a==1) $title_location .= ', '; } if($title_location == '' or $title_location == ', ') $title_location = ''; } } else { $log .= '
[0] - Erreur d\'accès à la page : get_http_response_code : '.get_http_response_code($url).'
'; $log .= ''; if($test == 1) echo '
'.$log.'
'; // A FAIRE : cookie default ou search about IP reverse (autre service) $title_location = $lat.','.$lng; } if($title_location != '') { //$title_location = mb_convert_encoding($title_location, 'ISO-8859-1', 'UTF-8'); //$title_location = mb_convert_encoding($title_location, 'UTF-8', 'ISO-8859-1'); //$title_location = ''.$title_location.''; return $title_location; } } } // Cut sentence without cutting a word after n characters // ---------------------------------------------------------------------------- function cutSentence(string $string, int $maxChars, string $etc = '…'): string { // Charset $enc = 'UTF-8'; // Si on est déjà sous la limite, on renvoie tel quel if (mb_strlen($string, $enc) <= $maxChars) { return $string; } // On coupe pur et dur à maxChars $substr = mb_substr($string, 0, $maxChars, $enc); // On cherche le dernier espace pour ne pas couper un mot $lastSpace = mb_strrpos($substr, ' ', 0, $enc); if ($lastSpace !== false) { $substr = mb_substr($substr, 0, $lastSpace, $enc); } // On colle le suffixe return $substr . $etc; } // If string is only with UPPERCASES --> Uppercases. // ---------------------------------------------------------------------------- function ajusterMajuscules($chaine) { if ($chaine === strtoupper($chaine)) { // La chaîne est entièrement en majuscules //$chaine = @mb_convert_encoding($chaine, 'ISO-8859-1', 'UTF-8'); $chaine = ucfirst(strtolower($chaine)); //$chaine = @mb_convert_encoding($chaine, 'UTF-8', 'ISO-8859-1'); } return $chaine; } function limiterChaine($chaine, $limite) { // Vérifier si la longueur de la chaîne est inférieure ou égale à la limite if (strlen($chaine) <= $limite) { return $chaine; // Pas besoin de couper, retourner la chaîne telle quelle } else { // Couper la chaîne à la limite et récupérer la partie avant la limite $chaineLimite = substr($chaine, 0, $limite); // Trouver la position du dernier espace dans la partie coupée $dernierEspace = strrpos($chaineLimite, ' '); // Si un espace est trouvé, couper à cet espace if ($dernierEspace !== false) { $chaineLimite = substr($chaineLimite, 0, $dernierEspace); } return $chaineLimite; } } function unique_id_to_imagepath($unique_id) { $prefixe = substr($unique_id, 0, 5); $resultat = implode('/', str_split($prefixe)) . '/' . $unique_id; return $resultat; } function unique_id_to_jsonpath($unique_id) { $prefixe = substr($unique_id, 0, 6); $resultat = implode('/', str_split($prefixe)) . '/' . $unique_id . '.json'; return $resultat; } // id_cat > cat_name_LANGUE - no BD function obtenirTexte($id_cat, $langue) { global $test, $base_path, $is_local; if ($is_local) { $chemin_fichier = $base_path . "/yutugo.com/yutugo.com/cache/places/content/cat/categories_google_maps_$langue.json"; } else { $chemin_fichier = $base_path . "/cache/places/content/cat/categories_google_maps_$langue.json"; } if (file_exists($chemin_fichier)) { $contenu_json = file_get_contents($chemin_fichier); $contenu_json = mb_convert_encoding($contenu_json, 'UTF-8', 'ISO-8859-1'); $donnees = json_decode($contenu_json, true); foreach ($donnees as $categorie) { if ($categorie['id_cat'] == $id_cat) { if (isset($categorie['yutugo_cat']) && $categorie['yutugo_cat'] == 0) { return null; // Ne rien renvoyer si yutugo_cat == 0 } $cle_nom = 'cat_name_' . $langue; return $categorie[$cle_nom] ?? null; } } if ($test == 1) { return '
obtenirTexte() > [' . $id_cat . ' (' . $langue . ') not found]
'; } } else { if ($test == 1) { return '
obtenirTexte() > Le fichier JSON n\'existe pas pour la langue ' . $langue . ' [' . $chemin_fichier . ']
'; } } return null; } // id_cat > parent_cat - no BD function obtenirParentcat($id_cat, $langue) { global $test; global $base_path; global $is_local; // Chemin vers le fichier JSON //$chemin_fichier = $base_path."/yutugo.com/yutugo.com/cache/places/content/cat/categories_google_maps_$langue.json"; if ($is_local) { $chemin_fichier = $base_path."/yutugo.com/yutugo.com/cache/places/content/cat/categories_google_maps_$langue.json"; } else { $chemin_fichier = $base_path."/cache/places/content/cat/categories_google_maps_$langue.json"; } // Vérifier si le fichier existe if (file_exists($chemin_fichier)) { // Lire le contenu du fichier JSON $contenu_json = file_get_contents($chemin_fichier); // Décoder le JSON en tableau associatif $donnees = json_decode($contenu_json, true); // Rechercher le texte correspondant à l'id_cat foreach ($donnees as $categorie) { if ($categorie['id_cat'] == $id_cat) { return $categorie['parent_cat']; } } if($test == 1) return '
obtenirParentcat > ['.$id_cat.' ('.$langue.') not found]
'; } else { if($test == 1) return '
obtenirParentcat > Le fichier JSON n\'existe pas pour la langue '.$langue.' ['.$chemin_fichier.' - '.file_exists($chemin_fichier).']
'; } } // Prévision de durée de script // -------------------------------------------------------------------------------------------------------------------- function previsionTime($timeStart, $totalToDo, $totalDone) { $timeDone = time() - $timeStart; $timeToDo = ($totalDone > 0) ? ($timeDone / $totalDone) * $totalToDo : 0; // Éviter division par zéro return gmdate("H:i:s", (int) $timeToDo); // Conversion explicite en entier } // EXIF : lire SOFTWARE data // -------------------------------------------------------------------------------------------------------------------- function ExifReadDataSoftware ($fimage) { $test=0; $imageType = @exif_imagetype($fimage); if ($imageType !== false && filesize($fimage)>0) { $exif = @exif_read_data($fimage, 0, true); if (is_array($exif) || is_object($exif)) { foreach ($exif as $key => $section){ foreach ($section as $name => $val){ $valm = $val; if ($name == "FileDateTime"){ $valm = date("Y-m-d H:i:s", $val); } //if ($name == "FileType"){ $valm = $imgtyp[$val]; } if ($name == "BitsPerSample"){ $valm = ""; foreach ($val as $keybps => $sectionbps){ $valm .= $keybps.":: ".$sectionbps."
"; } } if($name == 'Software' && $test==1) echo "
[".$key."] ".$name.": ".$valm."
"; } } } } } // EXIF : Modifier SOFTWARE data // -------------------------------------------------------------------------------------------------------------------- function ExifWriteDataSoftware ($image_to_change) { $test=0; // Chemin de l'image //$imagePath = $all_path_image_originale; // Nouvelle valeur pour IFD0 Software (remplacez '' par la valeur souhaitée) $newIFD0SoftwareValue = 'Yutugo'; // Commande Exiftool pour modifier la valeur IFD0 Software //$command = "C:/EasyPHP-Devserver-17/eds-binaries/exiftool/exiftool -IFD0:Software=Z \"$imagePath\" -overwrite_original"; //$command = "C:/EasyPHP-Devserver-17/eds-binaries/exiftool/exiftool -ver"; $command = "C:/EasyPHP-Devserver-17/eds-binaries/exiftool/exiftool -IFD0:Software=$newIFD0SoftwareValue \"C:/EasyPHP-Devserver-17/eds-www/yutugo.com/yutugo.com/cache/places/top_images_webp/$image_to_change\" -overwrite_original"; if($test==1) echo '
command:'.$command.'
'; // Exécution de la commande système exec($command, $output, $status); // Vérification de l'état de l'exécution if ($status === 0) { if($test==1) echo "
La valeur IFD0 Software a été modifiée avec succès.
"; } else { if($test==1) { echo "
Erreur lors de la modification de la valeur IFD0 Software. Status :".$status.'
'; // Afficher les éventuelles erreurs retournées par Exiftool print_r($output); } } } // Transforme une liste id_cat_all en texte (FR, ...) // ============================================================================================== function idCatAllToTexte($ids, $langue) { // Utiliser une expression régulière pour diviser les identifiants preg_match_all('/\b\d+\b/', $ids, $matches); // Récupérer les identifiants depuis les correspondances $idsArray = $matches[0]; // Initialiser un tableau pour stocker les noms de catégories $nomsCategories = array(); $nomsCategoriesSpecials = array(); // Identifiant spécial à mettre en dernier (trop généraliste) $identifiantSpecial = 3660; // Appliquer obtenirTexte à chaque identifiant foreach ($idsArray as $id) { $nomCategorie = obtenirTexte($id, $langue); // Vérifier si l'identifiant est égal à 3660 if ($id == $identifiantSpecial) { // Mettre cet élément dans le tableau des spéciaux $nomsCategoriesSpecials[] = $nomCategorie; } else { // Mettre cet élément dans le tableau général $nomsCategories[] = $nomCategorie; } } // Fusionner les tableaux en ajoutant les spéciaux à la fin $nomsCategories = array_merge($nomsCategories, $nomsCategoriesSpecials); // Rejoindre les noms de catégories en une chaîne $resultat = implode(', ', $nomsCategories); // Supprimer une virgule finale accidentelle $resultat = rtrim($resultat, ', '); return $resultat; } function idCatAllToTexteAndLinks($ids, $langue, $Lat, $Lng) { // Extraire les identifiants numériques preg_match_all('/\b\d+\b/', $ids, $matches); $idsArray = $matches[0]; $liensCategories = array(); $liensSpecials = array(); $identifiantSpecial = 3660; foreach ($idsArray as $id) { $nomCategorie = obtenirTexte($id, $langue); // Si pas de nom (null ou vide), on ignore cette catégorie if (empty($nomCategorie)) { continue; } $lien = '' . htmlspecialchars($nomCategorie) . ''; if ($id == $identifiantSpecial) { $liensSpecials[] = $lien; } else { $liensCategories[] = $lien; } } // Ajouter les catégories spéciales à la fin $liensCategories = array_merge($liensCategories, $liensSpecials); // Retourner la chaîne HTML finale (sans doublons de virgule) return implode(', ', $liensCategories); } function websiteDisplay($url) { // Vérifier si $url est vide if (empty($url)) { return $url; } // Retire le protocole (http:// ou https://) $url = preg_replace('#^https?://#', '', $url); // Retire le "www." du début $url = preg_replace('#^www\.#', '', $url); // Retire tout après le premier '/' $url = preg_replace('#/.*#', '', $url); // Cas des exceptions pour Facebook, Instagram, Twitter $exceptions = array('facebook.com', 'instagram.com', 'twitter.com', 'x.com'); foreach ($exceptions as $exception) { if (strpos($url, $exception) !== false) { return $url; } } return $url; } function convertirTelephone($telephone) { // Vérifier si la variable est une chaîne de caractères non vide if (is_string($telephone) && $telephone !== '') { // Supprimer les espaces et les caractères non numériques $telephone = preg_replace('/[^0-9]/', '', $telephone); // Vérifier si le numéro ne commence pas déjà par le caractère "+" if (substr($telephone, 0, 1) !== '+') { // Vérifier si le numéro commence par "0", ce qui indique un numéro français if (substr($telephone, 0, 1) === '0') { // Supprimer le "0" initial $telephone = substr($telephone, 1); // Ajouter le code pays pour la France $telephone = '+33' . $telephone; } } } else { // Gérer les cas où $telephone est nul ou non valide $telephone = ''; } return $telephone; } function limiterAffichage($chaine, $limite = 30) { if (strlen($chaine) > $limite) { return substr($chaine, 0, $limite) . '...'; } else { return $chaine; } } function display_search_history($id) { if (isset($_COOKIE['search_history'])) { $searches = json_decode($_COOKIE['search_history'], true); if (!empty($searches)) { // Utiliser un tableau associatif pour vérifier les doublons $seen = []; echo '
'; echo 'Recherches récentes'; echo "
    "; foreach ($searches as $search) { $city = stripslashes($search['city']); $state = stripslashes($search['state']); //$latitude = htmlspecialchars($search['latitude'], ENT_QUOTES, 'UTF-8'); //$longitude = htmlspecialchars($search['longitude'], ENT_QUOTES, 'UTF-8'); $latitude = isset($search['latitude']) ? round(floatval(htmlspecialchars($search['latitude'], ENT_QUOTES, 'UTF-8')), 6) : null; $longitude = isset($search['longitude']) ? round(floatval(htmlspecialchars($search['longitude'], ENT_QUOTES, 'UTF-8')), 6) : null; $key = $city . ',' . $state . ',' . $latitude . ',' . $longitude; if (!isset($seen[$key])) { $seen[$key] = true; $link = "?c=50&lat=$latitude&lng=$longitude"; $displayCity = htmlspecialchars($city, ENT_NOQUOTES, 'UTF-8'); $displayState = htmlspecialchars($state, ENT_NOQUOTES, 'UTF-8'); $displayCity = htmlspecialchars_decode($displayCity, ENT_QUOTES); $displayState = htmlspecialchars_decode($displayState, ENT_QUOTES); echo "
  • • $displayCity, $displayState
  • "; } } echo '
'; echo '
'; } else { echo ""; } } else { echo ""; } } // Fonction pour extraire la langue principale à partir de l'en-tête HTTP_ACCEPT_LANGUAGE function getPreferredLanguage($http_accept_language) { // Vérifier si l'en-tête est vide if (empty($http_accept_language)) { return 'en'; // Langue par défaut } // Initialiser un tableau pour stocker les langues et leurs poids $languages = array(); // Diviser la chaîne en segments individuels $lang_parse = explode(',', $http_accept_language); foreach ($lang_parse as $lang) { // Diviser chaque segment en langue et poids $parts = explode(';q=', $lang); $locale = strtolower(trim($parts[0])); $weight = isset($parts[1]) ? (float)$parts[1] : 1.0; // Poids par défaut à 1.0 // Stocker la langue et son poids $languages[$locale] = $weight; } // Trier les langues par poids décroissant arsort($languages, SORT_NUMERIC); // Retourner la langue avec le poids le plus élevé return key($languages); } // Display Meteo weather - 5 days. Mode 1 : Full display - Mode 2 : picto only // --------------------------------------------------------------------------- function meteo($lat, $lng, $type, $c1) { $test = 0; static $instanceCount = 0; $instanceCount++; // Vérification de la connexion MySQL if (!$c1 || !($c1 instanceof mysqli) || $c1->connect_errno) { return ''; } else include 'connexion/connexion.php'; // Identifiants uniques pour chaque instance $iconId = "weather-icon" . $instanceCount; // Arrondir latitude et longitude au dixième pour la précision $roundedLat = round($lat, 1); $roundedLng = round($lng, 1); // Vérifier si les données météo sont déjà en cache dans la base de données $query = "SELECT weather_data, updated_at FROM meteo WHERE lat = ? AND lng = ?"; $stmt = mysqli_prepare($c1, $query); mysqli_stmt_bind_param($stmt, 'dd', $roundedLat, $roundedLng); mysqli_stmt_execute($stmt); mysqli_stmt_bind_result($stmt, $cachedWeatherData, $updatedAt); mysqli_stmt_fetch($stmt); mysqli_stmt_close($stmt); $data = null; if ($cachedWeatherData) { // Vérifier si les données en cache sont récentes (moins de 6 heures) $lastUpdated = new DateTime($updatedAt); $currentTime = new DateTime(); $interval = $currentTime->diff($lastUpdated); if ($interval->h < 6) { // Utiliser les données en cache $data = json_decode($cachedWeatherData, true); } //echo 'cachedWeatherData'; } // Si pas de données récentes ou pas de cache, appeler l'API météo if (!$data) { // echo 'NoncachedWeatherData'; $apiUrl = "https://api.open-meteo.com/v1/forecast?latitude={$lat}&longitude={$lng}&hourly=windspeed_100m,winddirection_100m,precipitation_probability,precipitation,windspeed_10m,uv_index&daily=temperature_2m_min,temperature_2m_max,weathercode,sunrise,sunset,uv_index_max&timezone=auto"; $weatherData = @file_get_contents($apiUrl); if ($weatherData === false) { // URL de secours $backupApiUrl = "https://yutugo.net/meteo/meteo-external.php?lat={$lat}&lng={$lng}"; // Tenter de récupérer les données depuis l'URL de secours $weatherData = @file_get_contents($backupApiUrl); if ($weatherData === false) { if($test == 1) return '

Erreur : Impossible de récupérer les données météo.

'; } } $data = json_decode($weatherData, true); if (empty($data) || !isset($data['daily']['temperature_2m_min'][0])) { return ''; } // Mettre à jour ou insérer les nouvelles données dans la base $query = "REPLACE INTO meteo (lat, lng, weather_data, updated_at) VALUES (?, ?, ?, NOW())"; $stmt = mysqli_prepare($c1, $query); $weatherDataJson = json_encode($data); mysqli_stmt_bind_param($stmt, 'dds', $roundedLat, $roundedLng, $weatherDataJson); mysqli_stmt_execute($stmt); mysqli_stmt_close($stmt); } // Initialisation des variables avec des valeurs par défaut $precipitationProbability = 0; $maxWindSpeed100m = 'N/A'; $uvIndexMax = 0; $sunriseTime = 'N/A'; $sunsetTime = 'N/A'; $minTemp = 'N/A'; $maxTemp = 'N/A'; $dominantWindDirection = 0; // Extraction des données journalières if (!empty($data['daily'])) { $minTemp = htmlspecialchars($data['daily']['temperature_2m_min'][0] ?? 'N/A'); $maxTemp = htmlspecialchars($data['daily']['temperature_2m_max'][0] ?? 'N/A'); $uvIndexMax = round($data['daily']['uv_index_max'][0] ?? 0, 1); $sunriseTime = isset($data['daily']['sunrise'][0]) ? substr($data['daily']['sunrise'][0], 11, 5) : 'N/A'; $sunsetTime = isset($data['daily']['sunset'][0]) ? substr($data['daily']['sunset'][0], 11, 5) : 'N/A'; $precipitationProbability = round(max($data['hourly']['precipitation_probability'] ?? [0]) / 10) * 10; } // Extraction des données horaires pour le vent if (!empty($data['hourly'])) { $windSpeeds100m = array_slice($data['hourly']['windspeed_100m'] ?? [], 0, 6); $windDirections = array_slice($data['hourly']['winddirection_100m'] ?? [], 0, 6); $maxWindSpeed100m = !empty($windSpeeds100m) ? round(max($windSpeeds100m) / 5) * 5 : 0; $dominantWindDirection = !empty($windDirections) ? round(array_sum($windDirections) / count($windDirections)) : 0; } // Correspondance entre le weatherCode et les descriptions/icônes $weatherIcons = [ 0 => ["☀", "Soleil"], 1 => ["🌤", "Soleil avec quelques nuages"], 2 => ["⛅", "Nuages épars"], 3 => ["☁", "Nuageux"], 45 => ["🌫", "Brouillard"], 48 => ["🌫", "Brouillard givrant"], 51 => ["🌧", "Bruine légère"], 53 => ["🌧", "Bruine"], 55 => ["🌧", "Bruine forte"], 61 => ["🌦", "Pluie légère"], 63 => ["🌦", "Pluie modérée"], 65 => ["🌧", "Pluie forte"], 71 => ["❄", "Neige légère"], 73 => ["❄", "Neige modérée"], 75 => ["❄", "Neige forte"], 80 => ["🌦", "Averses légères"], 81 => ["🌦", "Averses modérées"], 82 => ["🌦", "Averses fortes"], 95 => ["⚡", "Orages légers"], 96 => ["⚡", "Orages avec grêle"], 99 => ["⚡", "Orages violents"] ]; $weatherCode = $data['daily']['weathercode'][0] ?? null; $weatherIcon = $weatherIcons[$weatherCode][0] ?? ''; $weatherDescription = $weatherIcons[$weatherCode][1] ?? ''; // Fonctions utilitaires pour l'affichage $getClassByThreshold = function($value, $orangeThreshold, $redThreshold) { if ($value >= $redThreshold) { return 'important-red'; } elseif ($value >= $orangeThreshold) { return 'important-orange'; } return ''; }; $getWindArrow = function($degrees) { $arrows = ["↑", "↗", "→", "↘", "↓", "↙", "←", "↖"]; return $arrows[round($degrees / 45) % 8]; }; // Générer le HTML en fonction du type $html = ''; if ($type == 1) { $html .= ""; $html .= "
"; $html .= "
"; $html .= "
Aujourd'hui
"; $html .= "
{$weatherIcon}
"; $html .= "
{$minTemp}°C / {$maxTemp}°C
"; $html .= "
Pluie : {$precipitationProbability}%
"; $html .= "
Vent : {$maxWindSpeed100m} km/h " . $getWindArrow($dominantWindDirection) . "
"; $html .= "
UV : {$uvIndexMax}
"; $html .= "
\"Lever{$sunriseTime} - {$sunsetTime} \"Couché
"; $html .= "
"; } elseif ($type == 2) { $html .= "{$weatherIcon}"; } return $html; } // Fonctions utilitaires function roundToNearestFive($value) { return round($value / 5) * 5; } function roundToNearestTen($value) { return round($value / 10) * 10; } function roundToHalf($value) { return round($value * 2) / 2; } function getClassByThreshold($value, $orangeThreshold, $redThreshold) { if ($value >= $redThreshold) { return 'important-red'; } elseif ($value >= $orangeThreshold) { return 'important-orange'; } return ''; } function getTempClass($value, $type) { if ($type === 'min') { if ($value <= -10) { return 'important-red'; } elseif ($value <= 0) { return 'important-orange'; } } elseif ($type === 'max') { if ($value >= 35) { return 'important-red'; } elseif ($value >= 30) { return 'important-orange'; } } return ''; } function getWindArrow($degrees) { $arrows = ["↑", "↗", "→", "↘", "↓", "↙", "←", "↖"]; return $arrows[round($degrees / 45) % 8]; } function getRainDescription($probability) { if ($probability == 0) { return "Pas de pluie"; } elseif ($probability <= 20) { return "Improbable"; } elseif ($probability <= 50) { return "Possible"; } elseif ($probability <= 90) { return "Probable"; } else { return "Certaine"; } } function get_location_from_ip($ip) { // URL de l'API $api_url = "https://ipinfo.io/{$ip}?token=721446117ead1d"; // Récupération des données depuis l'API $response = @file_get_contents($api_url); if ($response !== false) { // Décoder la réponse JSON $data = json_decode($response, true); if (isset($data['loc'])) { // Extraire la latitude et la longitude list($latitude, $longitude) = explode(',', $data['loc']); return [ 'latitude' => (float) $latitude, 'longitude' => (float) $longitude, 'region' => isset($data['region']) ? $data['region'] : null, 'country' => isset($data['country']) ? $data['country'] : null, 'api_url' => isset($data['api_url']) ? $data['api_url'] : null, ]; } } // Localisation par défaut (France métropolitaine) // A FAIRE : randomiser les lieux par défaut et faire tourner return [ 'api_url' => 'https - '.$ip, 'latitude' => 48.8566, // Latitude de la France 'longitude' => 2.3522, // Longitude de la France 'region' => 'France', 'country' => 'FR', ]; } /************************************ * 1) HOURS - ENCODAGE DES HORAIRES BRUTS * algo idée : https://chatgpt.com/c/67b99c5b-9d88-8002-8dde-4bf77979e4f7
tests : https://chatgpt.com/c/67b99937-5664-8002-96cf-6be2532a4b4c
https://chatgpt.com/c/67cca0ad-7bcc-8002-9dd8-8d84779f6948 https://chatgpt.com/c/67cd90a0-c534-8002-aaa4-6b07989678fd https://chatgpt.com/c/67b75f9b-f3d4-8002-92c0-ae859c17bdb7 ************************************/ /** * Nettoie la chaîne brute d'horaires. * - Remplace les caractères d'encodage problématiques. * - Uniformise le séparateur des intervalles en remplaçant " to " par "-". * - Supprime le contenu entre parenthèses (même imbriqué). * - Supprime certains termes non pertinents. */ function hours_cleanHours($raw) { $clean = trim($raw); $search = [" ", "é", "Ã", "–", "\xE2\x80\xAF"]; $replace = [" ", "é", "à", "-", " "]; if (!is_null($clean)) { $clean = str_replace($search, $replace, $clean); $clean = str_replace(' to ', '-', $clean); } // Supprime tout contenu entre parenthèses, même imbriqué $clean = preg_replace('/\s*\((?>[^()]+|(?R))*\)/u', '', $clean); // Supprime certains termes $clean = preg_replace('/Holiday hours/i', '', $clean); $clean = preg_replace('/Hide open hours for the week/i', '', $clean); return trim($clean); } /** * https://x.com/i/grok?conversation=1949885510618390566 * Parse la chaîne nettoyée pour extraire un planning par jour. * - Découpe le texte sur virgules ou points-virgules. * - Si un segment commence par un nom de jour suivi d'un deux-points, il est utilisé pour définir le jour courant. * - Si le segment correspond exactement à un nom de jour, on met à jour le jour courant. * - Sinon, le segment est traité comme un horaire pour le dernier jour identifié. * - Le cas "Open 24 hours" est géré en affectant l’intervalle [00:00, 24:00]. * - Si un horaire se termine avant son début, il est scindé sur deux jours (overnight). */ function hours_parseHours($text) { $daysMapping = [ 'monday' => 'MO', 'tuesday' => 'TU', 'wednesday' => 'WE', 'thursday' => 'TH', 'friday' => 'FR', 'saturday' => 'SA', 'sunday' => 'SU', 'lundi' => 'MO', 'mardi' => 'TU', 'mercredi' => 'WE', 'jeudi' => 'TH', 'vendredi' => 'FR', 'samedi' => 'SA', 'dimanche' => 'SU' ]; $result = ['MO'=>[], 'TU'=>[], 'WE'=>[], 'TH'=>[], 'FR'=>[], 'SA'=>[], 'SU'=>[]]; $lastMeridiem = ['MO'=>null, 'TU'=>null, 'WE'=>null, 'TH'=>null, 'FR'=>null, 'SA'=>null, 'SU'=>null]; // Découpage sur virgules ou points-virgules $parts = preg_split('/[;,]/', $text); $currentDay = null; // Regex pour un intervalle horaire, par ex. "9:30 AM-12 PM" ou "23:00-05:00" $patternInterval = '/(\d{1,2})([:h]?(\d{1,2}))?\s*(AM|PM)?\s*[-–]\s*(\d{1,2})([:h]?(\d{1,2}))?\s*(AM|PM)?/iu'; foreach ($parts as $part) { $part = trim($part); if (empty($part)) continue; // Détection d'un segment commençant par un nom de jour suivi d'un deux-points ou d'une virgule if (preg_match('/^(monday|tuesday|wednesday|thursday|friday|saturday|sunday|lundi|mardi|mercredi|jeudi|vendredi|samedi|dimanche)\s*,?\s*[:,]?\s*(.*)$/iu', $part, $match)) { $currentDay = $daysMapping[strtolower($match[1])]; $timeText = trim($match[2]); } // Si le segment correspond exactement à un nom de jour elseif (preg_match('/^(monday|tuesday|wednesday|thursday|friday|saturday|sunday|lundi|mardi|mercredi|jeudi|vendredi|samedi|dimanche)$/iu', $part, $match2)) { $currentDay = $daysMapping[strtolower($match2[1])]; continue; } else { if ($currentDay === null) continue; $timeText = $part; } if ($currentDay === null) continue; // Gérer "Closed" / "Fermé" if (stripos($timeText, 'closed') !== false || stripos($timeText, 'ferm') !== false) { continue; } // Gérer "Open 24 hours" et "Ouvert 24h/24" (et variantes) if (preg_match('/open\s+24\s*(hours|heures)|ouvert\s+24\s*h\/24|ouvert\s+24h/i', $timeText)) { $result[$currentDay] = [['start'=>'00:00', 'end'=>'24:00']]; continue; } // Tester l'intervalle if (preg_match($patternInterval, $timeText, $matches)) { $startHour = (int)$matches[1]; $startMinute = (isset($matches[3]) && $matches[3] !== '') ? (int)$matches[3] : 0; $endHour = (int)$matches[5]; $endMinute = (isset($matches[7]) && $matches[7] !== '') ? (int)$matches[7] : 0; $startMeridiem = isset($matches[4]) ? strtoupper($matches[4]) : ''; $endMeridiem = isset($matches[8]) ? strtoupper($matches[8]) : ''; // Si aucun AM/PM n'est fourni, on considère que c'est en format 24h if ($startMeridiem === '' && $endMeridiem === '') { // Rien à faire, c'est du 24h } else { // Gestion AM/PM manquants if (empty($startMeridiem)) { if (!empty($lastMeridiem[$currentDay])) { $startMeridiem = $lastMeridiem[$currentDay]; } elseif (!empty($endMeridiem)) { $startMeridiem = $endMeridiem; } else { $startMeridiem = 'AM'; } } if ($startMeridiem === 'PM' && $startHour < 12) { $startHour += 12; } elseif ($startMeridiem === 'AM' && $startHour == 12) { $startHour = 0; } if (empty($endMeridiem)) { if (!empty($lastMeridiem[$currentDay])) { $endMeridiem = $lastMeridiem[$currentDay]; } else { $endMeridiem = 'AM'; } } if ($endMeridiem === 'PM' && $endHour < 12) { $endHour += 12; } elseif ($endMeridiem === 'AM' && $endHour == 12) { $endHour = 0; } $lastMeridiem[$currentDay] = $endMeridiem; } // Gestion des horaires overnight (ex: 23:00-05:00) if ($endHour < $startHour) { // Intervalle pour le jour courant : [startHour,24:00] $result[$currentDay][] = [ 'start' => sprintf("%02d:%02d", $startHour, $startMinute), 'end' => "24:00" ]; // Jour suivant $order = ['MO','TU','WE','TH','FR','SA','SU']; $index = array_search($currentDay, $order); $nextIndex = ($index + 1) % count($order); $nextDay = $order[$nextIndex]; // Intervalle pour le jour suivant : [00:00,endHour] $result[$nextDay][] = [ 'start' => "00:00", 'end' => sprintf("%02d:%02d", $endHour, $endMinute) ]; } else { $result[$currentDay][] = [ 'start' => sprintf("%02d:%02d", $startHour, $startMinute), 'end' => sprintf("%02d:%02d", $endHour, $endMinute) ]; } } } return $result; } /** * Encode les intervalles d'un jour en une chaîne binaire sur 96 segments (15 minutes chacun) * puis convertit cette chaîne en hexadécimal. */ function hours_encodeDayWithBinary($intervals, &$binaryOut = null) { $bits = array_fill(0, 96, 0); foreach ($intervals as $interval) { list($startHour, $startMinute) = explode(':', $interval['start']); list($endHour, $endMinute) = explode(':', $interval['end']); $startIndex = (int) ($startHour * 4 + ($startMinute / 15)); $endIndex = (int) ($endHour * 4 + ($endMinute / 15)); for ($i = $startIndex; $i < $endIndex && $i < 96; $i++) { $bits[$i] = 1; } } $binaryString = implode('', $bits); $binaryOut = $binaryString; $hexString = ''; for ($i = 0; $i < 96; $i += 4) { $group = substr($binaryString, $i, 4); $hexDigit = strtoupper(dechex(bindec($group))); $hexString .= $hexDigit; } return $hexString; } /** * Fonction qui englobe la logique : prend un $raw (horaires bruts), * nettoie, parse, puis encode en hex. * Retourne un tableau : * [ * 'hex' => [ 'MO'=>'...','TU'=>'...',... ], * 'binary' => [ 'MO'=>'...','TU'=>'...',... ] * ] */ /* function hours_encodeRawHoursToHex($raw) { // 1) Nettoyage $clean = hours_cleanHours($raw); // 2) Parsing $parsed = hours_parseHours($clean); // 3) Encodage $encodedHex = []; $encodedBinary = []; foreach (['MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU'] as $day) { $hex = hours_encodeDayWithBinary($parsed[$day], $bin); $encodedHex[$day] = $hex; $encodedBinary[$day] = $bin; } return ['hex' => $encodedHex, 'binary' => $encodedBinary]; } */ function hours_encodeRawHoursToHex($raw) { // 1) Nettoyage $clean = hours_cleanHours($raw); // 2) Parsing $parsed = hours_parseHours($clean); // Vérifier si le parsing est vide if (empty($parsed) || !is_array($parsed)) { return; } // 3) Encodage $encodedHex = []; $encodedBinary = []; foreach (['MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU'] as $day) { if (!isset($parsed[$day])) { continue; // Ignore les jours absents } $hex = hours_encodeDayWithBinary($parsed[$day], $bin); $encodedHex[$day] = $hex; $encodedBinary[$day] = $bin; } // Si tout est vide, ne rien retourner if (empty($encodedHex) && empty($encodedBinary)) { return; } return ['hex' => $encodedHex, 'binary' => $encodedBinary]; } /************************************** * 2) DECODAGE ET FONCTIONS ANNEXES * **************************************/ /** * Convertit un index de quart d'heure en format "HH:MM". */ function hours_quarterToTime($index) { $hour = floor($index / 4); $minute = ($index % 4) * 15; return sprintf("%02d:%02d", $hour, $minute); } /** * Décode une chaîne hexadécimale représentant une journée en intervalles horaires. */ function hours_decodeDay($hex) { $binaryString = ''; for ($i = 0; $i < strlen($hex); $i++) { $digit = $hex[$i]; $binaryString .= str_pad(base_convert($digit, 16, 2), 4, '0', STR_PAD_LEFT); } $intervals = []; $inInterval = false; $startIndex = 0; for ($i = 0; $i < 96; $i++) { if (!$inInterval && $binaryString[$i] === '1') { $inInterval = true; $startIndex = $i; } elseif ($inInterval && $binaryString[$i] === '0') { $inInterval = false; $endIndex = $i; $intervals[] = [ 'start' => hours_quarterToTime($startIndex), 'end' => hours_quarterToTime($endIndex) ]; } } // Si on termine la journée en étant encore ouvert if ($inInterval) { $intervals[] = [ 'start' => hours_quarterToTime($startIndex), 'end' => hours_quarterToTime(96) ]; } return $intervals; } /** * Décode l'ensemble des horaires encodés (hexadécimal) de la semaine. * Retourne un tableau, par ex: * [ * 'MO' => "09:00-12:00, 14:00-18:00", * 'TU' => "08:30-12:15, ...", * ... * ] */ function hours_decodeHours($encodedHex) { $decoded = []; foreach ($encodedHex as $day => $hex) { $intervals = hours_decodeDay($hex); $intervalsStr = []; foreach ($intervals as $interval) { $intervalsStr[] = $interval['start'] . '-' . $interval['end']; } $decoded[$day] = implode(', ', $intervalsStr); } return $decoded; } /** * **hours_parseOpeningHours** : * Reçoit un tableau d’hexa (ou la partie ['hex'] de `hours_encodeRawHoursToHex`), * décode pour chaque jour, puis renvoie un format exploitable * par l’affichage graphique : * [ * 'Monday' => [[9.0,12.0], [14.0, 18.0]], * 'Tuesday' => [ ... ], * ... * ] * On simplifie en exprimant les heures sous forme de flottants (HH + MM/60). */ function hours_parseOpeningHours($encodedHex) { $dayMap = [ 'MO' => 'Monday', 'TU' => 'Tuesday', 'WE' => 'Wednesday', 'TH' => 'Thursday', 'FR' => 'Friday', 'SA' => 'Saturday', 'SU' => 'Sunday' ]; $decoded = hours_decodeHours($encodedHex); $result = [ 'Monday' => [], 'Tuesday' => [], 'Wednesday' => [], 'Thursday' => [], 'Friday' => [], 'Saturday' => [], 'Sunday' => [], ]; // $decoded[ 'MO' ] = "09:00-12:00, 14:00-18:00" foreach ($decoded as $dayCode => $intervalStr) { if (!isset($dayMap[$dayCode])) { continue; } $dayName = $dayMap[$dayCode]; if (trim($intervalStr) === '') { // Aucune plage (fermé toute la journée) continue; } $intervalsList = explode(',', $intervalStr); foreach ($intervalsList as $interval) { $interval = trim($interval); if (!$interval) { continue; } list($start, $end) = explode('-', $interval); // start = "09:00", end = "12:00" list($sh, $sm) = explode(':', $start); list($eh, $em) = explode(':', $end); $startFloat = intval($sh) + (intval($sm)/60); $endFloat = intval($eh) + (intval($em)/60); $result[$dayName][] = [$startFloat, $endFloat]; } } return $result; } /************************************ * 3) AFFICHAGE GRAPHIQUE (CALENDRIER) ************************************/ /** * Affiche les horaires (en blocs horaires) sous forme de grille. * Entrée: $openingHoursHex = tableau hexa * $currentTimeChange = string ("+2 hours", "+30 minutes", etc.) ou null */ function hours_displayOpeningHours($openingHoursHex, $currentTimeChange) { //echo '


'; $days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]; // Convertir le format de l'heure actuelle en objet DateTime $currentTime = new DateTime(); if ($currentTimeChange !== null) { $currentTime->modify($currentTimeChange); } $currentDay = $currentTime->format("l"); // Nom du jour actuel $currentHour = $currentTime->format("G"); // Heure actuelle $currentMinute = $currentTime->format("i"); // Parse des horaires hex -> structure $hoursArray = hours_parseOpeningHours($openingHoursHex); // Tableau de traduction des jours (anglais->français), pour l'affichage $daysTranslation = [ "Monday" => "Lundi", "Tuesday" => "Mardi", "Wednesday" => "Mercredi", "Thursday" => "Jeudi", "Friday" => "Vendredi", "Saturday" => "Samedi", "Sunday" => "Dimanche", ]; // Afficher les heures au-dessus de chaque colonne (0h..23h) $displayHours = "
"; $displayHours .= "
"; // Espace pour le nom du jour for ($i = 0; $i < 24; $i++) { $style = "width: 13px; text-align: left; font-size: 8px; transform: rotate(270deg); margin-bottom:5px; overflow:visible;"; // Mettre en gras l'heure actuelle if ($i == $currentHour) { $style .= "font-weight: bold; font-size:9px;"; } // Affichage éventuel des minutes (optionnel) $displayMinute = ($i == $currentHour) ? $currentMinute : ''; $displayHours .= "
".str_pad($i, 2, "0", STR_PAD_LEFT)."h$displayMinute
"; } $displayHours .= "
"; // On crée le tableau jour x heures $displayHours .= "
"; foreach ($days as $day) { $displayHours .= "
"; // Nom du jour (français), en gras si c'est le jour courant $displayHours .= "" . $daysTranslation[$day] . ""; // Récupère les plages pour ce jour $dayHours = isset($hoursArray[$day]) ? $hoursArray[$day] : []; // De 0h à 23h (24 cases) for ($i = 0; $i < 24; $i++) { $style = "width: 10px; height: 15px; margin-right: 3px; border-radius: 2px;"; $isOpen = false; // On vérifie si l'heure $i tombe dans l'une des plages foreach ($dayHours as $range) { list($start, $end) = $range; // start/end sont des floats (ex: 9.0, 9.5, 14.0...) // Gestion "overnight" simplifiée: ($start > $end) => on considère qu'on traverse minuit // Ici, on reste basique: si i se trouve dans le créneau, c'est open if (($start < $end && $i >= $start && $i < $end) || ($start > $end && ($i >= $start || $i < $end))) { $isOpen = true; break; } } // Couleur selon ouvert/fermé if ($isOpen) { $style .= "background-color: #58D68D;"; // Vert } else { $style .= "background-color: #EBEDEF;"; // Gris } // Si c'est le jour actuel et l'heure actuelle => on surligne différemment if ($day === $currentDay && $i == $currentHour) { if ($isOpen) { $style .= "background-color: #145A32;"; // Vert foncé } else { $style .= "background-color: #EC7063;"; // Rouge clair } } $displayHours .= "
"; } $displayHours .= "
"; } $displayHours .= "
"; // On peut echo ou return return $displayHours; } /************************************ * 4) FONCTION DE TRI POUR L’AFFICHAGE ************************************/ /** * Sortie attendue : chaîne qui colle le jour actuel en premier. * Exemple : "Monday>09:00-12:00,14:00-18:00|Tuesday>Closed|..." */ function hours_sortOpeningHours($openingHoursHex, $timeNow) { $dayMap = [ 'MO' => 'Monday', 'TU' => 'Tuesday', 'WE' => 'Wednesday', 'TH' => 'Thursday', 'FR' => 'Friday', 'SA' => 'Saturday', 'SU' => 'Sunday' ]; // On décode d'abord $decoded = hours_decodeHours($openingHoursHex); // On crée un tableau type [ [ "Monday", "09:00-12:00,14:00-18:00" ], ... ] $final = []; foreach ($dayMap as $dc => $dn) { // Si pas d'intervalle => c'est fermé $final[] = [$dn, isset($decoded[$dc]) && $decoded[$dc] !== '' ? $decoded[$dc] : 'Closed']; } // On repositionne le jour actuel en premier $currentDay = date('l', strtotime($timeNow)); $index = -1; foreach ($final as $i => $val) { if ($val[0] === $currentDay) { $index = $i; break; } } if ($index >= 0) { $final = array_merge(array_slice($final, $index), array_slice($final, 0, $index)); } // On bâtit la chaîne : "Monday>09:00-12:00,14:00-18:00|Tuesday>09:00-12:00|..." $parts = []; foreach ($final as $f) { $parts[] = $f[0].'>'.$f[1]; } return implode('|', $parts); } /************************************ * 5) AFFICHAGE TEXTUEL (MENU DÉROULANT) ************************************/ /** * Affiche la liste des horaires de la semaine dans un menu déroulant, * en commençant par le jour actuel. On reçoit en entrée le tableau hexa. * * Dépend de hours_sortOpeningHours(...). */ function hours_hoursTextualDisplay($openingHoursHex, $timeNow) { $sortedOpeningHours = hours_sortOpeningHours($openingHoursHex, $timeNow); // Ex: "Monday>09:00-12:00,14:00-18:00|Tuesday>Closed|..." $days = explode('|', $sortedOpeningHours); // Extraire $currentDay $currentDay = date('l', strtotime($timeNow)); // On va reconstruire un tableau exploitable plus facilement // Mais dans le code original, on voyait "array_search($currentDay, array_column($days, 0))" => // or on n'a pas un array de sub-arrays. On va juste itérer. // // On va juste afficher dans l'ordre, le jour actuel étant en premier dans $days. $daysTranslation = [ 'Monday' => 'Lundi', 'Tuesday' => 'Mardi', 'Wednesday' => 'Mercredi', 'Thursday' => 'Jeudi', 'Friday' => 'Vendredi', 'Saturday' => 'Samedi', 'Sunday' => 'Dimanche', ]; $output = ''; $rows = []; foreach ($days as $index => $dayLine) { if (!$dayLine) continue; // dayLine => "Monday>09:00-12:00,14:00-18:00" list($dayName, $hours) = explode('>', $dayLine); // Jour en français $dayNameFrench = isset($daysTranslation[$dayName]) ? $daysTranslation[$dayName] : $dayName; // Construire texte if (strcasecmp($hours, 'Closed') === 0) { $hoursText = "Fermé toute la journée"; } elseif (strcasecmp($hours, 'Open24hours') === 0) { $hoursText = "Ouvert 24h/24"; } elseif (strcasecmp($hours, 'Ouvert 24h/24') === 0) { $hoursText = "Ouvert 24h/24"; } else { // On affiche tel quel // (Possibilité de reformatter en HH:MM) $timeRanges = explode(',', $hours); $formattedTimeRanges = []; foreach ($timeRanges as $range) { // ex: "09:00-12:00" $range = trim($range); $formattedTimeRanges[] = $range; } $hoursText = implode(' puis ', $formattedTimeRanges); } $rows[] = [$dayNameFrench, $hoursText]; } // On affiche la première ligne + flèche, puis les autres sont hidden par défaut $output .= "
"; if (count($rows) > 0) { $output .= "
" . "" . $rows[0][0] . "
"; $output .= "
" . "" . $rows[0][1] . "
"; } $output .= "
"; // Le reste for ($i = 1; $i < count($rows); $i++) { $output .= ""; } // Script de toggle $output .= << var toggleState = false; function toggleRows() { var rows = document.querySelectorAll('.row'); for (var i = 1; i < rows.length; i++) { rows[i].style.display = (toggleState ? 'none' : 'block'); } toggleState = !toggleState; // Changer la flèche var fleche = document.querySelector('.fleche'); if (fleche) fleche.innerHTML = (toggleState ? '▲' : '▼'); } HTML; return $output; } /************************************ * 6) PROCHAINE RÉOUVERTURE ************************************/ /** * hours_delayOpenClose * * - Si l'établissement est ouvert, renvoie "Ferme dans 2h 30min." (ou "Ferme à 16:30." si vous préférez). * - S'il est fermé mais rouvrira plus tard dans la journée, renvoie "Rouvre dans 1h 15min." * - Si c'est fermé et que la prochaine ouverture est un autre jour, renvoie "Rouvre demain à 07:00." ou "Rouvre vendredi à 07:00." * */ function hours_delayOpenClose($openingHoursHex, $currentDateTime = 'now') { //=== Helpers internes ========================================= // Convertit "HH:MM" (ou un float) en float. Ex: "09:15" => 9.25 $timeToFloat = function($time) { if (is_numeric($time)) { // Déjà un float return floatval($time); } // Sinon c'est "HH:MM" list($h, $m) = explode(':', $time); return intval($h) + intval($m)/60; }; // Convertit un float (9.25) en "HH:MM" (09:15). $floatToTime = function($float) { $h = floor($float); $m = ($float - $h) * 60; return sprintf('%02d:%02d', $h, $m); }; // Renvoie la différence entre deux horaires "HH:MM" en minutes (peut être négative si end < start). $minutesDifference = function($start, $end) use ($timeToFloat) { $startFloat = $timeToFloat($start); $endFloat = $timeToFloat($end); return round(($endFloat - $startFloat) * 60); }; // Formate un nombre de minutes en style "2h 30min" $formatMinutes = function($minutes) { if ($minutes <= 0) { return "0 min"; } $h = floor($minutes / 60); $m = $minutes % 60; if ($h > 0 && $m > 0) { return $h.'h '.$m.'min'; } elseif ($h > 0) { return $h.'h'; } else { return $m.'min'; } }; // Recherche du prochain jour où ça ouvre $daysTranslation = [ 'Monday' => 'lundi', 'Tuesday' => 'mardi', 'Wednesday' => 'mercredi', 'Thursday' => 'jeudi', 'Friday' => 'vendredi', 'Saturday' => 'samedi', 'Sunday' => 'dimanche', ]; $getNextOpening = function($parsed, DateTime $dateObj) use ($daysTranslation, $floatToTime) { // On essaie de voir dans les 7 jours suivants for ($i = 1; $i <= 7; $i++) { $checkDate = (clone $dateObj)->modify("+{$i} days"); $checkDay = $checkDate->format('l'); $intervals = isset($parsed[$checkDay]) ? $parsed[$checkDay] : []; if (count($intervals) > 0) { // On prend la 1ère plage $startFloat = $intervals[0][0]; $startHM = $floatToTime($startFloat); // "09:00" if ($i == 1) { return "Rouvre demain à {$startHM}."; } $jourFR = isset($daysTranslation[$checkDay]) ? $daysTranslation[$checkDay] : $checkDay; return "Rouvre {$jourFR} à {$startHM}."; } } // Si rien trouvé, fermé toute la semaine return ""; }; //=== Corps principal ======================================== // Parse -> [ "Monday" => [[9.0,12.0], [14.0,18.0]], ... ] $parsed = hours_parseOpeningHours($openingHoursHex); // Jour et heure courante $date = new DateTime($currentDateTime); $currentDay = $date->format('l'); // "Monday" $currentHM = $date->format('H:i'); // "14:00" $currentF = $timeToFloat($currentHM); // ex: 14.0 // Intervalles aujourd'hui $intervalsToday = isset($parsed[$currentDay]) ? $parsed[$currentDay] : []; // 1) Aucune plage => fermé toute la journée => on cherche la prochaine ouverture if (count($intervalsToday) === 0) { return $getNextOpening($parsed, $date); } // 2) Parcourt les intervalles pour voir où l'heure courante se situe foreach ($intervalsToday as $interval) { list($startF, $endF) = $interval; // ex: [9.0, 12.0] if ($currentF < $startF) { // Fermé jusqu'à $startF $startHM = $floatToTime($startF); // "09:00" // Diff en minutes $diffM = $minutesDifference($currentHM, $startHM); // "Rouvre dans 2h" ou "Rouvre à 09:00" // Au choix, on peut faire : return "Rouvre dans ".$formatMinutes($diffM)."."; // ou => return "Rouvre à {$startHM}."; } elseif ($currentF >= $startF && $currentF < $endF) { // On est DANS la plage => c’est ouvert $endHM = $floatToTime($endF); $diffM = $minutesDifference($currentHM, $endHM); return "Ferme dans ".$formatMinutes($diffM)."."; // ou => return "Ferme à {$endHM}."; } // sinon, $currentF >= $endF => on check la plage suivante } // 3) Si on est passé hors de toutes les plages (après la dernière) => fermé => chercher la prochaine ouverture (jour suivant) return $getNextOpening($parsed, $date); } /************************************ * 7) TEST OUVERT/FERMÉ MINIMALISTE ************************************/ /** * Indique si c'est ouvert ou fermé à l'heure actuelle (approximation à l'heure pleine). * $openingHoursHex : le tableau hexa * $currentTimeChange : ex "+2 hours", null... */ function hours_isOpenNowMinimalist($openingHoursHex, $currentTimeChange = null) { // Convertir le format de l'heure actuelle en objet DateTime $currentTime = new DateTime(); if ($currentTimeChange !== null) { $currentTime->modify($currentTimeChange); } $currentDay = $currentTime->format("l"); // Monday, ... $currentHour = $currentTime->format("G"); //$currentMinute = $currentTime->format("i"); // non utilisé ici // On parse en plages $hoursArray = hours_parseOpeningHours($openingHoursHex); // Récupère les plages du jour actuel $dayHours = isset($hoursArray[$currentDay]) ? $hoursArray[$currentDay] : []; // On teste si l'heure courante tombe dans une plage foreach ($dayHours as $range) { list($start, $end) = $range; // ex: [9.0, 12.0] // Test simpliste : on ignore les minutes if ($currentHour >= floor($start) && $currentHour < ceil($end)) { // Pour un affichage stylé return " Ouvert. "; } } return " Fermé. "; } ?>
Warning: Cannot modify header information - headers already sent by (output started at /var/www/vhosts/yutugo.com/httpdocs/include/functions.php:1) in /var/www/vhosts/yutugo.com/httpdocs/index.php on line 34

Fatal error: Uncaught Error: Call to undefined function latlng_to_location() in /var/www/vhosts/yutugo.com/httpdocs/index.php:293 Stack trace: #0 {main} thrown in /var/www/vhosts/yutugo.com/httpdocs/index.php on line 293