| Server IP : 46.105.57.169 / Your IP : 216.73.217.35 Web Server : Apache System : Linux webm002.cluster120.gra.hosting.ovh.net 6.18.42-ovh-vps-grsec-zfs+ #1 SMP PREEMPT_DYNAMIC Wed Aug 5 15:59:48 CEST 2026 x86_64 User : verseaumee ( 152031) PHP Version : 8.5.7 Disable Function : _dyuweyrj4,_dyuweyrj4r,dl MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /home/verseaumee/quaadraa/app/Controllers/ |
Upload File : |
<?php
namespace App\Controllers;
use App\Core\Lang;
use App\Core\Security;
use App\Models\PageModel;
use App\Models\NewsModel;
use App\Models\SubsidiaryModel;
use App\Models\Database;
class PageController
{
private string $lang;
public function __construct(private Lang $langService)
{
$this->lang = $langService->getCurrent();
date_default_timezone_set('Africa/Lome');
}
private function render(string $view, array $data = []): void
{
$data['lang'] = $this->lang;
$data['langService'] = $this->langService;
$data['t'] = fn(string $k, array $r = []) => $this->langService->t($k, $r);
$data['e'] = fn(mixed $v) => Security::e($v);
$data['config'] = require dirname(__DIR__, 2) . '/config.php';
extract($data, EXTR_SKIP);
$viewFile = dirname(__DIR__, 2) . "/views/{$view}.php";
if (!file_exists($viewFile)) {
http_response_code(500);
die("View not found: {$view}");
}
$layoutFile = dirname(__DIR__, 2) . '/views/layout.php';
require $layoutFile;
}
private function view(string $view, array $data = []): string
{
ob_start();
extract($data, EXTR_SKIP);
require dirname(__DIR__, 2) . "/views/{$view}.php";
return ob_get_clean();
}
public function home(array $params = []): void
{
$featured = NewsModel::getFeatured($this->lang, 4);
$grouped = SubsidiaryModel::groupedByPole($this->lang);
$this->render('pages/home', [
'title' => 'QUAADRAA — Growth Accelerator',
'meta_desc' => $this->langService->t('meta.home_desc'),
'featured' => $featured,
'grouped' => $grouped,
'page' => 'home',
]);
}
public function about(array $params = []): void
{
$slug = $this->lang === 'fr' ? 'qui-sommes-nous' : 'about';
$page = PageModel::getBySlug($slug, $this->lang);
$this->render('pages/about', [
'title' => $this->langService->t('nav.about') . ' — QUAADRAA',
'meta_desc' => $page['meta_desc'] ?? '',
'page' => 'about',
'pageData' => $page,
]);
}
public function vision(array $params = []): void
{
$this->render('pages/vision', [
'title' => $this->langService->t('nav.vision') . ' — QUAADRAA',
'meta_desc'=> $this->langService->t('meta.vision_desc'),
'page' => 'vision',
]);
}
public function activities(array $params = []): void
{
$grouped = SubsidiaryModel::groupedByPole($this->lang);
$this->render('pages/activities', [
'title' => $this->langService->t('nav.activities') . ' — QUAADRAA',
'meta_desc'=> $this->langService->t('meta.activities_desc'),
'grouped' => $grouped,
'page' => 'activities',
]);
}
public function pole(array $params = []): void
{
$pole = $params['pole'] ?? '';
$subs = SubsidiaryModel::getByPole($pole, $this->lang);
if (empty($subs)) {
http_response_code(404);
$this->render('errors/404', ['title' => '404']);
return;
}
$poleLabel = $this->langService->t("poles.{$pole}");
$this->render('pages/pole', [
'title' => $poleLabel . ' — QUAADRAA',
'meta_desc' => "Découvrez le pôle {$poleLabel} du groupe QUAADRAA.",
'pole' => $pole,
'poleLabel' => $poleLabel,
'subs' => $subs,
'page' => 'activities',
]);
}
public function subsidiary(array $params = []): void
{
$slug = $params['slug'] ?? '';
$sub = SubsidiaryModel::getBySlug($slug, $this->lang);
if (!$sub) {
http_response_code(404);
$this->render('errors/404', ['title' => '404']);
return;
}
$newsRel = Database::fetchAll(
'SELECT * FROM news WHERE subsidiary_id = (SELECT id FROM subsidiaries WHERE slug = :slug)
AND lang = :lang AND is_published = 1 ORDER BY published_at DESC LIMIT 3',
[':slug' => $slug, ':lang' => $this->lang]
);
$this->render('pages/subsidiary', [
'title' => $sub['name'] . ' — QUAADRAA',
'meta_desc'=> $sub['meta_desc'],
'sub' => $sub,
'newsRel' => $newsRel,
'page' => 'activities',
]);
}
public function newsList(array $params = []): void
{
$config = require dirname(__DIR__, 2) . '/config.php';
$perPage = $config['pagination']['news_per_page'];
$currentPage = max(1, (int)($_GET['p'] ?? 1));
$total = NewsModel::count($this->lang);
$news = NewsModel::getAll($this->lang, $currentPage, $perPage);
$pages = (int)ceil($total / $perPage);
$this->render('pages/news-list', [
'title' => $this->langService->t('nav.news') . ' — QUAADRAA',
'meta_desc' => $this->langService->t('meta.news_desc'),
'news' => $news,
'currentPage' => $currentPage,
'totalPages' => $pages,
'page' => 'news',
]);
}
public function newsDetail(array $params = []): void
{
$slug = $params['slug'] ?? '';
$article = NewsModel::getBySlug($slug, $this->lang);
if (!$article) {
http_response_code(404);
$this->render('errors/404', ['title' => '404']);
return;
}
$this->render('pages/news-detail', [
'title' => $article['title'] . ' — QUAADRAA',
'meta_desc'=> $article['excerpt'],
'article' => $article,
'page' => 'news',
]);
}
public function contact(array $params = []): void
{
$this->render('pages/contact', [
'title' => $this->langService->t('nav.contact') . ' — QUAADRAA',
'meta_desc'=> $this->langService->t('meta.contact_desc'),
'page' => 'contact',
'csrf' => Security::csrfToken(),
'success' => false,
'errors' => [],
]);
}
public function contactSubmit(array $params = []): void
{
Security::verifyCsrf();
if (!empty($_POST['website_check'])) {
Security::log('SPAM_DETECTED', 'Tentative via honeypot depuis IP: ' . ($_SERVER['REMOTE_ADDR'] ?? 'inconnue'));
$this->render('pages/contact', [
'title' => $this->langService->t('nav.contact') . ' — QUAADRAA',
'success' => true,
'errors' => [],
'csrf' => Security::csrfToken(),
'page' => 'contact',
]);
return;
}
if (!Security::rateLimit('contact_' . ($_SERVER['REMOTE_ADDR'] ?? 'unknown'), 3, 600)) {
Security::log('RATE_LIMIT_EXCEEDED', 'Limitation atteinte par IP: ' . ($_SERVER['REMOTE_ADDR'] ?? 'inconnue'));
$this->render('pages/contact', [
'title' => $this->langService->t('nav.contact') . ' — QUAADRAA',
'errors' => ['rate' => $this->langService->t('contact.rate_limit')],
'success' => false,
'csrf' => Security::csrfToken(),
'page' => 'contact',
]);
return;
}
$errors = [];
$name = trim($_POST['full_name'] ?? '');
$email = Security::sanitizeEmail($_POST['email'] ?? '');
$phone = trim($_POST['phone'] ?? '');
$company = trim($_POST['company'] ?? '');
$subject = trim($_POST['subject'] ?? '');
$message = trim($_POST['message'] ?? '');
if (strlen($name) < 2) $errors['full_name'] = $this->langService->t('contact.err_name');
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) $errors['email'] = $this->langService->t('contact.err_email');
if (strlen($subject) < 3) $errors['subject'] = $this->langService->t('contact.err_subject');
if (strlen($message) < 10) $errors['message'] = $this->langService->t('contact.err_message');
if (!empty($errors)) {
$this->render('pages/contact', [
'title' => $this->langService->t('nav.contact') . ' — QUAADRAA',
'errors' => $errors,
'old' => $_POST,
'success' => false,
'csrf' => Security::csrfToken(),
'page' => 'contact',
]);
return;
}
Database::insert(
'INSERT INTO contacts (full_name, email, phone, company, subject, message, lang, ip_address)
VALUES (:full_name, :email, :phone, :company, :subject, :message, :lang, :ip)',
[
':full_name' => $name,
':email' => $email,
':phone' => $phone,
':company' => $company,
':subject' => $subject,
':message' => $message,
':lang' => $this->lang,
':ip' => $_SERVER['REMOTE_ADDR'] ?? '',
]
);
$this->render('pages/contact', [
'title' => $this->langService->t('nav.contact') . ' — QUAADRAA',
'success' => true,
'errors' => [],
'csrf' => Security::csrfToken(),
'page' => 'contact',
]);
}
public static function getTranslatedUrlFromSlug(string $slug, string $targetLang): string
{
$map = [
'fr' => [
'about' => 'qui-sommes-nous',
'vision' => 'vision',
'activities' => 'activites',
'news' => 'actualites'
],
'en' => [
'qui-sommes-nous' => 'about',
'vision' => 'vision',
'activites' => 'activities',
'actualites' => 'news'
]
];
return $map[$targetLang][$slug] ?? $slug;
}
}