| Current Path : /home/happyrenas/find.myreco.online/v2/ajax/ |
Linux webd005.cluster105.gra.hosting.ovh.net 5.15.206-ovh-vps-grsec-zfs-classid #1 SMP Fri May 15 02:41:25 UTC 2026 x86_64 |
| Current File : /home/happyrenas/find.myreco.online/v2/ajax/recherche_hebergements.php |
<?php
header('Content-Type: application/json; charset=utf-8');
session_start();
include("../configuration.php");
include("../includes/fonctions.php");
$debug_mode = (int)($_GET['debug'] ?? 0) === 1;
$ville_pays = trim($_GET['ville_pays'] ?? '');
$rayon_km = (int)($_GET['rayon_km'] ?? 10);
$nombre_voyageurs = (int)($_GET['nombre_voyageurs'] ?? 0);
$force_live = (int)($_GET['force_live'] ?? 0);
// Filtres (optionnels)
// - types: liste CSV (hotel,location,camping)
// - piscine: 1 (uniquement les hébergements avec piscine)
$types_param = trim($_GET['types'] ?? '');
$piscine = (int)($_GET['piscine'] ?? 0);
$allowed_types = ['hotel','location','camping'];
$types = [];
if ($types_param !== '') {
foreach (explode(',', strtolower($types_param)) as $t) {
$t = trim($t);
if ($t !== '' && in_array($t, $allowed_types, true)) $types[] = $t;
}
$types = array_values(array_unique($types));
}
if ($rayon_km <= 0) $rayon_km = 10;
if ($ville_pays === '') {
echo json_encode(['ok' => false, 'error' => "Veuillez sélectionner une ville."]);
exit;
}
$parts = array_map('trim', explode(',', $ville_pays));
$ville_clean = trim($parts[0] ?? '');
$postal_clean = '';
$pays_clean = '';
if (count($parts) >= 3) {
// Nouveau format : Ville, CP, FR
$postal_clean = trim($parts[1] ?? '');
$pays_clean = strtoupper(trim($parts[2] ?? ''));
} else {
// Ancien format : Ville, FR
$pays_clean = strtoupper(trim($parts[1] ?? ''));
}
if ($ville_clean === '' || $pays_clean === '') {
echo json_encode(['ok' => false, 'error' => "Format ville invalide. Utilisez : Ville, CP, FR"]);
exit;
}
$PLACEHOLDER_REL = '/img/placeholder.svg';
function applyPhotoSrc(&$results, $placeholderRel) {
$root = rtrim(UPLOADS_WWW_ROOT, '/');
foreach ($results as &$r) {
$pl = $r['photo_locale'] ?? '';
// Debug defaults
$r['photo_local_exists'] = false;
$r['photo_local_abs'] = null;
// si photo_locale ressemble à un chemin local
if (is_string($pl) && $pl !== '' && $pl[0] === '/') {
$abs = $root . $pl;
$r['photo_local_abs'] = $abs;
if (file_exists($abs)) {
$r['photo_local_exists'] = true;
$r['photo_src'] = $pl; // ✅ on affiche la locale
continue;
}
}
// sinon -> placeholder (et on n'affiche jamais l'externe)
$r['photo_src'] = $placeholderRel;
}
unset($r);
}
/* --------------------------------------------------------------------------
Filtres côté serveur (appliqués sur les résultats Live ou Cache)
- Laisse le cache stocker les résultats « complets »
- Filtre seulement la réponse JSON renvoyée au front
----------------------------------------------------------------------------*/
function _norm($s){
$s = strtolower(trim((string)$s));
// désaccentuer si possible
if ($s !== '' && function_exists('iconv')) {
$tmp = @iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $s);
if ($tmp !== false && $tmp !== '') $s = $tmp;
}
return $s;
}
function canon_type($raw){
$s = _norm($raw);
if ($s === '') return '';
// camping
if (strpos($s, 'camp') !== false) return 'camping';
// hotel
if (strpos($s, 'hotel') !== false) return 'hotel';
// location (gite / appart / maison / villa / chalet...)
if (
strpos($s, 'location') !== false ||
strpos($s, 'gite') !== false ||
strpos($s, 'appart') !== false ||
strpos($s, 'apartment') !== false ||
strpos($s, 'maison') !== false ||
strpos($s, 'villa') !== false ||
strpos($s, 'chalet') !== false ||
strpos($s, 'bnb') !== false
) return 'location';
// fallback
return '';
}
function has_piscine($item){
if (!is_array($item)) return false;
$eq = $item['equipements'] ?? null;
// cas: equipements = array
if (is_array($eq)) {
foreach ($eq as $v) {
$t = _norm($v);
if ($t !== '' && strpos($t, 'piscine') !== false) return true;
if ($t !== '' && strpos($t, 'pool') !== false) return true;
}
return false;
}
// cas: equipements = string
if (is_string($eq) && trim($eq) !== '') {
$t = _norm($eq);
return (strpos($t, 'piscine') !== false) || (strpos($t, 'pool') !== false);
}
return false;
}
function apply_filters($results, $types, $piscine, $debug_mode = false, &$filter_debug = []){
if (!is_array($results)) return [];
$types = is_array($types) ? $types : [];
$piscine = (int)$piscine === 1;
$filter_debug = [
'types_demandes' => $types,
'piscine' => $piscine,
'nb_avant_filtre' => count($results),
'items' => []
];
if (empty($types) && !$piscine) return $results;
$out = [];
foreach ($results as $it){
if (!is_array($it)) continue;
$rawType = $it['type_hebergement'] ?? ($it['type'] ?? '');
$ct = canon_type($rawType);
$keep_type = true;
if (!empty($types)) {
$keep_type = ($ct !== '' && in_array($ct, $types, true));
}
$keep_piscine = true;
if ($piscine) {
$keep_piscine = has_piscine($it);
}
if ($debug_mode) {
$filter_debug['items'][] = [
'id' => $it['id'] ?? '',
'name' => $it['name'] ?? '',
'type_hebergement_raw' => $rawType,
'type_canon' => $ct,
'keep_type' => $keep_type,
'keep_piscine' => $keep_piscine,
];
}
if (!$keep_type) continue;
if (!$keep_piscine) continue;
$out[] = $it;
}
$filter_debug['nb_apres_filtre'] = count($out);
return $out;
}
function normalizePhotosLocalJsonValue($value)
{
if (is_array($value)) {
return array_values(array_filter($value, function ($v) {
return is_string($v) && trim($v) !== '';
}));
}
if (!is_string($value) || trim($value) === '') {
return [];
}
$decoded = json_decode($value, true);
if (!is_array($decoded)) {
return [];
}
return array_values(array_filter($decoded, function ($v) {
return is_string($v) && trim($v) !== '';
}));
}
function patchPhotosLocalJson(&$results, $db)
{
if (!is_array($results) || empty($results)) {
return false;
}
$modified = false;
$tokens = [];
foreach ($results as $it) {
$token = trim((string)($it['token'] ?? ''));
if ($token !== '') {
$tokens[] = $token;
}
}
$tokens = array_values(array_unique($tokens));
if (empty($tokens)) {
foreach ($results as &$it) {
$it['photos_local_json'] = normalizePhotosLocalJsonValue($it['photos_local_json'] ?? []);
}
unset($it);
return false;
}
$escaped = array_map(function ($t) use ($db) {
return "'" . $db->escape($t) . "'";
}, $tokens);
$in = implode(',', $escaped);
$rows = $db->get_results("
SELECT token, photos_local_json
FROM heb
WHERE token IN ($in)
");
$map = [];
if ($rows) {
foreach ($rows as $r) {
$map[$r->token] = normalizePhotosLocalJsonValue($r->photos_local_json ?? '');
}
}
foreach ($results as &$it) {
$token = trim((string)($it['token'] ?? ''));
$current = normalizePhotosLocalJsonValue($it['photos_local_json'] ?? []);
if ($token !== '' && isset($map[$token])) {
if ($current !== $map[$token]) {
$modified = true;
}
$it['photos_local_json'] = $map[$token];
} else {
$it['photos_local_json'] = $current;
}
}
unset($it);
return $modified;
}
/* ✅ Cache serveur (sauf si force_live=1) */
if (!$force_live) {
$requete_cache = "
SELECT resultat_json, compteur
FROM ville_recherche_cache
WHERE ville = '" . $db->escape($ville_clean) . "'
AND postal_code = '" . $db->escape($postal_clean) . "'
AND nombre_voyageurs = " . (int)$nombre_voyageurs . "
AND pays = '" . $db->escape($pays_clean) . "'
AND rayon_km = " . (int)$rayon_km . "
LIMIT 1
";
$cache = $db->get_row($requete_cache);
if ($cache && !empty($cache->resultat_json)) {
$db->query("
UPDATE ville_recherche_cache
SET compteur = compteur + 1, last_search = NOW()
WHERE ville = '" . $db->escape($ville_clean) . "'
AND postal_code = '" . $db->escape($postal_clean) . "'
AND nombre_voyageurs = " . (int)$nombre_voyageurs . "
AND pays = '" . $db->escape($pays_clean) . "'
AND rayon_km = " . (int)$rayon_km . "
");
$results = json_decode($cache->resultat_json, true);
if (!is_array($results)) $results = [];
//applyPlaceholderIfMissingLocal($results, $PLACEHOLDER_REL);
/* ✅ PATCH : si des photo_locale sont désormais dispo en DB, on les remonte dans le cache */
$modified = false;
$tokens_missing = [];
$modified_photos_local = patchPhotosLocalJson($results, $db);
foreach ($results as $it) {
if (!empty($it['token']) && empty($it['photo_locale'])) {
$tokens_missing[] = $it['token'];
}
}
$tokens_missing = array_values(array_unique($tokens_missing));
if (!empty($tokens_missing)) {
$escaped = array_map(function($t) use ($db) {
return "'" . $db->escape($t) . "'";
}, $tokens_missing);
$in = implode(',', $escaped);
$rows = $db->get_results("
SELECT token, photo_locale
FROM heb
WHERE token IN ($in)
AND photo_locale IS NOT NULL
AND photo_locale <> ''
");
$map = [];
if ($rows) {
foreach ($rows as $r) {
$map[$r->token] = $r->photo_locale;
}
}
foreach ($results as &$it) {
if (!empty($it['token']) && empty($it['photo_locale']) && isset($map[$it['token']])) {
$it['photo_locale'] = $map[$it['token']];
$modified = true;
}
}
unset($it);
// ✅ On met à jour le JSON en cache pour les prochains hits
if ($modified || $modified_photos_local) {
$db->query("
UPDATE ville_recherche_cache
SET resultat_json = '" . $db->escape(json_encode($results, JSON_UNESCAPED_UNICODE)) . "'
WHERE ville = '" . $db->escape($ville_clean) . "'
AND postal_code = '" . $db->escape($postal_clean) . "'
AND nombre_voyageurs = " . (int)$nombre_voyageurs . "
AND pays = '" . $db->escape($pays_clean) . "'
AND rayon_km = " . (int)$rayon_km . "
LIMIT 1
");
}
}
// Appliquer les filtres sur les résultats (le cache reste complet)
$filtered = apply_filters($results, $types, $piscine);
applyPhotoSrc($filtered, $PLACEHOLDER_REL);
echo json_encode([
'ok' => true,
'from_cache' => true,
'ville' => $ville_clean,
'postal_code' => $postal_clean,
'nombre_voyageurs' => $nombre_voyageurs,
'pays' => $pays_clean,
'rayon_km' => $rayon_km,
'count' => count($filtered),
'results' => $filtered,
]);
exit;
}
}
/* Live */
$results_full = rechercherHebergementsProches($ville_pays, $db, $rayon_km,$nombre_voyageurs);
patchPhotosLocalJson($results_full, $db);
//applyPlaceholderIfMissingLocal($results, $PLACEHOLDER_REL);
if (isset($results_full['erreur'])) {
echo json_encode(['ok' => false, 'error' => $results_full['erreur']]);
exit;
}
if ($nombre_voyageurs) {
/* Upsert cache */
$requete_insert_cache = "
INSERT INTO ville_recherche_cache (ville, postal_code, pays, rayon_km, nombre_voyageurs, resultat_json, compteur, last_search)
VALUES (
'" . $db->escape($ville_clean) . "',
'" . $db->escape($postal_clean) . "',
'" . $db->escape($pays_clean) . "',
" . (int)$rayon_km . ",
" . (int)$nombre_voyageurs . ",
'" . $db->escape(json_encode($results_full, JSON_UNESCAPED_UNICODE)) . "',
1,
NOW()
)
ON DUPLICATE KEY UPDATE
resultat_json = VALUES(resultat_json),
compteur = compteur + 1,
last_search = NOW()
";
$db->query($requete_insert_cache);
}
// Appliquer les filtres sur les résultats (le cache reste complet)
$filter_debug = [];
$filtered = apply_filters($results_full, $types, $piscine, $debug_mode, $filter_debug);
applyPhotoSrc($filtered, $PLACEHOLDER_REL);
$response = [
'ok' => true,
'from_cache' => false,
'ville' => $ville_clean,
'postal_code' => $postal_clean,
'pays' => $pays_clean,
'rayon_km' => $rayon_km,
'nombre_voyageurs' => $nombre_voyageurs,
'count' => count($filtered),
'results' => $filtered,
];
if ($debug_mode) {
$response['debug_filter'] = $filter_debug;
$response['debug_recherche'] = [
'ville_pays' => $ville_pays,
'ville_clean' => $ville_clean,
'postal_clean' => $postal_clean,
'pays_clean' => $pays_clean,
'rayon_km' => $rayon_km,
'nombre_voyageurs' => $nombre_voyageurs,
'requete_insert_cache' => $requete_insert_cache ?? '',
];
}
echo json_encode($response, JSON_UNESCAPED_UNICODE);
exit;