<?php
/**
 * Description of Firmar
 *
 * @author yerko
 */

require '../firmarDTE/xmlseclibs/xmlseclibs.php';

class Firmar{
    
    var $dteFirmarRuta;
    var $dteFirmarNombre;
    var $dteFirmarXML;
    var $dteFrimarTipo;
    var $tipoLibro;
    var $arrDteFirmadoRuta;
    var $sDteTimbradoXML;
    var $pkRuta;
    var $pkPass;
    var $foliosRuta;
    var $tipoDTE;
    var $sTimbre;
    var $arrfoliosRuta= array (33=>'../FOLIOS/Folios_factura.xml'
,34=>'../FOLIOS/Folios_factura_exenta.xml'
,46=>'../FOLIOS/Folios_factura_compra.xml'
,52=>'../FOLIOS/Folios_guia.xml'
,56=>'../FOLIOS/Folios_nd.xml'
,61=>'../FOLIOS/Folios_nc.xml');
    
////// variables para RecepArchivo
    var $recepArch;             // string xml
    var $arrRecepArchivoRuta;   // array con rutas

////// variables para RecepArchivo
    var $recepCom;          // string xml
    var $arrRecepComRuta;   // array con rutas

////// variables para RecepMercaderia
    var $recepMerc;          // string xml
    var $arrRecepMercRuta;   // array con rutas
    
    
    public function __construct() {
        
    } 
    
    public function Procesa() {
        
        $this->getXMLdteFirmar();
        $this->getTipoDocumentoFirmar();
        if ($this->dteFrimarTipo=="DTE") {
            $this->TimbrarDTE();
            $this->FirmarDTE();
        }
        
        echo "<pre>";
        echo '<a href="'.$this->arrDteFirmadoRuta['archivo'].'">'.$this->arrDteFirmadoRuta['archivo'].'</a>';//exit();
    }
    
////// procesar RecepArchivo
    public function ProcesarRecepArchivo() {
        $this->firmarRecepArchivo();
        echo "<pre>";
        echo '<a href="'.$this->arrRecepArchivoRuta['archivo'].'">'.$this->arrRecepArchivoRuta['archivo'].'</a>';//exit();
    }
////// procesar RecepArchivo
    public function ProcesarRecepCom() {
        $this->firmarRecepCom();
        echo "<pre>";
        echo '<a href="'.$this->arrRecepComRuta['archivo'].'">'.$this->arrRecepComRuta['archivo'].'</a>';//exit();
    }
    
////// procesar RecepArchivo
    public function ProcesarRecepMerc() {
        
        $this->firmarRecepMercaderia();
        echo "<pre>";
        echo '<a href="'.$this->arrRecepMercRuta['archivo'].'">'.$this->arrRecepMercRuta['archivo'].'</a>';//exit();
    }
    
    
    public function getXMLdteFirmar(){
        
        $this->dteFirmarXML =  utf8_encode(str_replace('<?xml version="1.0" encoding="UTF-8"?>'.chr(10), '',  file_get_contents($this->dteFirmarRuta)));
    }
    
    public function getTipoDocumentoFirmar(){
        $oDoc = new DOMDocument('1.0', 'ISO-8859-1');
        $oDoc->loadXML($this->dteFirmarXML);
        
        $this->dteFrimarTipo = $oDoc->firstChild->nodeName;
        
        if ( $this->dteFrimarTipo == "EnvioLibro"){
            var_dump($oDoc->getElementsByTagName("TipoOperacion")->item(0));
            if ( $oDoc->getElementsByTagName("TipoOperacion")->item(0) == NULL )
            {
                $this->tipoLibro = "GUIAS" ;
            }
            else
            {
                $arrNodo = $this->domnode_to_array($oDoc->getElementsByTagName("TipoOperacion")->item(0));
                $this->tipoLibro =$arrNodo;
            }
        }
    }


    public function TimbrarDTE(){
        $oDoc =  new DOMDocument('1.0', 'ISO-8859-1');

        $oDoc->loadXML($this->dteFirmarXML);
        $oDTEs=$oDoc->getElementsByTagName('DTE');
        
        $aDatos= $this-> obtieneDatosDTEdesdeXML($oDTEs->item(0));
          
        $sl=chr(10);
        $initTab=chr(9).chr(9);
        $tab=chr(9).$initTab;
        $dbltab=chr(9).chr(9).$initTab;
         
        $sCodTdo=$aDatos['Encabezado']['IdDoc']['TipoDTE'];
        
        $this->tipoDTE = $sCodTdo;
        $this->foliosRuta=  $this->arrfoliosRuta[$this->tipoDTE];
        
        if(isset($aDatos['Detalle'][0]))
            $sDesc=  $this-> quitarEspecialesXML($aDatos['Detalle'][0]['NmbItem']);
        else
            $sDesc= $this-> quitarEspecialesXML($aDatos['Detalle']['NmbItem']);
        
        $oXmlAut= new DOMDocument();
        $oXmlAut->load($this->foliosRuta);
        
        $sCaf=$oXmlAut->saveXML($oXmlAut->getElementsByTagName('CAF')->item(0));
        
       
        $sXmlDD=$tab.'<DD>'.$sl.     
        $dbltab.'<RE>'.$aDatos['Encabezado']['Emisor']['RUTEmisor'].'</RE>'.$sl.
        $dbltab.'<TD>'.$sCodTdo.'</TD>'.$sl.
        $dbltab.'<F>'.$aDatos['Encabezado']['IdDoc']['Folio'].'</F>'.$sl.
        $dbltab.'<FE>'.$aDatos['Encabezado']['IdDoc']['FchEmis'].'</FE>'.$sl.
        $dbltab.'<RR>'.$aDatos['Encabezado']['Receptor']['RUTRecep'].'</RR>'.$sl;
        
        
        $sXmlDD.=$dbltab.'<RSR>'.substr($this -> quitarEspecialesXML($aDatos['Encabezado']['Receptor']['RznSocRecep']), 0, 40).'</RSR>'.$sl;
        
        
        $sXmlDD.=$dbltab.'<MNT>'.$aDatos['Encabezado']['Totales']['MntTotal'].'</MNT>'.$sl.
        $dbltab.'<IT1>'.substr($sDesc, 0, 40).'</IT1>'.$sl.
        $sCaf.$sl.
        $dbltab.'<TSTED>'.date('Y-m-d').'T'.date('H:i:s').'</TSTED>'.$sl.
        $tab.'</DD>';
        
        $sCafTimbre = utf8_decode(trim(preg_replace('/[\n\r\t]/', '', $sXmlDD)));
        
        $sFirmaDD='';
        $sPK=$oXmlAut->getElementsByTagName('RSASK')->item(0)->nodeValue;
        
        
        if (openssl_sign($sCafTimbre, $sFirmaDD, $sPK, OPENSSL_ALGO_SHA1)){
            $sFirmaDD=  base64_encode($sFirmaDD);
        }else{
            echo "error en la firma del timbre";
        }
        
        $sXml=$initTab.'<TED version="1.0">'.$sl.
                     $sXmlDD.$sl.
                $tab.'<FRMT algoritmo="SHA1withRSA">'.
             $sFirmaDD.'</FRMT>'.$sl.
        $initTab.'</TED>'.$sl.
        $initTab.'<TmstFirma>'.date('Y-m-d').'T'.date('H:i:s').'</TmstFirma>'.$sl;
        
        $this -> sTimbre = utf8_decode(trim(preg_replace('/[\n\r\t]/', '', '<TED version="1.0">'.$sXmlDD.'<FRMT algoritmo="SHA1withRSA">'.'</FRMT>'.'</TED>')));
        
        $oFrag = $oDoc->createDocumentFragment();
        $oFrag->appendXML($sXml);
        $oDocumento=$oDoc->getElementsByTagName('Documento');
        
        $oDocumento->item(0)->appendChild($oFrag);
        
        $this->sDteTimbradoXML = $oDoc->saveXML() ;
        
    }
    
    public function FirmarDTE(){
        $arrPKCertificado = $this->staticGetArrayPrivateKey() ;
        
        $this->arrDteFirmadoRuta=$this->singXmlString($this->sDteTimbradoXML, $arrPKCertificado, array('node'=>'Documento', 'ruta'=>'../DOC/FIRMADO/', 'archivo'=>  str_replace('.xml', '_', $this->dteFirmarNombre).'f.xml'));
    }
    
    public function FirmarLibro(){
        $arrPKCertificado = $this->staticGetArrayPrivateKey() ;
       
        $this->arrDteFirmadoRuta=$this->singXmlString($this->dteFirmarXML, $arrPKCertificado, array('node'=>'Documento', 'ruta'=>'../DOC/FIRMADO/', 'archivo'=>str_replace('.xml', '_', $this->dteFirmarNombre). rand(1000, 1000000).'.xml'));
    }
    
/*************************************************************/
////// metodo para firmar el documento RecepArchivo
    public function firmarRecepArchivo() {
        $arrPKCertificado = $this->staticGetArrayPrivateKey();
        $this->arrRecepArchivoRuta=$this->singXmlString($this->recepArch, $arrPKCertificado, array('node'=>'Resultado', 'ruta'=>'../DOC/FIRMADO/', 'archivo'=> $this-> dteFirmarNombre ));
    }
////// metodo para firmar el documento RecepArchivo
    public function firmarRecepCom() {
        $arrPKCertificado = $this->staticGetArrayPrivateKey();
        $this->arrRecepComRuta=$this->singXmlString($this->recepCom, $arrPKCertificado, array('node'=>'Resultado', 'ruta'=>'../DOC/FIRMADO/', 'archivo'=> $this->dteFirmarNombre ));
    }
////// metodo para firmar los recibos
   public function firmarReciboRM($xml) {
        $arrPKCertificado = $this->staticGetArrayPrivateKey();
        return $this->singXmlString($xml, $arrPKCertificado, array('node'=>'DocumentoRecibo', 'ruta'=>'../DOC/PASO/', 'archivo'=>str_replace('.xml', '_', $this->dteFirmarNombre). rand(1000, 1000000).'.xml'));
    }
////// metodo para firmar el documento RecepArchivo
    public function firmarRecepMercaderia() {
        $arrPKCertificado = $this->staticGetArrayPrivateKey();
        $this->arrRecepMercRuta=$this->singXmlString($this->recepMerc, $arrPKCertificado, array('node'=>'SetRecibos', 'ruta'=>'../DOC/FIRMADO/', 'archivo'=> $this->dteFirmarNombre ));
    }
    
    
    /******* OBTIENE DATOS ASOCIADOS AL DTE EN FORMATO XML************************/     
      function obtieneDatosDTEdesdeXML($oDTE){
        $aDocto=array();

         $oCab=$oDTE->getElementsByTagName('Documento');
        $aDatosDTE=$this->domnode_to_array($oCab->item(0));
        
        return $aDatosDTE;
     }
     
/******** FUNCION QUE REEMPLAZA LOS CARACTERES ESPECIALES , SEGUN NORMA SII ***/     
      function quitarEspecialesXML($sCad){
        $sCad=str_replace("&","&amp;",$sCad);
        $sCad=str_replace("<","&lt;",$sCad);
        $sCad=str_replace(">","&gt;",$sCad);
       // $sCad=str_replace('"',"&#34;",$sCad);
       // $sCad=str_replace("'","&#39;",$sCad);
        return $sCad;
     }     
     
      public function domnode_to_array($node) {
            $output = array();
            
            switch ($node->nodeType) {
                case XML_CDATA_SECTION_NODE:
                case XML_TEXT_NODE:
                    $output = trim($node->textContent);
                break;
                case XML_ELEMENT_NODE:
                    for ($i=0, $m=$node->childNodes->length; $i<$m; $i++) { 
                        $child = $node->childNodes->item($i);
                        $v = $this->domnode_to_array($child);
                        
                        if(isset($child->tagName)) {
                            $t = $child->tagName;
                            if(!isset($output[$t])) {
                                $output[$t] = array();
                            }
                            $output[$t][] = $v;
                        }else if ($v != '') {
                             $output = (string) $v;
                        }
                     }
                     
                     if(is_array($output)) {
                        if($node->attributes->length) {
                             $a = array();
                             foreach($node->attributes as $attrName => $attrNode) {
                                $a[$attrName] = (string) $attrNode->value;
                             }
                             $output['@attributes'] = $a;
                        }
                        
                        foreach ($output as $t => $v) {
                            if(is_array($v) && count($v)==1 && $t!='@attributes') {
                                $output[$t] = $v[0];
                            }
                        }
                    }
                break;
            }
            return $output;
      }
      
/*********** ESTE SACA EL PFX *************************************************/      
      public function staticGetArrayPrivateKey(){
            $sPkcs12 = file_get_contents($this->pkRuta);
            $aKey = array();
            openssl_pkcs12_read($sPkcs12, $aKey, $this->pkPass);
            return $aKey;
      }
      
      public function singXmlString($sXml, $aKey, $options=array()){
            
            $oDoc = new DOMDocument('1.0', 'ISO-8859-1'); 
            $oDoc->formatOutput = FALSE; 
            $oDoc->preserveWhiteSpace = TRUE;
            
            if (isset($options['ruta'])){
                if (isset($options['archivo'])){
                    $aResp['archivo']=$options['ruta'].$options['archivo'];
                }else{
                    $aResp['archivo']=$options['ruta'].date('Ymd-His').'_xml_sign.xml';
                }
                $bEsTemp=false;
            }else{
                $aResp['archivo']=RUTA_ARCHIVOS_TMP.date('Ymd-His').'_xml_sign.xml';
                $bEsTemp=true;
            }
            
            if (file_exists($aResp['archivo'])) {
                    unlink($aResp['archivo']);
            }
            
            $oDoc->loadXML($sXml);
            
            $objDSig = new XMLSecurityDSig(FALSE);
            $objDSig->setCanonicalMethod(XMLSecurityDSig::C14N);
            
            $options['prefix'] = (!isset($options['prefix']))?'':$options['prefix'];
            $options['prefix_ns'] =  (!isset($options['prefix_ns']))?'':$options['prefix_ns'];
            $options['force_uri'] = (!isset($options['force_uri']))?TRUE:$options['force_uri'];
            $options['id_name'] = (!isset($options['id_name']))?'ID':$options['id_name'];
            $options['uri'] = (!isset($options['uri']))?NULL:$options['uri'];
            $options['overwrite'] =(!isset($options['overwrite']))?false:$options['overwrite'];;
            
            $options['node']=(!isset($options['node']))?NULL:$options['node'];
            if ($options['node'] != NULL){
                $oNodeDocto=$oDoc->getElementsByTagName($options['node'])->item(0);
                $objDSig->addReference($oNodeDocto, XMLSecurityDSig::SHA1, array('http://www.w3.org/2000/09/xmldsig#enveloped-signature'), $options);
            }else{
                $objDSig->addReference($oDoc, XMLSecurityDSig::SHA1, array('http://www.w3.org/2000/09/xmldsig#enveloped-signature'), $options);
            }

            $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'private'));
            
            $objKey->loadKey($aKey["pkey"]);
            $objDSig->add509Cert($aKey["cert"]);
            $objDSig->sign($objKey, $oDoc->documentElement);
           
            $oDoc->save($aResp['archivo']);
            $aResp['contenido']=str_replace('<?xml version="1.0"?>'.chr(10), '',file_get_contents( $aResp['archivo']));
            
            if ($bEsTemp){
                unlink($aResp['archivo']);
            }
            return $aResp; // CONTENIDO DEL XML SIN TAG DE VERSION Y LA RuTA DONDE ESTA EL ARCHIVO
      }
      
}
