mirror of
https://github.com/manualdousuario/marreta.git
synced 2025-09-01 10:10:14 +00:00
implementado fastroute para controle e segurança de rotas
This commit is contained in:
parent
4cd475c8ef
commit
bc06a7cbc9
12 changed files with 570 additions and 539 deletions
133
app/api.php
133
app/api.php
|
@ -1,133 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* URL Analysis API
|
||||
* API para análise de URLs
|
||||
*
|
||||
* This file implements a REST endpoint that receives URLs via GET
|
||||
* and returns processed results in JSON format.
|
||||
*
|
||||
* Este arquivo implementa um endpoint REST que recebe URLs via GET
|
||||
* e retorna resultados processados em formato JSON.
|
||||
*
|
||||
* Features / Funcionalidades:
|
||||
* - URL validation / Validação de URLs
|
||||
* - Content analysis / Análise de conteúdo
|
||||
* - Error handling / Tratamento de erros
|
||||
* - CORS support / Suporte a CORS
|
||||
*/
|
||||
|
||||
require_once 'config.php';
|
||||
require_once 'inc/URLAnalyzer.php';
|
||||
require_once 'inc/Language.php';
|
||||
|
||||
// Initialize language system with default language
|
||||
// Inicializa o sistema de idiomas com o idioma padrão
|
||||
Language::init(LANGUAGE);
|
||||
|
||||
// Set content type as JSON
|
||||
// Define o tipo de conteúdo como JSON
|
||||
header('Content-Type: application/json');
|
||||
|
||||
// Enable CORS (Cross-Origin Resource Sharing)
|
||||
// Habilita CORS (Cross-Origin Resource Sharing)
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
header('Access-Control-Allow-Methods: GET');
|
||||
|
||||
// Get request URL from path
|
||||
// Obtém a URL da requisição a partir do path
|
||||
$path = $_SERVER['REQUEST_URI'];
|
||||
$prefix = '/api/';
|
||||
|
||||
if (strpos($path, $prefix) === 0) {
|
||||
$url = urldecode(substr($path, strlen($prefix)));
|
||||
|
||||
/**
|
||||
* Function to send standardized JSON response
|
||||
* Função para enviar resposta JSON padronizada
|
||||
*
|
||||
* @param array $data Data to be sent in response / Dados a serem enviados na resposta
|
||||
* @param int $statusCode HTTP status code / Código de status HTTP
|
||||
*/
|
||||
function sendResponse($data, $statusCode = 200)
|
||||
{
|
||||
http_response_code($statusCode);
|
||||
$response = [
|
||||
'status' => $statusCode
|
||||
];
|
||||
|
||||
if (isset($data['error'])) {
|
||||
$response['error'] = $data['error'];
|
||||
} else if (isset($data['url'])) {
|
||||
$response['url'] = $data['url'];
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Basic URL validation
|
||||
// Validação básica da URL
|
||||
if (!$url || !filter_var($url, FILTER_VALIDATE_URL)) {
|
||||
sendResponse([
|
||||
'error' => [
|
||||
'type' => URLAnalyzer::ERROR_INVALID_URL,
|
||||
'message' => Language::getMessage('INVALID_URL')['message']
|
||||
]
|
||||
], 400);
|
||||
}
|
||||
|
||||
try {
|
||||
// Instantiate URL analyzer
|
||||
// Instancia o analisador de URLs
|
||||
$analyzer = new URLAnalyzer();
|
||||
|
||||
// Try to analyze the provided URL
|
||||
// Tenta analisar a URL fornecida
|
||||
$analyzer->analyze($url);
|
||||
|
||||
// If analysis is successful, return the processed URL
|
||||
// Se a análise for bem-sucedida, retorna a URL processada
|
||||
sendResponse([
|
||||
'url' => SITE_URL . '/p/' . $url
|
||||
], 200);
|
||||
} catch (URLAnalyzerException $e) {
|
||||
// Get error details from the exception
|
||||
// Obtém detalhes do erro da exceção
|
||||
$errorType = $e->getErrorType();
|
||||
$additionalInfo = $e->getAdditionalInfo();
|
||||
|
||||
// Add error header for better client-side handling
|
||||
// Adiciona header de erro para melhor tratamento no cliente
|
||||
header('X-Error-Type: ' . $errorType);
|
||||
if ($additionalInfo) {
|
||||
header('X-Error-Info: ' . $additionalInfo);
|
||||
}
|
||||
|
||||
sendResponse([
|
||||
'error' => [
|
||||
'type' => $errorType,
|
||||
'message' => $e->getMessage(),
|
||||
'details' => $additionalInfo ?: null
|
||||
]
|
||||
], $e->getCode());
|
||||
} catch (Exception $e) {
|
||||
// Handle any other unexpected errors
|
||||
// Trata quaisquer outros erros inesperados
|
||||
sendResponse([
|
||||
'error' => [
|
||||
'type' => URLAnalyzer::ERROR_GENERIC_ERROR,
|
||||
'message' => Language::getMessage('GENERIC_ERROR')['message']
|
||||
]
|
||||
], 500);
|
||||
}
|
||||
} else {
|
||||
// Return 404 error for endpoints not found
|
||||
// Retorna erro 404 para endpoints não encontrados
|
||||
sendResponse([
|
||||
'error' => [
|
||||
'type' => URLAnalyzer::ERROR_NOT_FOUND,
|
||||
'message' => Language::getMessage('NOT_FOUND')['message']
|
||||
]
|
||||
], 404);
|
||||
}
|
|
@ -4,11 +4,13 @@
|
|||
"aws/aws-sdk-php": "^3.0",
|
||||
"php-curl-class/php-curl-class": "^11.0",
|
||||
"php-webdriver/webdriver": "^1.15",
|
||||
"monolog/monolog": "^3.8.1"
|
||||
"monolog/monolog": "^3.8.1",
|
||||
"nikic/fast-route": "^1.3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Inc\\": "inc/"
|
||||
"Inc\\": "inc/",
|
||||
"App\\": "src/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,10 +16,10 @@
|
|||
* - Selenium extraction support when enabled by domain / Suporte a extração via Selenium quando habilitado por domínio
|
||||
*/
|
||||
|
||||
require_once 'Rules.php';
|
||||
require_once 'Cache.php';
|
||||
require_once 'Logger.php';
|
||||
require_once 'Language.php';
|
||||
require_once __DIR__ . '/Rules.php';
|
||||
require_once __DIR__ . '/Cache.php';
|
||||
require_once __DIR__ . '/Logger.php';
|
||||
require_once __DIR__ . '/Language.php';
|
||||
|
||||
use Curl\Curl;
|
||||
use Facebook\WebDriver\Remote\DesiredCapabilities;
|
||||
|
@ -253,14 +253,14 @@ class URLAnalyzer
|
|||
$host = preg_replace('/^www\./', '', $host);
|
||||
|
||||
if (in_array($host, BLOCKED_DOMAINS)) {
|
||||
Logger::getInstance()->log($cleanUrl, 'BLOCKED_DOMAIN');
|
||||
Logger::getInstance()->logUrl($cleanUrl, 'BLOCKED_DOMAIN');
|
||||
$this->throwError(self::ERROR_BLOCKED_DOMAIN);
|
||||
}
|
||||
|
||||
// Check URL status code before proceeding
|
||||
$redirectInfo = $this->checkStatus($cleanUrl);
|
||||
if ($redirectInfo['httpCode'] !== 200) {
|
||||
Logger::getInstance()->log($cleanUrl, 'INVALID_STATUS_CODE', "HTTP {$redirectInfo['httpCode']}");
|
||||
Logger::getInstance()->logUrl($cleanUrl, 'INVALID_STATUS_CODE', "HTTP {$redirectInfo['httpCode']}");
|
||||
if ($redirectInfo['httpCode'] === 404) {
|
||||
$this->throwError(self::ERROR_NOT_FOUND);
|
||||
} else {
|
||||
|
@ -296,7 +296,7 @@ class URLAnalyzer
|
|||
return $processedContent;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
Logger::getInstance()->log($cleanUrl, strtoupper($fetchStrategy) . '_ERROR', $e->getMessage());
|
||||
Logger::getInstance()->logUrl($cleanUrl, strtoupper($fetchStrategy) . '_ERROR', $e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
@ -326,7 +326,7 @@ class URLAnalyzer
|
|||
}
|
||||
|
||||
// If we get here, all strategies failed
|
||||
Logger::getInstance()->log($cleanUrl, 'GENERAL_FETCH_ERROR');
|
||||
Logger::getInstance()->logUrl($cleanUrl, 'GENERAL_FETCH_ERROR');
|
||||
if ($lastError) {
|
||||
$message = $lastError->getMessage();
|
||||
if (strpos($message, 'DNS') !== false) {
|
||||
|
|
217
app/index.php
217
app/index.php
|
@ -1,214 +1,17 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Página principal do sistema / Main system page
|
||||
* Arquivo de entrada da aplicação
|
||||
* Application entry point
|
||||
*
|
||||
* Este arquivo implementa a interface web principal, incluindo:
|
||||
* - Formulário para análise de URLs
|
||||
* - Tratamento de mensagens de erro/sucesso
|
||||
* - Documentação da API
|
||||
* - Interface para bookmarklet
|
||||
* - Links para serviços alternativos
|
||||
*
|
||||
* This file implements the main web interface, including:
|
||||
* - URL analysis form
|
||||
* - Error/success message handling
|
||||
* - API documentation
|
||||
* - Bookmarklet interface
|
||||
* - Links to alternative services
|
||||
* Este arquivo inicializa o sistema de roteamento e despacha as requisições
|
||||
* para os manipuladores apropriados usando FastRoute.
|
||||
*
|
||||
* This file initializes the routing system and dispatches requests
|
||||
* to appropriate handlers using FastRoute.
|
||||
*/
|
||||
|
||||
require_once 'config.php';
|
||||
require_once 'inc/Cache.php';
|
||||
require_once 'inc/Language.php';
|
||||
require_once __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
// Inicialização das traduções / Initialize translations
|
||||
Language::init(LANGUAGE);
|
||||
|
||||
// Inicialização de variáveis / Variable initialization
|
||||
$message = '';
|
||||
$message_type = '';
|
||||
$url = '';
|
||||
|
||||
// Processa mensagens de erro/alerta da query string / Process error/warning messages from query string
|
||||
if (isset($_GET['message'])) {
|
||||
$message_key = $_GET['message'];
|
||||
$messageData = Language::getMessage($message_key);
|
||||
$message = $messageData['message'];
|
||||
$message_type = $messageData['type'];
|
||||
}
|
||||
|
||||
// Processa submissão do formulário / Process form submission
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['url'])) {
|
||||
$url = filter_var($_POST['url'], FILTER_SANITIZE_URL);
|
||||
if (filter_var($url, FILTER_VALIDATE_URL)) {
|
||||
header('Location: ' . SITE_URL . '/p/' . urlencode($url));
|
||||
exit;
|
||||
} else {
|
||||
$messageData = Language::getMessage('INVALID_URL');
|
||||
$message = $messageData['message'];
|
||||
$message_type = $messageData['type'];
|
||||
}
|
||||
}
|
||||
|
||||
// Inicializa o cache para contagem / Initialize cache for counting
|
||||
$cache = new Cache();
|
||||
$cache_folder = $cache->getCacheFileCount();
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="<?php echo Language::getCurrentLanguage(); ?>">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title><?php echo SITE_NAME; ?></title>
|
||||
<link rel="icon" href="<?php echo SITE_URL; ?>/assets/svg/marreta.svg" type="image/svg+xml">
|
||||
<meta name="theme-color" content="#2563eb">
|
||||
<link rel="manifest" href="<?php echo SITE_URL; ?>/manifest.json">
|
||||
|
||||
<!-- PWA meta tags -->
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="application-name" content="<?php echo SITE_NAME; ?>">
|
||||
|
||||
<!-- Open Graph meta tags -->
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="<?php echo SITE_URL; ?>" />
|
||||
<meta property="og:title" content="<?php echo SITE_NAME; ?>" />
|
||||
<meta property="og:description" content="<?php echo htmlspecialchars(SITE_DESCRIPTION); ?>" />
|
||||
<meta property="og:image" content="<?php echo SITE_URL; ?>/assets/opengraph.png" />
|
||||
<script src="https://cdn.tailwindcss.com/3.4.15"></script>
|
||||
</head>
|
||||
|
||||
<body class="bg-gray-50 min-h-screen">
|
||||
<div class="container mx-auto px-4 py-8 max-w-4xl">
|
||||
<!-- Cabeçalho da página / Page header -->
|
||||
<div class="text-center mb-8">
|
||||
<h1 class="text-4xl font-bold text-gray-800 mb-4">
|
||||
<img src="assets/svg/marreta.svg" class="inline-block w-12 h-12 mb-2" alt="Marreta">
|
||||
<?php echo SITE_NAME; ?>
|
||||
</h1>
|
||||
<p class="text-gray-600 text-lg"><?php echo SITE_DESCRIPTION; ?></p>
|
||||
<p class="text-gray-600 text-lg">
|
||||
<span class="font-bold text-blue-600">
|
||||
<?php echo number_format($cache_folder, 0, ',', '.'); ?>
|
||||
</span>
|
||||
<span><?php echo Language::get('walls_destroyed'); ?></span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Formulário principal de análise de URLs / Main URL analysis form -->
|
||||
<div class="bg-white rounded-xl shadow-lg p-8 mb-8">
|
||||
<form id="urlForm" method="POST" onsubmit="return validateForm()" class="space-y-6">
|
||||
<div class="relative">
|
||||
<div class="flex items-stretch">
|
||||
<span class="inline-flex items-center px-5 rounded-l-lg border border-r-0 border-gray-300 bg-gray-50 text-gray-500">
|
||||
<img src="assets/svg/link.svg" class="w-6 h-6" alt="Link">
|
||||
</span>
|
||||
<input type="url"
|
||||
name="url"
|
||||
id="url"
|
||||
class="flex-1 block w-full rounded-none rounded-r-lg text-lg py-4 border border-l-0 border-gray-300 bg-gray-50 focus:border-blue-500 focus:ring-blue-500 shadow-sm bg-gray-50"
|
||||
placeholder="<?php echo Language::get('url_placeholder'); ?>"
|
||||
value="<?php echo htmlspecialchars($url); ?>"
|
||||
required
|
||||
pattern="https?://.+"
|
||||
title="<?php echo Language::getMessage('INVALID_URL')['message']; ?>">
|
||||
</div>
|
||||
<button type="submit"
|
||||
class="mt-4 w-full inline-flex justify-center items-center px-6 py-4 border border-transparent text-lg font-medium rounded-lg text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-colors duration-200">
|
||||
<img src="assets/svg/search.svg" class="w-6 h-6 mr-3" alt="Search">
|
||||
<?php echo Language::get('analyze_button'); ?>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Aviso sobre bloqueadores de anúncios / Ad blocker warning -->
|
||||
<div class="mt-4 text-sm text-gray-600 flex items-start">
|
||||
<p><?php echo str_replace('{site_name}', SITE_NAME, Language::get('adblocker_warning')); ?></p>
|
||||
</div>
|
||||
|
||||
<!-- Área de mensagens de erro/alerta / Error/warning message area -->
|
||||
<?php if ($message): ?>
|
||||
<div class="mt-6 <?php echo $message_type === 'error' ? 'bg-red-50 border-red-400' : 'bg-yellow-50 border-yellow-400'; ?> border-l-4 p-4 rounded-r">
|
||||
<div class="flex">
|
||||
<div class="flex-shrink-0">
|
||||
<?php if ($message_type === 'error'): ?>
|
||||
<img src="assets/svg/error.svg" class="w-6 h-6" alt="Error">
|
||||
<?php else: ?>
|
||||
<img src="assets/svg/warning.svg" class="w-6 h-6" alt="Warning">
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<p class="text-base <?php echo $message_type === 'error' ? 'text-red-700' : 'text-yellow-700'; ?>">
|
||||
<?php echo htmlspecialchars($message); ?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Adicionar como aplicativo / Add as app (mobile only) -->
|
||||
<div class="bg-white rounded-xl shadow-lg p-8 mt-8 mb-8 md:hidden">
|
||||
<h2 class="text-xl font-semibold text-gray-800 mb-6 flex items-center">
|
||||
<img src="assets/svg/marreta.svg" class="w-6 h-6 mr-3" alt="App">
|
||||
<?php echo Language::get('add_as_app'); ?>
|
||||
</h2>
|
||||
<div class="space-y-4">
|
||||
<p class="text-gray-600">
|
||||
<?php echo str_replace('{site_name}', SITE_NAME, Language::get('add_as_app_description')); ?>
|
||||
</p>
|
||||
<div class="bg-gray-50 rounded-lg p-4">
|
||||
<ol class="list-decimal list-inside space-y-2 text-gray-700">
|
||||
<li><?php echo Language::get('add_as_app_step1'); ?></li>
|
||||
<li><?php echo Language::get('add_as_app_step2'); ?></li>
|
||||
<li><?php echo Language::get('add_as_app_step3'); ?></li>
|
||||
<li><?php echo str_replace('{site_name}', SITE_NAME, Language::get('add_as_app_step4')); ?></li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Seção de Bookmarklet / Bookmarklet section (desktop only) -->
|
||||
<div class="bg-white rounded-xl shadow-lg p-8 mt-8 mb-8 hidden md:block">
|
||||
<h2 class="text-xl font-semibold text-gray-800 mb-6 flex items-center">
|
||||
<img src="assets/svg/bookmark.svg" class="w-6 h-6 mr-3" alt="Favoritos">
|
||||
<?php echo Language::get('bookmarklet_title'); ?>
|
||||
</h2>
|
||||
<div class="space-y-4">
|
||||
<p class="text-gray-600">
|
||||
<?php echo str_replace('{site_name}', SITE_NAME, Language::get('bookmarklet_description')); ?>
|
||||
</p>
|
||||
<div class="flex justify-center">
|
||||
<a href="javascript:(function(){let currentUrl=window.location.href;window.location.href='<?php echo SITE_URL; ?>/p/'+encodeURIComponent(currentUrl);})()"
|
||||
class="inline-flex items-center px-6 py-3 border-2 border-blue-500 font-medium rounded-lg text-blue-600 bg-white hover:bg-blue-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-colors duration-200 cursor-move"
|
||||
onclick="return false;">
|
||||
<img src="assets/svg/marreta.svg" class="w-5 h-5 mr-2" alt="Marreta">
|
||||
<?php echo str_replace('{site_name}', SITE_NAME, Language::get('open_in')); ?>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-gray-600 text-center text-sm">
|
||||
<p>
|
||||
<?php echo Language::get('open_source_description'); ?>
|
||||
</p>
|
||||
<p class="mt-2">
|
||||
<a href="https://github.com/manualdousuario/marreta/wiki/API-Rest" target="_blank" class="underline">API Rest</a> ● <a href="https://github.com/manualdousuario/marreta/" target="_blank" class="underline">Github</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Scripts JavaScript -->
|
||||
<script>
|
||||
<?php
|
||||
$js_file = 'assets/js/scripts.js';
|
||||
if (file_exists($js_file)) {
|
||||
echo file_get_contents($js_file);
|
||||
}
|
||||
?>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
$router = new App\Router();
|
||||
$router->dispatch();
|
||||
|
|
95
app/p.php
95
app/p.php
|
@ -1,95 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* URL Processor
|
||||
* Processador de URLs
|
||||
*
|
||||
* This file is responsible for:
|
||||
* - Receiving URLs through the /p/ path
|
||||
* - Validating URL format
|
||||
* - Processing content using URLAnalyzer
|
||||
* - Displaying processed content or redirecting in case of error
|
||||
*
|
||||
* Este arquivo é responsável por:
|
||||
* - Receber URLs através do path /p/
|
||||
* - Validar o formato da URL
|
||||
* - Processar o conteúdo usando o URLAnalyzer
|
||||
* - Exibir o conteúdo processado ou redirecionar em caso de erro
|
||||
*
|
||||
* Usage example / Exemplo de uso:
|
||||
* /p/https://exemplo.com
|
||||
*/
|
||||
|
||||
require_once 'config.php';
|
||||
require_once 'inc/URLAnalyzer.php';
|
||||
|
||||
// Extract URL from request path
|
||||
// Extrai a URL do path da requisição
|
||||
$path = $_SERVER['REQUEST_URI'];
|
||||
$prefix = '/p/';
|
||||
|
||||
if (strpos($path, $prefix) === 0) {
|
||||
// Remove prefix and decode URL
|
||||
// Remove o prefixo e decodifica a URL
|
||||
$url = urldecode(substr($path, strlen($prefix)));
|
||||
|
||||
// Validate URL format
|
||||
// Valida o formato da URL
|
||||
if (filter_var($url, FILTER_VALIDATE_URL)) {
|
||||
$analyzer = new URLAnalyzer();
|
||||
try {
|
||||
// Check for redirects
|
||||
// Verifica se há redirecionamentos
|
||||
$redirectInfo = $analyzer->checkStatus($url);
|
||||
|
||||
// If there's a redirect and the final URL is different
|
||||
// Se houver redirecionamento e a URL final for diferente
|
||||
if ($redirectInfo['hasRedirect'] && $redirectInfo['finalUrl'] !== $url) {
|
||||
// Redirect to final URL
|
||||
// Redireciona para a URL final
|
||||
header('Location: ' . SITE_URL . '/p/' . urlencode($redirectInfo['finalUrl']));
|
||||
exit;
|
||||
}
|
||||
|
||||
// If there's no redirect or if already at final URL
|
||||
// Se não houver redirecionamento ou se já estiver na URL final
|
||||
// Try to analyze and process the URL
|
||||
// Tenta analisar e processar a URL
|
||||
$content = $analyzer->analyze($url);
|
||||
// Display processed content
|
||||
// Exibe o conteúdo processado
|
||||
echo $content;
|
||||
exit;
|
||||
} catch (URLAnalyzerException $e) {
|
||||
// Get error type and additional info from exception
|
||||
// Obtém o tipo de erro e informações adicionais da exceção
|
||||
$errorType = $e->getErrorType();
|
||||
$additionalInfo = $e->getAdditionalInfo();
|
||||
|
||||
// Handle blocked domain with redirect URL
|
||||
// Trata domínio bloqueado com URL de redirecionamento
|
||||
if ($errorType === URLAnalyzer::ERROR_BLOCKED_DOMAIN && $additionalInfo) {
|
||||
header('Location: ' . trim($additionalInfo) . '?message=' . $errorType);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Redirect to home page with error message
|
||||
// Redireciona para a página inicial com mensagem de erro
|
||||
header('Location: /?message=' . $errorType);
|
||||
exit;
|
||||
} catch (Exception $e) {
|
||||
// Handle any other unexpected errors
|
||||
// Trata quaisquer outros erros inesperados
|
||||
header('Location: /?message=' . URLAnalyzer::ERROR_GENERIC_ERROR);
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
// Invalid URL / URL inválida
|
||||
header('Location: /?message=' . URLAnalyzer::ERROR_INVALID_URL);
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
// Invalid path / Path inválido
|
||||
header('Location: /?message=' . URLAnalyzer::ERROR_NOT_FOUND);
|
||||
exit;
|
||||
}
|
81
app/pwa.php
81
app/pwa.php
|
@ -1,81 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* PWA Share Target Handler
|
||||
*
|
||||
* This script handles the PWA (Progressive Web App) share target functionality.
|
||||
* It receives a URL parameter via GET request and performs a 301 permanent
|
||||
* redirect to the /p/{URL} endpoint. If no URL is provided, redirects to
|
||||
* the homepage.
|
||||
*
|
||||
* Security measures:
|
||||
* - URL sanitization to prevent XSS attacks
|
||||
* - URL encoding to ensure proper parameter handling
|
||||
*
|
||||
* Este script gerencia a funcionalidade de compartilhamento do PWA (Progressive Web App).
|
||||
* Ele recebe um parâmetro URL via requisição GET e realiza um redirecionamento
|
||||
* permanente 301 para o endpoint /p/{URL}. Se nenhuma URL for fornecida,
|
||||
* redireciona para a página inicial.
|
||||
*
|
||||
* Medidas de segurança:
|
||||
* - Sanitização da URL para prevenir ataques XSS
|
||||
* - Codificação da URL para garantir o correto tratamento dos parâmetros
|
||||
*/
|
||||
|
||||
require_once 'config.php';
|
||||
|
||||
// Get URL and text parameters from GET request
|
||||
// Obtém os parâmetros URL e text da requisição GET
|
||||
$url = $_GET['url'] ?? '';
|
||||
$text = $_GET['text'] ?? '';
|
||||
|
||||
/**
|
||||
* Validates if a given URL is valid
|
||||
* Valida se uma URL fornecida é válida
|
||||
*
|
||||
* @param string $url URL to validate / URL para validar
|
||||
* @return bool Returns true if URL is valid, false otherwise / Retorna true se a URL for válida, false caso contrário
|
||||
*/
|
||||
function isValidUrl($url) {
|
||||
// First sanitize the URL
|
||||
// Primeiro sanitiza a URL
|
||||
$sanitized_url = filter_var($url, FILTER_SANITIZE_URL);
|
||||
|
||||
// Then validate it
|
||||
// Então valida
|
||||
return filter_var($sanitized_url, FILTER_VALIDATE_URL) !== false;
|
||||
}
|
||||
|
||||
// Check URL parameter first
|
||||
// Verifica primeiro o parâmetro URL
|
||||
if (!empty($url) && isValidUrl($url)) {
|
||||
$redirect_url = $url;
|
||||
}
|
||||
// If URL is not valid, check text parameter
|
||||
// Se a URL não é válida, verifica o parâmetro text
|
||||
elseif (!empty($text) && isValidUrl($text)) {
|
||||
$redirect_url = $text;
|
||||
}
|
||||
// If text is not a URL but contains content, try to extract URL from it
|
||||
// Se o texto não é uma URL mas contém conteúdo, tenta extrair URL dele
|
||||
elseif (!empty($text)) {
|
||||
if (preg_match('/https?:\/\/[^\s]+/', $text, $matches)) {
|
||||
$redirect_url = $matches[0];
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a valid URL, redirect to it
|
||||
// Se temos uma URL válida, redireciona para ela
|
||||
if (isset($redirect_url)) {
|
||||
// Sanitize URL to prevent XSS
|
||||
// Sanitiza a URL para prevenir XSS
|
||||
$redirect_url = htmlspecialchars($redirect_url, ENT_QUOTES, 'UTF-8');
|
||||
|
||||
header('HTTP/1.1 301 Moved Permanently');
|
||||
header('Location: /p/' . urlencode($redirect_url));
|
||||
exit;
|
||||
}
|
||||
|
||||
// If no valid URL found in either parameter, redirect to homepage
|
||||
// Se nenhuma URL válida foi encontrada em nenhum dos parâmetros, redireciona para a página inicial
|
||||
header('Location: /');
|
||||
exit;
|
179
app/src/Router.php
Normal file
179
app/src/Router.php
Normal file
|
@ -0,0 +1,179 @@
|
|||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
use FastRoute;
|
||||
|
||||
/**
|
||||
* Classe Router - Gerenciador de rotas da aplicação
|
||||
* Router Class - Application route manager
|
||||
*
|
||||
* Esta classe implementa o sistema de roteamento usando FastRoute para:
|
||||
* - Gerenciar todas as rotas da aplicação
|
||||
* - Processar requisições HTTP
|
||||
* - Direcionar para os manipuladores apropriados
|
||||
*
|
||||
* This class implements the routing system using FastRoute to:
|
||||
* - Manage all application routes
|
||||
* - Process HTTP requests
|
||||
* - Direct to appropriate handlers
|
||||
*/
|
||||
class Router
|
||||
{
|
||||
/**
|
||||
* Instância do dispatcher do FastRoute
|
||||
* FastRoute dispatcher instance
|
||||
*/
|
||||
private $dispatcher;
|
||||
|
||||
/**
|
||||
* Construtor - Inicializa as rotas da aplicação
|
||||
* Constructor - Initializes application routes
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->dispatcher = FastRoute\simpleDispatcher(function(FastRoute\RouteCollector $r) {
|
||||
// Rota principal - página inicial
|
||||
// Main route - home page
|
||||
$r->addRoute('GET', '/', function() {
|
||||
// Inicialização das variáveis para a view principal
|
||||
// Initialize variables for the main view
|
||||
require_once __DIR__ . '/../config.php';
|
||||
require_once __DIR__ . '/../inc/Cache.php';
|
||||
require_once __DIR__ . '/../inc/Language.php';
|
||||
|
||||
\Language::init(LANGUAGE);
|
||||
|
||||
$message = '';
|
||||
$message_type = '';
|
||||
$url = '';
|
||||
|
||||
// Processa mensagens da query string
|
||||
// Process query string messages
|
||||
if (isset($_GET['message'])) {
|
||||
$message_key = $_GET['message'];
|
||||
$messageData = \Language::getMessage($message_key);
|
||||
$message = $messageData['message'];
|
||||
$message_type = $messageData['type'];
|
||||
}
|
||||
|
||||
// Processa submissão do formulário
|
||||
// Process form submission
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['url'])) {
|
||||
$url = filter_var($_POST['url'], FILTER_SANITIZE_URL);
|
||||
if (filter_var($url, FILTER_VALIDATE_URL)) {
|
||||
header('Location: ' . SITE_URL . '/p/' . urlencode($url));
|
||||
exit;
|
||||
} else {
|
||||
$messageData = \Language::getMessage('INVALID_URL');
|
||||
$message = $messageData['message'];
|
||||
$message_type = $messageData['type'];
|
||||
}
|
||||
}
|
||||
|
||||
// Inicializa o cache para contagem
|
||||
// Initialize cache for counting
|
||||
$cache = new \Cache();
|
||||
$cache_folder = $cache->getCacheFileCount();
|
||||
|
||||
require __DIR__ . '/views/home.php';
|
||||
});
|
||||
|
||||
// Rota da API - inclui api.php existente
|
||||
// API route - includes existing api.php
|
||||
$r->addRoute('GET', '/api/{url:.+}', function($vars) {
|
||||
$_GET['url'] = $vars['url'];
|
||||
require __DIR__ . '/api.php';
|
||||
});
|
||||
|
||||
// Rota da API sem parâmetros - redireciona para raiz
|
||||
// API route without parameters - redirects to root
|
||||
$r->addRoute('GET', '/api[/]', function() {
|
||||
header('Location: /');
|
||||
exit;
|
||||
});
|
||||
|
||||
// Rota de processamento - inclui p.php existente
|
||||
// Processing route - includes existing p.php
|
||||
$r->addRoute('GET', '/p/{url:.+}', function($vars) {
|
||||
$_GET['url'] = $vars['url'];
|
||||
require __DIR__ . '/p.php';
|
||||
});
|
||||
|
||||
// Rota de processamento com query parameter ou sem parâmetros
|
||||
// Processing route with query parameter or without parameters
|
||||
$r->addRoute('GET', '/p[/]', function() {
|
||||
if (isset($_GET['url']) || isset($_GET['text'])) {
|
||||
$url = isset($_GET['url']) ? $_GET['url'] : '';
|
||||
$text = isset($_GET['text']) ? $_GET['text'] : '';
|
||||
|
||||
// Check which parameter is a valid URL
|
||||
if (filter_var($url, FILTER_VALIDATE_URL)) {
|
||||
header('Location: /p/' . urlencode($url));
|
||||
exit;
|
||||
} elseif (filter_var($text, FILTER_VALIDATE_URL)) {
|
||||
header('Location: /p/' . urlencode($text));
|
||||
exit;
|
||||
} else {
|
||||
header('Location: /?message=INVALID_URL');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
header('Location: /');
|
||||
exit;
|
||||
});
|
||||
|
||||
// Rota do manifesto PWA - inclui manifest.php existente
|
||||
// PWA manifest route - includes existing manifest.php
|
||||
$r->addRoute('GET', '/manifest.json', function() {
|
||||
require __DIR__ . '/views/manifest.php';
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Despacha a requisição para a rota apropriada
|
||||
* Dispatches the request to the appropriate route
|
||||
*/
|
||||
public function dispatch()
|
||||
{
|
||||
$httpMethod = $_SERVER['REQUEST_METHOD'];
|
||||
$uri = $_SERVER['REQUEST_URI'];
|
||||
|
||||
// Remove a query string mas mantém para processamento
|
||||
// Strip query string but keep for processing
|
||||
$queryString = '';
|
||||
if (false !== $pos = strpos($uri, '?')) {
|
||||
$queryString = substr($uri, $pos);
|
||||
$uri = substr($uri, 0, $pos);
|
||||
}
|
||||
$uri = rawurldecode($uri);
|
||||
|
||||
// Parse query string parameters
|
||||
if ($queryString) {
|
||||
parse_str(substr($queryString, 1), $_GET);
|
||||
}
|
||||
|
||||
$routeInfo = $this->dispatcher->dispatch($httpMethod, $uri);
|
||||
|
||||
switch ($routeInfo[0]) {
|
||||
case FastRoute\Dispatcher::NOT_FOUND:
|
||||
require_once __DIR__ . '/../config.php';
|
||||
header('Location: ' . SITE_URL);
|
||||
exit;
|
||||
|
||||
case FastRoute\Dispatcher::METHOD_NOT_ALLOWED:
|
||||
header("HTTP/1.0 405 Method Not Allowed");
|
||||
echo '405 Method Not Allowed';
|
||||
break;
|
||||
|
||||
case FastRoute\Dispatcher::FOUND:
|
||||
$handler = $routeInfo[1];
|
||||
$vars = $routeInfo[2];
|
||||
call_user_func($handler, $vars);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
119
app/src/api.php
Normal file
119
app/src/api.php
Normal file
|
@ -0,0 +1,119 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* URL Analysis API
|
||||
* API para análise de URLs
|
||||
*
|
||||
* This file implements a REST endpoint that receives URLs via GET
|
||||
* and returns processed results in JSON format.
|
||||
*
|
||||
* Este arquivo implementa um endpoint REST que recebe URLs via GET
|
||||
* e retorna resultados processados em formato JSON.
|
||||
*
|
||||
* Features / Funcionalidades:
|
||||
* - URL validation / Validação de URLs
|
||||
* - Content analysis / Análise de conteúdo
|
||||
* - Error handling / Tratamento de erros
|
||||
* - CORS support / Suporte a CORS
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/../config.php';
|
||||
require_once __DIR__ . '/../inc/URLAnalyzer.php';
|
||||
require_once __DIR__ . '/../inc/Language.php';
|
||||
|
||||
// Initialize language system with default language
|
||||
// Inicializa o sistema de idiomas com o idioma padrão
|
||||
Language::init(LANGUAGE);
|
||||
|
||||
// Set content type as JSON
|
||||
// Define o tipo de conteúdo como JSON
|
||||
header('Content-Type: application/json');
|
||||
|
||||
// Enable CORS (Cross-Origin Resource Sharing)
|
||||
// Habilita CORS (Cross-Origin Resource Sharing)
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
header('Access-Control-Allow-Methods: GET');
|
||||
|
||||
/**
|
||||
* Function to send standardized JSON response
|
||||
* Função para enviar resposta JSON padronizada
|
||||
*
|
||||
* @param array $data Data to be sent in response / Dados a serem enviados na resposta
|
||||
* @param int $statusCode HTTP status code / Código de status HTTP
|
||||
*/
|
||||
function sendResponse($data, $statusCode = 200)
|
||||
{
|
||||
http_response_code($statusCode);
|
||||
$response = [
|
||||
'status' => $statusCode
|
||||
];
|
||||
|
||||
if (isset($data['error'])) {
|
||||
$response['error'] = $data['error'];
|
||||
} else if (isset($data['url'])) {
|
||||
$response['url'] = $data['url'];
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Get URL from Router
|
||||
// Obtém a URL do Router
|
||||
$url = isset($_GET['url']) ? urldecode($_GET['url']) : '';
|
||||
|
||||
// Basic URL validation
|
||||
// Validação básica da URL
|
||||
if (!$url || !filter_var($url, FILTER_VALIDATE_URL)) {
|
||||
sendResponse([
|
||||
'error' => [
|
||||
'type' => URLAnalyzer::ERROR_INVALID_URL,
|
||||
'message' => Language::getMessage('INVALID_URL')['message']
|
||||
]
|
||||
], 400);
|
||||
}
|
||||
|
||||
try {
|
||||
// Instantiate URL analyzer
|
||||
// Instancia o analisador de URLs
|
||||
$analyzer = new URLAnalyzer();
|
||||
|
||||
// Try to analyze the provided URL
|
||||
// Tenta analisar a URL fornecida
|
||||
$analyzer->analyze($url);
|
||||
|
||||
// If analysis is successful, return the processed URL
|
||||
// Se a análise for bem-sucedida, retorna a URL processada
|
||||
sendResponse([
|
||||
'url' => SITE_URL . '/p/' . $url
|
||||
], 200);
|
||||
} catch (URLAnalyzerException $e) {
|
||||
// Get error details from the exception
|
||||
// Obtém detalhes do erro da exceção
|
||||
$errorType = $e->getErrorType();
|
||||
$additionalInfo = $e->getAdditionalInfo();
|
||||
|
||||
// Add error header for better client-side handling
|
||||
// Adiciona header de erro para melhor tratamento no cliente
|
||||
header('X-Error-Type: ' . $errorType);
|
||||
if ($additionalInfo) {
|
||||
header('X-Error-Info: ' . $additionalInfo);
|
||||
}
|
||||
|
||||
sendResponse([
|
||||
'error' => [
|
||||
'type' => $errorType,
|
||||
'message' => $e->getMessage(),
|
||||
'details' => $additionalInfo ?: null
|
||||
]
|
||||
], $e->getCode());
|
||||
} catch (Exception $e) {
|
||||
// Handle any other unexpected errors
|
||||
// Trata quaisquer outros erros inesperados
|
||||
sendResponse([
|
||||
'error' => [
|
||||
'type' => URLAnalyzer::ERROR_GENERIC_ERROR,
|
||||
'message' => Language::getMessage('GENERIC_ERROR')['message']
|
||||
]
|
||||
], 500);
|
||||
}
|
88
app/src/p.php
Normal file
88
app/src/p.php
Normal file
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* URL Processor
|
||||
* Processador de URLs
|
||||
*
|
||||
* This file is responsible for:
|
||||
* - Receiving URLs through the /p/ path
|
||||
* - Validating URL format
|
||||
* - Processing content using URLAnalyzer
|
||||
* - Displaying processed content or redirecting in case of error
|
||||
*
|
||||
* Este arquivo é responsável por:
|
||||
* - Receber URLs através do path /p/
|
||||
* - Validar o formato da URL
|
||||
* - Processar o conteúdo usando o URLAnalyzer
|
||||
* - Exibir o conteúdo processado ou redirecionar em caso de erro
|
||||
*
|
||||
* Usage examples / Exemplos de uso:
|
||||
* /p/https://exemplo.com
|
||||
* /p/?url=https://exemplo.com
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/../config.php';
|
||||
require_once __DIR__ . '/../inc/URLAnalyzer.php';
|
||||
|
||||
// Get URL from either path parameter or query string
|
||||
// Obtém a URL do parâmetro de path ou query string
|
||||
$url = '';
|
||||
if (isset($_GET['url'])) {
|
||||
$url = urldecode($_GET['url']);
|
||||
}
|
||||
|
||||
// Validate URL format
|
||||
// Valida o formato da URL
|
||||
if (filter_var($url, FILTER_VALIDATE_URL)) {
|
||||
$analyzer = new URLAnalyzer();
|
||||
try {
|
||||
// Check for redirects
|
||||
// Verifica se há redirecionamentos
|
||||
$redirectInfo = $analyzer->checkStatus($url);
|
||||
|
||||
// If there's a redirect and the final URL is different
|
||||
// Se houver redirecionamento e a URL final for diferente
|
||||
if ($redirectInfo['hasRedirect'] && $redirectInfo['finalUrl'] !== $url) {
|
||||
// Redirect to final URL
|
||||
// Redireciona para a URL final
|
||||
header('Location: ' . SITE_URL . '/p/' . urlencode($redirectInfo['finalUrl']));
|
||||
exit;
|
||||
}
|
||||
|
||||
// If there's no redirect or if already at final URL
|
||||
// Se não houver redirecionamento ou se já estiver na URL final
|
||||
// Try to analyze and process the URL
|
||||
// Tenta analisar e processar a URL
|
||||
$content = $analyzer->analyze($url);
|
||||
// Display processed content
|
||||
// Exibe o conteúdo processado
|
||||
echo $content;
|
||||
exit;
|
||||
} catch (URLAnalyzerException $e) {
|
||||
// Get error type and additional info from exception
|
||||
// Obtém o tipo de erro e informações adicionais da exceção
|
||||
$errorType = $e->getErrorType();
|
||||
$additionalInfo = $e->getAdditionalInfo();
|
||||
|
||||
// Handle blocked domain with redirect URL
|
||||
// Trata domínio bloqueado com URL de redirecionamento
|
||||
if ($errorType === URLAnalyzer::ERROR_BLOCKED_DOMAIN && $additionalInfo) {
|
||||
header('Location: ' . trim($additionalInfo) . '?message=' . $errorType);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Redirect to home page with error message
|
||||
// Redireciona para a página inicial com mensagem de erro
|
||||
header('Location: /?message=' . $errorType);
|
||||
exit;
|
||||
} catch (Exception $e) {
|
||||
// Handle any other unexpected errors
|
||||
// Trata quaisquer outros erros inesperados
|
||||
header('Location: /?message=' . URLAnalyzer::ERROR_GENERIC_ERROR);
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
// Invalid URL / URL inválida
|
||||
header('Location: /?message=' . URLAnalyzer::ERROR_INVALID_URL);
|
||||
exit;
|
||||
}
|
157
app/src/views/home.php
Normal file
157
app/src/views/home.php
Normal file
|
@ -0,0 +1,157 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="<?php echo Language::getCurrentLanguage(); ?>">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<title><?php echo SITE_NAME; ?></title>
|
||||
<link rel="icon" href="<?php echo SITE_URL; ?>/assets/svg/marreta.svg" type="image/svg+xml">
|
||||
<meta name="theme-color" content="#2563eb">
|
||||
<link rel="manifest" href="<?php echo SITE_URL; ?>/manifest.json">
|
||||
|
||||
<!-- PWA meta tags -->
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="application-name" content="<?php echo SITE_NAME; ?>">
|
||||
|
||||
<!-- Open Graph meta tags -->
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="<?php echo SITE_URL; ?>" />
|
||||
<meta property="og:title" content="<?php echo SITE_NAME; ?>" />
|
||||
<meta property="og:description" content="<?php echo htmlspecialchars(SITE_DESCRIPTION); ?>" />
|
||||
<meta property="og:image" content="<?php echo SITE_URL; ?>/assets/opengraph.png" />
|
||||
<script src="https://cdn.tailwindcss.com/3.4.15"></script>
|
||||
</head>
|
||||
|
||||
<body class="bg-gray-50 min-h-screen">
|
||||
<div class="container mx-auto px-4 py-8 max-w-4xl">
|
||||
<!-- Cabeçalho da página / Page header -->
|
||||
<div class="text-center mb-8">
|
||||
<h1 class="text-4xl font-bold text-gray-800 mb-4">
|
||||
<img src="assets/svg/marreta.svg" class="inline-block w-12 h-12 mb-2" alt="Marreta">
|
||||
<?php echo SITE_NAME; ?>
|
||||
</h1>
|
||||
<p class="text-gray-600 text-lg"><?php echo SITE_DESCRIPTION; ?></p>
|
||||
<p class="text-gray-600 text-lg">
|
||||
<span class="font-bold text-blue-600">
|
||||
<?php echo number_format($cache_folder, 0, ',', '.'); ?>
|
||||
</span>
|
||||
<span><?php echo Language::get('walls_destroyed'); ?></span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Formulário principal de análise de URLs / Main URL analysis form -->
|
||||
<div class="bg-white rounded-xl shadow-lg p-8 mb-8">
|
||||
<form id="urlForm" method="POST" onsubmit="return validateForm()" class="space-y-6">
|
||||
<div class="relative">
|
||||
<div class="flex items-stretch">
|
||||
<span class="inline-flex items-center px-5 rounded-l-lg border border-r-0 border-gray-300 bg-gray-50 text-gray-500">
|
||||
<img src="assets/svg/link.svg" class="w-6 h-6" alt="Link">
|
||||
</span>
|
||||
<input type="url"
|
||||
name="url"
|
||||
id="url"
|
||||
class="flex-1 block w-full rounded-none rounded-r-lg text-lg py-4 border border-l-0 border-gray-300 bg-gray-50 focus:border-blue-500 focus:ring-blue-500 shadow-sm bg-gray-50"
|
||||
placeholder="<?php echo Language::get('url_placeholder'); ?>"
|
||||
value="<?php echo htmlspecialchars($url); ?>"
|
||||
required
|
||||
pattern="https?://.+"
|
||||
title="<?php echo Language::getMessage('INVALID_URL')['message']; ?>">
|
||||
</div>
|
||||
<button type="submit"
|
||||
class="mt-4 w-full inline-flex justify-center items-center px-6 py-4 border border-transparent text-lg font-medium rounded-lg text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-colors duration-200">
|
||||
<img src="assets/svg/search.svg" class="w-6 h-6 mr-3" alt="Search">
|
||||
<?php echo Language::get('analyze_button'); ?>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Aviso sobre bloqueadores de anúncios / Ad blocker warning -->
|
||||
<div class="mt-4 text-sm text-gray-600 flex items-start">
|
||||
<p><?php echo str_replace('{site_name}', SITE_NAME, Language::get('adblocker_warning')); ?></p>
|
||||
</div>
|
||||
|
||||
<!-- Área de mensagens de erro/alerta / Error/warning message area -->
|
||||
<?php if ($message): ?>
|
||||
<div class="mt-6 <?php echo $message_type === 'error' ? 'bg-red-50 border-red-400' : 'bg-yellow-50 border-yellow-400'; ?> border-l-4 p-4 rounded-r">
|
||||
<div class="flex">
|
||||
<div class="flex-shrink-0">
|
||||
<?php if ($message_type === 'error'): ?>
|
||||
<img src="assets/svg/error.svg" class="w-6 h-6" alt="Error">
|
||||
<?php else: ?>
|
||||
<img src="assets/svg/warning.svg" class="w-6 h-6" alt="Warning">
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<p class="text-base <?php echo $message_type === 'error' ? 'text-red-700' : 'text-yellow-700'; ?>">
|
||||
<?php echo htmlspecialchars($message); ?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Adicionar como aplicativo / Add as app (mobile only) -->
|
||||
<div class="bg-white rounded-xl shadow-lg p-8 mt-8 mb-8 md:hidden">
|
||||
<h2 class="text-xl font-semibold text-gray-800 mb-6 flex items-center">
|
||||
<img src="assets/svg/marreta.svg" class="w-6 h-6 mr-3" alt="App">
|
||||
<?php echo Language::get('add_as_app'); ?>
|
||||
</h2>
|
||||
<div class="space-y-4">
|
||||
<p class="text-gray-600">
|
||||
<?php echo str_replace('{site_name}', SITE_NAME, Language::get('add_as_app_description')); ?>
|
||||
</p>
|
||||
<div class="bg-gray-50 rounded-lg p-4">
|
||||
<ol class="list-decimal list-inside space-y-2 text-gray-700">
|
||||
<li><?php echo Language::get('add_as_app_step1'); ?></li>
|
||||
<li><?php echo Language::get('add_as_app_step2'); ?></li>
|
||||
<li><?php echo Language::get('add_as_app_step3'); ?></li>
|
||||
<li><?php echo str_replace('{site_name}', SITE_NAME, Language::get('add_as_app_step4')); ?></li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Seção de Bookmarklet / Bookmarklet section (desktop only) -->
|
||||
<div class="bg-white rounded-xl shadow-lg p-8 mt-8 mb-8 hidden md:block">
|
||||
<h2 class="text-xl font-semibold text-gray-800 mb-6 flex items-center">
|
||||
<img src="assets/svg/bookmark.svg" class="w-6 h-6 mr-3" alt="Favoritos">
|
||||
<?php echo Language::get('bookmarklet_title'); ?>
|
||||
</h2>
|
||||
<div class="space-y-4">
|
||||
<p class="text-gray-600">
|
||||
<?php echo str_replace('{site_name}', SITE_NAME, Language::get('bookmarklet_description')); ?>
|
||||
</p>
|
||||
<div class="flex justify-center">
|
||||
<a href="javascript:(function(){let currentUrl=window.location.href;window.location.href='<?php echo SITE_URL; ?>/p/'+encodeURIComponent(currentUrl);})()"
|
||||
class="inline-flex items-center px-6 py-3 border-2 border-blue-500 font-medium rounded-lg text-blue-600 bg-white hover:bg-blue-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-colors duration-200 cursor-move"
|
||||
onclick="return false;">
|
||||
<img src="assets/svg/marreta.svg" class="w-5 h-5 mr-2" alt="Marreta">
|
||||
<?php echo str_replace('{site_name}', SITE_NAME, Language::get('open_in')); ?>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-gray-600 text-center text-sm">
|
||||
<p>
|
||||
<?php echo Language::get('open_source_description'); ?>
|
||||
</p>
|
||||
<p class="mt-2">
|
||||
<a href="https://github.com/manualdousuario/marreta/wiki/API-Rest" target="_blank" class="underline">API Rest</a> ● <a href="https://github.com/manualdousuario/marreta/" target="_blank" class="underline">Github</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Scripts JavaScript -->
|
||||
<script>
|
||||
<?php
|
||||
$js_file = 'assets/js/scripts.js';
|
||||
if (file_exists($js_file)) {
|
||||
echo file_get_contents($js_file);
|
||||
}
|
||||
?>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -9,8 +9,8 @@
|
|||
* Ele define o comportamento da aplicação quando instalada em um dispositivo e sua aparência.
|
||||
*/
|
||||
|
||||
require_once 'config.php';
|
||||
require_once 'inc/Language.php';
|
||||
require_once __DIR__ . '/../../config.php';
|
||||
require_once __DIR__ . '/../../inc/Language.php';
|
||||
|
||||
header('Content-Type: application/json');
|
||||
|
14
default.conf
14
default.conf
|
@ -48,18 +48,10 @@ server {
|
|||
return 403;
|
||||
}
|
||||
|
||||
# All requests go through index.php for FastRoute routing
|
||||
# Todas as requisições passam pelo index.php para roteamento FastRoute
|
||||
location / {
|
||||
try_files $uri $uri/ $uri/index.php?$args;
|
||||
}
|
||||
|
||||
location ~ ^/(api|p)/ {
|
||||
try_files $uri $uri/ /$1.php;
|
||||
}
|
||||
|
||||
# Serve manifest.json from manifest.php
|
||||
# Serve manifest.json a partir do manifest.php
|
||||
location = /manifest.json {
|
||||
rewrite ^ /manifest.php last;
|
||||
try_files $uri $uri/ /index.php?$args;
|
||||
}
|
||||
|
||||
location ~ \.php$ {
|
||||
|
|
Loading…
Add table
Reference in a new issue