First Commit

This commit is contained in:
marco
2026-09-01 10:46:29 -03:00
commit bf96b77e9c
10000 changed files with 3508600 additions and 0 deletions
+42
View File
@@ -0,0 +1,42 @@
<?php
namespace App\Helpers;
/**
* SysCMS - Encryption Helper
*
* Simple AES-256-CBC encryption for sensitive data like API Keys.
*/
class Crypto
{
private static $cipher = "AES-256-CBC";
/**
* Encrypts a string using the APP_KEY as secret
*/
public static function encrypt(string $data): string
{
$key = substr(hash('sha256', env('APP_KEY', 'syscms-default-key')), 0, 32);
$ivlen = openssl_cipher_iv_length(self::$cipher);
$iv = openssl_random_pseudo_bytes($ivlen);
$ciphertext = openssl_encrypt($data, self::$cipher, $key, $options = 0, $iv);
return base64_encode($iv . $ciphertext);
}
/**
* Decrypts a string
*/
public static function decrypt(string $data): string
{
try {
$key = substr(hash('sha256', env('APP_KEY', 'syscms-default-key')), 0, 32);
$decoded = base64_decode($data);
$ivlen = openssl_cipher_iv_length(self::$cipher);
$iv = substr($decoded, 0, $ivlen);
$ciphertext = substr($decoded, $ivlen);
return openssl_decrypt($ciphertext, self::$cipher, $key, $options = 0, $iv);
} catch (\Exception $e) {
return $data; // Return original if decryption fails (e.g. not encrypted yet)
}
}
}
+132
View File
@@ -0,0 +1,132 @@
<?php
namespace App\Helpers;
use Illuminate\Database\Capsule\Manager as DB;
class DateFormatter
{
private static $defaultFormat = 'd/m/Y';
private static $cachedFormat = null;
/**
* Format a date according to the company's configuration.
*
* @param string|null $date The date string (Y-m-d or Y-m-d H:i:s).
* @param bool $includeTime Whether to include time in the formatted string.
* @return string
*/
public static function format(?string $date, bool $includeTime = false): string
{
if (empty($date)) {
return '';
}
// Try to detect if date is already formatted (simple check for '/')
if (strpos($date, '/') !== false) {
return $date;
}
try {
$format = self::getCompanyDateFormat();
// If the format is just date but time is requested, append time format
if ($includeTime) {
// Heuristic: if format doesn't seem to have time, add it
if (strpos($format, 'H') === false) {
$format .= ' H:i';
}
}
$timestamp = strtotime($date);
if ($timestamp === false) {
return $date; // Return original if parsing fails
}
return date($format, $timestamp);
} catch (\Exception $e) {
// Fallback
return date(self::$defaultFormat . ($includeTime ? ' H:i' : ''), strtotime($date));
}
}
/**
* Get the date format for the current company.
* Caches the result in memory (static property) and session.
*
* @return string
*/
private static function getCompanyDateFormat(): string
{
if (self::$cachedFormat) {
return self::$cachedFormat;
}
// Check session
if (isset($_SESSION['bus_date_format'])) {
self::$cachedFormat = $_SESSION['bus_date_format'];
return self::$cachedFormat;
}
// Fetch from database if user is logged in
if (isset($_SESSION['user_bus_id'])) {
try {
$busId = $_SESSION['user_bus_id'];
$company = DB::table('bus')
->where('bus_id', $busId)
->select('bus_date_format')
->first();
if ($company && !empty($company->bus_date_format)) {
$_SESSION['bus_date_format'] = $company->bus_date_format;
self::$cachedFormat = $company->bus_date_format;
return self::$cachedFormat;
}
} catch (\Exception $e) {
// Log error if needed, but return default for now
}
}
// Fallback default
self::$cachedFormat = self::$defaultFormat;
return self::$cachedFormat;
}
/**
* Converts a formatted date back to MySQL format (Y-m-d).
*
* @param string $date Formatted date string
* @return string|null Y-m-d formatted date or null on failure
*/
public static function toMySQL(string $date): ?string
{
if (empty($date)) {
return null;
}
// If already Y-m-d (contains - and no /)
if (strpos($date, '-') !== false && strpos($date, '/') === false) {
return $date;
}
// Try to parse from company format
$format = self::getCompanyDateFormat();
$d = \DateTime::createFromFormat($format, $date);
if ($d && $d->format($format) === $date) {
return $d->format('Y-m-d');
}
// Try common fallback formats
$formats = ['d/m/Y', 'm/d/Y', 'Y/m/d'];
foreach ($formats as $fmt) {
$d = \DateTime::createFromFormat($fmt, $date);
if ($d && $d->format($fmt) === $date) {
return $d->format('Y-m-d');
}
}
return null;
}
}
+173
View File
@@ -0,0 +1,173 @@
<?php
/**
* SysCMS - Content Management System
*
* Copyright (c) 2025 Marco Costa
* All rights reserved.
*
* Author: Marco Costa
* Email: contato@syspanel.com.br
* Project: SysCMS
*
* This software is licensed, not sold.
* Permission is granted to use this software
* subject to the terms of the SysCMS Commercial License.
*
* Redistribution, sublicensing, resale, or
* disclosure of this software, in whole or in part,
* is strictly prohibited without prior written permission.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
*/
use Dotenv\Dotenv;
if (!function_exists('load_env')) {
/**
* Loads environment variables from the .env file
*
* @param string|null $path Path to the project root directory
* @return void
*/
function load_env(?string $path = null): void
{
static $loaded = false;
if ($loaded) {
return;
}
$path = $path ?? dirname(__DIR__, 2);
if (file_exists($path . '/.env')) {
$dotenv = Dotenv::createImmutable($path);
$dotenv->load();
$loaded = true;
}
}
}
if (!function_exists('get_env')) {
/**
* Gets an environment variable with a default value
*
* @param string $key Variable name
* @param mixed $default Default value if not exists
* @return mixed
*/
function get_env(string $key, $default = null)
{
return $_ENV[$key] ?? $_SERVER[$key] ?? $default;
}
}
if (!function_exists('env')) {
/**
* Alias for get_env to maintain compatibility
*
* @param string $key Variable name
* @param mixed $default Default value if not exists
* @return mixed
*/
function env(string $key, $default = null)
{
return get_env($key, $default);
}
}
if (!function_exists('env_bool')) {
/**
* Gets an environment variable as boolean
*
* @param string $key Variable name
* @param bool $default Default value if not exists
* @return bool
*/
function env_bool(string $key, bool $default = false): bool
{
$value = get_env($key, $default);
if (is_bool($value)) {
return $value;
}
return filter_var($value, FILTER_VALIDATE_BOOLEAN);
}
}
if (!function_exists('env_int')) {
/**
* Gets an environment variable as integer
*
* @param string $key Variable name
* @param int $default Default value if not exists
* @return int
*/
function env_int(string $key, int $default = 0): int
{
return (int) get_env($key, $default);
}
}
if (!function_exists('get_db_config')) {
/**
* Gets database configuration from environment variables
*
* @return array
*/
function get_db_config(): array
{
return [
'driver' => get_env('DB_DRIVER', get_env('DB_CONNECTION', 'mysql')),
'host' => get_env('DB_HOST', 'localhost'),
'port' => get_env('DB_PORT', '3306'),
'database' => get_env('DB_DATABASE', 'syscms'),
'username' => get_env('DB_USERNAME', 'root'),
'password' => get_env('DB_PASSWORD', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
];
}
}
if (!function_exists('get_app_config')) {
/**
* Gets application configuration from environment variables
*
* @return array
*/
function get_app_config(): array
{
return [
'name' => get_env('APP_NAME', 'SysCMS'),
'env' => get_env('APP_ENV', 'development'),
'debug' => env_bool('APP_DEBUG', true),
'url' => get_env('APP_URL', 'http://localhost:16240'),
'timezone' => get_env('APP_TIMEZONE', 'America/Sao_Paulo'),
'key' => get_env('APP_KEY', ''),
];
}
}
if (!function_exists('get_mail_config')) {
/**
* Gets email configuration from environment variables
*
* @return array
*/
function get_mail_config(): array
{
return [
'transport' => get_env('MAIL_TRANSPORT', 'smtp'),
'host' => get_env('MAIL_HOST', 'localhost'),
'port' => get_env('MAIL_PORT', '587'),
'username' => get_env('MAIL_USERNAME', ''),
'password' => get_env('MAIL_PASSWORD', ''),
'encryption' => get_env('MAIL_ENCRYPTION', 'tls'),
'from_address' => get_env('MAIL_FROM_ADDRESS', ''),
'from_name' => get_env('MAIL_FROM_NAME', 'SysCMS'),
];
}
}
+58
View File
@@ -0,0 +1,58 @@
<?php
namespace App\Helpers;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
class Log
{
private static $logger;
private static function getLogger()
{
if (!self::$logger) {
self::$logger = new Logger('syscms');
// Logs should be in /logs as per RULES.md
$logPath = __DIR__ . '/../../logs/app.log';
$logDir = dirname($logPath);
if (!is_dir($logDir)) {
mkdir($logDir, 0777, true);
}
self::$logger->pushHandler(new StreamHandler($logPath, Logger::DEBUG));
}
return self::$logger;
}
public static function info($message, array $context = [])
{
self::getLogger()->info($message, $context);
}
public static function error($message, array $context = [])
{
self::getLogger()->error($message, $context);
}
public static function warning($message, array $context = [])
{
self::getLogger()->warning($message, $context);
}
public static function debug($message, array $context = [])
{
self::getLogger()->debug($message, $context);
}
/**
* Specialized write for audit logs
*/
public static function write($message, $module = 'general', $context = [])
{
if (!is_array($context)) {
$context = [];
}
$context['module'] = $module;
self::getLogger()->info($message, $context);
}
}
+221
View File
@@ -0,0 +1,221 @@
<?php
namespace App\Helpers;
/**
* Helper para gerenciar o Editor Quill no sistema SysCMS
*/
class QuillHelper
{
/**
* Renderiza um campo de texto com o editor Quill
*
* @param string $name Nome do campo
* @param string $id ID do elemento
* @param string $value Valor inicial
* @param array $options Opções adicionais
* @return string HTML do campo com o editor
*/
public static function renderEditor(string $name, string $id, string $value = '', array $options = []): string
{
// Opções padrão
$defaultOptions = [
'class' => 'quill-editor',
'style' => 'height: 300px;',
'placeholder' => 'Digite seu conteúdo aqui...'
];
// Mesclar opções
$options = array_merge($defaultOptions, $options);
// Construir atributos
$attributes = '';
foreach ($options as $key => $value) {
if ($key !== 'value') {
$attributes .= ' ' . $key . '="' . htmlspecialchars($value) . '"';
}
}
// Retornar HTML do campo
return sprintf(
'<textarea name="%s" id="%s"%s>%s</textarea>',
htmlspecialchars($name),
htmlspecialchars($id),
$attributes,
htmlspecialchars($value)
);
}
/**
* Renderiza um campo de texto simples (sem Quill)
*
* @param string $name Nome do campo
* @param string $id ID do elemento
* @param string $value Valor inicial
* @param array $options Opções adicionais
* @return string HTML do campo
*/
public static function renderTextarea(string $name, string $id, string $value = '', array $options = []): string
{
// Opções padrão
$defaultOptions = [
'class' => 'form-control',
'rows' => 5
];
// Mesclar opções
$options = array_merge($defaultOptions, $options);
// Construir atributos
$attributes = '';
foreach ($options as $key => $value) {
if ($key !== 'value') {
$attributes .= ' ' . $key . '="' . htmlspecialchars($value) . '"';
}
}
// Retornar HTML do campo
return sprintf(
'<textarea name="%s" id="%s"%s>%s</textarea>',
htmlspecialchars($name),
htmlspecialchars($id),
$attributes,
htmlspecialchars($value)
);
}
/**
* Renderiza um campo de texto com editor (Quill ou textarea simples)
* baseado na configuração do sistema
*
* @param string $name Nome do campo
* @param string $id ID do elemento
* @param string $value Valor inicial
* @param array $options Opções adicionais
* @return string HTML do campo
*/
public static function renderField(string $name, string $id, string $value = '', array $options = []): string
{
// Verificar se o Quill está habilitado
$useQuill = self::isQuillEnabled();
if ($useQuill) {
return self::renderEditor($name, $id, $value, $options);
} else {
return self::renderTextarea($name, $id, $value, $options);
}
}
/**
* Verifica se o editor Quill está habilitado no sistema
*
* @return bool True se o Quill estiver habilitado
*/
public static function isQuillEnabled(): bool
{
// Verificar variável de ambiente
$useQuill = getenv('APP_EDITOR_QUILL') ?: 'true';
return filter_var($useQuill, FILTER_VALIDATE_BOOLEAN);
}
/**
* Obtém a configuração do Quill em formato JSON
*
* @return string Configuração em formato JSON
*/
public static function getQuillConfig(): string
{
$config = [
'theme' => 'snow',
'placeholder' => 'Digite seu conteúdo aqui...',
'modules' => [
'toolbar' => [
['bold', 'italic', 'underline', 'strike'],
['blockquote', 'code-block'],
[{ 'header': [1, 2] }],
[{ 'list': 'ordered'}, { 'list': 'bullet' }],
[{ 'script': 'sub'}, { 'script': 'super' }],
[{ 'indent': '-1'}, { 'indent': '+1' }],
[{ 'direction': 'rtl' }],
[{ 'size': ['small', false, 'large', 'huge'] }],
[{ 'header': [1, 2, 3, 4, 5, 6, false] }],
[{ 'color': [] }, { 'background': [] }],
[{ 'font': [] }],
[{ 'align': [] }],
['link', 'image'],
['clean']
]
]
];
return json_encode($config);
}
/**
* Renderiza o script de inicialização do Quill
*
* @return string Script de inicialização
*/
public static function renderInitScript(): string
{
if (!self::isQuillEnabled()) {
return '';
}
$config = self::getQuillConfig();
$configJson = json_encode($config);
return <<<HTML
<script>
// Configuração personalizada do Quill
const quillSysConfig = {$configJson};
// Sobrescrever configuração padrão se necessário
if (typeof window.quillDefaultConfig !== 'undefined') {
window.quillDefaultConfig = Object.assign(window.quillDefaultConfig, quillSysConfig);
}
</script>
HTML;
}
/**
* Limpa o conteúdo HTML gerado pelo Quill para segurança
*
* @param string $html Conteúdo HTML
* @return string HTML limpo
*/
public static function sanitizeHtml(string $html): string
{
// Lista de tags permitidas
$allowedTags = '<p><br><strong><em><u><s><h1><h2><h3><h4><h5><h6><ul><ol><li><blockquote><pre><code><a><img>';
// Remover atributos perigosos
$html = strip_tags($html, $allowedTags);
// Remover atributos de estilo e eventos
$html = preg_replace('/\s*(on\w+|style|id|class)=["\'][^"\']*["\']/', '', $html);
return $html;
}
/**
* Converte o conteúdo do Quill para texto puro
*
* @param string $html Conteúdo HTML
* @return string Texto puro
*/
public static function htmlToText(string $html): string
{
// Remover tags HTML
$text = strip_tags($html);
// Converter entidades HTML
$text = html_entity_decode($text, ENT_QUOTES, 'UTF-8');
// Normalizar espaços em branco
$text = preg_replace('/\s+/', ' ', $text);
return trim($text);
}
}