simplificação de documentação

This commit is contained in:
Renan Bernordi 2025-01-29 20:46:05 -03:00
parent d9ef063243
commit 1f5fb428a3
19 changed files with 252 additions and 693 deletions

48
.gitignore vendored
View file

@ -6,46 +6,18 @@ app/cache/*.gz
TODO.md TODO.md
node_modules node_modules
# Created by https://www.toptal.com/developers/gitignore/api/composer,windows,macos,linux
# Edit at https://www.toptal.com/developers/gitignore?templates=composer,windows,macos,linux
### Composer ###
composer.phar composer.phar
/vendor/ /vendor/
# Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control
# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file
# composer.lock
### Linux ###
*~ *~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden* .fuse_hidden*
# KDE directory preferences
.directory .directory
# Linux trash folder which might appear on any partition or disk
.Trash-* .Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs* .nfs*
### macOS ###
# General
.DS_Store .DS_Store
.AppleDouble .AppleDouble
.LSOverride .LSOverride
# Icon must end with two \r
Icon Icon
# Thumbnails
._* ._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100 .DocumentRevisions-V100
.fseventsd .fseventsd
.Spotlight-V100 .Spotlight-V100
@ -53,42 +25,22 @@ Icon
.Trashes .Trashes
.VolumeIcon.icns .VolumeIcon.icns
.com.apple.timemachine.donotpresent .com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB .AppleDB
.AppleDesktop .AppleDesktop
Network Trash Folder Network Trash Folder
Temporary Items Temporary Items
.apdisk .apdisk
### macOS Patch ###
# iCloud generated files
*.icloud *.icloud
### Windows ###
# Windows thumbnail cache files
Thumbs.db Thumbs.db
Thumbs.db:encryptable Thumbs.db:encryptable
ehthumbs.db ehthumbs.db
ehthumbs_vista.db ehthumbs_vista.db
# Dump file
*.stackdump *.stackdump
# Folder config file
[Dd]esktop.ini [Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/ $RECYCLE.BIN/
# Windows Installer files
*.cab *.cab
*.msi *.msi
*.msix *.msix
*.msm *.msm
*.msp *.msp
# Windows shortcuts
*.lnk *.lnk
# End of https://www.toptal.com/developers/gitignore/api/composer,windows,macos,linux

View file

@ -1,7 +1,6 @@
FROM php:8.3-fpm FROM php:8.3-fpm
# Install PHP dependencies and extensions # Install PHP dependencies and extensions
# Instala dependências e extensões do PHP
RUN apt-get update && apt-get install -y \ RUN apt-get update && apt-get install -y \
nginx \ nginx \
nano \ nano \
@ -16,32 +15,30 @@ RUN apt-get update && apt-get install -y \
&& docker-php-ext-enable redis opcache && docker-php-ext-enable redis opcache
# Copy OPCache configuration # Copy OPCache configuration
# Copia a configuração do OPCache
COPY opcache.ini /usr/local/etc/php/conf.d/opcache.ini COPY opcache.ini /usr/local/etc/php/conf.d/opcache.ini
# Install Composer # Install Composer
# Instala o Composer RUN curl -sS https: //getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
# Copy webservice configuration # Copy webservice configuration
# Copia a configuração do webservice
COPY default.conf /etc/nginx/sites-available/default COPY default.conf /etc/nginx/sites-available/default
# Create and copy app folder
RUN mkdir -p /app RUN mkdir -p /app
COPY app/ /app/ COPY app/ /app/
# Install composer packages
WORKDIR /app WORKDIR /app
RUN composer install --no-interaction --optimize-autoloader RUN composer install --no-interaction --optimize-autoloader
# Copy and configure initialization script permissions # Copy and configure initialization script permissions
# Copia e configura permissões do script de inicialização
COPY docker-entrypoint.sh /usr/local/bin/ COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh RUN chmod +x /usr/local/bin/docker-entrypoint.sh
# Create cache and logs folders
RUN mkdir -p /app/cache /app/logs RUN mkdir -p /app/cache /app/logs
# Configure base permissions for /app directory # Configure base permissions for /app directory
# Configura permissões base para o diretório /app
RUN chown -R www-data:www-data /app \ RUN chown -R www-data:www-data /app \
&& chmod -R 755 /app && chmod -R 755 /app

View file

@ -1,84 +1,56 @@
<?php <?php
/** /**
* Main configuration file * System configuration manager
* Arquivo de configuração principal * - Loads and validates environment variables
* * - Defines global constants for system settings
* This file contains all global system settings, including: * - Manages security rules and external service configs
* Este arquivo contém todas as configurações globais do sistema, incluindo:
*
* - Environment variables loading / Carregamento de variáveis de ambiente
* - System constants definition / Definições de constantes do sistema
* - Security settings / Configurações de segurança
* - Bot and user agent settings / Configurações de bots e user agents
* - Blocked domains list / Lista de domínios bloqueados
* - S3 cache settings / Configurações de cache S3
*/ */
require_once __DIR__ . '/vendor/autoload.php'; require_once __DIR__ . '/vendor/autoload.php';
try { try {
// Initialize environment variables // Load environment variables
// Inicializa as variáveis de ambiente
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__); $dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load(); $dotenv->load();
// Validate required fields // Validate required fields
// Valida campos obrigatórios
$dotenv->required([ $dotenv->required([
'SITE_NAME', 'SITE_NAME',
'SITE_DESCRIPTION', 'SITE_DESCRIPTION',
'SITE_URL' 'SITE_URL'
])->notEmpty(); ])->notEmpty();
// Custom URL validation // Validate URL format
// Validação personalizada de URL
if (!filter_var($_ENV['SITE_URL'], FILTER_VALIDATE_URL)) { if (!filter_var($_ENV['SITE_URL'], FILTER_VALIDATE_URL)) {
throw new Exception('SITE_URL must be a valid URL'); throw new Exception('SITE_URL must be a valid URL');
} }
/** // Core system settings
* Basic system settings
* Configurações básicas do sistema
*/
define('SITE_NAME', $_ENV['SITE_NAME']); define('SITE_NAME', $_ENV['SITE_NAME']);
define('SITE_DESCRIPTION', $_ENV['SITE_DESCRIPTION']); define('SITE_DESCRIPTION', $_ENV['SITE_DESCRIPTION']);
define('SITE_URL', $_ENV['SITE_URL']); define('SITE_URL', $_ENV['SITE_URL']);
// Optional settings with default values // Optional settings with defaults
// Configurações opcionais com valores padrão
define('DNS_SERVERS', $_ENV['DNS_SERVERS'] ?? '1.1.1.1, 8.8.8.8'); define('DNS_SERVERS', $_ENV['DNS_SERVERS'] ?? '1.1.1.1, 8.8.8.8');
define('DISABLE_CACHE', isset($_ENV['DISABLE_CACHE']) ? define('DISABLE_CACHE', isset($_ENV['DISABLE_CACHE']) ? filter_var($_ENV['DISABLE_CACHE'], FILTER_VALIDATE_BOOLEAN) : false);
filter_var($_ENV['DISABLE_CACHE'], FILTER_VALIDATE_BOOLEAN) : false);
define('SELENIUM_HOST', $_ENV['SELENIUM_HOST'] ?? 'localhost:4444'); define('SELENIUM_HOST', $_ENV['SELENIUM_HOST'] ?? 'localhost:4444');
define('CACHE_DIR', __DIR__ . '/cache'); define('CACHE_DIR', __DIR__ . '/cache');
define('LANGUAGE', $_ENV['LANGUAGE'] ?? 'pt-br'); define('LANGUAGE', $_ENV['LANGUAGE'] ?? 'pt-br');
/** // Redis connection settings
* Redis settings
* Configurações do Redis
*/
define('REDIS_HOST', $_ENV['REDIS_HOST'] ?? 'localhost'); define('REDIS_HOST', $_ENV['REDIS_HOST'] ?? 'localhost');
define('REDIS_PORT', $_ENV['REDIS_PORT'] ?? 6379); define('REDIS_PORT', $_ENV['REDIS_PORT'] ?? 6379);
define('REDIS_PREFIX', $_ENV['REDIS_PREFIX'] ?? 'marreta:'); define('REDIS_PREFIX', $_ENV['REDIS_PREFIX'] ?? 'marreta:');
/** // Logging configuration
* Logging settings define('LOG_LEVEL', $_ENV['LOG_LEVEL'] ?? 'WARNING'); // DEBUG, INFO, WARNING, ERROR, CRITICAL
* Configurações de log
*/
define('LOG_LEVEL', $_ENV['LOG_LEVEL'] ?? 'WARNING'); // Available: DEBUG, INFO, WARNING, ERROR, CRITICAL
define('LOG_DAYS_TO_KEEP', 7); define('LOG_DAYS_TO_KEEP', 7);
/** // S3 cache configuration
* S3 Cache settings define('S3_CACHE_ENABLED', isset($_ENV['S3_CACHE_ENABLED']) ? filter_var($_ENV['S3_CACHE_ENABLED'], FILTER_VALIDATE_BOOLEAN) : false);
* Configurações de Cache S3
*/
define('S3_CACHE_ENABLED', isset($_ENV['S3_CACHE_ENABLED']) ?
filter_var($_ENV['S3_CACHE_ENABLED'], FILTER_VALIDATE_BOOLEAN) : false);
if (S3_CACHE_ENABLED) { if (S3_CACHE_ENABLED) {
// Validate required S3 settings when S3 cache is enabled
// Valida configurações obrigatórias do S3 quando o cache S3 está ativado
$dotenv->required([ $dotenv->required([
'S3_ACCESS_KEY', 'S3_ACCESS_KEY',
'S3_SECRET_KEY', 'S3_SECRET_KEY',
@ -94,10 +66,7 @@ try {
define('S3_ENDPOINT', $_ENV['S3_ENDPOINT'] ?? null); define('S3_ENDPOINT', $_ENV['S3_ENDPOINT'] ?? null);
} }
/** // Load security rules
* Load system configurations
* Carrega as configurações do sistema
*/
define('BLOCKED_DOMAINS', require __DIR__ . '/data/blocked_domains.php'); define('BLOCKED_DOMAINS', require __DIR__ . '/data/blocked_domains.php');
define('DOMAIN_RULES', require __DIR__ . '/data/domain_rules.php'); define('DOMAIN_RULES', require __DIR__ . '/data/domain_rules.php');
define('GLOBAL_RULES', require __DIR__ . '/data/global_rules.php'); define('GLOBAL_RULES', require __DIR__ . '/data/global_rules.php');

View file

@ -2,17 +2,13 @@
/** /**
* List of blocked domains * List of blocked domains
* Lista de domínios bloqueados
* *
* Defines domains that cannot be accessed by the system * Defines domains that cannot be accessed by the system
* due to usage policies or technical restrictions * due to usage policies or technical restrictions
*
* Define os domínios que não podem ser acessados pelo sistema
* por questões de política de uso ou restrições técnicas
*/ */
return [ return [
// News sites / Sites de notícias // News sites
//-- Content behind login access / Conteúdo fica atrás de um acesso de login //-- Content behind login access/hard paywall
'wsj.com', 'wsj.com',
'piaui.folha.uol.com.br', 'piaui.folha.uol.com.br',
'economist.com', 'economist.com',
@ -31,14 +27,15 @@ return [
'mittelbayerische.de', 'mittelbayerische.de',
'josimarfootball.com', 'josimarfootball.com',
'nordsee-zeitung.de', 'nordsee-zeitung.de',
//-- Technical access blocking / Bloqueio técnico de acesso ao conteúdo // List of common blocked sites to avoid unnecessary requests
//-- Technical access blocking
'bloomberg.com', 'bloomberg.com',
'sportskeeda.com', 'sportskeeda.com',
'kansascity.com', 'kansascity.com',
'fastcompany.com', 'fastcompany.com',
'expressnews.com', 'expressnews.com',
'nydailynews.com', 'nydailynews.com',
// Tracking services / Serviços de rastreamento //-- Tracking services
'metaffiliation.com', 'metaffiliation.com',
'google-analytics.com', 'google-analytics.com',
'googletagmanager.com', 'googletagmanager.com',
@ -59,7 +56,7 @@ return [
'fullstory.com', 'fullstory.com',
'heap.io', 'heap.io',
'clearbrain.com', 'clearbrain.com',
// Social networks / Redes sociais //-- Social networks
'facebook.com', 'facebook.com',
'instagram.com', 'instagram.com',
'twitter.com', 'twitter.com',
@ -73,7 +70,7 @@ return [
'redd.it', 'redd.it',
'bsky.app', 'bsky.app',
'threads.net', 'threads.net',
// Streaming services / Serviços de streaming //-- Streaming services
'netflix.com', 'netflix.com',
'hulu.com', 'hulu.com',
'disneyplus.com', 'disneyplus.com',
@ -81,32 +78,32 @@ return [
'spotify.com', 'spotify.com',
'youtube.com', 'youtube.com',
'twitch.tv', 'twitch.tv',
// E-commerce sites / Sites de comércio eletrônico //-- E-commerce sites
'amazon.com', 'amazon.com',
'ebay.com', 'ebay.com',
'aliexpress.com', 'aliexpress.com',
'mercadolivre.com.br', 'mercadolivre.com.br',
'shopify.com', 'shopify.com',
// File sharing / Compartilhamento de arquivos //-- File sharing
'mega.nz', 'mega.nz',
'mediafire.com', 'mediafire.com',
'wetransfer.com', 'wetransfer.com',
'dropbox.com', 'dropbox.com',
'torrent9.pe', 'torrent9.pe',
'thepiratebay.org', 'thepiratebay.org',
// Adult sites / Sites adultos //-- Adult sites
'pornhub.com', 'pornhub.com',
'xvideos.com', 'xvideos.com',
'xnxx.com', 'xnxx.com',
'onlyfans.com', 'onlyfans.com',
'privacy.com.br', 'privacy.com.br',
'fatalmodel.com', 'fatalmodel.com',
// Betting and gaming / Apostas e jogos //-- Betting and gaming
'bet365.com', 'bet365.com',
'betfair.com', 'betfair.com',
'pokerstars.com', 'pokerstars.com',
'casino.com', 'casino.com',
// Other popular sites / Outros sites populares //-- Other popular sites
'github.com', 'github.com',
'stackoverflow.com', 'stackoverflow.com',
'wikipedia.org', 'wikipedia.org',

View file

@ -2,38 +2,31 @@
/** /**
* Specific rule configurations for individual domains * Specific rule configurations for individual domains
* Configurações específicas de regras para domínios individuais
*
* This file contains custom rules for specific sites, allowing
* system behavior adjustment for each domain individually.
*
* Este arquivo contém regras personalizadas para sites específicos, permitindo
* ajustar o comportamento do sistema para cada domínio individualmente.
* *
* Domain rule structure / Estrutura das regras por domínio: * Domain rule structure / Estrutura das regras por domínio:
* - userAgent: Define custom User-Agent for the domain / Define um User-Agent personalizado para o domínio * - userAgent: Define custom User-Agent for the domain
* - headers: Custom HTTP headers for requests / Headers HTTP personalizados para requisições * - headers: Custom HTTP headers for requests
* - idElementRemove: Array of HTML IDs to be removed / Array de IDs HTML que devem ser removidos da página * - idElementRemove: Array of HTML IDs to be removed
* - classElementRemove: Array of HTML classes to be removed / Array de classes HTML que devem ser removidas * - classElementRemove: Array of HTML classes to be removed
* - scriptTagRemove: Array of scripts to be removed (partial match) / Array de scripts que devem ser removidos (partial match) * - scriptTagRemove: Array of scripts to be removed (partial match)
* - cookies: Associative array of cookies to be set (null removes cookie) / Array associativo de cookies a serem definidos (null remove o cookie) * - cookies: Associative array of cookies to be set (null removes cookie)
* - classAttrRemove: Array of classes to be removed from elements / Array de classes a serem removidas de elementos * - classAttrRemove: Array of classes to be removed from elements
* - customCode: String containing custom JavaScript code / String contendo código JavaScript personalizado * - customCode: String containing custom JavaScript code
* - customStyle: String containing custom CSS code / String contendo código CSS personalizado * - customStyle: String containing custom CSS code
* - excludeGlobalRules: Associative array of global rules to exclude for this domain / Array associativo de regras globais a serem excluídas para este domínio * - excludeGlobalRules: Associative array of global rules to exclude for this domain
* Example / Exemplo: * Example:
* 'excludeGlobalRules' => [ * 'excludeGlobalRules' => [
* 'scriptTagRemove' => ['gtm.js', 'ga.js'], // Excludes specific scripts from global rules / Exclui scripts específicos das regras globais * 'scriptTagRemove' => ['gtm.js', 'ga.js'],
* 'classElementRemove' => ['subscription'] // Excludes specific classes from global rules / Exclui classes específicas das regras globais * 'classElementRemove' => ['subscription']
* ] * ]
* - fetchStrategies: String indicating which fetch strategy to use. Available values: / String indicando qual estratégia de fetch usar. Valores disponíveis: * - fetchStrategies: String indicating which fetch strategy to use. Available values:
* - fetchContent: Use standard fetch with domain rules / Usa fetch padrão com regras do domínio * - fetchContent: Use standard fetch with domain rules
* - fetchFromWaybackMachine: Try to fetch from Internet Archive / Tenta buscar do Internet Archive * - fetchFromWaybackMachine: Try to fetch from Internet Archive
* - fetchFromSelenium: Use Selenium for extraction / Usa Selenium para extração * - fetchFromSelenium: Use Selenium for extraction
* - socialReferrers: Add random social media headers / Adiciona headers randomicos de redes sociais * - socialReferrers: Add random social media headers
* - fromGoogleBot: Adds simulation of request coming from Google Bot / Adiciona simulação de requisição vinda do Google Bot * - fromGoogleBot: Adds simulation of request coming from Google Bot
* - removeElementsByTag: Remove specific elements via DOM / Remove elementos especificos via DOM * - removeElementsByTag: Remove specific elements via DOM
* - removeCustomAttr: Remove custom attributes from elements / Remove custom attributes from elements * - removeCustomAttr: Remove custom attributes from elements
*/ */
return [ return [
'nsctotal.com.br' => [ 'nsctotal.com.br' => [

View file

@ -2,23 +2,12 @@
/** /**
* Global rule configurations applied to all domains * Global rule configurations applied to all domains
* Configurações globais de regras aplicadas a todos os domínios
*
* This file defines rules that are applied by default to all sites,
* organized into categories for better maintenance and understanding.
*
* Este arquivo define regras que são aplicadas por padrão a todos os sites,
* organizadas em categorias para melhor manutenção e compreensão.
* *
* Note: These rules can be overridden or disabled for specific domains * Note: These rules can be overridden or disabled for specific domains
* using the 'excludeGlobalRules' configuration in domain_rules.php * using the 'excludeGlobalRules' configuration in domain_rules.php
*
* Nota: Estas regras podem ser sobrescritas ou desativadas para domínios específicos
* usando a configuração 'excludeGlobalRules' em domain_rules.php
*/ */
return [ return [
// HTML classes to be removed from all pages // Classes to be removed from all pages:
// Classes HTML a serem removidas de todas as páginas
'classElementRemove' => [ 'classElementRemove' => [
'subscription', 'subscription',
'subscriber-content', 'subscriber-content',
@ -40,8 +29,7 @@ return [
'signup-overlay', 'signup-overlay',
'onesignal-slidedown-container' 'onesignal-slidedown-container'
], ],
// Scripts to be removed from all pages // Scripts to be removed from all pages:
// Scripts a serem removidos de todas as páginas
'scriptTagRemove' => [ 'scriptTagRemove' => [
'gtm.js', 'gtm.js',
'ga.js', 'ga.js',

View file

@ -6,48 +6,27 @@ use Inc\Cache\S3Storage;
use Inc\Cache\RedisStorage; use Inc\Cache\RedisStorage;
/** /**
* Class responsible for system cache management * System cache management with multiple storage backends (disk/S3)
* Classe responsável pelo gerenciamento de cache do sistema * Uses SHA-256 hashed URLs as unique identifiers
* * Implements gzip compression for space efficiency
* This class implements functionalities to store and retrieve
* cached content, supporting multiple storage backends (disk or S3).
* The cache is organized by URLs converted to unique IDs using SHA-256.
* Content is compressed using gzip to save space.
*
* Esta classe implementa funcionalidades para armazenar e recuperar
* conteúdo em cache, suportando múltiplos backends de armazenamento (disco ou S3).
* O cache é organizado por URLs convertidas em IDs únicos usando SHA-256.
* O conteúdo é comprimido usando gzip para economizar espaço.
*/ */
class Cache class Cache
{ {
/** /** @var CacheStorageInterface Cache storage implementation */
* @var CacheStorageInterface Storage implementation for cache
* @var CacheStorageInterface Implementação de storage para o cache
*/
private $storage; private $storage;
/** /** @var RedisStorage Redis instance for file counting */
* @var RedisStorage Redis instance for file counting
* @var RedisStorage Instância do Redis para contagem de arquivos
*/
private $redisStorage; private $redisStorage;
/** /**
* Class constructor * Initializes storage based on configuration
* Construtor da classe * Uses S3Storage if configured and enabled
* * Defaults to DiskStorage otherwise
* Initializes appropriate storage based on configuration
* Inicializa o storage apropriado baseado na configuração
*/ */
public function __construct() public function __construct()
{ {
// Initialize RedisStorage for file counting
// Inicializa o RedisStorage para contagem de arquivos
$this->redisStorage = new RedisStorage(CACHE_DIR); $this->redisStorage = new RedisStorage(CACHE_DIR);
// If S3 is configured and active, use S3Storage
// Se S3 está configurado e ativo, usa S3Storage
if (defined('S3_CACHE_ENABLED') && S3_CACHE_ENABLED === true) { if (defined('S3_CACHE_ENABLED') && S3_CACHE_ENABLED === true) {
$this->storage = new S3Storage([ $this->storage = new S3Storage([
'key' => S3_ACCESS_KEY, 'key' => S3_ACCESS_KEY,
@ -59,51 +38,30 @@ class Cache
'endpoint' => defined('S3_ENDPOINT') ? S3_ENDPOINT : null 'endpoint' => defined('S3_ENDPOINT') ? S3_ENDPOINT : null
]); ]);
} else { } else {
// Otherwise, use disk storage
// Caso contrário, usa o storage em disco
$this->storage = new DiskStorage(CACHE_DIR); $this->storage = new DiskStorage(CACHE_DIR);
} }
} }
/** /** Gets total number of cached files */
* Gets the count of cached files
* Obtém a contagem de arquivos em cache
*
* @return int Number of files in cache / Número de arquivos em cache
*/
public function getCacheFileCount(): int public function getCacheFileCount(): int
{ {
return $this->redisStorage->countCacheFiles(); return $this->redisStorage->countCacheFiles();
} }
/** /**
* Generates a unique ID for a URL * Generates unique cache ID from URL
* Gera um ID único para uma URL * Normalizes URL by removing protocol and www
* * Returns SHA-256 hash of normalized URL
* @param string $url URL for which the ID will be generated / URL para qual será gerado o ID
* @return string SHA-256 hash of the normalized URL / Hash SHA-256 da URL normalizada
*/ */
public function generateId($url) public function generateId($url)
{ {
// Remove protocol and www
// Remove protocolo e www
$url = preg_replace('#^https?://(www\.)?#', '', $url); $url = preg_replace('#^https?://(www\.)?#', '', $url);
// Generate unique ID using SHA-256
// Gera ID único usando SHA-256
return hash('sha256', $url); return hash('sha256', $url);
} }
/** /** Checks if cached version exists for URL */
* Checks if cache exists for a given URL
* Verifica se existe cache para uma determinada URL
*
* @param string $url URL to check / URL a ser verificada
* @return bool True if cache exists, False otherwise / True se existir cache, False caso contrário
*/
public function exists($url) public function exists($url)
{ {
// If DISABLE_CACHE is active, always return false
// Se DISABLE_CACHE está ativo, sempre retorna false
if (DISABLE_CACHE) { if (DISABLE_CACHE) {
return false; return false;
} }
@ -111,17 +69,9 @@ class Cache
return $this->storage->exists($this->generateId($url)); return $this->storage->exists($this->generateId($url));
} }
/** /** Retrieves cached content for URL */
* Retrieves cached content for a URL
* Recupera o conteúdo em cache de uma URL
*
* @param string $url URL of the content to retrieve / URL do conteúdo a ser recuperado
* @return string|null Cached content or null if it doesn't exist / Conteúdo em cache ou null se não existir
*/
public function get($url) public function get($url)
{ {
// If DISABLE_CACHE is active, always return null
// Se DISABLE_CACHE está ativo, sempre retorna null
if (DISABLE_CACHE) { if (DISABLE_CACHE) {
return null; return null;
} }
@ -129,18 +79,9 @@ class Cache
return $this->storage->get($this->generateId($url)); return $this->storage->get($this->generateId($url));
} }
/** /** Stores content in cache for URL */
* Stores content in cache for a URL
* Armazena conteúdo em cache para uma URL
*
* @param string $url URL associated with the content / URL associada ao conteúdo
* @param string $content Content to be cached / Conteúdo a ser armazenado em cache
* @return bool True if cache was saved successfully, False otherwise / True se o cache foi salvo com sucesso, False caso contrário
*/
public function set($url, $content) public function set($url, $content)
{ {
// If DISABLE_CACHE is active, don't generate cache
// Se DISABLE_CACHE está ativo, não gera cache
if (DISABLE_CACHE) { if (DISABLE_CACHE) {
return true; return true;
} }

View file

@ -3,39 +3,27 @@
namespace Inc\Cache; namespace Inc\Cache;
/** /**
* Interface for cache storage implementations * Defines the contract for cache storage implementations
* Interface para implementações de armazenamento de cache
*
* This interface defines the required methods for any cache storage implementation.
* Esta interface define os métodos necessários para qualquer implementação de armazenamento de cache.
*/ */
interface CacheStorageInterface interface CacheStorageInterface
{ {
/** /**
* Checks if cache exists for a given ID * Checks if cached content exists for given ID
* Verifica se existe cache para um determinado ID * @param string $id Unique cache identifier
*
* @param string $id Cache ID / ID do cache
* @return bool True if cache exists, false otherwise / True se o cache existir, false caso contrário
*/ */
public function exists(string $id): bool; public function exists(string $id): bool;
/** /**
* Retrieves cached content * Retrieves cached content by ID
* Recupera o conteúdo em cache * @return string|null Cached content or null if missing
*
* @param string $id Cache ID / ID do cache
* @return string|null Cached content or null if not found / Conteúdo em cache ou null se não encontrado
*/ */
public function get(string $id): ?string; public function get(string $id): ?string;
/** /**
* Stores content in cache * Stores content in cache with specified ID
* Armazena conteúdo em cache * @param string $id Cache entry identifier
* * @param string $content Content to store
* @param string $id Cache ID / ID do cache * @return bool Storage success status
* @param string $content Content to be stored / Conteúdo a ser armazenado
* @return bool True if successful, false otherwise / True se bem sucedido, false caso contrário
*/ */
public function set(string $id, string $content): bool; public function set(string $id, string $content): bool;
} }

View file

@ -3,25 +3,19 @@
namespace Inc\Cache; namespace Inc\Cache;
/** /**
* Disk-based cache storage implementation * Disk-based cache storage
* Implementação de armazenamento de cache em disco * Implements file-based caching using gzip compression
*
* This class implements file-based caching using gzip compression
* Esta classe implementa cache baseado em arquivos usando compressão gzip
*/ */
class DiskStorage implements CacheStorageInterface class DiskStorage implements CacheStorageInterface
{ {
/** /**
* @var string Directory where cache files will be stored * @var string Directory for cache files
* @var string Diretório onde os arquivos de cache serão armazenados
*/ */
private $cacheDir; private $cacheDir;
/** /**
* Class constructor * Class constructor
* Construtor da classe * @param string $cacheDir Base directory for cache storage
*
* @param string $cacheDir Base directory for cache storage / Diretório base para armazenamento do cache
*/ */
public function __construct(string $cacheDir) public function __construct(string $cacheDir)
{ {
@ -33,10 +27,8 @@ class DiskStorage implements CacheStorageInterface
/** /**
* Checks if cache exists for a given ID * Checks if cache exists for a given ID
* Verifica se existe cache para um determinado ID * @param string $id Cache ID
* * @return bool True if cache exists, false otherwise
* @param string $id Cache ID / ID do cache
* @return bool True if cache exists, false otherwise / True se o cache existir, false caso contrário
*/ */
public function exists(string $id): bool public function exists(string $id): bool
{ {
@ -46,10 +38,8 @@ class DiskStorage implements CacheStorageInterface
/** /**
* Retrieves cached content * Retrieves cached content
* Recupera o conteúdo em cache * @param string $id Cache ID
* * @return string|null Cached content or null if not found
* @param string $id Cache ID / ID do cache
* @return string|null Cached content or null if not found / Conteúdo em cache ou null se não encontrado
*/ */
public function get(string $id): ?string public function get(string $id): ?string
{ {
@ -69,11 +59,9 @@ class DiskStorage implements CacheStorageInterface
/** /**
* Stores content in cache * Stores content in cache
* Armazena conteúdo em cache * @param string $id Cache ID
* * @param string $content Content to be stored
* @param string $id Cache ID / ID do cache * @return bool True if successful, false otherwise
* @param string $content Content to be stored / Conteúdo a ser armazenado
* @return bool True if successful, false otherwise / True se bem sucedido, false caso contrário
*/ */
public function set(string $id, string $content): bool public function set(string $id, string $content): bool
{ {

View file

@ -6,77 +6,53 @@ use Redis;
/** /**
* Redis-based cache storage implementation * Redis-based cache storage implementation
* Implementação de armazenamento de cache baseado em Redis * Provides cache storage and file counting functionality using Redis
*
* This class provides cache storage and file counting functionality using Redis
* Esta classe fornece armazenamento de cache e funcionalidade de contagem de arquivos usando Redis
*
* @property \Redis|null $redis Redis client instance
*/ */
class RedisStorage implements CacheStorageInterface class RedisStorage implements CacheStorageInterface
{ {
/** /**
* @var \Redis|null Redis client instance * @var \Redis|null Redis client instance
* @var \Redis|null Instância do cliente Redis
*/ */
private $redis; private $redis;
/** /**
* @var string Cache directory for file counting * @var string Cache directory for file counting
* @var string Diretório de cache para contagem de arquivos
*/ */
private $cacheDir; private $cacheDir;
/** /**
* Class constructor * Class constructor
* Construtor da classe * @param string $cacheDir Base directory for cache storage
*
* @param string $cacheDir Base directory for cache storage / Diretório base para armazenamento do cache
*/ */
public function __construct(string $cacheDir) public function __construct(string $cacheDir)
{ {
$this->cacheDir = $cacheDir; $this->cacheDir = $cacheDir;
// Try to initialize Redis connection // Try to initialize Redis connection
// Tenta inicializar conexão Redis
try { try {
/** @var \Redis $redis */
$this->redis = new \Redis(); $this->redis = new \Redis();
$this->redis->connect(REDIS_HOST, REDIS_PORT, 2.5); $this->redis->connect(REDIS_HOST, REDIS_PORT, 2.5);
$this->redis->setOption(\Redis::OPT_PREFIX, REDIS_PREFIX); $this->redis->setOption(\Redis::OPT_PREFIX, REDIS_PREFIX);
} catch (\Exception $e) { } catch (\Exception $e) {
// If it fails, set redis to null
// Se falhar, define redis como null
$this->redis = null; $this->redis = null;
} }
} }
/** /**
* Counts the number of files in the cache directory * Counts the number of files in the cache directory
* Conta o número de arquivos no diretório de cache * @return int Number of files in the cache directory
*
* @return int Number of files in the cache directory / Número de arquivos no diretório de cache
*/ */
public function countCacheFiles(): int public function countCacheFiles(): int
{ {
// Key to store file count in Redis
// Chave para armazenar a contagem de arquivos no Redis
$cacheCountKey = 'cache_file_count'; $cacheCountKey = 'cache_file_count';
// If Redis is available
// Se Redis estiver disponível
if ($this->redis !== null) { if ($this->redis !== null) {
// Check if the key exists and has a value
// Verifica se a chave existe e tem valor
/** @var string|false $cachedCount */
$cachedCount = $this->redis->get($cacheCountKey); $cachedCount = $this->redis->get($cacheCountKey);
if ($cachedCount !== false) { if ($cachedCount !== false) {
return (int)$cachedCount; return (int)$cachedCount;
} }
} }
// If Redis is not available or key is empty, count .gz files
// Se Redis não estiver disponível ou chave vazia, conta arquivos .gz
$fileCount = 0; $fileCount = 0;
$iterator = new \FilesystemIterator($this->cacheDir); $iterator = new \FilesystemIterator($this->cacheDir);
foreach ($iterator as $file) { foreach ($iterator as $file) {
@ -85,8 +61,6 @@ class RedisStorage implements CacheStorageInterface
} }
} }
// If Redis is available, save the count
// Se Redis estiver disponível, salva a contagem
if ($this->redis !== null) { if ($this->redis !== null) {
$this->redis->set($cacheCountKey, $fileCount); $this->redis->set($cacheCountKey, $fileCount);
} }
@ -96,9 +70,7 @@ class RedisStorage implements CacheStorageInterface
/** /**
* Updates the file count in Redis * Updates the file count in Redis
* Atualiza a contagem de arquivos no Redis * @param int $count Number of files
*
* @param int $count Number of files / Número de arquivos
*/ */
public function updateCacheFileCount(int $count): void public function updateCacheFileCount(int $count): void
{ {
@ -109,10 +81,8 @@ class RedisStorage implements CacheStorageInterface
/** /**
* Checks if cache exists for a given ID * Checks if cache exists for a given ID
* Verifica se existe cache para um determinado ID * @param string $id Cache ID
* * @return bool True if cache exists, false otherwise
* @param string $id Cache ID / ID do cache
* @return bool True if cache exists, false otherwise / True se o cache existir, false caso contrário
*/ */
public function exists(string $id): bool public function exists(string $id): bool
{ {
@ -121,10 +91,8 @@ class RedisStorage implements CacheStorageInterface
/** /**
* Retrieves cached content * Retrieves cached content
* Recupera o conteúdo em cache * @param string $id Cache ID
* * @return string|null Cached content or null if not found
* @param string $id Cache ID / ID do cache
* @return string|null Cached content or null if not found / Conteúdo em cache ou null se não encontrado
*/ */
public function get(string $id): ?string public function get(string $id): ?string
{ {
@ -132,36 +100,25 @@ class RedisStorage implements CacheStorageInterface
return null; return null;
} }
/** @var string|false $content */
$content = $this->redis->get($id); $content = $this->redis->get($id);
return $content === false ? null : $content; return $content === false ? null : $content;
} }
/** /**
* Stores content in cache * Stores content in cache
* Armazena conteúdo em cache * @param string $id Cache ID
* * @param string $content Content to be stored
* @param string $id Cache ID / ID do cache * @return bool True if successful, false otherwise
* @param string $content Content to be stored / Conteúdo a ser armazenado
* @return bool True if successful, false otherwise / True se bem sucedido, false caso contrário
*/ */
public function set(string $id, string $content): bool public function set(string $id, string $content): bool
{ {
// If Redis is not available, return false
// Se Redis não estiver disponível, retorna false
if ($this->redis === null) { if ($this->redis === null) {
return false; return false;
} }
// When saving a new file, update the count
// Ao salvar um novo arquivo, atualiza a contagem
/** @var bool $result */
$result = $this->redis->set($id, $content); $result = $this->redis->set($id, $content);
if ($result) { if ($result) {
// Increment file count in Redis
// Incrementa a contagem de arquivos no Redis
/** @var string|false $currentCount */
$currentCount = $this->redis->get('cache_file_count') ?: 0; $currentCount = $this->redis->get('cache_file_count') ?: 0;
$this->redis->set('cache_file_count', $currentCount + 1); $this->redis->set('cache_file_count', $currentCount + 1);
} }

View file

@ -7,42 +7,33 @@ use Aws\Exception\AwsException;
/** /**
* AWS S3-based cache storage implementation * AWS S3-based cache storage implementation
* Implementação de armazenamento de cache baseado em AWS S3 * Provides cache storage functionality using Amazon S3 or compatible services
*
* This class provides cache storage functionality using Amazon S3 or compatible services
* Esta classe fornece funcionalidade de armazenamento de cache usando Amazon S3 ou serviços compatíveis
*/ */
class S3Storage implements CacheStorageInterface class S3Storage implements CacheStorageInterface
{ {
/** /**
* @var S3Client AWS S3 Client * @var S3Client AWS S3 Client
* @var S3Client Cliente AWS S3
*/ */
private $s3Client; private $s3Client;
/** /**
* @var string S3 bucket name * @var string S3 bucket name
* @var string Nome do bucket S3
*/ */
private $bucket; private $bucket;
/** /**
* @var string Prefix for objects in the bucket (optional) * @var string Prefix for objects in the bucket (optional)
* @var string Prefixo para os objetos no bucket (opcional)
*/ */
private $prefix; private $prefix;
/** /**
* @var string ACL for S3 objects * @var string ACL for S3 objects
* @var string ACL para os objetos no S3
*/ */
private $acl; private $acl;
/** /**
* Class constructor * Class constructor
* Construtor da classe * @param array $config AWS S3 configuration
*
* @param array $config AWS S3 configuration / Configuração do AWS S3
*/ */
public function __construct(array $config) public function __construct(array $config)
{ {
@ -56,11 +47,8 @@ class S3Storage implements CacheStorageInterface
]; ];
// Add custom endpoint if provided // Add custom endpoint if provided
// Adiciona endpoint personalizado se fornecido
if (!empty($config['endpoint'])) { if (!empty($config['endpoint'])) {
$clientConfig['endpoint'] = $config['endpoint']; $clientConfig['endpoint'] = $config['endpoint'];
// Use path-style endpoints when a custom endpoint is provided
// Use endpoints estilo path quando um endpoint personalizado é fornecido
$clientConfig['use_path_style_endpoint'] = true; $clientConfig['use_path_style_endpoint'] = true;
} }
@ -73,10 +61,8 @@ class S3Storage implements CacheStorageInterface
/** /**
* Generates the complete object key in S3 * Generates the complete object key in S3
* Gera a chave completa do objeto no S3 * @param string $id Cache ID
* * @return string Complete S3 object key
* @param string $id Cache ID / ID do cache
* @return string Complete S3 object key / Chave completa do objeto no S3
*/ */
private function getObjectKey(string $id): string private function getObjectKey(string $id): string
{ {
@ -85,10 +71,8 @@ class S3Storage implements CacheStorageInterface
/** /**
* Checks if cache exists for a given ID * Checks if cache exists for a given ID
* Verifica se existe cache para um determinado ID * @param string $id Cache ID
* * @return bool True if cache exists, false otherwise
* @param string $id Cache ID / ID do cache
* @return bool True if cache exists, false otherwise / True se o cache existir, false caso contrário
*/ */
public function exists(string $id): bool public function exists(string $id): bool
{ {
@ -98,17 +82,14 @@ class S3Storage implements CacheStorageInterface
$this->getObjectKey($id) $this->getObjectKey($id)
); );
} catch (AwsException $e) { } catch (AwsException $e) {
// Log error if needed / Registra erro se necessário
return false; return false;
} }
} }
/** /**
* Retrieves cached content * Retrieves cached content
* Recupera o conteúdo em cache * @param string $id Cache ID
* * @return string|null Cached content or null if not found
* @param string $id Cache ID / ID do cache
* @return string|null Cached content or null if not found / Conteúdo em cache ou null se não encontrado
*/ */
public function get(string $id): ?string public function get(string $id): ?string
{ {
@ -136,11 +117,9 @@ class S3Storage implements CacheStorageInterface
/** /**
* Stores content in cache * Stores content in cache
* Armazena conteúdo em cache * @param string $id Cache ID
* * @param string $content Content to be stored
* @param string $id Cache ID / ID do cache * @return bool True if successful, false otherwise
* @param string $content Content to be stored / Conteúdo a ser armazenado
* @return bool True if successful, false otherwise / True se bem sucedido, false caso contrário
*/ */
public function set(string $id, string $content): bool public function set(string $id, string $content): bool
{ {
@ -156,12 +135,11 @@ class S3Storage implements CacheStorageInterface
'Body' => $compressedContent, 'Body' => $compressedContent,
'ACL' => $this->acl, 'ACL' => $this->acl,
'ContentEncoding' => 'gzip', 'ContentEncoding' => 'gzip',
'CacheControl' => 'max-age=31536000' // 1 year / 1 ano 'CacheControl' => 'max-age=31536000' // 1 year
]); ]);
return true; return true;
} catch (AwsException $e) { } catch (AwsException $e) {
// Log error if needed / Registra erro se necessário
return false; return false;
} }
} }

View file

@ -1,27 +1,17 @@
<?php <?php
/** /**
* Language Management Class * Manages language translations and localization
* Classe de Gerenciamento de Idiomas * Loads language files based on system configuration
* * Provides fallback to default language on missing resources
* This class handles the loading and retrieval of language-specific strings
* Esta classe lida com o carregamento e recuperação de strings específicas do idioma
*
* Features / Funcionalidades:
* - Language initialization / Inicialização de idioma
* - Translation retrieval / Recuperação de traduções
* - Message handling / Manipulação de mensagens
* - Fallback language support / Suporte a idioma de fallback
*/ */
class Language { class Language {
private static $translations = []; private static $translations = [];
private static $currentLanguage = 'pt-br'; private static $currentLanguage = 'pt-br';
/** /**
* Initialize the language system * Initializes language resources
* Inicializa o sistema de idiomas * @param string $language ISO language code (e.g., 'en', 'pt-br')
*
* @param string $language Language code (e.g., 'en', 'pt-br') / Código do idioma (ex: 'en', 'pt-br')
*/ */
public static function init($language = 'pt-br') { public static function init($language = 'pt-br') {
self::$currentLanguage = strtolower($language); self::$currentLanguage = strtolower($language);
@ -30,31 +20,25 @@ class Language {
if (file_exists($langFile)) { if (file_exists($langFile)) {
self::$translations = require $langFile; self::$translations = require $langFile;
} else { } else {
// Fallback to pt-br if language file doesn't exist // Fallback to default language
// Volta para pt-br se o arquivo de idioma não existir
self::$currentLanguage = 'pt-br'; self::$currentLanguage = 'pt-br';
self::$translations = require __DIR__ . '/../languages/pt-br.php'; self::$translations = require __DIR__ . '/../languages/pt-br.php';
} }
} }
/** /**
* Get a translation by key * Retrieves translation for specified key
* Obtém uma tradução por chave * @param string $key Translation identifier
* * @param string $default Fallback value if key not found
* @param string $key Translation key / Chave da tradução
* @param string $default Default value if key not found / Valor padrão se a chave não for encontrada
* @return string Translation text / Texto traduzido
*/ */
public static function get($key, $default = '') { public static function get($key, $default = '') {
return self::$translations[$key] ?? $default; return self::$translations[$key] ?? $default;
} }
/** /**
* Get a message by key * Gets structured message data
* Obtém uma mensagem por chave * @param string $key Message identifier
* * @return array Message content and type
* @param string $key Message key / Chave da mensagem
* @return array Message data (message and type) / Dados da mensagem (mensagem e tipo)
*/ */
public static function getMessage($key) { public static function getMessage($key) {
return self::$translations['messages'][$key] ?? [ return self::$translations['messages'][$key] ?? [
@ -63,12 +47,7 @@ class Language {
]; ];
} }
/** /** Gets active language code */
* Get current language code
* Obtém o código do idioma atual
*
* @return string Current language code / Código do idioma atual
*/
public static function getCurrentLanguage() { public static function getCurrentLanguage() {
return self::$currentLanguage; return self::$currentLanguage;
} }

View file

@ -10,62 +10,42 @@ use Monolog\Level;
use Exception; use Exception;
/** /**
* Error logging and monitoring class * Centralized logging system using Monolog
* Classe de monitoramento e registro de erros * Implements file rotation and log level configuration
* * Supports multiple output handlers
* This class implements error logging functionality using Monolog
* for monitoring and tracking application errors.
*
* Esta classe implementa funcionalidades de registro de erros usando Monolog
* para monitoramento e rastreamento de erros da aplicação.
*/ */
class Logger class Logger
{ {
/** /** @var Logger|null Singleton instance */
* @var Logger|null Singleton instance
* @var Logger|null Instância singleton
*/
private static $instance = null; private static $instance = null;
/** /** @var MonologLogger Core logging instance */
* @var MonologLogger Monolog logger instance
* @var MonologLogger Instância do logger Monolog
*/
private $logger; private $logger;
/** /** @var array Log level mapping */
* @var array Log level mapping
* @var array Mapeamento de níveis de log
*/
private $logLevels = [ private $logLevels = [
'DEBUG' => \Monolog\Level::Debug, 'DEBUG' => Level::Debug,
'INFO' => \Monolog\Level::Info, 'INFO' => Level::Info,
'WARNING' => \Monolog\Level::Warning, 'WARNING' => Level::Warning,
'ERROR' => \Monolog\Level::Error, 'ERROR' => Level::Error,
'CRITICAL' => \Monolog\Level::Critical 'CRITICAL' => Level::Critical
]; ];
/** /**
* Private constructor to prevent direct instantiation * Initializes logging system with file rotation
* Construtor privado para prevenir instanciação direta * Configures log format and retention policy
* * Adds stderr output in DEBUG mode
* Initializes Monolog logger with file rotation
* Inicializa o logger Monolog com rotação de arquivos
*/ */
private function __construct() private function __construct()
{ {
$this->logger = new MonologLogger('marreta'); $this->logger = new MonologLogger('marreta');
// Setup rotating file handler with 7 days retention
// Configura manipulador de arquivo rotativo com retenção de 7 dias
$handler = new RotatingFileHandler( $handler = new RotatingFileHandler(
__DIR__ . '/../logs/app.log', __DIR__ . '/../logs/app.log',
LOG_DAYS_TO_KEEP, LOG_DAYS_TO_KEEP,
$this->getLogLevel() $this->getLogLevel()
); );
// Custom line format
// Formato de linha personalizado
$dateFormat = "Y-m-d H:i:s"; $dateFormat = "Y-m-d H:i:s";
$output = "[%datetime%] %level_name%: %message% %context% %extra%\n"; $output = "[%datetime%] %level_name%: %message% %context% %extra%\n";
$formatter = new LineFormatter($output, $dateFormat); $formatter = new LineFormatter($output, $dateFormat);
@ -73,21 +53,14 @@ class Logger
$this->logger->pushHandler($handler); $this->logger->pushHandler($handler);
// If LOG_LEVEL is DEBUG, also log to stderr
// Se LOG_LEVEL for DEBUG, também loga no stderr
if (defined('LOG_LEVEL') && LOG_LEVEL === 'DEBUG') { if (defined('LOG_LEVEL') && LOG_LEVEL === 'DEBUG') {
$streamHandler = new StreamHandler('php://stderr', \Monolog\Level::Debug); $streamHandler = new StreamHandler('php://stderr', Level::Debug);
$streamHandler->setFormatter($formatter); $streamHandler->setFormatter($formatter);
$this->logger->pushHandler($streamHandler); $this->logger->pushHandler($streamHandler);
} }
} }
/** /** @return Logger Singleton instance */
* Gets singleton instance
* Obtém instância singleton
*
* @return Logger Instance of Logger / Instância do Logger
*/
public static function getInstance(): Logger public static function getInstance(): Logger
{ {
if (self::$instance === null) { if (self::$instance === null) {
@ -96,12 +69,7 @@ class Logger
return self::$instance; return self::$instance;
} }
/** /** Determines active log level from configuration */
* Gets configured log level from environment or default
* Obtém nível de log configurado do ambiente ou padrão
*
* @return Level Monolog log level / Nível de log do Monolog
*/
private function getLogLevel(): Level private function getLogLevel(): Level
{ {
$configLevel = defined('LOG_LEVEL') ? LOG_LEVEL : 'WARNING'; $configLevel = defined('LOG_LEVEL') ? LOG_LEVEL : 'WARNING';
@ -109,39 +77,29 @@ class Logger
} }
/** /**
* Logs a message with context at specified level * Records log entry with context
* Registra uma mensagem com contexto no nível especificado * @param string $message Log message
* * @param array $context Additional context data
* @param string $message Log message / Mensagem de log * @param string $level Log severity level
* @param array $context Additional context data / Dados adicionais de contexto
* @param string $level Log level / Nível de log
*/ */
public function log(string $message, array $context = [], string $level = 'WARNING'): void public function log(string $message, array $context = [], string $level = 'WARNING'): void
{ {
$logLevel = $this->logLevels[$level] ?? \Monolog\Level::Warning; $logLevel = $this->logLevels[$level] ?? Level::Warning;
$this->logger->log($logLevel, $message, $context); $this->logger->log($logLevel, $message, $context);
} }
/** /** Logs error message with context */
* Logs an error with context
* Registra um erro com contexto
*
* @param string $message Error message / Mensagem de erro
* @param array $context Additional context data / Dados adicionais de contexto
*/
public function error(string $message, array $context = []): void public function error(string $message, array $context = []): void
{ {
$this->log($message, $context, 'ERROR'); $this->log($message, $context, 'ERROR');
} }
/** /**
* Logs a URL-specific error * Logs URL-specific error details
* Registra um erro específico de URL * @param string $url Problematic URL
* * @param string $error_group Error category
* @param string $url The URL that generated the error / A URL que gerou o erro * @param string $message_error Additional error details
* @param string $error_group Error group/category / Grupo/categoria do erro * @param string $level Log severity level
* @param string $message_error Additional error details / Detalhes adicionais do erro
* @param string $level Log level / Nível de log
*/ */
public function logUrl(string $url, string $error_group, string $message_error = '', string $level = 'WARNING'): void public function logUrl(string $url, string $error_group, string $message_error = '', string $level = 'WARNING'): void
{ {

View file

@ -1,43 +1,19 @@
<?php <?php
/** /**
* Class responsible for content manipulation rules management * Manages domain-specific content manipulation rules
* Classe responsável pelo gerenciamento de regras de manipulação de conteúdo * Handles rule merging between global and domain-specific configurations
* * Supports multiple rule types for web content manipulation
* This class implements a rules system for different web domains,
* allowing system behavior customization for each site.
* Includes functionalities for paywall removal, specific elements,
* cookie manipulation and custom code execution.
*
* Esta classe implementa um sistema de regras para diferentes domínios web,
* permitindo a personalização do comportamento do sistema para cada site.
* Inclui funcionalidades para remoção de paywalls, elementos específicos,
* manipulação de cookies e execução de códigos customizados.
*/ */
class Rules class Rules
{ {
/** /** @var array Domain-specific rule configurations */
* Associative array containing specific rules for each domain
* Array associativo contendo regras específicas para cada domínio
*
* Possible configurations for each domain:
* Configurações possíveis para cada domínio:
* @var array
*/
private $domainRules = DOMAIN_RULES; private $domainRules = DOMAIN_RULES;
/** /** @var array Expanded global rule set */
* Expanded global rules
* Regras globais expandidas
* @var array
*/
private $globalRules = GLOBAL_RULES; private $globalRules = GLOBAL_RULES;
/** /** @var array Supported rule types */
* List of supported rule types
* Lista de tipos de regras suportados
* @var array
*/
private $supportedRuleTypes = [ private $supportedRuleTypes = [
'userAgent', 'userAgent',
'headers', 'headers',
@ -57,11 +33,8 @@ class Rules
]; ];
/** /**
* Gets the base domain by removing www prefix * Extracts root domain by removing www prefix
* Obtém o domínio base removendo o prefixo www * @param string $domain Full domain name
*
* @param string $domain Full domain / Domínio completo
* @return string Base domain without www / Domínio base sem www
*/ */
private function getBaseDomain($domain) private function getBaseDomain($domain)
{ {
@ -69,11 +42,9 @@ class Rules
} }
/** /**
* Splits a domain into its constituent parts * Generates domain variations for rule matching
* Divide um domínio em suas partes constituintes * @param string $domain Original domain
* * @return array Sorted domain combinations by length
* @param string $domain Domain to be split / Domínio a ser dividido
* @return array Array with all possible domain combinations / Array com todas as combinações possíveis do domínio
*/ */
private function getDomainParts($domain) private function getDomainParts($domain)
{ {
@ -93,11 +64,9 @@ class Rules
} }
/** /**
* Gets specific rules for a domain * Retrieves merged rules for a domain
* Obtém as regras específicas para um domínio * @param string $domain Target domain
* * @return array|null Combined ruleset or global rules
* @param string $domain Domain to search rules for / Domínio para buscar regras
* @return array|null Array with merged rules or null if not found / Array com regras mescladas ou null se não encontrar
*/ */
public function getDomainRules($domain) public function getDomainRules($domain)
{ {
@ -117,43 +86,28 @@ class Rules
} }
} }
// If no specific rules found, return only global rules
// Se não encontrou regras específicas, retorna apenas as regras globais
return $this->getGlobalRules(); return $this->getGlobalRules();
} }
/** /**
* Merges domain-specific rules with global rules * Combines domain rules with global configuration
* Mescla regras específicas do domínio com regras globais * @param array $rules Domain-specific rules
*
* @param array $rules Domain-specific rules / Regras específicas do domínio
* @return array Merged rules / Regras mescladas
*/ */
private function mergeWithGlobalRules($rules) private function mergeWithGlobalRules($rules)
{ {
$globalRules = $this->getGlobalRules(); $globalRules = $this->getGlobalRules();
$mergedRules = []; $mergedRules = [];
// Process global rules exclusions $excludeGlobalRules = $rules['excludeGlobalRules'] ?? [];
// Processa as exclusões de regras globais unset($rules['excludeGlobalRules']);
$excludeGlobalRules = isset($rules['excludeGlobalRules']) ? $rules['excludeGlobalRules'] : [];
unset($rules['excludeGlobalRules']); // Remove from rules array to avoid processing as normal rule / Remove do array de regras para não ser processado como regra normal
// First, add all global rules except excluded ones
// Primeiro, adiciona todas as regras globais, exceto as excluídas
foreach ($globalRules as $ruleType => $globalTypeRules) { foreach ($globalRules as $ruleType => $globalTypeRules) {
if (!in_array($ruleType, $this->supportedRuleTypes)) { if (!in_array($ruleType, $this->supportedRuleTypes)) continue;
continue;
}
if (isset($excludeGlobalRules[$ruleType])) { if (isset($excludeGlobalRules[$ruleType])) {
// If rule type is an associative array (like cookies or headers) if (is_assoc_array($globalTypeRules)) {
// Se o tipo de regra é um array associativo (como cookies ou headers)
if (is_array($globalTypeRules) && array_keys($globalTypeRules) !== range(0, count($globalTypeRules) - 1)) {
$mergedRules[$ruleType] = array_diff_key($globalTypeRules, array_flip($excludeGlobalRules[$ruleType])); $mergedRules[$ruleType] = array_diff_key($globalTypeRules, array_flip($excludeGlobalRules[$ruleType]));
} else { } else {
// For simple arrays (like classElementRemove)
// Para arrays simples (como classElementRemove)
$mergedRules[$ruleType] = array_diff($globalTypeRules, $excludeGlobalRules[$ruleType]); $mergedRules[$ruleType] = array_diff($globalTypeRules, $excludeGlobalRules[$ruleType]);
} }
} else { } else {
@ -161,27 +115,17 @@ class Rules
} }
} }
// Then, merge with domain-specific rules
// Depois, mescla com as regras específicas do domínio
foreach ($rules as $ruleType => $domainTypeRules) { foreach ($rules as $ruleType => $domainTypeRules) {
if (!in_array($ruleType, $this->supportedRuleTypes)) { if (!in_array($ruleType, $this->supportedRuleTypes)) continue;
continue;
}
if (!isset($mergedRules[$ruleType])) { if (!isset($mergedRules[$ruleType])) {
$mergedRules[$ruleType] = $domainTypeRules; $mergedRules[$ruleType] = $domainTypeRules;
continue; continue;
} }
// If rule type already exists, merge appropriately
// Se o tipo de regra já existe, mescla apropriadamente
if (in_array($ruleType, ['cookies', 'headers'])) { if (in_array($ruleType, ['cookies', 'headers'])) {
// For cookies and headers, preserve keys
// Para cookies e headers, preserva as chaves
$mergedRules[$ruleType] = array_merge($mergedRules[$ruleType], $domainTypeRules); $mergedRules[$ruleType] = array_merge($mergedRules[$ruleType], $domainTypeRules);
} else { } else {
// For other types, merge as simple arrays
// Para outros tipos, mescla como arrays simples
$mergedRules[$ruleType] = array_values(array_unique(array_merge( $mergedRules[$ruleType] = array_values(array_unique(array_merge(
$mergedRules[$ruleType], $mergedRules[$ruleType],
(array)$domainTypeRules (array)$domainTypeRules
@ -192,14 +136,14 @@ class Rules
return $mergedRules; return $mergedRules;
} }
/** /** @return array Global rule configuration */
* Returns all global rules
* Retorna todas as regras globais
*
* @return array Array with all global rules / Array com todas as regras globais
*/
public function getGlobalRules() public function getGlobalRules()
{ {
return $this->globalRules; return $this->globalRules;
} }
} }
// Helper function for associative array check
function is_assoc_array($array) {
return array_keys($array) !== range(0, count($array) - 1);
}

View file

@ -1,19 +1,14 @@
<?php <?php
/** /**
* Class responsible for URL analysis and processing * Class for URL analysis and processing
* Classe responsável pela análise e processamento de URLs * URL analysis and cleaning
* * Content caching
* This class implements functionalities for: * DNS resolution
* Esta classe implementa funcionalidades para: * HTTP requests with multiple attempts
* * Content processing based on domain-specific rules
* - URL analysis and cleaning / Análise e limpeza de URLs * Wayback Machine support
* - Content caching / Cache de conteúdo * Selenium extraction support
* - DNS resolution / Resolução DNS
* - HTTP requests with multiple attempts / Requisições HTTP com múltiplas tentativas
* - Content processing based on domain-specific rules / Processamento de conteúdo baseado em regras específicas por domínio
* - Wayback Machine support as fallback / Suporte a Wayback Machine como fallback
* - Selenium extraction support when enabled by domain / Suporte a extração via Selenium quando habilitado por domínio
*/ */
require_once __DIR__ . '/Rules.php'; require_once __DIR__ . '/Rules.php';
@ -31,7 +26,6 @@ use Inc\Logger;
/** /**
* Custom exception class for URL analysis errors * Custom exception class for URL analysis errors
* Classe de exceção personalizada para erros de análise de URL
*/ */
class URLAnalyzerException extends Exception class URLAnalyzerException extends Exception
{ {
@ -81,8 +75,7 @@ class URLAnalyzer
]; ];
/** /**
* Helper method to throw standardized errors * Helper method to throw errors
* Método auxiliar para lançar erros padronizados
*/ */
private function throwError($errorType, $additionalInfo = '') private function throwError($errorType, $additionalInfo = '')
{ {
@ -95,24 +88,19 @@ class URLAnalyzer
} }
/** /**
* @var array List of available User Agents for requests * @var array List of User Agents
* @var array Lista de User Agents disponíveis para requisições
*/ */
private $userAgents = [ private $userAgents = [
// Google News bot // Google News bot
// Bot do Google News
'Googlebot-News', 'Googlebot-News',
// Mobile Googlebot // Mobile Googlebot
// Googlebot para dispositivos móveis
'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/W.X.Y.Z Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)', 'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/W.X.Y.Z Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)',
// Desktop Googlebot // Desktop Googlebot
// Googlebot para desktop
'Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; Googlebot/2.1; +http://www.google.com/bot.html) Chrome/W.X.Y.Z Safari/537.36' 'Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; Googlebot/2.1; +http://www.google.com/bot.html) Chrome/W.X.Y.Z Safari/537.36'
]; ];
/** /**
* @var array List of social media referrers * @var array List of social media referrers
* @var array Lista de referenciadores de mídia social
*/ */
private $socialReferrers = [ private $socialReferrers = [
// Twitter // Twitter
@ -125,35 +113,28 @@ class URLAnalyzer
]; ];
/** /**
* @var array List of DNS servers for resolution * @var array List of DNS servers
* @var array Lista de servidores DNS para resolução
*/ */
private $dnsServers; private $dnsServers;
/** /**
* @var Rules Instance of rules class * @var Rules Instance of rules class
* @var Rules Instância da classe de regras
*/ */
private $rules; private $rules;
/** /**
* @var Cache Instance of cache class * @var Cache Instance of cache class
* @var Cache Instância da classe de cache
*/ */
private $cache; private $cache;
/** /**
* @var array List of rules activated during processing * @var array List of activated rules
* @var array Lista de regras ativadas durante o processamento
*/ */
private $activatedRules = []; private $activatedRules = [];
/** /**
* Class constructor * Class constructor
* Construtor da classe * Initializes dependencies
*
* Initializes required dependencies
* Inicializa as dependências necessárias
*/ */
public function __construct() public function __construct()
{ {
@ -164,10 +145,8 @@ class URLAnalyzer
/** /**
* Check if a URL has redirects and return the final URL * Check if a URL has redirects and return the final URL
* Verifica se uma URL tem redirecionamentos e retorna a URL final * @param string $url URL to check redirects
* * @return array Array with final URL and if there was a redirect
* @param string $url URL to check redirects / URL para verificar redirecionamentos
* @return array Array with final URL and if there was a redirect / Array com a URL final e se houve redirecionamento
*/ */
public function checkStatus($url) public function checkStatus($url)
{ {
@ -196,10 +175,8 @@ class URLAnalyzer
/** /**
* Get a random user agent, with possibility of using Google bot * Get a random user agent, with possibility of using Google bot
* Obtém um user agent aleatório, com possibilidade de usar o Google bot * @param bool $preferGoogleBot Whether to prefer Google bot user agents
* * @return string Selected user agent
* @param bool $preferGoogleBot Whether to prefer Google bot user agents / Se deve preferir user agents do Google bot
* @return string Selected user agent / User agent selecionado
*/ */
private function getRandomUserAgent($preferGoogleBot = false) private function getRandomUserAgent($preferGoogleBot = false)
{ {
@ -211,9 +188,7 @@ class URLAnalyzer
/** /**
* Get a random social media referrer * Get a random social media referrer
* Obtém um referenciador de mídia social aleatório * @return string Selected referrer
*
* @return string Selected referrer / Referenciador selecionado
*/ */
private function getRandomSocialReferrer() private function getRandomSocialReferrer()
{ {
@ -222,24 +197,21 @@ class URLAnalyzer
/** /**
* Main method for URL analysis * Main method for URL analysis
* Método principal para análise de URLs * @param string $url URL to be analyzed
* * @return string Processed content
* @param string $url URL to be analyzed / URL a ser analisada * @throws URLAnalyzerException In case of processing errors
* @return string Processed content / Conteúdo processado
* @throws URLAnalyzerException In case of processing errors / Em caso de erros durante o processamento
*/ */
public function analyze($url) public function analyze($url)
{ {
// Reset activated rules for new analysis // Reset activated rules for new analysis
// Reset das regras ativadas para nova análise
$this->activatedRules = []; $this->activatedRules = [];
// 1. Check cache / Verifica cache // 1. Check cache
if ($this->cache->exists($url)) { if ($this->cache->exists($url)) {
return $this->cache->get($url); return $this->cache->get($url);
} }
// 2. Check blocked domains / Verifica domínios bloqueados // 2. Check blocked domains
$host = parse_url($url, PHP_URL_HOST); $host = parse_url($url, PHP_URL_HOST);
if (!$host) { if (!$host) {
$this->throwError(self::ERROR_INVALID_URL); $this->throwError(self::ERROR_INVALID_URL);
@ -263,11 +235,11 @@ class URLAnalyzer
} }
try { try {
// 4. Get domain rules and check fetch strategy / Obtenha regras de domínio e verifique a estratégia de busca // 4. Get domain rules and check fetch strategy
$domainRules = $this->getDomainRules($host); $domainRules = $this->getDomainRules($host);
$fetchStrategy = isset($domainRules['fetchStrategies']) ? $domainRules['fetchStrategies'] : null; $fetchStrategy = isset($domainRules['fetchStrategies']) ? $domainRules['fetchStrategies'] : null;
// If a specific fetch strategy is defined, use only that / Se uma estratégia de busca específica for definida, use somente essa // If a specific fetch strategy is defined, use only that
if ($fetchStrategy) { if ($fetchStrategy) {
try { try {
$content = null; $content = null;
@ -319,7 +291,7 @@ class URLAnalyzer
} }
} }
// If we get here, all strategies failed // If all strategies failed
Logger::getInstance()->logUrl($url, 'GENERAL_FETCH_ERROR'); Logger::getInstance()->logUrl($url, 'GENERAL_FETCH_ERROR');
if ($lastError) { if ($lastError) {
$message = $lastError->getMessage(); $message = $lastError->getMessage();
@ -337,7 +309,7 @@ class URLAnalyzer
} catch (URLAnalyzerException $e) { } catch (URLAnalyzerException $e) {
throw $e; throw $e;
} catch (Exception $e) { } catch (Exception $e) {
// Map generic exceptions to appropriate error types // Map exceptions to error types
$message = $e->getMessage(); $message = $e->getMessage();
if (strpos($message, 'DNS') !== false) { if (strpos($message, 'DNS') !== false) {
$this->throwError(self::ERROR_DNS_FAILURE); $this->throwError(self::ERROR_DNS_FAILURE);
@ -355,7 +327,6 @@ class URLAnalyzer
/** /**
* Fetch content from URL * Fetch content from URL
* Busca conteúdo da URL
*/ */
private function fetchContent($url) private function fetchContent($url)
{ {
@ -375,7 +346,7 @@ class URLAnalyzer
$curl->setOpt(CURLOPT_DNS_SERVERS, implode(',', $this->dnsServers)); $curl->setOpt(CURLOPT_DNS_SERVERS, implode(',', $this->dnsServers));
$curl->setOpt(CURLOPT_ENCODING, ''); $curl->setOpt(CURLOPT_ENCODING, '');
// Additional anti-detection headers / Cabeçalhos anti-detecção adicionais // Additional anti-detection headers
$curl->setHeaders([ $curl->setHeaders([
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language' => 'en-US,en;q=0.5', 'Accept-Language' => 'en-US,en;q=0.5',
@ -384,7 +355,7 @@ class URLAnalyzer
'DNT' => '1' 'DNT' => '1'
]); ]);
// Set Google bot specific headers / Definir cabeçalhos específicos do bot do Google // Set Google bot specific headers
if (isset($domainRules['fromGoogleBot'])) { if (isset($domainRules['fromGoogleBot'])) {
$curl->setUserAgent($this->getRandomUserAgent(true)); $curl->setUserAgent($this->getRandomUserAgent(true));
$curl->setHeaders([ $curl->setHeaders([
@ -393,7 +364,7 @@ class URLAnalyzer
]); ]);
} }
// Add domain-specific headers / Adicionar cabeçalhos específicos de domínio // Add domain-specific headers
if (isset($domainRules['headers'])) { if (isset($domainRules['headers'])) {
$curl->setHeaders($domainRules['headers']); $curl->setHeaders($domainRules['headers']);
} }
@ -421,8 +392,7 @@ class URLAnalyzer
} }
/** /**
* Try to get content from Internet Archive's Wayback Machine * Try to get content from Wayback Machine
* Tenta obter conteúdo do Wayback Machine do Internet Archive
*/ */
private function fetchFromWaybackMachine($url) private function fetchFromWaybackMachine($url)
{ {
@ -467,7 +437,7 @@ class URLAnalyzer
$content = $curl->response; $content = $curl->response;
// Remove Wayback Machine toolbar and cache URLs / Remover a barra de ferramentas do Wayback Machine e URLs de cache // Remove Wayback Machine toolbar and cache URLs
$content = preg_replace('/<!-- BEGIN WAYBACK TOOLBAR INSERT -->.*?<!-- END WAYBACK TOOLBAR INSERT -->/s', '', $content); $content = preg_replace('/<!-- BEGIN WAYBACK TOOLBAR INSERT -->.*?<!-- END WAYBACK TOOLBAR INSERT -->/s', '', $content);
$content = preg_replace('/https?:\/\/web\.archive\.org\/web\/\d+im_\//', '', $content); $content = preg_replace('/https?:\/\/web\.archive\.org\/web\/\d+im_\//', '', $content);
@ -476,7 +446,6 @@ class URLAnalyzer
/** /**
* Try to get content using Selenium * Try to get content using Selenium
* Tenta obter conteúdo usando Selenium
*/ */
private function fetchFromSelenium($url, $browser = 'firefox') private function fetchFromSelenium($url, $browser = 'firefox')
{ {
@ -548,7 +517,6 @@ class URLAnalyzer
/** /**
* Get specific rules for a domain * Get specific rules for a domain
* Obtém regras específicas para um domínio
*/ */
private function getDomainRules($domain) private function getDomainRules($domain)
{ {
@ -557,7 +525,6 @@ class URLAnalyzer
/** /**
* Process HTML content applying domain rules * Process HTML content applying domain rules
* Processa conteúdo HTML aplicando regras de domínio
*/ */
private function processContent($content, $host, $url) private function processContent($content, $host, $url)
{ {
@ -573,7 +540,7 @@ class URLAnalyzer
$xpath = new DOMXPath($dom); $xpath = new DOMXPath($dom);
// Process canonical tags / Processar tags canônicas // Process canonical tags
$canonicalLinks = $xpath->query("//link[@rel='canonical']"); $canonicalLinks = $xpath->query("//link[@rel='canonical']");
if ($canonicalLinks !== false) { if ($canonicalLinks !== false) {
foreach ($canonicalLinks as $link) { foreach ($canonicalLinks as $link) {
@ -583,7 +550,7 @@ class URLAnalyzer
} }
} }
// Add new canonical tag / Adicionar nova tag canônica // Add new canonical tag
$head = $xpath->query('//head')->item(0); $head = $xpath->query('//head')->item(0);
if ($head) { if ($head) {
$newCanonical = $dom->createElement('link'); $newCanonical = $dom->createElement('link');
@ -592,12 +559,12 @@ class URLAnalyzer
$head->appendChild($newCanonical); $head->appendChild($newCanonical);
} }
// Fix relative URLs / Corrigir URLs relativas // Fix relative URLs
$this->fixRelativeUrls($dom, $xpath, $url); $this->fixRelativeUrls($dom, $xpath, $url);
$domainRules = $this->getDomainRules($host); $domainRules = $this->getDomainRules($host);
// Apply domain rules / Aplicar regras de domínio // Apply domain rules
if (isset($domainRules['customStyle'])) { if (isset($domainRules['customStyle'])) {
$styleElement = $dom->createElement('style'); $styleElement = $dom->createElement('style');
$styleElement->appendChild($dom->createTextNode($domainRules['customStyle'])); $styleElement->appendChild($dom->createTextNode($domainRules['customStyle']));
@ -612,16 +579,16 @@ class URLAnalyzer
$dom->getElementsByTagName('body')[0]->appendChild($scriptElement); $dom->getElementsByTagName('body')[0]->appendChild($scriptElement);
} }
// Remove unwanted elements / Remover elementos indesejados // Remove unwanted elements
$this->removeUnwantedElements($dom, $xpath, $domainRules); $this->removeUnwantedElements($dom, $xpath, $domainRules);
// Clean inline styles / Limpar estilos inline // Clean inline styles
$this->cleanInlineStyles($xpath); $this->cleanInlineStyles($xpath);
// Add Brand Bar / Adicionar barra de marca // Add Brand bar
$this->addBrandBar($dom, $xpath); $this->addBrandBar($dom, $xpath);
// Add debug panel / Adicionar painel de debug // Add Debug panel
$this->addDebugBar($dom, $xpath); $this->addDebugBar($dom, $xpath);
return $dom->saveHTML(); return $dom->saveHTML();
@ -629,7 +596,6 @@ class URLAnalyzer
/** /**
* Remove unwanted elements based on domain rules * Remove unwanted elements based on domain rules
* Remove elementos indesejados com base nas regras de domínio
*/ */
private function removeUnwantedElements($dom, $xpath, $domainRules) private function removeUnwantedElements($dom, $xpath, $domainRules)
{ {
@ -715,7 +681,7 @@ class URLAnalyzer
if (isset($domainRules['removeCustomAttr'])) { if (isset($domainRules['removeCustomAttr'])) {
foreach ($domainRules['removeCustomAttr'] as $attrPattern) { foreach ($domainRules['removeCustomAttr'] as $attrPattern) {
if (strpos($attrPattern, '*') !== false) { if (strpos($attrPattern, '*') !== false) {
// For wildcard attributes (e.g. data-*) / Para atributos com wildcard (ex: data-*) // For wildcard attributes (e.g. data-*)
$elements = $xpath->query('//*'); $elements = $xpath->query('//*');
if ($elements !== false) { if ($elements !== false) {
$pattern = '/^' . str_replace('*', '.*', $attrPattern) . '$/'; $pattern = '/^' . str_replace('*', '.*', $attrPattern) . '$/';
@ -735,7 +701,7 @@ class URLAnalyzer
$this->activatedRules[] = "removeCustomAttr: $attrPattern"; $this->activatedRules[] = "removeCustomAttr: $attrPattern";
} }
} else { } else {
// For non-wildcard attributes / Para atributos sem wildcard // For non-wildcard attributes
$elements = $xpath->query("//*[@$attrPattern]"); $elements = $xpath->query("//*[@$attrPattern]");
if ($elements !== false && $elements->length > 0) { if ($elements !== false && $elements->length > 0) {
foreach ($elements as $element) { foreach ($elements as $element) {
@ -749,8 +715,7 @@ class URLAnalyzer
} }
/** /**
* Clean inline styles that might interfere with content visibility * Clean inline styles
* Limpa estilos inline que podem interferir na visibilidade do conteúdo
*/ */
private function cleanInlineStyles($xpath) private function cleanInlineStyles($xpath)
{ {
@ -767,8 +732,7 @@ class URLAnalyzer
} }
/** /**
* Add Brand Bar CTA and debug panel * Add Brand Bar in pages
* Adiciona CTA da marca e painel de debug
*/ */
private function addBrandBar($dom, $xpath) private function addBrandBar($dom, $xpath)
{ {
@ -783,10 +747,8 @@ class URLAnalyzer
} }
} }
/** /**
* Add debug panel if LOG_LEVEL is DEBUG * Add debug panel if LOG_LEVEL is DEBUG
* Adicionar painel de depuração se LOG_LEVEL for DEBUG
*/ */
private function addDebugBar($dom, $xpath) private function addDebugBar($dom, $xpath)
{ {
@ -815,7 +777,6 @@ class URLAnalyzer
/** /**
* Remove specific classes from an element * Remove specific classes from an element
* Remove classes específicas de um elemento
*/ */
private function removeClassNames($element, $classesToRemove) private function removeClassNames($element, $classesToRemove)
{ {
@ -837,7 +798,6 @@ class URLAnalyzer
/** /**
* Fix relative URLs in a DOM document * Fix relative URLs in a DOM document
* Corrige URLs relativas em um documento DOM
*/ */
private function fixRelativeUrls($dom, $xpath, $baseUrl) private function fixRelativeUrls($dom, $xpath, $baseUrl)
{ {

View file

@ -1,13 +1,9 @@
<?php <?php
/** /**
* Arquivo de entrada da aplicação
* Application entry point * Application entry point
* *
* Este arquivo inicializa o sistema de roteamento e despacha as requisições * Initializes the routing system and dispatches requests
* para os manipuladores apropriados usando FastRoute.
*
* This file initializes the routing system and dispatches requests
* to appropriate handlers using FastRoute. * to appropriate handlers using FastRoute.
*/ */

View file

@ -3,20 +3,15 @@
* *
* The service worker acts as a network proxy and share target handler, * The service worker acts as a network proxy and share target handler,
* enabling the PWA to receive shared URLs from other applications. * enabling the PWA to receive shared URLs from other applications.
*
* O service worker atua como um proxy de rede e manipulador de compartilhamento,
* permitindo que o PWA receba URLs compartilhadas de outros aplicativos.
*/ */
// Handles all network requests // Handles all network requests
// Gerencia todas as requisições de rede
self.addEventListener('fetch', (event) => { self.addEventListener('fetch', (event) => {
event.respondWith(fetch(event.request)); event.respondWith(fetch(event.request));
}); });
/** /**
* Share target event handler - processes URLs shared from other applications * Share target event handler - processes URLs shared from other applications
* Manipulador do evento share_target - processa URLs compartilhadas de outros aplicativos
*/ */
self.addEventListener('share_target', (event) => { self.addEventListener('share_target', (event) => {
event.respondWith((async () => { event.respondWith((async () => {

View file

@ -8,30 +8,24 @@ server {
server_name _; server_name _;
# Hide NGINX version to reduce exposed information # Hide NGINX version to reduce exposed information
# Oculta a versão do NGINX para reduzir informações expostas
server_tokens off; server_tokens off;
# NGINX-specific security configurations # NGINX-specific security configurations
# Configurações de segurança específicas do NGINX
# Limit upload size to prevent denial of service attacks # Limit upload size to prevent denial of service attacks
# Limita o tamanho de uploads para prevenir ataques de negação de serviço
client_max_body_size 10M; client_max_body_size 10M;
client_body_buffer_size 128k; client_body_buffer_size 128k;
# Disable directory listing to prevent structure exposure # Disable directory listing to prevent structure exposure
# Desativa listagem de diretórios para evitar exposição de estrutura
autoindex off; autoindex off;
# Block access to sensitive directories # Block access to sensitive directories
# Bloqueia acesso a diretórios sensíveis
location ~ ^/(logs|cache|inc|data|cli|bin|languages|vendor)/ { location ~ ^/(logs|cache|inc|data|cli|bin|languages|vendor)/ {
deny all; deny all;
return 403; return 403;
} }
# All requests go through index.php for FastRoute routing # All requests go through index.php for FastRoute routing
# Todas as requisições passam pelo index.php para roteamento FastRoute
location / { location / {
try_files $uri $uri/ /index.php?$args; try_files $uri $uri/ /index.php?$args;
} }
@ -41,26 +35,22 @@ server {
fastcgi_pass 127.0.0.1:9000; fastcgi_pass 127.0.0.1:9000;
# Hide header that reveals PHP version # Hide header that reveals PHP version
# Oculta cabeçalho que revela a versão do PHP
fastcgi_hide_header X-Powered-By; fastcgi_hide_header X-Powered-By;
} }
# Block access to hidden files and directories # Block access to hidden files and directories
# Bloqueia acesso a arquivos e diretórios ocultos
location ~ /\. { location ~ /\. {
deny all; deny all;
return 404; return 404;
} }
# Block access to configuration and database files # Block access to configuration and database files
# Bloqueia acesso a arquivos de configuração e banco de dados
location ~ \.(sql|conf|ini)$ { location ~ \.(sql|conf|ini)$ {
deny all; deny all;
return 404; return 404;
} }
# Minimize logs to reduce information exposure # Minimize logs to reduce information exposure
# Minimiza logs para reduzir exposição de informações
access_log /dev/null; access_log /dev/null;
error_log /dev/stderr warn; error_log /dev/stderr warn;
} }

View file

@ -1,55 +1,44 @@
#!/bin/bash #!/bin/bash
########################################### ###########################################
# Marreta Docker Entrypoint # Docker Entrypoint
#
# This script initializes the Marreta container:
# - Configures environment variables
# - Adjusts directory permissions
# - Starts and checks services (PHP-FPM and Nginx)
#
# Este script inicializa o container do Marreta:
# - Configura variáveis de ambiente
# - Ajusta permissões dos diretórios
# - Inicia e verifica serviços (PHP-FPM e Nginx)
########################################### ###########################################
# Cores de saída / Output colors # Output colors
RED='\033[0;31m' RED='\033[0;31m'
GREEN='\033[0;32m' GREEN='\033[0;32m'
YELLOW='\033[1;33m' YELLOW='\033[1;33m'
NC='\033[0m' # No Color / Sem Cor NC='\033[0m'
# Função de log de sucesso / Success log function # Success log function
log_success() { log_success() {
echo -e "${GREEN}[✓] $1${NC}" echo -e "${GREEN}[✓] $1${NC}"
} }
# Função de log de erro / Error log function # Error log function
log_error() { log_error() {
echo -e "${RED}[✗] $1${NC}" echo -e "${RED}[✗] $1${NC}"
exit 1 exit 1
} }
# Função de log de informação / Info log function # Info log function
log_info() { log_info() {
echo -e "${YELLOW}[i] $1${NC}" echo -e "${YELLOW}[i] $1${NC}"
} }
echo -e "\n${YELLOW}=== Starting Marreta ===${NC}\n" echo -e "\n${YELLOW}=== Starting Marreta ===${NC}\n"
# === Configuração das Variáveis de Ambiente / Environment Variables Configuration === # Environment Variables Configuration
log_info "Configuring environment variables..." log_info "Configuring environment variables..."
# Arquivo de ambiente (.env) / Env file (.env) # Env file (.env)
ENV_FILE="/app/.env" ENV_FILE="/app/.env"
# Limpa o arquivo de ambiente / Clean Env file # Clean Env file
> "$ENV_FILE" > "$ENV_FILE"
while IFS='=' read -r key value; do while IFS='=' read -r key value; do
# If value contains spaces and is not already quoted, add quotes # If value contains spaces and is not already quoted, add quotes
# Se o valor contém espaços e não está entre aspas, adiciona aspas
if [[ "$value" =~ \ ]] && ! [[ "$value" =~ ^\".*\"$ ]]; then if [[ "$value" =~ \ ]] && ! [[ "$value" =~ ^\".*\"$ ]]; then
value="\"$value\"" value="\"$value\""
fi fi
@ -59,7 +48,7 @@ done < <(env)
log_success "Environment variables configured" log_success "Environment variables configured"
# === Ajuste de Permissões / Permissions Adjustment === # Permissions Adjustment
log_info "Adjusting directory permissions..." log_info "Adjusting directory permissions..."
chown -R www-data:www-data /app/cache /app/logs chown -R www-data:www-data /app/cache /app/logs
@ -67,7 +56,7 @@ chmod -R 775 /app/cache /app/logs
log_success "Permissions adjusted" log_success "Permissions adjusted"
# === Funções de Verificação de Serviços / Service Check Functions === # Service Check Functions
check_nginx() { check_nginx() {
if ! pgrep nginx > /dev/null; then if ! pgrep nginx > /dev/null; then
log_error "Failed to start Nginx" log_error "Failed to start Nginx"
@ -84,10 +73,10 @@ check_php_fpm() {
fi fi
} }
# === Inicialização dos Serviços / Services Initialization === # Services Initialization
echo -e "\n${YELLOW}=== Starting services ===${NC}\n" echo -e "\n${YELLOW}=== Starting services ===${NC}\n"
# Diretório do PHP-FPM / PHP-FPM Directory # PHP-FPM Directory
if [ ! -d /var/run/php ]; then if [ ! -d /var/run/php ]; then
log_info "Creating PHP-FPM directory..." log_info "Creating PHP-FPM directory..."
mkdir -p /var/run/php mkdir -p /var/run/php
@ -95,13 +84,13 @@ if [ ! -d /var/run/php ]; then
log_success "PHP-FPM directory created" log_success "PHP-FPM directory created"
fi fi
# Iniciando PHP-FPM / Starting PHP-FPM # Starting PHP-FPM
log_info "Starting PHP-FPM..." log_info "Starting PHP-FPM..."
php-fpm & php-fpm &
sleep 3 sleep 3
check_php_fpm check_php_fpm
# Verificando configuração do Nginx / Checking Nginx configuration # Checking Nginx configuration
log_info "Checking Nginx configuration..." log_info "Checking Nginx configuration..."
nginx -t nginx -t
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
@ -110,7 +99,7 @@ else
log_success "Valid Nginx configuration" log_success "Valid Nginx configuration"
fi fi
# Iniciando Nginx / Starting Nginx # Starting Nginx
log_info "Starting Nginx..." log_info "Starting Nginx..."
nginx -g "daemon off;" & nginx -g "daemon off;" &
sleep 3 sleep 3
@ -118,8 +107,8 @@ check_nginx
echo -e "\n${GREEN}=== Marreta initialized ===${NC}\n" echo -e "\n${GREEN}=== Marreta initialized ===${NC}\n"
# Aguarda qualquer processo terminar / Wait for any process to exit # Wait for any process to exit
wait -n wait -n
# Sai com o status do processo que terminou primeiro / Exit with status of process that exited first # Exit with status of process that exited first
exit $? exit $?