Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save iqdavidh/67a3e0d14ac84be51bf9ea0dd0669ec5 to your computer and use it in GitHub Desktop.
Save iqdavidh/67a3e0d14ac84be51bf9ea0dd0669ec5 to your computer and use it in GitHub Desktop.
<?php
/**
* Copyright (c) 2017 Edgar Merino
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* Demuestra cómo saltar el captcha para autenticarse ante el portal CFDI
* del SAT. Probado con los cambios del 01/sep/2017.
*
* Más información:
* https://medium.com/@emerino/saltar-captcha-al-autenticar-en-portal-cfdi-del-sat-d4a42b621ac3
*
* @author emerino <donvodka@gmail.com>
*/
// credenciales de autenticación, cambiar por reales
$rfc = "RFC";
$ciec = "CIEC";
$authMethod = 4 // ID del método NetIQ que soporta auth sin captcha
// inicializar la instancia de curl (handle), se reutilizará la misma a lo largo
// del script
$ch = curl_init();
// el archivo donde se almacenarán las cookies de estas peticiones
$cookieJar = tempnam(sys_get_temp_dir(), "sat-netiq-auth_");
// opciones globales, usadas para todas las peticiones
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookieJar);
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookieJar);
// necesario para devolver la respuesta de las peticiones como cadena en lugar
// de enviarla a stdout
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// esta petición inicia el proceso de autenticación, se debe ejecutar por GET
$url = "https://cfdiau.sat.gob.mx/nidp/app/login?id=$authMethod&sid=0&option=credential";
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, false);
curl_exec($ch);
// para la petición por POST, ya no es necesario enviar
// el id del método de autenticación, esta información
// está en las cookies obtenidas en la petición anterior
// y enviadas como contexto de esta nueva petición
$url = "https://cfdiau.sat.gob.mx/nidp/app/login?sid=0";
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
// deben enviarse por POST las credenciales
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array(
"option" => "credential",
"Ecom_User_ID" => $rfc,
"Ecom_Password" => $ciec
)));
curl_exec($ch);
// es necesario hacer un GET a la URL principal, para obtener
// las variables requeridas para completar la autenticación
$url = "https://portalcfdi.facturaelectronica.sat.gob.mx";
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, false);
$response = curl_exec($ch);
// el GET anterior genera un html con un formulario que hay
// que ejecutar manualmente, se extraen los parámetros wa, wresult y wctx
// para enviarlo por POST a la siguiente URL
$url = "https://cfdicontribuyentes.accesscontrol.windows.net/v2/wsfederation";
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(params($response)));
$response = curl_exec($ch);
// este POST nos autentica completamente en el sistema del SAT
$url = "https://portalcfdi.facturaelectronica.sat.gob.mx";
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(params($response)));
curl_exec($ch);
// la respuesta de la siguiente petición GET debe devolver un HTML donde
// se encuentra la cadena 'RFC Autenticado', a partir de aquí cualquier
// petición al portal del SAT estará autenticada (importante enviar las cookies
// almacenadas en el cookieJar).
$url = "https://portalcfdi.facturaelectronica.sat.gob.mx";
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, false);
$response = curl_exec($ch);
$msg = (strstr($response, "RFC Autenticado:")) ?
"Autenticado exitosamente" :
"Ocurrió un error al autenticar";
echo "$msg\n";
// cleanup
curl_close($ch);
unlink($cookieJar);
/**
* Esta función extrae los parámetros "wa, "wresult" y "wctx" de los inputs
* del formulario que se encuentra en $response.
* @param string $response
* @return array los parámetros (valores) extraídos de la respuesta
*/
function params($response) {
$doc = new DOMDocument();
$doc->loadHTML($response);
$xpath = new DOMXPath($doc);
$form = $doc->getElementsByTagName("form")->item(0);
$params = array(
"wa",
"wresult",
"wctx"
);
$pairs = array();
foreach ($params as $param) {
$entries = $xpath->query("input[@name='" . $param . "']", $form);
$pairs[$param] = $entries->item(0)->getAttribute("value");
}
return $pairs;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment