File: /homepages/35/d993672390/htdocs/dermiteseborrheique/includes/social.php
<?php
/**
* social.php — Fonctions utilitaires du module social
*/
declare(strict_types=1);
if (!defined('DS_APP')) die('Accès direct interdit.');
class Social
{
// ── Slug SEO ──────────────────────────────────────────────────────────────
public static function makeSlug(string $title, int $id): string
{
$slug = mb_strtolower($title);
$slug = str_replace(
['é','è','ê','ë','à','â','ä','î','ï','ô','ö','ù','û','ü','ç','œ','æ'],
['e','e','e','e','a','a','a','i','i','o','o','u','u','u','c','oe','ae'],
$slug
);
$slug = preg_replace('/[^a-z0-9\s-]/', '', $slug);
$slug = preg_replace('/[\s-]+/', '-', trim($slug));
$slug = mb_substr($slug, 0, 80);
$slug = rtrim($slug, '-');
return $id . '-' . $slug;
}
// ── URL d'un post ─────────────────────────────────────────────────────────
public static function postUrl(array $post): string
{
return url('social/post/' . $post['slug'] . '/');
}
// ── URL d'un profil ───────────────────────────────────────────────────────
public static function profileUrl(string $username): string
{
return url('social/u/' . rawurlencode($username) . '/');
}
// ── Sanitize body (markdown simplifié) ────────────────────────────────────
public static function renderBody(string $body): string
{
$body = e($body);
// Gras **text**
$body = preg_replace('/\*\*(.+?)\*\*/s', '<strong>$1</strong>', $body);
// Italique *text*
$body = preg_replace('/\*(.+?)\*/s', '<em>$1</em>', $body);
// Lien [texte](url)
$body = preg_replace(
'/\[([^\]]+)\]\((https?:\/\/[^\)]+)\)/',
'<a href="$2" rel="nofollow noopener" target="_blank">$1</a>',
$body
);
// Retours à la ligne
$body = nl2br($body);
return $body;
}
// ── Pseudo forum (auto si non défini) ────────────────────────────────────
public static function getForumUsername(array $user): string
{
return $user['forum_username'] ?? 'utilisateur_' . $user['id'];
}
// ── Vote ──────────────────────────────────────────────────────────────────
public static function vote(int $userId, string $type, int $targetId, int $value): array
{
// Récupérer vote existant
$existing = db_fetch(
"SELECT id, value FROM social_votes
WHERE user_id=? AND target_type=? AND target_id=?",
[$userId, $type, $targetId]
);
$table = $type === 'post' ? 'social_posts' : 'social_replies';
$delta = 0;
if ($existing) {
if ($existing['value'] === $value) {
// Annuler le vote
db_execute("DELETE FROM social_votes WHERE id=?", [$existing['id']]);
$delta = -$value;
} else {
// Changer le vote
db_execute("UPDATE social_votes SET value=? WHERE id=?", [$value, $existing['id']]);
$delta = $value * 2;
}
} else {
db_insert(
"INSERT INTO social_votes (user_id, target_type, target_id, value) VALUES (?,?,?,?)",
[$userId, $type, $targetId, $value]
);
$delta = $value;
}
if ($delta !== 0) {
db_execute("UPDATE {$table} SET score = score + ? WHERE id=?", [$delta, $targetId]);
// Karma de l'auteur
$authorId = db_fetch("SELECT user_id FROM {$table} WHERE id=?", [$targetId])['user_id'] ?? null;
if ($authorId && $authorId !== $userId) {
db_execute("UPDATE users SET forum_karma = forum_karma + ? WHERE id=?", [$delta, $authorId]);
}
}
$newScore = db_fetch("SELECT score FROM {$table} WHERE id=?", [$targetId])['score'] ?? 0;
return ['success' => true, 'score' => $newScore, 'delta' => $delta];
}
// ── Tags : parse & update ─────────────────────────────────────────────────
public static function parseTags(string $raw): array
{
$tags = array_map('trim', explode(',', $raw));
$tags = array_filter($tags, fn($t) => mb_strlen($t) >= 2 && mb_strlen($t) <= 30);
$tags = array_map(fn($t) => mb_strtolower(preg_replace('/[^a-z0-9\-éèêàâîôùûç ]/i', '', $t)), $tags);
return array_values(array_unique(array_slice($tags, 0, 5)));
}
public static function updateTagCounts(array $tags): void
{
foreach ($tags as $tag) {
$slug = self::makeTagSlug($tag);
db_execute(
"INSERT INTO social_tags (slug, label, post_count) VALUES (?,?,1)
ON DUPLICATE KEY UPDATE label=VALUES(label), post_count = post_count + 1",
[$slug, $tag]
);
}
}
public static function makeTagSlug(string $tag): string
{
$tag = mb_strtolower($tag);
$tag = str_replace(
['é','è','ê','ë','à','â','ä','î','ï','ô','ö','ù','û','ü','ç'],
['e','e','e','e','a','a','a','i','i','o','o','u','u','u','c'],
$tag
);
return preg_replace('/[^a-z0-9-]/', '-', trim($tag));
}
// ── Excerpt ───────────────────────────────────────────────────────────────
public static function excerpt(string $body, int $len = 160): string
{
// Stripper le markdown avant l'extrait
$plain = $body;
$plain = preg_replace('/\*\*(.+?)\*\*/s', '$1', $plain); // **gras**
$plain = preg_replace('/\*(.+?)\*/s', '$1', $plain); // *italique*
$plain = preg_replace('/\[([^\]]+)\]\([^\)]+\)/', '$1', $plain); // [lien](url)
$plain = preg_replace('/#{1,6}\s/', '', $plain); // # titres
$plain = strip_tags($plain);
$plain = preg_replace('/\s+/', ' ', trim($plain));
return mb_strlen($plain) > $len
? mb_substr($plain, 0, $len) . '…'
: $plain;
}
// ── Temps relatif ─────────────────────────────────────────────────────────
public static function timeAgo(string $datetime): string
{
$diff = time() - strtotime($datetime);
return match(true) {
$diff < 60 => 'à l\'instant',
$diff < 3600 => round($diff/60) . ' min',
$diff < 86400 => round($diff/3600) . 'h',
$diff < 604800 => round($diff/86400) . 'j',
default => date('d/m/Y', strtotime($datetime)),
};
}
// ── Vérification username disponible ──────────────────────────────────────
public static function isUsernameAvailable(string $username, int $excludeUserId = 0): bool
{
if (!preg_match('/^[a-zA-Z0-9_-]{3,30}$/', $username)) return false;
$count = db_count(
"SELECT COUNT(*) FROM users WHERE forum_username = ? AND id != ?",
[$username, $excludeUserId]
);
return $count === 0;
}
}