Last active
February 17, 2024 21:34
-
-
Save luizvaz/6c3e2c1e6bc7d310898107c9f95476bb 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 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 | |
]; | |
} | |
} |
Obrigado Luiz.!!
Abraço
Cara, você pode me ajudar com um projeto em que estou trabalhando? Por favor
Oi.
Preciso emitir notas pelo município de Viamão/RS, que usa o padrão ABRASF.
Baixei o teu código, fiz umas atualizações, porque o PHP não aceitou algumas coisas, removi o extends, mas parei em um erro:
Fatal error: Cannot use "parent" when current class scope has no parent in D:\Dropbox\www\nfse\smarapd_203.php on line 32
Tem algo que possa ser feito para resolver isso?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
É só alterar rpsAsXML() de acordo com a sua necessidade, colocando as tags que não estão presentes que você precise.
Pode retirar o
extends \Provedores\webService\webService
.Basta chamar o gerarNfse() para gerar uma nova nota.
Note que eu uso alguns valores de uma propriedade rps, basta preencher essas propriedades usando um objeto stdClass.