First Commit
This commit is contained in:
Executable
+42
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+132
@@ -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;
|
||||
}
|
||||
}
|
||||
Executable
+173
@@ -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'),
|
||||
];
|
||||
}
|
||||
}
|
||||
Executable
+58
@@ -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);
|
||||
}
|
||||
}
|
||||
Executable
+221
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user