'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);
?>