- 
      
 - 
        
Save allanfreitas/2e68f9fc15ec017d8f2c41da18ccfea7 to your computer and use it in GitHub Desktop.  
    Assinatura e Envio de XML SMARAPD padrão ABRASF 2.03 (Vila Velha)
  
        
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | <?php | |
| /** | |
| * User: LuizVAz | |
| * Date: 28/02/2021 | |
| * Time: 19:46 | |
| */ | |
| namespace Provedores\webService; | |
| use DOMDocument; | |
| use DOMXPath; | |
| use Exception; | |
| use RobRichards\XMLSecLibs\XMLSecEnc; | |
| use RobRichards\XMLSecLibs\XMLSecurityDSig; | |
| use RobRichards\XMLSecLibs\XMLSecurityKey; | |
| use Slim\App; | |
| use Slim\Http\Request; | |
| use Slim\Http\Response; | |
| use stdClass; | |
| class smarapd_v001 extends \Provedores\webService\webService | |
| { | |
| private $cnpj; | |
| private $dir; | |
| private $nfs_dir; | |
| private $rps_dir; | |
| protected $rps_id; | |
| protected $rps_serie; | |
| private $user; | |
| public function __construct(Request $request, Response $response, App $app){ | |
| parent::__construct($request, $response, $app); | |
| $ym = date('Ym'); | |
| $this->dir = $dir = getenv('BASE_PATH'); | |
| $this->user = "your_code"; | |
| $this->cnpj = "your_code"; | |
| $this->inscricaoMunicipal = "your_code"; | |
| $this->rps_dir = "$dir/$cnpj/rps/$ym/"; | |
| $this->nfs_dir = "$dir/$cnpj/nfse/$ym/"; | |
| $this->rps_id = date('Ymd') . str_pad(time() - strtotime("today"), 5, '0'); | |
| $this->rps_serie = "ws1"; | |
| } | |
| public function consultar(stdClass $rps){ | |
| $this->rps = $rps; | |
| return $this->consultaNFsePorRps(); | |
| } | |
| public function consultaNFsePorRps(): stdClass | |
| { | |
| // Retorno | |
| $return = new stdClass(); | |
| $return->status = 500; | |
| $return->data = array("success" => false); | |
| // Parametros | |
| $rps_numero = $this->rps_id; | |
| $rps_serie = $this->rps_serie; | |
| $rps_tipo = "1"; | |
| $rps_cnpj = $this->cnpj; | |
| $rps_im = $this->inscricaoMunicipal; | |
| $envelope = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> | |
| <soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:nfse=\"http://nfse.abrasf.org.br\"> | |
| <soapenv:Header/> | |
| <soapenv:Body> | |
| <nfse:consultarNfsePorRps> | |
| <xml><![CDATA[<?xml version=\"1.0\" encoding=\"UTF-8\"?> | |
| <ConsultarNfseRpsEnvio xmlns=\"http://www.abrasf.org.br/nfse.xsd\"> | |
| <IdentificacaoRps> | |
| <Numero>$rps_numero</Numero> | |
| <Serie>$rps_serie</Serie> | |
| <Tipo>$rps_tipo</Tipo> | |
| </IdentificacaoRps> | |
| <Prestador> | |
| <CpfCnpj> | |
| <Cnpj>$rps_cnpj</Cnpj> | |
| </CpfCnpj> | |
| <InscricaoMunicipal>$rps_im</InscricaoMunicipal> | |
| </Prestador> | |
| </ConsultarNfseRpsEnvio>]]></xml> | |
| </nfse:consultarNfsePorRps> | |
| </soapenv:Body> | |
| </soapenv:Envelope>"; | |
| $url = $this->end_prod; | |
| if ($this->rps->ambienteEmissao && (strtolower($this->rps->ambienteEmissao) === "homologacao")){ | |
| $url = $this->end_homo; | |
| } | |
| $ret = $this->sendRequest($envelope, "", $url); | |
| $html = $ret['html']; | |
| $httpcode = $ret['code']; | |
| if ($httpcode!=200){ | |
| preg_match_all('/<faultstring>(.*?)<\/faultstring>/s', html_entity_decode($html), $matches); | |
| $response = (count($matches)&&count($matches[1])?$matches[1][0]:$html); | |
| $return->data['errors'][] = [ | |
| "codigo" => $httpcode, | |
| "mensagem" => $response, | |
| "correcao" => "" | |
| ]; | |
| return $return; | |
| } | |
| // Extrai Retorno SOAP | |
| preg_match_all('/<return>(.*?)<\/return>/s', html_entity_decode($html), $matches); | |
| $response = (count($matches)&&count($matches[1])?$matches[1][0]:$html); | |
| // Parse | |
| $return->status = $httpcode; | |
| $this->parseRetorno($response, $return); | |
| return $return; | |
| } | |
| public function emitir(stdClass $rps){ | |
| $this->rps = $rps; | |
| return $this->gerarNfse(); | |
| } | |
| public function gerarNfse(): stdClass | |
| { | |
| //Live Mode | |
| $live = true; | |
| //Retorno | |
| $return = new stdClass(); | |
| $return->status = 500; | |
| $return->data = array("success" => false); | |
| $rps_dir = $this->rps_dir; | |
| //rps_id ou idExterno | |
| $rps_id = (property_exists($this->rps, 'idExterno'))?$this->rps->idExterno:$this->rps_id; | |
| if (!$rps_id){ | |
| $rps_id = date('Ymd') . str_pad(time() - strtotime("today"), 5, '0'); | |
| $this->rps_id = $rps_id; | |
| } else | |
| $this->rps_id = $rps_id; | |
| //Garante que o diretório exista | |
| $fname = "${rps_dir}${rps_id}.xml"; | |
| if (!file_exists("${rps_dir}")) { | |
| mkdir("${rps_dir}", 0777, true); | |
| } | |
| $envelope = | |
| "<soapenv:Envelope ". | |
| " xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" ". | |
| " xmlns:nfse=\"http://nfse.abrasf.org.br\">". | |
| " <soapenv:Header/>". | |
| " <soapenv:Body>". | |
| " <nfse:recepcionarLoteRpsSincrono>". | |
| " <xml><![CDATA[%DadosMsg%]]></xml>". | |
| " </nfse:recepcionarLoteRpsSincrono>". | |
| " </soapenv:Body>". | |
| "</soapenv:Envelope>"; | |
| //Ambiente: 1 = Produção, 2 = Homologação | |
| $amb = '1'; | |
| if ($this->rps->ambienteEmissao && (strtolower($this->rps->ambienteEmissao) === "homologacao")){ | |
| $amb = '2'; | |
| } | |
| if ($live) { | |
| //xml | |
| $xml = $this->rpsAsXML(); | |
| /* $xml = str_ireplace('<?xml version="1.0" encoding="utf-8"?>', '', $xml); */ | |
| file_put_contents("$fname", $xml); | |
| //$cab = htmlentities($cab, ENT_XML1 | ENT_NOQUOTES); | |
| //$xml = htmlentities($xml, ENT_XML1 | ENT_NOQUOTES); | |
| //$envelope = str_replace('%CabMsg%', $cab, $envelope); | |
| $envelope = str_replace('%DadosMsg%', $xml, $envelope); | |
| file_put_contents("${rps_dir}${rps_id}.soap", $envelope); | |
| } | |
| if ($live) { | |
| //Live Mode | |
| $url = $this->end_prod; | |
| if ($this->rps->ambienteEmissao && (strtolower($this->rps->ambienteEmissao) === "homologacao")){ | |
| $url = $this->end_homo; | |
| } | |
| $ret = $this->sendRequest($envelope, "", $url); | |
| $html = $ret["html"]; | |
| // Converte de UTF-8 para ISO-8859 | |
| //$html = utf8_decode(curl_exec($ch)); | |
| $httpcode = $ret["code"]; | |
| $return->status = $httpcode; | |
| file_put_contents("$fname.ret", $html); | |
| $html = utf8_decode($html); //Converter Depois de Salvo | |
| } else { | |
| //Test Mode | |
| $httpcode = 200; | |
| $return->status = $httpcode; | |
| $html = file_get_contents("$fname.ret"); | |
| } | |
| if ($httpcode!=200){ | |
| preg_match_all('/<faultstring>(.*?)<\/faultstring>/s', html_entity_decode($html), $matches); | |
| $response = (count($matches)&&count($matches[1])?$matches[1][0]:$html); | |
| $return->data['errors'][] = [ | |
| "codigo" => $httpcode, | |
| "mensagem" => $response, | |
| "correcao" => "" | |
| ]; | |
| return $return; | |
| } | |
| //Extrai | |
| preg_match_all('/<return>(.*?)<\/return>/s', html_entity_decode($html), $matches); | |
| $response = (count($matches)&&count($matches[1])?$matches[1][0]:$html); | |
| $return = $this->parseRetorno($response, $return); | |
| return $return; | |
| } | |
| public function parseRetorno($response, $return): stdClass | |
| { | |
| $dom = new DOMDocument(); | |
| $dom->preserveWhiteSpace = false; | |
| //Verifica falha ao processar XML de RETORNO | |
| if (@$dom->loadXML($response) === false){ | |
| //Retorno | |
| $return->data['errors'][] = [ | |
| "codigo" => "500", | |
| "mensagem" => "$response", | |
| "correcao" => "Contate o suporte!" | |
| ]; | |
| return $return; | |
| } | |
| $xp = new DOMXPath($dom); | |
| $xp->registerNamespace('fake', "http://nfse.abrasf.org.br"); | |
| // /retornoNfseLote/errors/erro | |
| $nodes = $xp->query("/*/*/*[name()='MensagemRetorno']"); | |
| if ($nodes->length != 0){ | |
| if (!array_key_exists('errors', $return->data)) | |
| $return->data['errors'] = []; | |
| for ($i = 0; $i<$nodes->length; $i++){ | |
| $msg = $nodes->item($i); | |
| //Tags | |
| $cod = $msg->getElementsByTagName("Codigo"); | |
| if ($cod->length>0) { | |
| $cod = $cod->item(0); | |
| $cod = $cod->nodeValue; | |
| if (strlen($cod)>5) $cod = "E00"; //Texto redundante | |
| } else | |
| $cod = "E00"; | |
| $txt = $msg->getElementsByTagName("Mensagem"); | |
| if ($txt->length>0) { | |
| $txt = $txt->item(0); | |
| $txt = $txt->nodeValue; | |
| } else | |
| $txt = ""; | |
| $cor = $msg->getElementsByTagName("Correcao"); | |
| if ($cor->length>0) { | |
| $cor = $cor->item(0); | |
| $cor = $cor->nodeValue; | |
| } else | |
| $cor = ""; | |
| //Retorno | |
| $return->data['errors'][] = [ | |
| "codigo" => $cod, | |
| "mensagem" => $txt, | |
| "correcao" => $cor | |
| ]; | |
| } | |
| return $return; | |
| } | |
| // Resposta EnviarLoteRpsSincrono | |
| $nodes = $xp->query("/*[name()='EnviarLoteRpsSincronoResposta']"); | |
| if ($nodes->length != 0){ | |
| $nfseId = ""; | |
| $msg = $nodes->item(0); | |
| $proto = $msg->getElementsByTagName("Protocolo"); | |
| $proto = ($proto->length>0)?$proto = $proto->item(0)->nodeValue:"0"; | |
| $return->data['protocolo'] = $proto; | |
| $lote = $msg->getElementsByTagName("NumeroLote"); | |
| $lote = ($lote->length>0)?$lote = $lote->item(0)->nodeValue:"0"; | |
| $return->data['numeroLote'] = $lote; | |
| // Consulta por Lote não funciona | |
| // Precisa pegar pelo RPS | |
| $return = $this->consultaNFsePorRps(); | |
| // Pussui Erros | |
| if (array_key_exists('errors', $return->data)){ | |
| return $return; | |
| } | |
| // Salva Retorno | |
| $num = $return->data["numero"]; | |
| $nfs_dir = $this->nfs_dir; | |
| $fname = "${nfs_dir}${num}.xml"; | |
| if (!file_exists(dirname("$fname"))) { | |
| mkdir(dirname("$fname"), 0777, true); | |
| } | |
| file_put_contents($fname, $msg->ownerDocument->saveXML()); | |
| $return->data['success'] = true; | |
| } | |
| // Possui Nota | |
| $nodes = $xp->query("//CompNfse"); | |
| if ($nodes->length != 0) { | |
| $nfseId = ""; | |
| $msg = $nodes->item(0); | |
| $id = $msg->getElementsByTagName("InfNfse"); | |
| $id = ($id->length && ($id = $id->item(0)->getAttribute("Id")))?$id:$this->rps_id; | |
| $num = $msg->getElementsByTagName("Numero"); | |
| $num = ($num->length)?$num->item(0)->nodeValue:$this->rps_id; | |
| $cod = $msg->getElementsByTagName("CodigoVerificacao"); | |
| $cod = ($cod->length)?$cod->item(0)->nodeValue:"N/D"; | |
| $dat = $msg->getElementsByTagName("DataEmissao"); | |
| $dat = ($dat->length)?$dat->item(0)->nodeValue:""; | |
| $dat = str_ireplace(' ', 'T', $dat); | |
| $return->data['nfseId'] = $id; | |
| $return->data['numero'] = $num; | |
| $return->data['codigoVerificacao'] = $cod; | |
| $return->data['dataEmissao'] = $dat; | |
| $return->data['success'] = true; | |
| } | |
| return $return; | |
| } | |
| public function rpsAsXML() | |
| { | |
| //DOM | |
| $dom = new DOMDocument('1.0', 'utf-8'); | |
| $dom->formatOutput = true; | |
| $dom->preserveWhiteSpace = true; | |
| $dom->appendChild($enviarLoteRpsSincronoEnvio = $dom->createElement("EnviarLoteRpsSincronoEnvio")); | |
| $enviarLoteRpsSincronoEnvio->setAttribute("xmlns", "http://www.abrasf.org.br/nfse.xsd"); | |
| // LoteRps | |
| $enviarLoteRpsSincronoEnvio->appendChild($loteRps = $dom->createElement("LoteRps")); | |
| $loteId = date('Ymd') . str_pad(time() - strtotime("today"), 5, '0'); | |
| $loteRps->setAttribute("versao", "2.03"); | |
| $loteRps->setAttribute("Id", "$loteId"); | |
| $loteRps->appendChild( $dom->createElement("NumeroLote", "$loteId")); | |
| $loteRps->appendChild( $cpfCnpj = $dom->createElement("CpfCnpj")); | |
| $cpfCnpj->appendChild( $dom->createElement("Cnpj", $this->conf->cnpj)); | |
| $loteRps->appendChild( $dom->createElement("InscricaoMunicipal", $this->conf->inscricaoMunicipal)); | |
| $loteRps->appendChild( $dom->createElement("QuantidadeRps", "1")); | |
| // ListaRps | |
| $loteRps->appendChild( $listaRps = $dom->createElement("ListaRps")); | |
| //Rps | |
| $listaRps->appendChild( $rps1 = $dom->createElement("Rps")); | |
| //InfDeclaracaoPrestacaoServico | |
| $rps1->appendChild( $infDec = $dom->createElement("InfDeclaracaoPrestacaoServico")); | |
| $infDec->setAttribute("Id", "A".$this->rps_id); | |
| //Rps | |
| $infDec->appendChild( $rps2 = $dom->createElement("Rps")); | |
| $rps2->setAttribute("Id", "B".$this->rps_id); | |
| //IdentificacaoRps | |
| $rps2->appendChild( $identificacaoRps = $dom->createElement("IdentificacaoRps")); | |
| $identificacaoRps->appendChild($dom->createElement("Numero",$this->rps_id)); | |
| $identificacaoRps->appendChild($dom->createElement("Serie",$this->rps_serie)); | |
| $identificacaoRps->appendChild($dom->createElement("Tipo","1")); | |
| //Formato yyyy-mm-dd | |
| $dataEmissao = date("Y-m-d"); | |
| if ($this->rps->dataEmissao){ | |
| $dataEmissao = new \DateTime($this->rps->dataEmissao); | |
| $dataEmissao = $dataEmissao->format('Y-m-d'); | |
| } | |
| //DataEmissao | |
| $rps2->appendChild($dom->createElement("DataEmissao",$dataEmissao)); | |
| //Status | |
| $rps2->appendChild($dom->createElement("Status","1")); | |
| //Competencia | |
| $infDec->appendChild($dom->createElement("Competencia",$dataEmissao)); | |
| //Servico | |
| $servico = $dom->createElement("Servico"); | |
| //Valores | |
| $valores = $dom->createElement("Valores"); | |
| $valorTotal = 0.00; | |
| $valor = (property_exists($this->rps->servico, 'valorServicos')?0.00+$this->rps->servico->valorServicos:0); | |
| if (!$valor) | |
| $valor = (property_exists($this->rps, 'valorTotal')?0.00+$this->rps->valorTotal:0); | |
| if ($valor == 0) | |
| throw new Exception("Informação servico->valorServicos não informada."); | |
| $valores->appendChild( | |
| $dom->createElement("ValorServicos", $this->formatValor($valor)) | |
| ); | |
| $valorTotal += $valor; | |
| $valor = (property_exists($this->rps->servico, 'valorDeducoes')?0.00+$this->rps->servico->valorDeducoes:0); | |
| if ($valor) | |
| $valores->appendChild( | |
| $dom->createElement("ValorDeducoes", $this->formatValor($valor)) | |
| ); | |
| $valorTotal -= $valor; | |
| $aliquotaIss = 0; | |
| if (property_exists($this->rps->servico, 'aliquotaIss')) | |
| $aliquotaIss = 0.00+$this->rps->servico->aliquotaIss; | |
| if ($aliquotaIss == 0) | |
| if (property_exists($this->rps->servico, 'aliquota')) | |
| $aliquotaIss = 0.00+$this->rps->servico->aliquota; | |
| if ($aliquotaIss == 0) | |
| throw new Exception("Informação aliquotaIss não encontrada."); | |
| $valorIss = round($valorTotal * $aliquotaIss, 2, PHP_ROUND_HALF_EVEN); | |
| $valores->appendChild($dom->createElement("ValorIss", $this->formatValor($valorIss*1))); | |
| $valores->appendChild($dom->createElement("Aliquota", $this->formatValor($aliquotaIss*100))); | |
| $servico->appendChild($valores); | |
| //Servico | |
| //issRetido | |
| $issRetido = (property_exists($this->rps, 'issRetidoFonte')?$this->rps->issRetidoFonte:false); | |
| $servico->appendChild($dom->createElement("IssRetido", $issRetido?'1':'2')); | |
| //itemListaServicoLC116 | |
| $itemListaServico = (property_exists($this->rps, 'itemListaServicoLC116')?$this->rps->itemListaServicoLC116:false); | |
| if (!$itemListaServico) | |
| $itemListaServico = (property_exists($this->rps->servico, 'itemListaServico')?$this->rps->servico->itemListaServico:false); | |
| if (!$itemListaServico) | |
| $itemListaServico = $this->conf->itemListaServicoLC116; | |
| $servico->appendChild($dom->createElement("ItemListaServico", $itemListaServico)); | |
| //cnae | |
| /* | |
| $cnae = (property_exists($this->rps, 'cnae')?$this->rps->cnae:false); | |
| if (!$cnae) | |
| $cnae = $this->conf->cnae; | |
| $servico->appendChild($dom->createElement("CodigoCnae", $cnae)); | |
| */ | |
| //codigoTributacaoMunicipio | |
| $codigoTributacaoMunicipio = (property_exists($this->rps->servico, 'codigoTributacaoMunicipio')?$this->rps->servico->codigoTributacaoMunicipio:false); | |
| if ($codigoTributacaoMunicipio) | |
| $servico->appendChild($dom->createElement("CodigoTributacaoMunicipio", $codigoTributacaoMunicipio)); | |
| //descricao | |
| $descricao = (property_exists($this->rps->servico, 'discriminacao')?$this->rps->servico->discriminacao:""); | |
| if (!$descricao) | |
| $descricao = (property_exists($this->rps->servico, 'descricao')?$this->rps->servico->descricao:""); | |
| if (!$descricao) | |
| $descricao = $this->conf->descricaoServico; | |
| $observacao = (property_exists($this->rps->servico, 'observacao')?$this->rps->servico->observacao:""); | |
| $descricao = ($descricao) ? "$descricao\n$observacao" : $observacao; | |
| if ($descricao) { | |
| // Essa limpeza será feita logo abaixo | |
| //$descricao = str_replace(array("\r\n", "\r", "\n", "\t"), "", $descricao); | |
| //$descricao = $this->remove_accents($descricao); | |
| $servico->appendChild($dom->createElement("Discriminacao", $descricao)); | |
| } | |
| //codigoMunicipio | |
| $codigoMunicipio = (property_exists($this->rps->servico, 'codigoMunicipio')?$this->rps->servico->codigoMunicipio:0); | |
| if (!$codigoMunicipio) | |
| $codigoMunicipio = $this->conf->endereco->codigoIbgeCidade; | |
| $servico->appendChild($dom->createElement("CodigoMunicipio", $codigoMunicipio)); | |
| //exigibilidadeISS | |
| $servico->appendChild($dom->createElement("ExigibilidadeISS", "1")); | |
| //municipioIncidencia | |
| $municipioIncidencia = (property_exists($this->rps->servico, 'municipioPrestacaoServico')?$this->rps->servico->municipioPrestacaoServico:0); | |
| if (!$municipioIncidencia) | |
| $municipioIncidencia = $codigoMunicipio; | |
| $servico->appendChild($dom->createElement("MunicipioIncidencia", $municipioIncidencia)); | |
| $infDec->appendChild($servico); | |
| //prestador | |
| $infDec->appendChild($prestador = $dom->createElement("Prestador")); | |
| $cpfCnpj = $dom->createElement("CpfCnpj"); | |
| $cnpj = $dom->createElement("Cnpj", $this->conf->cnpj); | |
| $cpfCnpj->appendChild($cnpj); | |
| $prestador->appendChild($cpfCnpj); | |
| $im = $dom->createElement("InscricaoMunicipal", $this->conf->inscricaoMunicipal); | |
| $prestador->appendChild($im); | |
| //Tomador | |
| $infDec->appendChild($tomador = $dom->createElement("Tomador")); | |
| $identificacaoTomador = $dom->createElement("IdentificacaoTomador"); | |
| $cpfCnpj = $dom->createElement("CpfCnpj"); | |
| $doc = null; | |
| $temp = (property_exists($this->rps->cliente, 'cpfCnpj')?$this->rps->cliente->cpfCnpj:""); | |
| if (strlen($temp)==14) | |
| $doc = $dom->createElement("Cnpj", $this->rps->cliente->cpfCnpj); | |
| elseif (strlen($temp)==11) | |
| $doc = $dom->createElement("Cpf", $this->rps->cliente->cpfCnpj); | |
| if ($doc){ | |
| $cpfCnpj->appendChild($doc); | |
| $identificacaoTomador->appendChild($cpfCnpj); | |
| } | |
| if (property_exists($this->rps->cliente, 'inscricaoMunicipal')){ | |
| $doc = $dom->createElement('InscricaoMunicipal', $this->rps->cliente->inscricaoMunicipal); | |
| $identificacaoTomador->appendChild($doc); | |
| } | |
| $tomador->appendChild($identificacaoTomador); | |
| $temp = (property_exists($this->rps->cliente, 'nome')?$this->rps->cliente->nome:""); | |
| if (!$temp) | |
| $temp = (property_exists($this->rps->cliente, 'razaoSocial')?$this->rps->cliente->razaoSocial:""); | |
| if ($temp) | |
| $tomador->appendChild($dom->createElement("RazaoSocial", $temp)); | |
| //Endereço | |
| $endereco = $dom->createElement("Endereco"); | |
| $temp = (property_exists($this->rps->cliente->endereco, 'logradouro')?$this->rps->cliente->endereco->logradouro:""); | |
| if ($temp) | |
| $endereco->appendChild($dom->createElement("Endereco", $temp)); | |
| $temp = (property_exists($this->rps->cliente->endereco, 'numero')?$this->rps->cliente->endereco->numero:""); | |
| if ($temp) | |
| $endereco->appendChild($dom->createElement("Numero", $temp)); | |
| $temp = (property_exists($this->rps->cliente->endereco, 'bairro')?$this->rps->cliente->endereco->bairro:""); | |
| if ($temp) | |
| $endereco->appendChild($dom->createElement("Bairro", $temp)); | |
| $temp = (property_exists($this->rps->cliente->endereco, 'cidade')?$this->rps->cliente->endereco->cidade:""); | |
| if (!$temp) | |
| $temp = (property_exists($this->rps->cliente->endereco, 'codigoMunicipio')?$this->rps->cliente->endereco->codigoMunicipio:""); | |
| if ($temp) | |
| $endereco->appendChild($dom->createElement("CodigoMunicipio", $temp)); | |
| $temp = (property_exists($this->rps->cliente->endereco, 'UF')?$this->rps->cliente->endereco->UF:""); | |
| if ($temp) | |
| $endereco->appendChild($dom->createElement("Uf", $temp)); | |
| $temp = (property_exists($this->rps->cliente->endereco, 'CEP')?$this->rps->cliente->endereco->CEP:""); | |
| if ($temp) | |
| $endereco->appendChild($dom->createElement("Cep", $temp)); | |
| if ($endereco->childNodes->length > 0) | |
| $tomador->appendChild($endereco); | |
| //Contato | |
| $contato = $dom->createElement("Contato"); | |
| $temp = (property_exists($this->rps->cliente, 'telefone')?$this->rps->cliente->telefone:""); | |
| if ($temp) | |
| $contato->appendChild($dom->createElement("Telefone", $temp)); | |
| $temp = (property_exists($this->rps->cliente, 'email')?$this->rps->cliente->email:""); | |
| if ($temp) | |
| $contato->appendChild($dom->createElement("Email", $temp)); | |
| if ($tomador->childNodes->length > 0) | |
| $tomador->appendChild($contato); | |
| //RegimeEspecialTributacao | |
| if ($this->conf->regimeEspecialTributacao) | |
| $infDec->appendChild($dom->createElement("RegimeEspecialTributacao", $this->conf->regimeEspecialTributacao)); | |
| //OptanteSimplesNacional | |
| $infDec->appendChild($dom->createElement("OptanteSimplesNacional", $this->conf->optanteSimplesNacional?'1':'2')); | |
| $infDec->appendChild($dom->createElement("IncentivoFiscal", $this->conf->incentivadorCultural?'1':'2')); | |
| //Retorna o RPS em formato XML | |
| // limpeza do xml com a retirada dos TAB e Acentos | |
| $decl = str_replace(array("\t"), '', $dom->saveXML()); | |
| $decl = $this->remove_accents($decl); | |
| // Não remover a formatação depois de assinado | |
| $decl = $this->assinaXML($decl, 'InfDeclaracaoPrestacaoServico'); | |
| $decl = str_ireplace('<?xml version="1.0" encoding="UTF-8"?>', '', $decl); | |
| $lote = $this->assinaXML($decl, 'LoteRps'); | |
| return $lote; | |
| } | |
| function assinaXML($docxml, $tag){ | |
| try { | |
| $tagid = $tag; | |
| $crt_dir = dirname(dirname($this->rps_dir)) . '/cert'; | |
| $priKEY = "$crt_dir/pkey.pem"; | |
| $keypass = file_get_contents("$crt_dir/pass.txt"); | |
| $pubKEY = "$crt_dir/cert.pem"; | |
| // Habilita a manipulação de erros da libxml | |
| libxml_use_internal_errors(true); | |
| //limpar erros anteriores que possam estar em memória | |
| libxml_clear_errors(); | |
| // carrega o documento no DOM | |
| $xmldoc = new DOMDocument('1.0', 'UTF-8'); | |
| $xmldoc->preservWhiteSpace = true; //elimina espaços em branco | |
| $xmldoc->formatOutput = false; | |
| // muito importante deixar ativadas as opções para limpar os espacos em branco | |
| // e as tags vazias | |
| if (!$xmldoc->loadXML($docxml, LIBXML_NOBLANKS | LIBXML_NOXMLDECL | LIBXML_BIGLINES)) { | |
| $msg = "Erro ao carregar XML, provavel erro no proprio xml!!"; | |
| $errors = libxml_get_errors(); | |
| if (!empty($errors)) { | |
| $i = 1; | |
| foreach ($errors as $error) { | |
| $msg .= "\n [$i]-" . trim($error->message); | |
| } | |
| libxml_clear_errors(); | |
| } | |
| throw new Exception($msg); | |
| } | |
| //extrair a tag com os dados a serem assinados | |
| $xpath = new DOMXPath($xmldoc); | |
| $xpath->registerNamespace('ns', "http://www.abrasf.org.br/nfse.xsd"); | |
| $node = $xpath->query("//ns:{$tagid}")->item(0); | |
| if (!isset($node)) { | |
| $msg = "A tag <$tagid> não existe no XML!!"; | |
| throw new Exception($msg); | |
| } | |
| // Cria novo Security object | |
| $objDSig = new XMLSecurityDSig(''); | |
| // Usa a c14n exclusive canonicalization | |
| $objDSig->setCanonicalMethod(XMLSecurityDSig::C14N); | |
| // Assina usando SHA-1 | |
| $objDSig->addReference( | |
| $node, | |
| XMLSecurityDSig::SHA1, | |
| [ | |
| "http://www.w3.org/2000/09/xmldsig#enveloped-signature", | |
| "http://www.w3.org/TR/2001/REC-xml-c14n-20010315" | |
| ], | |
| [ | |
| 'id_name' => 'Id', | |
| 'overwrite' => false | |
| ] | |
| ); | |
| // Cria nova (private) Security key | |
| $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'private')); | |
| $objKey->passphrase = "$keypass"; | |
| $objKey->loadKey("$priKEY", TRUE); | |
| // Assina o XML | |
| $objDSig->sign($objKey); | |
| // Adiciona a public key para a signature | |
| $objDSig->add509Cert(file_get_contents("$pubKEY")); | |
| // Acrescenta a signature para o XML | |
| $objDSig->appendSignature($node->parentNode); | |
| $objDSig = null; | |
| //grava na string o objeto DOM | |
| $xml = $xmldoc->saveXML(); | |
| } catch (Exception $e) { | |
| throw $e; | |
| } | |
| //retorna o documento assinado | |
| return $xml; | |
| } //fim signXML | |
| function remove_accents($string) { | |
| if ( !preg_match('/[\x80-\xff]/', $string) ) | |
| return $string; | |
| $chars = array( | |
| // Decompositions for Latin-1 Supplement | |
| chr(195).chr(128) => 'A', chr(195).chr(129) => 'A', | |
| chr(195).chr(130) => 'A', chr(195).chr(131) => 'A', | |
| chr(195).chr(132) => 'A', chr(195).chr(133) => 'A', | |
| chr(195).chr(135) => 'C', chr(195).chr(136) => 'E', | |
| chr(195).chr(137) => 'E', chr(195).chr(138) => 'E', | |
| chr(195).chr(139) => 'E', chr(195).chr(140) => 'I', | |
| chr(195).chr(141) => 'I', chr(195).chr(142) => 'I', | |
| chr(195).chr(143) => 'I', chr(195).chr(145) => 'N', | |
| chr(195).chr(146) => 'O', chr(195).chr(147) => 'O', | |
| chr(195).chr(148) => 'O', chr(195).chr(149) => 'O', | |
| chr(195).chr(150) => 'O', chr(195).chr(153) => 'U', | |
| chr(195).chr(154) => 'U', chr(195).chr(155) => 'U', | |
| chr(195).chr(156) => 'U', chr(195).chr(157) => 'Y', | |
| chr(195).chr(159) => 's', chr(195).chr(160) => 'a', | |
| chr(195).chr(161) => 'a', chr(195).chr(162) => 'a', | |
| chr(195).chr(163) => 'a', chr(195).chr(164) => 'a', | |
| chr(195).chr(165) => 'a', chr(195).chr(167) => 'c', | |
| chr(195).chr(168) => 'e', chr(195).chr(169) => 'e', | |
| chr(195).chr(170) => 'e', chr(195).chr(171) => 'e', | |
| chr(195).chr(172) => 'i', chr(195).chr(173) => 'i', | |
| chr(195).chr(174) => 'i', chr(195).chr(175) => 'i', | |
| chr(195).chr(177) => 'n', chr(195).chr(178) => 'o', | |
| chr(195).chr(179) => 'o', chr(195).chr(180) => 'o', | |
| chr(195).chr(181) => 'o', chr(195).chr(182) => 'o', | |
| chr(195).chr(182) => 'o', chr(195).chr(185) => 'u', | |
| chr(195).chr(186) => 'u', chr(195).chr(187) => 'u', | |
| chr(195).chr(188) => 'u', chr(195).chr(189) => 'y', | |
| chr(195).chr(191) => 'y', | |
| // Decompositions for Latin Extended-A | |
| chr(196).chr(128) => 'A', chr(196).chr(129) => 'a', | |
| chr(196).chr(130) => 'A', chr(196).chr(131) => 'a', | |
| chr(196).chr(132) => 'A', chr(196).chr(133) => 'a', | |
| chr(196).chr(134) => 'C', chr(196).chr(135) => 'c', | |
| chr(196).chr(136) => 'C', chr(196).chr(137) => 'c', | |
| chr(196).chr(138) => 'C', chr(196).chr(139) => 'c', | |
| chr(196).chr(140) => 'C', chr(196).chr(141) => 'c', | |
| chr(196).chr(142) => 'D', chr(196).chr(143) => 'd', | |
| chr(196).chr(144) => 'D', chr(196).chr(145) => 'd', | |
| chr(196).chr(146) => 'E', chr(196).chr(147) => 'e', | |
| chr(196).chr(148) => 'E', chr(196).chr(149) => 'e', | |
| chr(196).chr(150) => 'E', chr(196).chr(151) => 'e', | |
| chr(196).chr(152) => 'E', chr(196).chr(153) => 'e', | |
| chr(196).chr(154) => 'E', chr(196).chr(155) => 'e', | |
| chr(196).chr(156) => 'G', chr(196).chr(157) => 'g', | |
| chr(196).chr(158) => 'G', chr(196).chr(159) => 'g', | |
| chr(196).chr(160) => 'G', chr(196).chr(161) => 'g', | |
| chr(196).chr(162) => 'G', chr(196).chr(163) => 'g', | |
| chr(196).chr(164) => 'H', chr(196).chr(165) => 'h', | |
| chr(196).chr(166) => 'H', chr(196).chr(167) => 'h', | |
| chr(196).chr(168) => 'I', chr(196).chr(169) => 'i', | |
| chr(196).chr(170) => 'I', chr(196).chr(171) => 'i', | |
| chr(196).chr(172) => 'I', chr(196).chr(173) => 'i', | |
| chr(196).chr(174) => 'I', chr(196).chr(175) => 'i', | |
| chr(196).chr(176) => 'I', chr(196).chr(177) => 'i', | |
| chr(196).chr(178) => 'IJ',chr(196).chr(179) => 'ij', | |
| chr(196).chr(180) => 'J', chr(196).chr(181) => 'j', | |
| chr(196).chr(182) => 'K', chr(196).chr(183) => 'k', | |
| chr(196).chr(184) => 'k', chr(196).chr(185) => 'L', | |
| chr(196).chr(186) => 'l', chr(196).chr(187) => 'L', | |
| chr(196).chr(188) => 'l', chr(196).chr(189) => 'L', | |
| chr(196).chr(190) => 'l', chr(196).chr(191) => 'L', | |
| chr(197).chr(128) => 'l', chr(197).chr(129) => 'L', | |
| chr(197).chr(130) => 'l', chr(197).chr(131) => 'N', | |
| chr(197).chr(132) => 'n', chr(197).chr(133) => 'N', | |
| chr(197).chr(134) => 'n', chr(197).chr(135) => 'N', | |
| chr(197).chr(136) => 'n', chr(197).chr(137) => 'N', | |
| chr(197).chr(138) => 'n', chr(197).chr(139) => 'N', | |
| chr(197).chr(140) => 'O', chr(197).chr(141) => 'o', | |
| chr(197).chr(142) => 'O', chr(197).chr(143) => 'o', | |
| chr(197).chr(144) => 'O', chr(197).chr(145) => 'o', | |
| chr(197).chr(146) => 'OE',chr(197).chr(147) => 'oe', | |
| chr(197).chr(148) => 'R',chr(197).chr(149) => 'r', | |
| chr(197).chr(150) => 'R',chr(197).chr(151) => 'r', | |
| chr(197).chr(152) => 'R',chr(197).chr(153) => 'r', | |
| chr(197).chr(154) => 'S',chr(197).chr(155) => 's', | |
| chr(197).chr(156) => 'S',chr(197).chr(157) => 's', | |
| chr(197).chr(158) => 'S',chr(197).chr(159) => 's', | |
| chr(197).chr(160) => 'S', chr(197).chr(161) => 's', | |
| chr(197).chr(162) => 'T', chr(197).chr(163) => 't', | |
| chr(197).chr(164) => 'T', chr(197).chr(165) => 't', | |
| chr(197).chr(166) => 'T', chr(197).chr(167) => 't', | |
| chr(197).chr(168) => 'U', chr(197).chr(169) => 'u', | |
| chr(197).chr(170) => 'U', chr(197).chr(171) => 'u', | |
| chr(197).chr(172) => 'U', chr(197).chr(173) => 'u', | |
| chr(197).chr(174) => 'U', chr(197).chr(175) => 'u', | |
| chr(197).chr(176) => 'U', chr(197).chr(177) => 'u', | |
| chr(197).chr(178) => 'U', chr(197).chr(179) => 'u', | |
| chr(197).chr(180) => 'W', chr(197).chr(181) => 'w', | |
| chr(197).chr(182) => 'Y', chr(197).chr(183) => 'y', | |
| chr(197).chr(184) => 'Y', chr(197).chr(185) => 'Z', | |
| chr(197).chr(186) => 'z', chr(197).chr(187) => 'Z', | |
| chr(197).chr(188) => 'z', chr(197).chr(189) => 'Z', | |
| chr(197).chr(190) => 'z', chr(197).chr(191) => 's' | |
| ); | |
| $string = strtr($string, $chars); | |
| return $string; | |
| } | |
| public function sendRequest(string $envelope, string $action, string $url): array | |
| { | |
| $headers = array( | |
| "Content-type: text/xml;charset=UTF-8", | |
| "Accept-Encoding: gzip,deflate", | |
| "SOAPAction: \"$action\"", | |
| "Content-length: " . strlen($envelope), | |
| ); | |
| $ch = curl_init(); | |
| curl_setopt($ch, CURLOPT_URL, $url); | |
| curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | |
| curl_setopt($ch, CURLOPT_TIMEOUT, 300); | |
| curl_setopt($ch, CURLOPT_POST, true); | |
| curl_setopt($ch, CURLOPT_POSTFIELDS, $envelope); | |
| curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); | |
| curl_setopt($ch, CURLOPT_ENCODING, "identity, deflate, gzip"); | |
| //A prefeitura bloqueia os IPs externos | |
| //$proxy = '200.255.122.174:8080'; | |
| //curl_setopt($ch, CURLOPT_PROXY, $proxy); | |
| //curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); | |
| $html = curl_exec($ch); | |
| // Converte de UTF-8 para ISO-8859 | |
| //$html = utf8_decode(curl_exec($ch)); | |
| $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); | |
| curl_close($ch); | |
| return [ | |
| "html" => $html, | |
| "code" => $httpcode | |
| ]; | |
| } | |
| } | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment