Segunda parte del codigo si lo quieren ver completo sigan la liga ... del inicio
Código PHP:
// {{{ Valida Sello
function valida_sello() {
/*
* Todos los archivos que se requieren para generar la cadena original
* fueron descargados del portal del SAT pero los tengo localmente
* almacenados en mi maquina para que el proceso sea mas rapido.
* Todos los archivos estan modificacion por el numero de version 2 a 1,
* para que no mande warning PHP
* La version de mi maquina los pueden obtener de la misma URL
* http://www.lacorona.com.mx/fortiz/sat/cadenaoriginal_TFD_1_0.xslt
* http://www.lacorona.com.mx/fortiz/sat/ecc.xslt
* http://www.lacorona.com.mx/fortiz/sat/...
*/
global $data, $xml;
$xsl = new DOMDocument;
switch ($data['version']) {
case "2.0":
$xsl->load('cadenaoriginal_2_0.xslt');
if (substr($data['fecha'],0,4)<2011) {
echo "md5 \n";
$algo = OPENSSL_ALGO_MD5;
} else {
echo "sha1 \n";
$algo =OPENSSL_ALGO_SHA1;
}
break;
case "2.2":
echo "2.2\n";
$xsl->load('cadenaoriginal_2_2.xslt');
echo "sha1 \n";
$algo = OPENSSL_ALGO_SHA1;
break;
case "3.0":
$xsl->load('cadenaoriginal_3_0.xslt');
if (substr($data['fecha'],0,4)<2011) {
echo "md5 \n";
$algo = OPENSSL_ALGO_MD5;
} else {
echo "sha1 \n";
$algo =OPENSSL_ALGO_SHA1;
}
break;
case "3.2":
echo "3.2\n";
$xsl->load('cadenaoriginal_3_2.xslt');
echo "sha1 \n";
$algo = OPENSSL_ALGO_SHA1;
break;
default:
echo "version incorrecta ".$data['version']."\n";
break;
}
$proc = new XSLTProcessor;
$proc->importStyleSheet($xsl);
$cadena = $proc->transformToXML($xml);
echo "Cadena Original<br><p align=left>$cadena</p><br>";
if ($algo==OPENSSL_ALGO_SHA1) {
$sha1=sha1($cadena);
echo "hash sha1=$sha1<br>";
} else {
$md5=md5($cadena);
echo "hash md5=$md5<br>";
}
if (!mb_check_encoding($cadena,"utf-8")) {
echo "<h3>Error no esta en UTF-8!</h3>";
}
/*
* El domicilio es opcional, pero si no lo ponemos el xslt del SAT genera
* doble pip en el pais ..., dice que el sello es correcto pero los PACs
* que validan bien lo rechazan ...
*/
$doble = preg_match('/.\|\|./',$cadena);
if ($doble===1) {
echo "<h3><font color=red>La cadena tiene doble pipes en medio ...</font></h3>";
}
// Primer certificado (o unico) del emisor
// Los demas certificados es del PAC, Timbre, etc.
$pem = (sizeof($data['cert'])<=1) ? $data['cert'] : $data['cert'][0];
$pem = eregi_replace("[\n|\r|\n\r]", '', $pem);
$pem = preg_replace('/\s\s+/', '', $pem);
// Si no incluye el certificado bajarlo del FTP del sat ....
if (strlen($pem)==0) {
echo "No incluye certificado interno, descargdo del FTP del sat ...<br>";
$no_cert = $data['no_cert'];
$p1=substr($no_cert,0,6);
$p2=substr($no_cert,6,6);
$p3=substr($no_cert,12,2);
$p4=substr($no_cert,14,2);
$p5=substr($no_cert,16,2);
$path = "ftp://ftp2.sat.gob.mx/certificados/FEA/$p1/$p2/$p3/$p4/$p5/$no_cert.cer";
$der = file_get_contents($path);
$pem = base64_encode($der);
echo "path=$path<br>";
}
$cert = "-----BEGIN CERTIFICATE-----\n".chunk_split($pem,64)."-----END CERTIFICATE-----\n";
$pubkeyid = openssl_get_publickey(openssl_x509_read($cert));
$ok = openssl_verify($cadena,
base64_decode($data['sell']),
$pubkeyid,
$algo);
if ($ok == 1) {
echo "<h3>Sello ok</h3>";
} else {
echo "<h3>Sello incorrecto</h3>";
while ($msg = openssl_error_string())
echo $msg. "\n";
}
openssl_free_key($pubkeyid);
echo "<hr>";
$paso = openssl_x509_parse($cert);
$serial = convierte($paso['serialNumber']);
if ($serial!=$data['no_cert']) {
echo "Serie reportada ".$data['no_cert']." serie usada $serial<br>";
}
}
// }}} Valida Sello
function valida_sello_tfd() {
global $data, $texto;
if ($data['sell'] != $data['sellocfd']) {
echo "<h3>sello Comprobante diferente que sello TFD!, manipulado?</h3>";
}
// Quita la parte del CFDI
$texto_tfd = preg_replace('{<cfdi:Comprobante.*<tfd:}is', '<tfd:', $texto);
$texto_tfd = trim(preg_replace('{</cfdi:.*$}is', '', $texto_tfd));
// Si no tiene el namespace definido, se agrega
if (strpos($texto_tfd,"xmlns:tfd")===FALSE) {
$texto_tfd = substr($texto_tfd,0,-2).' xmlns:tfd="http://www.sat.gob.mx/TimbreFiscalDigital" />';
}
// Solo se quedo el tfd:
$xml_tfd = new DOMDocument();
$ok = $xml_tfd->loadXML($texto_tfd);
$xsl = new DOMDocument;
$xsl->load('cadenaoriginal_TFD_1_0.xslt');
$proc = new XSLTProcessor;
$proc->importStyleSheet($xsl);
$cadena = $proc->transformToXML($xml_tfd);
echo "Cadena Original TFD<br><p align=left>$cadena</p><br>";
if (!mb_check_encoding($cadena,"utf-8")) {
echo "<h3>Error no esta en UTF-8!</h3>";
}
$no_cert=$data['no_cert_sat'];
$p1=substr($no_cert,0,6);
$p2=substr($no_cert,6,6);
$p3=substr($no_cert,12,2);
$p4=substr($no_cert,14,2);
$p5=substr($no_cert,16,2);
$path = "ftp://ftp2.sat.gob.mx/certificados/FEA/$p1/$p2/$p3/$p4/$p5/$no_cert.cer";
echo "Certificado SAT $path<br>";
$der = file_get_contents($path);
$pem = base64_encode($der);
$cert = "-----BEGIN CERTIFICATE-----\n".chunk_split($pem,64)."-----END CERTIFICATE-----\n";
// file_put_contents("/tmp/llave.cer.pem",$cert);
$pubkeyid = openssl_get_publickey(openssl_x509_read($cert));
$ok = openssl_verify($cadena,
base64_decode($data['sellosat']),
$pubkeyid,
OPENSSL_ALGO_SHA1);
if ($ok == 1) {
echo "<h3>Sello TFD ok</h3>";
} else {
echo "<h3>Sello TFD incorrecto</h3>";
while ($msg = openssl_error_string())
echo $msg. "\n";
}
openssl_free_key($pubkeyid);
echo "<hr>";
}
// }}} Valida Sello
// {{{ Valida este XML en el servidor del SAT
// ftp://ftp2.sat.gob.mx/asistencia_servicio_ftp/publicaciones/cfdi/WS_ConsultaCFDI.pdf
function valida_en_sat() {
global $data;
error_reporting(E_ALL);
require_once('nusoap/nusoap.php');
$url = "https://consultaqr.facturaelectronica.sat.gob.mx/consultacfdiservice.svc?wsdl";
$soapclient = new nusoap_client($url,$esWSDL=true);
$soapclient->soap_defencoding = 'UTF-8';
$soapclient->decode_utf8 = false;
$rfc_emisor = $data['rfc'];
$rfc_receptor = $data['rfc_receptor'];
$impo = (double)$data['total'];
$impo=sprintf("%.6f", $impo);
$impo = str_pad($impo,17,"0",STR_PAD_LEFT);
$uuid = strtoupper($data['uuid']);
$factura = "?re=$rfc_emisor&rr=$rfc_receptor&tt=$impo&id=$uuid";
$prm = array('expresionImpresa'=>$factura);
$buscar=$soapclient->call('Consulta',$prm);
echo "<h3>El portal del SAT reporta</h3>";
echo "El codigo: ".$buscar['ConsultaResult']['CodigoEstatus']."<br>";
echo "El estado: ".$buscar['ConsultaResult']['Estado']."<br>";
}
function convierte($dec) {
$hex=bcdechex($dec);
$ser="";
for ($i=1; $i<strlen($hex); $i=$i+2) {
$ser.=substr($hex,$i,1);
}
return $ser;
}
function bcdechex($dec) {
$last = bcmod($dec, 16);
$remain = bcdiv(bcsub($dec, $last), 16);
if($remain == 0) {
return dechex($last);
} else {
return bcdechex($remain).dechex($last);
}
}
function getpath($qry) {
global $xp;
$prm = array();
$nodelist = $xp->query($qry);
foreach ($nodelist as $tmpnode) {
$prm[] = trim($tmpnode->nodeValue);
}
$ret = (sizeof($prm)<=1) ? $prm[0] : $prm;
return($ret);
}
function display_xml_errors() {
global $texto;
$lineas = explode("\n", $texto);
$errors = libxml_get_errors();
echo "<pre>";
foreach ($errors as $error) {
echo display_xml_error($error, $lineas);
}
echo "</pre>";
libxml_clear_errors();
}
function display_xml_error($error, $lineas) {
$return = htmlspecialchars($lineas[$error->line - 1]) . "\n7";
$return .= str_repeat('-', $error->column) . "^\n";
switch ($error->level) {
case LIBXML_ERR_WARNING:
$return .= "Warning $error->code: ";
break;
case LIBXML_ERR_ERROR:
$return .= "Error $error->code: ";
break;
case LIBXML_ERR_FATAL:
$return .= "Fatal Error $error->code: ";
break;
}
$return .= trim($error->message) .
"\n Linea: $error->line" .
"\n Columna: $error->column";
echo "$return\n\n--------------------------------------------\n\n";
}
?></div></BODY></HTML>
http://www.lacorona.com.mx/fortiz/sat/cfdcvali.phps