platinum-place / php-dgii-xml-signer
Firmador XML para el uso del API de la DGII (Dirección General de Impuestos Internos) de República Dominicana
Installs: 64
Dependents: 0
Suggesters: 0
Security: 0
Stars: 2
Watchers: 1
Forks: 2
Open Issues: 0
pkg:composer/platinum-place/php-dgii-xml-signer
Requires
- php: ^8.1
- ext-dom: *
- ext-openssl: *
- selective/xmldsig: ^3.1
Requires (Dev)
- phpunit/phpunit: ^10.0|^11.0
README
Una librería en PHP para firmar documentos XML con firma digital conforme a los requerimientos de la Dirección General de Impuestos Internos (DGII) de República Dominicana para el sistema de Comprobantes Fiscales Electrónicos (e-CF).
Descripción
Este paquete proporciona las herramientas necesarias para firmar digitalmente documentos XML utilizando certificados digitales válidos, cumpliendo con las especificaciones técnicas establecidas por la DGII para la facturación electrónica en República Dominicana.
Características
- ✅ Firma digital de documentos XML según estándares XMLDSig
- ✅ Compatible con certificados digitales emitidos por entidades certificadoras autorizadas
- ✅ Cumple con las especificaciones técnicas de la DGII
- ✅ Soporte para Comprobantes Fiscales Electrónicos (e-CF)
- ✅ Validación de estructura XML antes del firmado
- ✅ Fácil integración en aplicaciones PHP existentes
Requisitos
- PHP 8.1 o superior
- Extensión OpenSSL habilitada
- Extensión XMLWriter habilitada
- Extensión DOMDocument habilitada
- Certificado digital válido emitido por una entidad certificadora autorizada
Aclaraciones
Aunque la documentación de la DGII explica cómo utilizar la librería XMLDSIG para leer los certificados, y esta aplicación está basada en esa documentación, destaco que, por lo menos para mí, hay una parte de la documentación que no está del todo clara.
A continuación, muestro algunos casos:
Caso 1: Cambiar la clase XmlSigner.php (o hacer una copia de la misma con los cambios de lugar)
Uno de estos casos se encuentra en la parte sobre la siguiente línea de código:
$canonicalData = $element->C14N(true, false);
Debería cambiarse a:
$canonicalData = $element->C14N(false, false);
Si bien la documentación explica que se debe cambiar esta línea, no menciona que también es necesario realizar el mismo cambio en otra parte del archivo:
$c14nSignedInfo = $signedInfoElement->C14N(true, false);
Debería cambiarse a:
$c14nSignedInfo = $signedInfoElement->C14N();
Este cambio debe realizarse específicamente en la línea 179 del archivo original.
Caso 2: Error al leer el certificado
La documentación menciona que la librería fue probada en PHP versiones 8.1.12 y 8.1.13, si utilizas el paquete en una version mas reciente, como 8.4 o 8.5, la validación falla debido a que el cifrado RC2-40-CBC utilizado en los archivos .p12 cambió en las versiones más recientes de OpenSSL, que normalmente vienen con PHP 8.2 en adelante.
Para solucionarlo, debemos modificar el archivo openssl.cnf para que admita el cifrado que necesitamos, cambiando la configuración por defecto al modo "legacy".
Habilitar cifrado "legacy"
-
Edita el archivo
openssl.cnfcon el siguiente comando:sudo nano /etc/ssl/openssl.cnf
-
Busca la sección [default_sect] y cámbiarla a:
[default_sect] activate = 1
-
Luego, busca la sección [legacy_sect] y cámbiarla a:
[legacy_sect] activate = 1
-
Por último, busca la sección [provider_sect] y cámbiarla a:
[provider_sect] default = default_sect legacy = legacy_sect
-
Finalmente, guardar los cambios, salir del archivo y reiniciar el entorno.
Instalación
Vía Composer (Recomendado)
composer require platinum-place/php-dgii-xml-signer
Instalación Manual
git clone https://github.com/platinum-place/php-dgii-xml-signer.git
cd php-dgii-xml-signer
composer install
Uso Básico
<?php use PlatinumPlace\DgiiXmlSigner\SignManager; $xmlDocument = '<?xml version="1.0" encoding="UTF-8"?> <ECF xmlns="http://dgii.gov.do/e-CF/v1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <Encabezado> <Version>1.0</Version> <IdDoc> <TipoeCF>31</TipoeCF> <eNCF>E310000000001</eNCF> <FechaVencimientoSecuencia>2024-12-31</FechaVencimientoSecuencia> </IdDoc> <Emisor> <RNCEmisor>123456789</RNCEmisor> <RazonSocialEmisor>Mi Empresa SRL</RazonSocialEmisor> </Emisor> <Comprador> <RNCComprador>987654321</RNCComprador> <RazonSocialComprador>Cliente SRL</RazonSocialComprador> </Comprador> <Totales> <MontoGravadoTotal>1000.00</MontoGravadoTotal> <MontoGravadoI1>1000.00</MontoGravadoI1> <MontoImpuesto1>180.00</MontoImpuesto1> <MontoTotal>1180.00</MontoTotal> </Totales> </Encabezado> <DetallesItems> <Item> <NumeroLinea>1</NumeroLinea> <CodigoItem>PROD001</CodigoItem> <DescripcionItem>Producto de ejemplo</DescripcionItem> <CantidadItem>1</CantidadItem> <PrecioUnitarioItem>1000.00</PrecioUnitarioItem> <MontoItem>1000.00</MontoItem> </Item> </DetallesItems> </ECF>'; try { $certContent = file_get_contents('/path/to/certificate.p12'); $certPassword = 'password'; $signedXML = (new SignManager)->sign($certContent, $certPassword, $xmlDocument); } catch (Exception $e) { echo "Error procesando e-CF: " . $e->getMessage() . "\n"; }
Licencia
Este proyecto está licenciado bajo la Licencia MIT. Ver el archivo LICENSE para más detalles.
Recursos Adicionales
- Documentación Oficial DGII - Facturación Electrónica
- Especificaciones Técnicas e-CF
- Guía de Implementación XMLDSig
Error OpenSSL
Más detalles sobre el error pueden encontrarse en el siguiente enlace de Stack Overflow:
Convert an old-style .p12 to .pem - Unsupported Algorithm RC2-40-CBC