<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

ini_set('log_errors', 1);
ini_set('error_log', 'erro.log'); // Salva os erros no arquivo erro.log

set_error_handler(function ($errno, $errstr, $errfile, $errline) {
    echo "Erro capturado: [$errno] $errstr - Arquivo: $errfile, Linha: $errline";
    error_log("Erro capturado: [$errno] $errstr - Arquivo: $errfile, Linha: $errline");
    die();
});

set_exception_handler(function ($exception) {
    echo "Exceção capturada: " . $exception->getMessage();
    error_log("Exceção capturada: " . $exception->getMessage());
    die();
});

date_default_timezone_set('America/Sao_Paulo');

// DADOS DO DESTINATÁRIO
$destinatario_numero = '17422651000172';
$destinatario_nome = 'CF RJ CONTABILIDADE LTDA';
$destinatario_tipo = 'PJ';
$destinatario_papel = 'contratante';

// DADOS DO ASSINANTE*/
$assinante_numero = '28076286000108';
$assinante_nome = 'ATIVO ADVISORY CONTABILIDADE LTDA';
$assinante_tipo = 'PJ';
$assinante_papel = 'autor pedido de dados';

// Certificado digital
$arquivoCertificado = 'ativo.pfx';
$senhaCertificado = 'Ativo@2024_';

// DATAS
$data_assinatura = date("Ymd");
$data_vigencia_termo = '+30 days';


function carregarCertificado()
{

	$arquivo = $GLOBALS['arquivoCertificado'];
    $senhaCertificado = $GLOBALS['senhaCertificado'];
    $certs = [];

	if (!file_exists($arquivo)) {
    	die("Erro: Certificado não encontrado.");
	}
	$conteudo = file_get_contents($arquivo);

	if (!$conteudo) {
    	die("Erro: O certificado existe, mas não pode ser lido.");
	}

	if (!openssl_pkcs12_read($conteudo, $certs, $senhaCertificado)) {
    	die("Erro: Não foi possível carregar o certificado digital. Senha errada?");
	}
	return $certs;
}

function obterPrivateKey($certificados)
{
	return $certificados["pkey"];
}

function obterCertificado($certificados)
{
	return $certificados["cert"];
}

function obterx509Certificate($certificados)
{
	// <X509Certificate>
	$x509Certificate = obterCertificado($certificados);
	$x509Certificate = str_replace('-----END CERTIFICATE-----', ' ', $x509Certificate);
	$x509Certificate = str_replace('-----BEGIN CERTIFICATE-----', ' ', $x509Certificate);
	return preg_replace("/\r|\n/", "", trim($x509Certificate));
}

function montarTermoAutorizacao()
{
    $stringRoot = "<?xml version='1.0' encoding='UTF-8'?><termoDeAutorizacao></termoDeAutorizacao>";

	$xmlNaoAssinado = new SimpleXMLElement($stringRoot );

	$dados = $xmlNaoAssinado->addChild('dados');

	$sistema = $dados->addChild('sistema');
	$sistema->addAttribute('id', 'API Integra Contador');

	$termo =  $dados->addChild('termo');
	$termo->addAttribute('texto', 'Autorizo a empresa CONTRATANTE, identificada neste termo de autorização como DESTINATÁRIO, a executar as requisições dos serviços web disponibilizados pela API INTEGRA CONTADOR, onde terei o papel de AUTOR PEDIDO DE DADOS no corpo da mensagem enviada na requisição do serviço web. Esse termo de autorização está assinado digitalmente com o certificado digital do PROCURADOR ou OUTORGADO DO CONTRIBUINTE responsável, identificado como AUTOR DO PEDIDO DE DADOS.');

	$avisoLegal = $dados->addChild('avisoLegal');
	$avisoLegal->addAttribute('texto', 'O acesso a estas informações foi autorizado pelo próprio PROCURADOR ou OUTORGADO DO CONTRIBUINTE, responsável pela informação, via assinatura digital. É dever do destinatário da autorização e consumidor deste acesso observar a adoção de base legal para o tratamento dos dados recebidos conforme artigos 7º ou 11º da LGPD (Lei n.º 13.709, de 14 de agosto de 2018), aos direitos do titular dos dados (art. 9º, 17 e 18, da LGPD) e aos princípios que norteiam todos os tratamentos de dados no Brasil (art. 6º, da LGPD).');

	$finalidade = $dados->addChild('finalidade');
	$finalidade->addAttribute('texto', 'A finalidade única e exclusiva desse TERMO DE AUTORIZAÇÃO, é garantir que o CONTRATANTE apresente a API INTEGRA CONTADOR esse consentimento do PROCURADOR ou OUTORGADO DO CONTRIBUINTE assinado digitalmente, para que possa realizar as requisições dos serviços web da API INTEGRA CONTADOR em nome do AUTOR PEDIDO DE DADOS (PROCURADOR ou OUTORGADO DO CONTRIBUINTE).');

	$dataAssinatura = $dados->addChild('dataAssinatura');
	$dataAssinatura->addAttribute('data', $GLOBALS['data_assinatura']);

	$vigencia = $dados->addChild('vigencia');
	$vigencia->addAttribute('data', date('Ymd', strtotime("+30 days")));
	//$vigencia->addAttribute('data', date('Ymd', $GLOBALS['data_vigencia_termo'],strtotime(date('Ymd'))));

	$destinatario = $dados->addChild('destinatario');
	$destinatario->addAttribute('numero', $GLOBALS['destinatario_numero']);
	$destinatario->addAttribute('nome', $GLOBALS['destinatario_nome']);
	$destinatario->addAttribute('tipo', $GLOBALS['destinatario_tipo']);
	$destinatario->addAttribute('papel', $GLOBALS['destinatario_papel']);

	$assinadoPor = $dados->addChild('assinadoPor');
	$assinadoPor->addAttribute('numero', $GLOBALS['assinante_numero']);
	$assinadoPor->addAttribute('nome', $GLOBALS['assinante_nome']);
	$assinadoPor->addAttribute('tipo', $GLOBALS['assinante_tipo']);
	$assinadoPor->addAttribute('papel', $GLOBALS['assinante_papel']);
	
	return $xmlNaoAssinado;
 }

function assinar($xmlNaoAssinado, $certificados)
{
	// Leitura do XML que contém o documento Termo de Autorização ainda não assinado
	$xml = new DOMDocument();

	// Preservando os espaços em branco
	$xml->preserveWhiteSpace = true;
	$xml->formatOutput = false;

	$xml->loadXML($xmlNaoAssinado->asXML());

	// Canonizar o conteúdo, exclusivo e sem comentários
	if (!$xml->documentElement) {
		throw new UnexpectedValueException('Indefindo o elemento documentElement');
	}

	$canonicalData = $xml->documentElement->C14N(true, false);

	// Calcular o digest
	$digestValue = openssl_digest($canonicalData, "sha256", true);
	if ($digestValue === false) {
		throw new UnexpectedValueException('Invalid digest value');
	}

	// Codificar para base64 (encode)
	$digestValue = base64_encode($digestValue);

	// Adiciona os elementos que vai compor a tag Signature com a assinatura digital
	$signatureElement = $xml->createElement('Signature');
	$signatureElement->setAttribute('xmlns', 'http://www.w3.org/2000/09/xmldsig#');
	$xml->documentElement->appendChild($signatureElement);

	$signedInfoElement = $xml->createElement('SignedInfo');
	$signatureElement->appendChild($signedInfoElement);

	$canonicalizationMethodElement = $xml->createElement('CanonicalizationMethod');
	$canonicalizationMethodElement->setAttribute('Algorithm', 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315');
	$signedInfoElement->appendChild($canonicalizationMethodElement);

	$signatureMethodElement = $xml->createElement('SignatureMethod');
	$signatureMethodElement->setAttribute('Algorithm', 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256');
	$signedInfoElement->appendChild($signatureMethodElement);

	$referenceElement = $xml->createElement('Reference');
	$referenceElement->setAttribute('URI', '');
	$signedInfoElement->appendChild($referenceElement);

	$transformsElement = $xml->createElement('Transforms');
	$referenceElement->appendChild($transformsElement);

	$transformElement = $xml->createElement('Transform');
	$transformElement->setAttribute('Algorithm', 'http://www.w3.org/2000/09/xmldsig#enveloped-signature');
	$transformsElement->appendChild($transformElement);

	$transformElement = $xml->createElement('Transform');
	$transformElement->setAttribute('Algorithm', 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315');
	$transformsElement->appendChild($transformElement);

	$digestMethodElement = $xml->createElement('DigestMethod');
	$digestMethodElement->setAttribute('Algorithm', 'http://www.w3.org/2001/04/xmlenc#sha256');
	$referenceElement->appendChild($digestMethodElement);

	$digestValueElement = $xml->createElement('DigestValue', $digestValue);
	$referenceElement->appendChild($digestValueElement);

	$signatureValueElement = $xml->createElement('SignatureValue', '');
	$signatureElement->appendChild($signatureValueElement);

	$keyInfoElement = $xml->createElement('KeyInfo');
	$signatureElement->appendChild($keyInfoElement);

	$X509Data = $xml->createElement('X509Data');
	$keyInfoElement->appendChild($X509Data);

	$X509Certificate = $xml->createElement('X509Certificate', obterx509Certificate($certificados));
	$X509Data->appendChild($X509Certificate);

	$c14nSignedInfo = $signedInfoElement->C14N(true, false);
	
	$status = openssl_sign($c14nSignedInfo, $signatureValue, obterPrivateKey($certificados), OPENSSL_ALGO_SHA256);

	if (!$status) {
		throw new XmlSignerException('Falha no cálculo da assinatura.');
	}

	$xpath = new DOMXpath($xml);
	$signatureValueElement = $xpath->query('//SignatureValue', $signatureElement)->item(0);
	$signatureValueElement->nodeValue = base64_encode($signatureValue);
	
	return $xml->saveXML(); 
}

$certificados = carregarCertificado();
$xmlNaoAssinado = montarTermoAutorizacao();
$resultado = assinar($xmlNaoAssinado, $certificados);
echo '<textarea>'.$resultado.'</textarea>';
echo '<textarea>'.base64_encode($resultado).'</textarea>';
?>
