first commit

This commit is contained in:
rodrigo committed 2025-04-10 23:07:21 -03:00
commit c9fb67e751
423 files changed
+53287

No files matched your search

+508
View File
@@ -0,0 +1,508 @@
<?php
// process_queue.php
ini_set('memory_limit', '512M');
date_default_timezone_set('America/Araguaina');
// Aumentar o tempo máximo de execução do script para 300 segundos (5 minutos)
set_time_limit(300);
// Verifique se a extensão `pcntl` está disponível
if (!function_exists('pcntl_fork')) {
die("A extensão pcntl não está disponível. Por favor, habilite-a para continuar.\n");
}
// Definir o número máximo de processos filhos
define('MAX_CHILDREN', 3);
$childProcesses = [];
// Função para registrar logs
function log_message($message, $level = 'INFO') {
$timestamp = date("Y-m-d H:i:s P"); // Inclui o fuso horário
// Apenas logar mensagens de nível INFO, ERROR e WARN
if (in_array($level, ['INFO', 'ERROR', 'WARN'])) {
file_put_contents('/var/log/process_queue.log', "[$timestamp] [$level] $message\n", FILE_APPEND);
}
}
log_message("Script iniciado.", 'INFO');
function process_file($row) {
// Cada processo filho deve estabelecer sua própria conexão com o banco de dados
$mysqli = new mysqli("10.15.0.42", "root", "34641747", "valida");
if ($mysqli->connect_error) {
log_message("Connection failed: " . $mysqli->connect_error, 'ERROR');
exit(1); // Sair com erro
}
// Assegurar que as mensagens de log incluam o ID do processo
$process_id = getmypid();
log_message("Processo $process_id: Processando arquivo ID " . $row['id'] . ": " . $row['file_path'], 'INFO');
try {
$file_path = $row['file_path'];
$queue_id = $row['id'];
$user_agent = $row['user_agent'];
$ip_address = $row['ip_address'];
$host_name = $row['host_name'];
$access_time = $row['access_time'] . ' ' . date("P"); // Adiciona fuso horário
$language = $row['language'];
$referer = $row['referer'];
$protocol = $row['protocol'];
$connection = $row['connection'];
$viewport_width = $row['viewport_width'];
$viewport_height = $row['viewport_height'];
$original_location = $row['original_location']; // Novo campo para localização original
// Recuperar a porta do cliente
$result_port = $mysqli->query("SELECT port FROM client_ports WHERE queue_id = $queue_id");
$client_port = $result_port->fetch_assoc()['port'] ?? 'N/A';
$result_port->free();
// Atualizar status para 'processing'
$stmt_update = $mysqli->prepare("UPDATE queue SET status = 'processing' WHERE id = ?");
$stmt_update->bind_param("i", $queue_id);
$stmt_update->execute();
$stmt_update->close();
log_message("Processo $process_id: Atualizou status para 'processing' para o arquivo ID $queue_id.", 'INFO');
// Gerar checksums
$checksums = generate_checksums($file_path);
// Capturar data e hora
$file_datetime = get_file_datetime($file_path);
// Registrar timestamp usando OpenTimestamps
$timestamp_result = register_timestamp_opentimestamps($file_path);
$signature_time = date("d/m/Y H:i:s P"); // Inclui fuso horário
if ($timestamp_result['success']) {
$ots_base64 = $timestamp_result['ots_base64'];
// Coletar dados do dispositivo
$device_data = [
'User Agent' => $user_agent,
'IP Address' => $ip_address . ':' . $client_port,
'Host Name' => $host_name,
'Access Time' => $access_time,
'Language' => $language,
'Referer' => $referer,
'Protocol' => $protocol,
'Connection' => $connection,
'Viewport Width' => $viewport_width,
'Viewport Height' => $viewport_height,
'Original Location' => $original_location // Adicionado
];
// Gerar PDF
$pdf_path = generate_pdf($file_path, [
'name' => basename($file_path),
'creation_time' => $file_datetime['creation_time'] . ' ' . date("P", filectime($file_path)),
'modification_time' => $file_datetime['modification_time'] . ' ' . date("P", filemtime($file_path)),
'upload_time' => $access_time,
'signature_time' => $signature_time
], $checksums, $device_data, $ots_base64);
// Atualizar status para 'completed'
$stmt_complete = $mysqli->prepare("UPDATE queue SET status = 'completed' WHERE id = ?");
$stmt_complete->bind_param("i", $queue_id);
$stmt_complete->execute();
$stmt_complete->close();
log_message("Processo $process_id: Processamento concluído para arquivo ID $queue_id: $file_path", 'INFO');
} else {
// Atualizar status para 'error'
$stmt_error = $mysqli->prepare("UPDATE queue SET status = 'error' WHERE id = ?");
$stmt_error->bind_param("i", $queue_id);
$stmt_error->execute();
$stmt_error->close();
log_message("Processo $process_id: Erro ao processar arquivo ID $queue_id: " . $timestamp_result['message'], 'ERROR');
}
} catch (Exception $e) {
// Atualizar status para 'error'
$stmt_exception = $mysqli->prepare("UPDATE queue SET status = 'error' WHERE id = ?");
$stmt_exception->bind_param("i", $queue_id);
$stmt_exception->execute();
$stmt_exception->close();
log_message("Processo $process_id: Exceção ao processar arquivo ID $queue_id: " . $e->getMessage(), 'ERROR');
}
$mysqli->close();
log_message("Processo $process_id: Fechou conexão com o banco de dados para o arquivo ID $queue_id.", 'INFO');
}
// Funções auxiliares (generate_checksums, get_file_datetime, register_timestamp_opentimestamps, generate_pdf)
// Mantenha estas funções como estão no seu código original, sem alterações. Certifique-se de que as funções não dependam de conexões globais de banco de dados.
require_once __DIR__ . '../../vendor/autoload.php';
// Função para gerar checksums
function generate_checksums($file_path) {
log_message("Gerando checksums para $file_path", 'INFO');
$start_time = microtime(true);
// Carregar o conteúdo do arquivo uma única vez
$file_content = file_get_contents($file_path);
$checksums = [
'sha256' => hash('sha256', $file_content),
'sha512' => hash('sha512', $file_content),
'md5' => hash('md5', $file_content)
];
$end_time = microtime(true);
log_message("Checksums gerados em " . round($end_time - $start_time, 4) . " segundos", 'INFO');
return $checksums;
}
// Função para capturar data e hora do arquivo
function get_file_datetime($file_path) {
log_message("Obtendo data e hora do arquivo para $file_path", 'INFO');
$start_time = microtime(true);
$creation_time = date("d/m/Y H:i:s P", filectime($file_path));
$modification_time = date("d/m/Y H:i:s P", filemtime($file_path));
$end_time = microtime(true);
log_message("Data e hora obtidas em " . round($end_time - $start_time, 4) . " segundos", 'INFO');
return [
'creation_time' => $creation_time,
'modification_time' => $modification_time
];
}
// Função para registrar timestamp usando OpenTimestamps
function register_timestamp_opentimestamps($file_path) {
log_message("Registrando timestamp para $file_path", 'INFO');
$start_time = microtime(true);
// Definir diretório de cache para OTS
$ots_cache_dir = '/var/www/html/ots_cache';
if (!is_dir($ots_cache_dir)) {
log_message("Diretório de cache OTS não existe. Criando em $ots_cache_dir", 'INFO');
if (!mkdir($ots_cache_dir, 0755, true)) {
log_message("Erro ao criar diretório de cache OTS: $ots_cache_dir", 'ERROR');
return ['success' => false, 'message' => "Erro ao criar diretório de cache OTS: $ots_cache_dir"];
}
chmod($ots_cache_dir, 0755); // Ajustar permissões
}
// Definir a variável de ambiente antes de executar o comando
$command_stamp = "OTS_CACHE_DIRECTORY=" . escapeshellarg($ots_cache_dir) . " ots stamp " . escapeshellarg($file_path) . " 2>&1";
log_message("Comando para executar: $command_stamp", 'INFO');
// Executar o comando
exec($command_stamp, $output_stamp, $return_var_stamp);
// Verificar o resultado da execução
if ($return_var_stamp !== 0) {
log_message("Erro ao registrar timestamp: " . implode("\n", $output_stamp), 'ERROR');
return ['success' => false, 'message' => 'Erro ao registrar timestamp: ' . implode("\n", $output_stamp)];
}
// Definir o caminho do arquivo .ots gerado
$ots_file = "{$file_path}.ots";
// Verificar se o arquivo .ots foi criado
if (!file_exists($ots_file)) {
log_message("Arquivo de timestamp não encontrado: $ots_file", 'ERROR');
return ['success' => false, 'message' => "Arquivo de timestamp não encontrado: $ots_file"];
}
// Codificar o arquivo .ots em base64
$ots_base64 = base64_encode(file_get_contents($ots_file));
$end_time = microtime(true);
log_message("Timestamp registrado e codificado em " . round($end_time - $start_time, 4) . " segundos", 'INFO');
return ['success' => true, 'ots_base64' => $ots_base64];
}
// Função para gerar PDF
function generate_pdf($uploaded_file_path, $document_info, $checksums, $device_data, $ots_base64) {
log_message("Gerando PDF para $uploaded_file_path", 'INFO');
$start_time = microtime(true);
// Criar uma nova instância do TCPDF
$pdf = new TCPDF();
// Configurações iniciais do PDF
$pdf->SetCreator(PDF_CREATOR);
$pdf->SetAuthor('Seu Nome ou Empresa');
$pdf->SetTitle('Prova de Autenticidade de Documento');
$pdf->SetSubject('Timestamping e Checksums');
// Remover as margens padrão
$pdf->SetMargins(10, 10, 10);
$pdf->SetHeaderMargin(0);
$pdf->SetFooterMargin(0);
// Desativar cabeçalhos e rodapés automáticos
$pdf->setPrintHeader(false);
$pdf->setPrintFooter(false);
// Configurar a fonte padrão uma vez
$pdf->SetFont('helvetica', '', 10);
// Verificar o tipo de arquivo para incorporar no PDF
$file_info = pathinfo($uploaded_file_path);
$extension = strtolower($file_info['extension']);
// Configurar o diretório temporário para o ImageMagick
$temp_dir = '/tmp/imagick';
if (!is_dir($temp_dir)) {
mkdir($temp_dir, 0777, true);
}
chmod($temp_dir, 0777); // Garantir permissões totais
// Configurar o diretório temporário para as imagens
$tmp_dir = '/tmp/image';
if (!is_dir($tmp_dir)) {
mkdir($tmp_dir, 0777, true);
}
chmod($tmp_dir, 0777); // Garantir permissões totais
// Criar uma única instância de Imagick
$imagick = new Imagick();
// Configurar o ambiente para otimização
putenv('MAGICK_TMPDIR=' . $temp_dir); // Defina um diretório temporário adequado
$imagick->setResourceLimit(Imagick::RESOURCETYPE_MEMORY, 512); // Ajuste conforme necessário
$imagick->setResourceLimit(Imagick::RESOURCETYPE_MAP, 512);
$imagick->setResourceLimit(Imagick::RESOURCETYPE_THREAD, 2);
try {
if (in_array($extension, ['jpg', 'jpeg', 'png', 'gif'])) {
log_message("Processando imagem $uploaded_file_path", 'INFO');
// Reduzir a resolução para 1200x900, mantendo a proporção
log_message("Reduzindo resolução da imagem para melhor qualidade e menor tamanho", 'INFO');
$imagick->readImage($uploaded_file_path);
$imagick->resizeImage(1200, 900, Imagick::FILTER_LANCZOS, 1, true);
// Configurar a compressão usando PNG para melhor qualidade sem perder transparência
if ($extension === 'png') {
$imagick->setImageFormat('png');
$imagick->stripImage(); // Remove metadados
$image_blob = $imagick->getImageBlob();
} else {
// Para JPEG e outros, usar alta qualidade com compressão balanceada
log_message("Configurando compressão da imagem para JPEG", 'INFO');
$imagick->setImageCompression(Imagick::COMPRESSION_JPEG);
$imagick->setImageCompressionQuality(85); // Maior qualidade
$imagick->stripImage(); // Remove metadados para reduzir o tamanho
$image_blob = $imagick->getImageBlob();
}
// Salvar a imagem temporariamente
$tmp_img = tempnam($tmp_dir, 'img_') . '.' . $extension;
log_message("Salvando imagem temporária em $tmp_img", 'INFO');
file_put_contents($tmp_img, $image_blob);
chmod($tmp_img, 0666); // Ajustar permissões do arquivo temporário
// Adicionar a imagem ao PDF
log_message("Adicionando imagem ao PDF", 'INFO');
$pdf->AddPage();
$pdf->Image('@' . $image_blob, 15, 40, 180, 160, '', '', 'C', false, 100, '', false, false, 1, false, false, false);
log_message("Imagem adicionada ao PDF", 'INFO');
// Remover a imagem temporária
if (file_exists($tmp_img)) {
log_message("Removendo imagem temporária $tmp_img", 'INFO');
unlink($tmp_img);
} else {
log_message("Imagem temporária $tmp_img não encontrada para remoção", 'WARN');
}
} elseif (in_array($extension, ['pdf'])) {
log_message("Processando PDF $uploaded_file_path", 'INFO');
// Verificar se a extensão Imagick está carregada
if (extension_loaded('imagick')) {
log_message("Imagick está carregado", 'INFO');
// Inicializar Imagick
try {
log_message("Inicializando Imagick para $uploaded_file_path", 'INFO');
$imagick->setResolution(150, 150); // Ajuste a resolução conforme necessário
$imagick->readImage($uploaded_file_path); // Ler todas as páginas do PDF
log_message("PDF lido com sucesso", 'INFO');
// Processar cada página do PDF
$page_count = $imagick->getNumberImages(); // Número total de páginas do PDF
for ($i = 0; $i < $page_count; $i++) {
$imagick->setIteratorIndex($i); // Define a página atual
$imagick->setImageFormat("jpeg"); // Configura o formato como JPEG
// Definir o fundo como branco
$imagick->setImageBackgroundColor('white');
$imagick = $imagick->mergeImageLayers(Imagick::LAYERMETHOD_FLATTEN);
// Reduz a resolução para 1600x1200, mantendo a proporção
$imagick->resizeImage(1600, 1200, Imagick::FILTER_LANCZOS, 1, true);
// Configura as opções de compressão
$imagick->setImageCompression(Imagick::COMPRESSION_JPEG);
$imagick->setImageCompressionQuality(85);
$imagick->stripImage(); // Remove metadados desnecessários
// Obter os dados da imagem
$image_data = $imagick->getImageBlob();
$tmp_img = tempnam($tmp_dir, 'pdf_page_') . '.jpg';
file_put_contents($tmp_img, $image_data); // Salvar página como JPEG temporária
chmod($tmp_img, 0666);
// Adicionar a página como imagem ao novo PDF
$pdf->AddPage();
$pdf->Image($tmp_img, 15, 40, 180, 160, '', '', 'C', false, 100, '', false, false, 1, false, false, false);
// Remover a imagem temporária
unlink($tmp_img);
}
// Limpar recursos do Imagick
$imagick->clear();
$imagick->destroy();
} catch (Exception $e) {
log_message("Erro ao inicializar ou processar imagem com Imagick: " . $e->getMessage(), 'ERROR');
}
} else {
log_message("Imagick não está carregado", 'WARN');
// Se Imagick não estiver disponível, apenas adicionar uma mensagem
$pdf->SetFont('helvetica', '', 12);
$pdf->Write(0, 'Visualização de PDF não suportada.');
}
} else {
log_message("Tipo de arquivo não suportado: $extension", 'WARN');
// Outros tipos de arquivo podem ser adicionados conforme necessidade
$pdf->SetFont('helvetica', '', 12);
$pdf->Write(0, 'Visualização deste tipo de arquivo não está disponível.');
}
} catch (Exception $e) {
log_message("Erro ao processar imagem: " . $e->getMessage(), 'ERROR');
}
// Adicionar uma nova página para as informações
$pdf->AddPage();
// Conteúdo das informações
$html = '<h2>Informações do Documento</h2>';
$html .= '<p><strong>Nome do Arquivo:</strong> ' . htmlspecialchars($document_info['name']) . '</p>';
$html .= '<p><strong>Data de Modificação:</strong> ' . htmlspecialchars($document_info['modification_time']) . '</p>';
$html .= '<p><strong>Data de Envio ao Servidor:</strong> ' . htmlspecialchars($document_info['upload_time']) . '</p>';
$html .= '<p><strong>Data e Hora da Assinatura:</strong> ' . htmlspecialchars($document_info['signature_time']) . ' (UTC-3)</p>';
$html .= '<h3>Checksums</h3>';
$html .= '<ul>';
$html .= '<li><strong>SHA-256:</strong> ' . htmlspecialchars($checksums['sha256']) . '</li>';
$html .= '<li><strong>SHA-512:</strong> ' . htmlspecialchars($checksums['sha512']) . '</li>';
$html .= '<li><strong>MD5:</strong> ' . htmlspecialchars($checksums['md5']) . '</li>';
$html .= '</ul>';
$html .= '<h3>Dados do Dispositivo</h3>';
$html .= '<ul>';
foreach ($device_data as $key => $value) {
$html .= '<li><strong>' . htmlspecialchars((string)$key) . ':</strong> ' . htmlspecialchars((string)$value) . '</li>';
}
$html .= '</ul>';
$orig_link= 'https://validar.martinsevieira.adv.br/uploads/';
$html .= '<h3>Arquivos Originais</h3>';
$html .= '<ul>';
$html .= '<li><a href="' . $orig_link . $document_info['name'] . '">Arquivo Original</a></li>';
$html .= '<li><a href="' . $orig_link . $document_info['name'] . '.ots">Arquivo OTS</a></li>';
$html .= '</ul>';
$html .= '<h3>Arquivo de Timestamp (OTS) em Base64</h3>';
$html .= '<pre>' . htmlspecialchars($ots_base64) . '</pre>';
$pdf->writeHTML($html, true, false, true, false, '');
// Salvar o PDF no servidor
$processed_dir = '/var/www/html/processed/';
if (!is_dir($processed_dir)) {
mkdir($processed_dir, 0777, true);
}
log_message("Salvando PDF no servidor", 'INFO');
$pdf_output_path = $processed_dir . uniqid('prova_') . '.pdf';
$pdf->Output($pdf_output_path, 'F');
$end_time = microtime(true);
log_message("PDF gerado em " . round($end_time - $start_time, 4) . " segundos", 'INFO');
// Limpar recursos do Imagick
$imagick->clear();
$imagick->destroy();
return $pdf_output_path;
}
// Recuperar todos os arquivos pendentes
$mysqli = new mysqli("10.15.0.42", "root", "34641747", "valida");
if ($mysqli->connect_error) {
log_message("Connection failed: " . $mysqli->connect_error, 'ERROR');
die("Connection failed: " . $mysqli->connect_error);
}
log_message("Conexão com o banco de dados estabelecida.", 'INFO');
// Recuperar todos os arquivos pendentes
$result = $mysqli->query("SELECT q.*, cp.port, q.original_location FROM queue q LEFT JOIN client_ports cp ON q.id = cp.queue_id WHERE q.status = 'pending'");
if ($result->num_rows > 0) {
log_message("Encontrados " . $result->num_rows . " arquivos pendentes para processar.", 'INFO');
while ($row = $result->fetch_assoc()) {
// Verificar se o número de processos filhos atingiu o máximo permitido
while (count($childProcesses) >= MAX_CHILDREN) {
// Esperar por qualquer processo filho terminar
$endedPid = pcntl_wait($status);
if ($endedPid > 0) {
unset($childProcesses[$endedPid]);
log_message("Processo filho $endedPid finalizado.", 'INFO');
}
}
// Fork do processo
$pid = pcntl_fork();
if ($pid == -1) {
// Erro ao fork
log_message("Erro ao criar processo filho.", 'ERROR');
} elseif ($pid) {
// Processo pai
$childProcesses[$pid] = true;
log_message("Criado processo filho $pid para o arquivo ID " . $row['id'] . ".", 'INFO');
} else {
// Processo filho
// Fecha a conexão do processo pai antes de iniciar no filho
$mysqli->close();
// Processa o arquivo
process_file($row);
// Finaliza o processo filho
exit(0);
}
}
// Após forçar todos os filhos a serem criados, esperar que terminem
while (count($childProcesses) > 0) {
$endedPid = pcntl_wait($status);
if ($endedPid > 0) {
unset($childProcesses[$endedPid]);
log_message("Processo filho $endedPid finalizado.", 'INFO');
}
}
log_message("Todas as tarefas foram submetidas para processamento.", 'INFO');
} else {
log_message("Nenhum arquivo pendente para processar.", 'INFO');
}
$mysqli->close();
log_message("Processamento da fila finalizado.", 'INFO');
?>