Sermepa¶
Esta clase implementa la pasarela de pago de Redsys:
<?php
/**
* Class Sermepa
*/
class Sermepa{
private $_setEntorno;
private $_setImporte;
private $_setMoneda;
private $_setPedido;
private $_setMerchantData;
private $_setProductoDescripcion;
private $_setTitular;
private $_setFuc;
private $_setTerminal;
private $_setTransactionType;
private $_setUrlNotificacion;
private $_setClave;
private $_setUrlOk;
private $_setUrlKo;
private $_setFirma;
private $_setNombreComercio;
private $_setIdioma;
private $_setMethods;
private $_setNameForm;
private $_setSubmit;
/**
* Constructor
*/
public function __construct()
{
$this->_setEntorno='https://sis-t.redsys.es:25443/sis/realizarPago';
$this->_setMoneda ='978';
$this->_setTerminal =1;
$this->_setMerchantData = '';
$this->_setTransactionType=0;
$this->_setIdioma = '001';
$this->_setMethods='T';
$this->_setNameForm = 'servired_form';
$this->_setSubmit = '';
}
/**
* Asignamos el idioma por defecto 001 = Español
*
* @param $codeidioma codigo de idioma [Castellano-001, Inglés-002, Catalán-003, Francés-004, Alemán-005, Holandés-006, Italiano-007, Sueco-008, Portugués-009, Valenciano-010, Polaco-011, Gallego-012 y Euskera-013.]
*/
public function set_idioma($codeidioma)
{
$this->_setIdioma = $codeidioma;
}
/**
* Asignamos que tipo de entorno vamos a usar si Pruebas o Real (por defecto esta en pruebas)
*
* @param string $entorno (pruebas, real)
*/
public function set_entorno($entorno='pruebas')
{
if(trim($entorno) == 'real'){
//real
//$this->_setEntorno='https://sis.sermepa.es/sis/realizarPago';
$this->_setEntorno='https://sis.redsys.es/sis/realizarPago';
//https://sis.redsys.es/sis/realizarPago
}
else{
//pruebas
$this->_setEntorno ='https://sis-t.redsys.es:25443/sis/realizarPago';
}
}
/**
* Retornamos la URL que va en el form para los pagos ya sea en pruebas o real
*
* @return string URL sermepa (real o pruebas)
*/
public function geturlentorno()
{
return $this->_setEntorno;
}
/**
* Asignamos el importe de la compra
*
* @param int $importe total de la compra a pagar
* @return bool|float|int Retornamos el importe ya modificado
*/
public function importe($importe=0)
{
$importe = $this->parseFloat($importe);
// sermepa nos dice Para Euros las dos últimas posiciones se consideran decimales.
$importe = intval(strval($importe*100));
$this->_setImporte=$importe;
}
/**
* Asignamos el tipo de moneda
*
* @param string $moneda 978 para Euros, 840 para Dólares, 826 para libras esterlinas y 392 para Yenes.
* @throws Exception
*/
public function moneda($moneda='978')
{
if($moneda == '978' || $moneda =='840' || $moneda =='826' || $moneda =='392' ){
$this->_setMoneda = $moneda;
}
else{
throw new Exception('Moneda no valida');
}
}
/**
* Asignamos el número de pedido a nuestra compra (Los 4 primeros dígitos deben ser numéricos)
*
* @param string $pedido Numero de pedido alfanumérico
* @throws Exception
*/
public function pedido($pedido='')
{
if(strlen(trim($pedido))> 0){
$this->_setPedido = $pedido;
}
else{
throw new Exception('Falta agregar el número de pedido');
}
}
/**
* Campo opcional para el comercio para ser incluidos en los datos enviados por la respuesta "on-line" al comercio si se ha elegido esta opción.
* @param string $datoscomercio Datos del comercio.
*/
public function set_datoscomercio($datoscomercio)
{
$this->_setMerchantData = trim($datoscomercio);
}
/**
* Asigmanos la descripción del producto (Obligatorio)
*
* @param string $producto Descripción del producto
* @throws Exception
*/
public function producto_descripcion($producto='')
{
if(strlen(trim($producto)) > 0){
//asignamos el producto
$this->_setProductoDescripcion = $producto;
}
else{
throw new Exception('Falta agregar la descripción del producto');
}
}
/**
* Asigmanos el nombre del usuario que realiza la compra (Obligatorio)
*
* @param string $titular Nombre del usuario (por ejemplo Juan Perez)
* @throws Exception
*/
public function titular($titular='')
{
if(strlen(trim($titular)) > 0){
$this->_setTitular = $titular;
}
else{
throw new Exception('Falta agregar el titular que realiza la compra');
}
}
/**
* Asignamos el código FUC del comercio (Obligatorio)
*
* @param string $fuc Código fuc que nos envía sermepa
* @throws Exception
*/
public function codigofuc($fuc='')
{
if(strlen(trim($fuc)) > 0){
$this->_setFuc = $fuc;
}
else{
throw new Exception('Falta agregar el código FUC');
}
}
/**
* Asignar el tipo de terminal por defecto 1 en Sadabell (Obligatorio)
*
* @param int $terminal Número de terminal que le asignará su banco.
* @throws Exception
*/
public function terminal($terminal=1)
{
if(intval($terminal) !=0){
$this->_setTerminal = $terminal;
}
else{
throw new Exception('El terminal no es valido');
}
}
/**
* Asignar el tipo de transacción por defecto 0 que es autorización (Obligatorio)
*
* @param int $transactiontype tipo de transacción
* @throws Exception
*/
public function transaction_type($transactiontype=0)
{
if(strlen(trim($transactiontype)) > 0){
$this->_setTransactionType= $transactiontype;
}
else{
throw new Exception('Falta agregar el tipo de transacción');
}
}
/**
* Nombre del comercio que será reflejado en el ticket del comercio (Opcional)
*
* @param string $nombrecomercio Nombre del comercio
*/
public function nombre_comercio($nombrecomercio='')
{
$nombrecomercio = trim($nombrecomercio);
$this->_setNombreComercio = $nombrecomercio;
}
/**
* Si el comercio tiene notificación "on-line". URL del comercio que recibirá un post con los datos de la transacción (Obligatorio).
*
* @param string $url_notificacion Url para guardar los datos recibidos por el comercio.
* @throws Exception
*/
public function url_notificacion($url_notificacion='')
{
if(strlen(trim($url_notificacion)) > 0){
$this->_setUrlNotificacion = $url_notificacion;
}
else{
throw new Exception('Falta agregar url de notificacion');
}
}
/**
* Si se envía será utilizado como URLOK ignorando el configurado en el módulo de administración en caso de tenerlo (Opcional).
*
* @param string $url Url donde mostrar un mensaje si se realizo correctamente el pago
*/
public function url_ok($url='')
{
$this->_setUrlOk = $url;
}#-#url_ok()
/**
* Si se envía será utilizado como URLKO ignorando el configurado en el módulo de administración en caso de tenerlo (Opcional).
*
* @param string $url Url donde mostrar un mensaje si se produjo un problema al realizar el
*/
public function url_ko($url='')
{
$this->_setUrlKo = $url;
}
/**
* Asignar la clave proporcionada por el banco (Obligatorio)
*
* @param string $clave Clave proporcionada por el Banco
* @throws Exception
*/
public function clave($clave='')
{
if(strlen(trim($clave)) > 0){
$this->_setClave = $clave;
}
else{
throw new Exception('Falta agregar la clave proporcionada por sermepa');
}
}
/**
* Tipo de Pago
*
* @param string $metodo [T = Pago con Tarjeta, R = Pago por Transferencia, D = Domiciliacion] por defecto es T
*/
public function methods($metodo='T')
{
$this->_setMethods= $metodo;
}
/**
* Firma que se envía a Sermepa (Obligatorio)
*
* @throws Exception
*/
public function firma()
{
//$mensaje = $this->_setImporte . $this->_setPedido . $this->_setFuc . $this->_setMoneda . $this->_setTransactionType . $this->_setUrlNotificacion . $this->_setClave;
$mensaje = $this->_setImporte . $this->_setPedido . $this->_setFuc . $this->_setMoneda . $this->_setTransactionType . $this->_setUrlNotificacion ."REQUIRED". $this->_setClave;
if(strlen(trim($mensaje)) > 0){
// Cálculo del SHA1
$this->_setFirma = strtoupper(sha1($mensaje));
}
else{
throw new Exception('Falta agregar la firma, Obligatorio');
}
}
/**
* Asignar el nombre del formulario
*
* @param string $nombre
*/
public function set_nameform($nombre = 'servired_form')
{
$this->_setNameForm = $nombre;
}
/**
* Generamos el Boto Submit
*
* @param string $nombre Nombre y ID del botón submit
* @param string $texto Texto que se mostrara en el botón
* @throws Exception
*/
public function submit($nombre = 'submitsermepa',$texto='Enviar')
{
if(strlen(trim($nombre))==0)
throw new Exception('Asigne nombre al boton submit');
$btnsubmit = '<input type="submit" name="'.$nombre.'" id="'.$nombre.'" value="'.$texto.'" />';
$this->_setSubmit = $btnsubmit;
}
/**
* Ejecutar la redirección automática al TPV
*/
public function ejecutarRedireccion()
{
echo $this->create_form();
echo '<script>document.forms["'.$this->_setNameForm.'"].submit();</script>';
}
/**
* Comprueba si la operación ha resultado satisfactoria
*
* @param array $postData Datos _$POST recibidos del TPV (url de notificación)
* @return bool
* @throws Exception
*/
public function comprobar($postData='')
{
if ($this->_setClave === null) {
throw new Exception('Falta agregar la clave proporcionada por sermepa');
}
try
{
if (isset($postData))
{
// creamos las variables para usar
$Ds_Response = $postData['Ds_Response']; //codigo de respuesta
$Ds_Amount = $postData['Ds_Amount']; //monto de la orden
$Ds_Order = $postData['Ds_Order']; //numero de orden
$Ds_MerchantCode = $postData['Ds_MerchantCode']; //codigo de comercio
$Ds_Currency = $postData['Ds_Currency']; //moneda
$firmaBanco = $postData['Ds_Signature']; //firma hecha por el banco
$Ds_Date = $postData['Ds_Date']; //fecha
// creamos la firma para comparar
$firma = strtoupper(sha1($Ds_Amount . $Ds_Order . $Ds_MerchantCode . $Ds_Currency . $Ds_Response . $this->_setClave));
$Ds_Response =(int) $Ds_Response; //convertimos la respuesta en un numero concreto.
//Comprueba la firma y respuesta
//Nota: solo en el caso de las preautenticaciones (preautorizaciones separadas), se devuelve un 0 si está autorizada y el titular se autentica y, un 1 si está autorizada y el titular no se autentica.
if ($firma == $firmaBanco) {
if ($Ds_Response < 100) {
return true;
}
else{
throw new Exception("Error en la transacción, código ".$Ds_Response);
}
} else {
throw new Exception("Las firmas no coinciden");
}
} else {
throw new Exception("Debes pasar la variable POST devuelta por el banco");
}
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
}
/**
* Generamos el form a incluir en el HTML
*
* @return string
*/
public function create_form()
{
$formulario='
<form action="'.$this->_setEntorno.'" method="post" id="'.$this->_setNameForm.'" name="'.$this->_setNameForm.'" >
<input type="hidden" name="Ds_Merchant_Amount" value="'.$this->_setImporte.'" />
<input type="hidden" name="Ds_Merchant_Currency" value="'.$this->_setMoneda.'" />
<input type="hidden" name="Ds_Merchant_Order" value="'.$this->_setPedido.'" />
<input type="hidden" name="Ds_Merchant_MerchantData" value="'.$this->_setMerchantData.'" />
<input type="hidden" name="Ds_Merchant_MerchantCode" value="'.$this->_setFuc.'" />
<input type="hidden" name="Ds_Merchant_Terminal" value="'.$this->_setTerminal.'" />
<input type="hidden" name="Ds_Merchant_TransactionType" value="'.$this->_setTransactionType.'" />
<input type="hidden" name="Ds_Merchant_Titular" value="'.$this->_setTitular.'" />
<input type="hidden" name="Ds_Merchant_MerchantName" value="'.$this->_setNombreComercio.'" />
<input type="hidden" name="Ds_Merchant_MerchantURL" value="'.$this->_setUrlNotificacion.'" />
<input type="hidden" name="Ds_Merchant_ProductDescription" value="'.$this->_setProductoDescripcion.'" />
<input type="hidden" name="Ds_Merchant_ConsumerLanguage " value="'.$this->_setIdioma.'" />
<input type="hidden" name="Ds_Merchant_UrlOK" value="'.$this->_setUrlOk.'" />
<input type="hidden" name="Ds_Merchant_UrlKO" value="'.$this->_setUrlKo.'" />
<input type="hidden" name="Ds_Merchant_PayMethods" value="'.$this->_setMethods.'" />
<input type="hidden" name="Ds_Merchant_MerchantSignature" value="'.$this->_setFirma.'" />
<input type="hidden" name="Ds_Merchant_Identifier" value="REQUIRED" />
';
$formulario.=$this->_setSubmit;
$formulario.='
</form>
';
return $formulario;
}
/**
* Parseo a Float
*
* @param $ptString
* @return bool|float
*/
private function parseFloat($ptString)
{
if (strlen($ptString) == 0) {
return false;
}
$pString = str_replace(" ", "", $ptString);
if (substr_count($pString, ",") > 1)
$pString = str_replace(",", "", $pString);
if (substr_count($pString, ".") > 1)
$pString = str_replace(".", "", $pString);
$pregResult = array();
$commaset = strpos($pString,',');
if ($commaset === false) {
$commaset = -1;
}
$pointset = strpos($pString,'.');
if ($pointset === false) {
$pointset = -1;
}
$pregResultA = array();
$pregResultB = array();
if ($pointset < $commaset) {
preg_match('#(([-]?[0-9]+(\.[0-9])?)+(,[0-9]+)?)#', $pString, $pregResultA);
}
preg_match('#(([-]?[0-9]+(,[0-9])?)+(\.[0-9]+)?)#', $pString, $pregResultB);
if ((isset($pregResultA[0]) && (!isset($pregResultB[0])
|| strstr($pregResultA[0],$pregResultB[0]) == 0
|| !$pointset))) {
$numberString = $pregResultA[0];
$numberString = str_replace('.','',$numberString);
$numberString = str_replace(',','.',$numberString);
}
elseif (isset($pregResultB[0]) && (!isset($pregResultA[0])
|| strstr($pregResultB[0],$pregResultA[0]) == 0
|| !$commaset)) {
$numberString = $pregResultB[0];
$numberString = str_replace(',','',$numberString);
}
else {
return false;
}
$result = (float)$numberString;
return $result;
}
}
?>
Y un ejemplo de utilización:
<?php
require_once 'sermepa.php';
try{
$pasarela = new Sermepa();
$pasarela->set_entorno("real");
$pasarela->set_idioma("001");
$pasarela->importe(999.99);
$pasarela->pedido('123456789012'); //generamos el número de recibo usando date por ejemplo
$pasarela->clave('Clave'); //clave asignada por el banco.
$pasarela->codigofuc('FUC');
$pasarela->producto_descripcion("Descripción del producto");
$pasarela->titular('Titular');
$pasarela->nombre_comercio('Nombre del comercio');
//Si el comercio tiene notificación "on-line". URL del comercio que recibirá un post con los datos de la transacción .
$pasarela->url_notificacion('http://tuWeb/notificacion.php');
$pasarela->url_ok('http://tuWeb/ok.php'); // Si le das aceptar finalizada la compra desde la pasarela de pagos
$pasarela->url_ko('http://tuWeb/ko.php'); // Si le das cancelar desde la pasarela de pagos
$pasarela->firma();
//Generamos botón submit
$pasarela->submit('nombre_submit','Credit card');
}
catch(Exception $e){
echo $e->getMessage();
}
$formulario = $pasarela->create_form();
echo $formulario;
?>