'youtube', 'id' => $id, 'thumb' => "https://i.ytimg.com/vi/$id/hqdefault.jpg"]; } if (preg_match('~dailymotion\.com/video/([A-Za-z0-9]+)|dai\.ly/([A-Za-z0-9]+)~i', $u, $m)) { $id = $m[1] ?: $m[2]; return ['provider' => 'dailymotion', 'id' => $id, 'thumb' => "https://www.dailymotion.com/thumbnail/video/$id"]; } $path = parse_url($u, PHP_URL_PATH) ?? ''; if (preg_match('~\.(mp4|webm|ogg)$~i', $path)) { return ['provider' => 'file', 'id' => null, 'thumb' => null]; } if (stripos($u, 'vimeo.com') !== false) { return ['provider' => 'vimeo', 'id' => null, 'thumb' => null]; } return ['provider' => 'other', 'id' => null, 'thumb' => null]; } // ID praticien $praticien_id = (int) ($_GET['id'] ?? 0); if ($praticien_id <= 0) { echo "
ID invalide.
"; exit; } // 1) Praticien $st = $pdo->prepare(" SELECT p.id, p.titre, p.nom, p.prenom, p.telephone, p.adresse, p.ville, p.code_postal, p.specialite, p.presentation, p.photo, p.video, p.disponibilite, COALESCE(pt.nom_affiche, p.nom) AS nom_affiche, COALESCE(pt.prenom_affiche, p.prenom) AS prenom_affiche, COALESCE(pt.ville_affichee, p.ville) AS ville_affichee, COALESCE(pt.titre, p.titre) AS titre_affiche, COALESCE(pt.specialite, p.specialite) AS specialite_affichee, COALESCE(pt.presentation, p.presentation) AS presentation_affichee, COALESCE(pt.disponibilite, p.disponibilite) AS disponibilite_affichee FROM praticien p LEFT JOIN praticien_traduction pt ON pt.praticien_id = p.id AND pt.langue = :lang WHERE p.id = :id LIMIT 1 "); $st->execute([ ':lang' => $currentLang, ':id' => $praticien_id, ]); $p = $st->fetch(PDO::FETCH_ASSOC); if (! $p) { echo "
" . ($translations['praticien_introuvable'] ?? 'Praticien introuvable') . "
"; exit; } $name = trim(($p['prenom_affiche'] ?? $p['prenom'] ?? '') . ' ' . ($p['nom_affiche'] ?? $p['nom'] ?? '')); $photo = ! empty($p['photo']) ? "/public/uploads/" . ltrim((string) $p['photo'], '/') : "/public/uploads/img/user_placeholder.png"; // Slug spécialité SEO depuis la valeur BDD $specSlug = ''; if (! empty($p['specialite'])) { $specDb = mb_strtolower(trim((string) $p['specialite']), 'UTF-8'); // 1) correspondance exacte foreach (seo_spec_map() as $slug => $cfg) { $dbVal = mb_strtolower(trim((string) ($cfg['db'] ?? '')), 'UTF-8'); if ($dbVal !== '' && $dbVal === $specDb) { $specSlug = $slug; break; } } // 2) commence par if ($specSlug === '') { foreach (seo_spec_map() as $slug => $cfg) { $dbVal = mb_strtolower(trim((string) ($cfg['db'] ?? '')), 'UTF-8'); if ($dbVal !== '' && mb_stripos($specDb, $dbVal, 0, 'UTF-8') === 0) { $specSlug = $slug; break; } } } // 3) contient if ($specSlug === '') { foreach (seo_spec_map() as $slug => $cfg) { $dbVal = mb_strtolower(trim((string) ($cfg['db'] ?? '')), 'UTF-8'); if ($dbVal !== '' && mb_stripos($specDb, $dbVal, 0, 'UTF-8') !== false) { $specSlug = $slug; break; } } } // 4) fallback propre : slug du texte libre if ($specSlug === '') { $specSlug = seo_slug((string) $p['specialite']); } } if ($specSlug === '') { $specSlug = 'specialiste'; } // Slug ville SEO $citySlug = ''; if (! empty($p['ville'])) { $citySlug = seo_city_slug_from_input((string) $p['ville']); } if ($citySlug === '') { $citySlug = 'france'; } // Slug nom $nameSlug = seo_slug($name); if ($nameSlug === '') { $nameSlug = 'profil'; } // URL SEO finale $prettyPath = '/specialistes/' . rawurlencode($specSlug) . '/' . rawurlencode($citySlug) . '/' . rawurlencode($nameSlug . '-' . (int) $p['id']) . '/'; $canonicalUrl = 'https://uslugi.fr' . $prettyPath; // Redirection 301 depuis ancienne URL $currentPath = parse_url($_SERVER['REQUEST_URI'] ?? '', PHP_URL_PATH) ?? ''; if ( ($currentPath === '/detail_public.php' || $currentPath === '/specialistes') && (int) ($_GET['id'] ?? 0) > 0 ) { $target = $prettyPath; $extra = $_GET; unset($extra['id'], $extra['slug']); if (! empty($extra)) { $target .= '?' . http_build_query($extra); } if (($_SERVER['REQUEST_URI'] ?? '') !== $target) { header('Location: ' . $target, true, 301); exit; } } // Variables SEO $seoTitle = $name; if (! empty($p['specialite_affichee'])) { $seoTitle .= ' — ' . $p['specialite_affichee']; } if (! empty($p['ville_affichee'])) { $seoTitle .= ' à ' . $p['ville_affichee']; } $seoTitle .= ' | Uslugi.fr'; $presentationShort = trim(strip_tags((string) ($p['presentation_affichee'] ?? $p['presentation'] ?? ''))); if ($presentationShort !== '') { $presentationShort = mb_substr($presentationShort, 0, 155, 'UTF-8'); } $seoDesc = $presentationShort !== '' ? $presentationShort : ( $name . (! empty($p['specialite_affichee']) ? ' — ' . $p['specialite_affichee'] : '') . (! empty($p['ville_affichee']) ? ' à ' . $p['ville_affichee'] : '') . '.' ); // 2) Vidéos additionnelles $vs = $pdo->prepare("SELECT id, url, title, ordre FROM praticien_video WHERE praticien_id=? ORDER BY ordre ASC, id DESC"); $vs->execute([$praticien_id]); $videos = $vs->fetchAll(PDO::FETCH_ASSOC); // 3) Avis: moyenne + total + dernier $avg = $pdo->prepare("SELECT ROUND(AVG(note),1) AS m, COUNT(*) AS c FROM avis_praticien WHERE praticien_id=? AND statut='publie'"); $avg->execute([$praticien_id]); $stats = $avg->fetch(PDO::FETCH_ASSOC) ?: ['m' => null, 'c' => 0]; $last = $pdo->prepare(" SELECT a.note, a.titre, a.commentaire, a.visit_date, a.created_at, c.prenom, c.nom FROM avis_praticien a LEFT JOIN client c ON c.id = a.client_id WHERE a.praticien_id = ? AND a.statut = 'publie' ORDER BY a.created_at DESC LIMIT 1 "); $last->execute([$praticien_id]); $lrow = $last->fetch(PDO::FETCH_ASSOC); ?> <?php echo h($seoTitle) ?>

:
:
:
:
:
:
<?php
                echo h(
                    trim($name)
                    . (! empty($p['specialite_affichee']) ? ' — ' . $p['specialite_affichee'] : '')
                    . (! empty($p['ville_affichee']) ? ' à ' . $p['ville_affichee'] : '')
                    . ' — Uslugi.fr'
            );
            ?>
★★★★★
★★★★★
: /5
()
★★★★★
★★★★★
•