['label' => 'Nome da aplicação', 'type' => 'text', 'required' => true], 'email_from' => ['label' => 'Email remetente', 'type' => 'email', 'required' => true], 'email_from_name' => ['label' => 'Nome do remetente', 'type' => 'text', 'required' => true], 'email_subject_prefix' => ['label' => 'Prefixo do assunto', 'type' => 'text', 'required' => false], 'reminder_hours' => ['label' => 'Horas de reminder', 'type' => 'number','required' => true], // Public contacts are NOT here: the site reads them from fitme3070_info, // edited in Gestão → Contactos (views/admin/info/edit.php). The fleet // template's contact_* / social_* settings were unused and got edited by // mistake, so they were removed from this form. // SEO defaults — used by site/includes/head.php when a page doesn't // set its own $page_title / $page_description / $page_image override. 'seo_default_title' => ['label' => 'SEO — título por defeito', 'type' => 'text', 'required' => false], 'seo_default_description' => ['label' => 'SEO — descrição por defeito', 'type' => 'text', 'required' => false], 'seo_keywords' => ['label' => 'SEO — palavras-chave', 'type' => 'text', 'required' => false], 'seo_twitter_handle' => ['label' => 'SEO — Twitter handle', 'type' => 'text', 'required' => false], 'seo_locale' => ['label' => 'SEO — locale (og:locale)', 'type' => 'text', 'required' => false], 'seo_title_separator' => ['label' => 'SEO — separador do título', 'type' => 'text', 'required' => false], ]; $current = settings_all(); $values = []; foreach ($fields as $key => $_) { $values[$key] = (string) ($current[$key] ?? ''); } $logo_light = (string) ($current['logo_light_filename'] ?? ''); $logo_dark = (string) ($current['logo_dark_filename'] ?? ''); $seo_image = (string) ($current['seo_default_image_filename'] ?? ''); $seo_dir = __DIR__ . '/../../assets/img/seo/'; function _settings_handle_logo_upload(array $file, string $dir, array $allowed, int $max, ?string $previous, array &$errors, string $kind): ?string { if (!isset($file['error']) || $file['error'] === UPLOAD_ERR_NO_FILE) { return null; } if ($file['error'] !== UPLOAD_ERR_OK) { $errors[] = "Falha no upload do logo {$kind}."; return null; } if ($file['size'] > $max) { $errors[] = "O logo {$kind} excede 2 MB."; return null; } // Tipo decidido pelo conteúdo, não pelo nome; SVG só sem scripts // (config/functions_images.php). $ext = upload_image_ext($file, $allowed); if ($ext === null) { $errors[] = "Tipo de ficheiro não permitido (ou SVG com conteúdo ativo) para o logo {$kind}."; return null; } if (!is_dir($dir) && !@mkdir($dir, 0755, true) && !is_dir($dir)) { $errors[] = "Não foi possível criar a pasta do logo {$kind}."; return null; } $name = bin2hex(random_bytes(16)) . '.' . $ext; if (!move_uploaded_file($file['tmp_name'], $dir . $name)) { $errors[] = "Não foi possível guardar o logo {$kind}."; return null; } if ($previous && $previous !== $name) { @unlink($dir . $previous); } return $name; } if ($_SERVER['REQUEST_METHOD'] === 'POST') { csrf_check(); foreach ($fields as $key => $meta) { $raw = trim((string) ($_POST[$key] ?? '')); $values[$key] = $raw; if ($meta['required'] && $raw === '') { $errors[] = "O campo \"{$meta['label']}\" é obrigatório."; continue; } if ($raw === '') continue; if ($meta['type'] === 'email' && !filter_var($raw, FILTER_VALIDATE_EMAIL)) { $errors[] = "Email inválido em \"{$meta['label']}\"."; } if ($meta['type'] === 'url' && !filter_var($raw, FILTER_VALIDATE_URL)) { $errors[] = "URL inválido em \"{$meta['label']}\"."; } if ($meta['type'] === 'number' && !ctype_digit($raw)) { $errors[] = "\"{$meta['label']}\" tem de ser um número inteiro."; } } $new_light = _settings_handle_logo_upload($_FILES['logo_light'] ?? [], $logo_dir, $allowed_ext, $max_upload, $logo_light, $errors, 'claro'); $new_dark = _settings_handle_logo_upload($_FILES['logo_dark'] ?? [], $logo_dir, $allowed_ext, $max_upload, $logo_dark, $errors, 'escuro'); // SEO share image — same upload helper, separate target directory. if (!is_dir($seo_dir)) @mkdir($seo_dir, 0755, true); $seo_allowed = ['png', 'jpg', 'jpeg', 'webp']; $new_seo_image = _settings_handle_logo_upload($_FILES['seo_default_image'] ?? [], $seo_dir, $seo_allowed, $max_upload, $seo_image, $errors, 'SEO'); if (!$errors) { $uid = (int) $_SESSION['user_id']; foreach ($fields as $key => $meta) { db_update_setting($pdo, $key, $values[$key], $uid); } if ($new_light !== null) { db_update_setting($pdo, 'logo_light_filename', $new_light, $uid); $logo_light = $new_light; } if ($new_dark !== null) { db_update_setting($pdo, 'logo_dark_filename', $new_dark, $uid); $logo_dark = $new_dark; } if ($new_seo_image !== null) { db_update_setting($pdo, 'seo_default_image_filename', $new_seo_image, $uid); $seo_image = $new_seo_image; } header('Location: ' . base_url('views/sysadmin/system_settings.php?updated=1')); exit; } } include __DIR__ . '/../../includes/header.php'; include __DIR__ . '/../../includes/navbar.php'; ?>