Cobrando por servicios a través de PayPal con PHP

Hace un tiempo necesitábamos crear un sistema de compras a través de PayPal con la particularidad de que teníamos recibir confirmación instantánea del pago para reflejar esas compras al usuario. Esta era la diferencia principal respecto de un carro de compra de una web donde vendes algo físicamente, en este caso no necesitas saber el estado de una compra, cuando el equipo de almacén prepare el pedido ya comprobará si se ha realizado el pago antes de servirlo. Nuestro caso es más complicado. Vendemos servicios que pueden ser suscripciones, créditos de uso en la web, servicios premium, acceso a zonas privadas… todo este tipo de opciones donde el usuario, después de pagar, vuelve a tu web para disfrutar de los servicios que ha comprado.

Al querer cobrar a través de PayPal tienes dos opciones, o creas botones estáticos (Comprar Ahora) desde la web de PayPal o generas los tuyos propios. El problema de crearlos estáticos es que debes crear uno por cada usuario y para cada servicio que necesites vender, algo absurdo para el caso que tratamos ya que estarías ante miles de botones. Al generar los tuyos propios puedes hacerlos normales o seguros, para que no se puedan modificar por el camino. Este es el método que deberías utilizar normalmente ya que, en los normales, un usuario experimentado puede modificar el importe a cobrar, algo que no deseas que ocurra.

Para que el sistema funcionase bien deberíamos recibir en una URL las compras realizadas de alguna manera que nos permitiese identificar al usuario que habia hecho la compra para añadirle los servicios en cuestión. La solución es crear botones firmados online utilizando como identificador de producto de compra el idUsuario de tu base de datos, de esta forma las confirmaciones de compra te indican el usuario al que pertenecen y ya puedas darle los servicios por los que ha pagado. Puedes utilizar combinaciones más elaboradas para reutilizar el sistema para distintos productos, por ejemplo idUsuario-idServicio (12345-3). Al recibirlo, con dividir la cadena por el guión ya tienes todo lo necesario. En nuestro caso había varios tipos de servicio pero se indentificaban por el coste del mismo, con lo cual con el identificador de usuario teníamos suficiente.

Aparentemente es sencillo el proceso, pero se complica ya que la documentación, a pesar de ser extensa, no esta del todo claro. Por un lado no está nada claro cómo configurar tu cuenta de PayPal para tener el sistema completo y por otro es bastante lioso el modo de crear los botones y recibir las confirmaciones. Vamos a explicarlo detalladamente ya que es un interesante ejercicio de programación en PHP.

Configurando la cuenta de PayPal

Lo primero que tienes que hacer es crear un certificado público X.509, único sistema que acepta PayPal.

Las instrucciones detallas las tienes aquí. básicamente necesitas tener openssl funcionando, cualquier sistema Linux lo tendrá instalado y sino tienes versiones para Windows.

openssl genrsa -out my-prvkey.pem 1024
openssl req -new -key my-prvkey.pem -x509 -days 3650 -out my-pubcert.pem

Con esto generamos primero la clave privada y a continuación el certificado público X.509 de esa clave. Es importante el parámetro -days, lo hemos puesto a 10 años para no tener problemas. En mi caso, la primera vez puse 365 días tal como viene en el ejemplo y al año dejó de funcionar sin que te dieses cuenta, fueron los usuarios los que nos avisaron. Guarda los dos archivos, my-prvkey.pem y my-pubcert.pem pues los necesitaremos a continuación.

Ya tenemos nuestro certificado preparado. Ahora debemos subirlo a PayPal para que sepa desencriptar nuestros botones. En tu cuenta de PayPal debes ir a:

Perfil->Configuración de pago codificado

Desde ahí, por un lado descargas el certificado público de PayPal, lo necesitaremos para codificar nuestros botones, y por otro subes tu certificado público que hemos llamado my-pubcert.pem. Obtendrás un ID de certificado, apúntatelo.

Si todo ha ido bien, ahora debemos configurar la cuenta para que PayPal sólamente acepte botones firmados, de manera que nadie pueda suplantar nuestra identidad con botones a otros precios, un detalle muy importante. Vamos entonces a:

Perfil->Preferencias de pago en el sitio Web

Primero activas Transferencia de datos de pago y te copias el Código Personal de Identidad que te indica, lo necesitaremos más adelante. A continuación, en la sección Pagos en el sitio Web codificado activamos la opción Bloquear pago en el sitio Web no codificado. Como véis no estaba tan claro el proceso.

Este paso no es obligatorio, pero haciéndolo conseguimos que el usuario vuelva a tu web una vez haya realizado el pago y, si ha sido correcto, tenga ya sus servicios disponibles. Activa la opción Retroceso automático e indica la URL de devolución, es decir, la URL donde será devuelto tu cliente, por ejemplo: http://www.tudominio.com/index.php?accion=creditos_paypalok

Finalmente activaremos la opción que nos permitirá recibir notificaciones de pagos online. Para ello vamos a:

Perfil->Preferencias de Notificación de pago instantánea

Y activaremos la notificación indicando la URL donde las vamos a recibir, por ejemplo, http://www.tudominio.com/secure/paypal/ipn.php.

Si has llegado a este punto, ya tienes todo lo necesario para comenzar con el código. Como recordatorio, necesitas:

  • Tu clave privada, my-prvkey.pem.
  • Tu certificado público, my-pubcert.pem.
  • Tu ID de certificado en PayPal
  • Tu Código Personal de Identidad
  • Certificado público de Paypal, paypal_cert_pem.txt.

Nos quedan, entonces, tres tareas pendientes:

  • Crear botones de compra
  • Crear el script de recepción de cobros realizados
  • Crear el script de vuelta después de una compra

Creando los botones

Comenzamos con el código. El único requerimiento es que tu instalación de PHP debe tener configurada la extensión openssl imprescindible para trabajar con los certificados. Con esta clase que encontré en su momento (me costó bastante localizar algo sencillo) tienes todo el proceso automatizado, sólo debes preocuparte por indicarle los datos que hemos ido guardando, los certificados y el ID del tu certificado en PayPal, simple ¿no?.

include("Class.PayPalEWP.php");
$paypal = &new PayPalEWP();
$paypal->setTempFileDirectory("/tmp");
$paypal->setCertificate("my-pubcert.pem", "my-prvkey.pem");
$paypal->setCertificateID("XXXXXXXXXX");
$paypal->setPayPalCertificate("paypal_cert_pem.txt");

$paypalParam = array(
    'cmd' => '_xclick',
    'business' => '[email protected]',
    'item_name' => 'Comprar Servicio X,
    'item_number' => $_SESSION['idUsuario'],
    'amount' => '5',
    'no_shipping' => '1',
    'currency_code' => 'EUR',
    'lc' => 'ES',
);
$form5="<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
            <input type="hidden" name="cmd" value="_s-xclick"/>
            <input type="hidden" name="encrypted" value="-----BEGIN PKCS7-----n".$paypal->encryptButton($paypalParam)."n-----END PKCS7-----"/>
            <input type="image" src="imagenes/comprar_paypal.gif" border="0" name="submit" alt="Realice pagos con PayPal: es rápido, gratis y seguro." style="border:0;">
        </form>";

El código es bastante claro.
Ya lo tenemos, $form5 contiene el código de tu botón.
Los parámetros importantes son:

  • item_name: informativo, para que tu cliente sepa lo que compra. Por ejemplo: compra de suscripción a noticias.
  • item_number: Aquí configuramos el idUsuario de tu cliente en tu base de datos, así sabes quién compra.
  • amount: Precio que le cobras, en este caso 5 euros.

Modifica estos y los demás parámetros para reflejar tus opciones y adecuarlos a tu aplicación. Al sacar el código de $form5 en tu página tienes listo el sistema de compra.

Recibiendo las notificaciones

La recepción de notificaciones es la piedra angular del sistema para estar seguros de que un cliente ha pagado por un servicio. PayPal ha pensado que puedes llegar a tener problamas temporales de conectividad que te impidan reconocer una compra, con lo cual obliga a que le confirmes que has recibido la confirmación reenviándole los mismos parámetros que te ha enviado. Un sistema curioso pero efectivo, no puedes suplantarlo puesto que no sabes los identificadores de operación que te va a enviar, así que sólo el receptor de la confirmación podrá confirmar la recepción. Lo que hacemos es crear una solicitud HTTP POST con todos los parámetros que nos ha enviado y se la devolvemos a PayPal. Si todo ha ido bien recibiremos un VERIFIED y podremos aceptar esa transaccion como válida y hacer el procesado que estimemos oportuno, comenzando por comprobar la duplicidad de la transacción ya que PayPal podría estar reenviándola y terminando por otorgar al usuario el servicio por el que ha pagado.

// read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-validate';
foreach ($_POST as $key => $value) {
    $value = urlencode(stripslashes($value));
    $req .= "&$key=$value";
}

// post back to PayPal system to validate
$header .= "POST /cgi-bin/webscr HTTP/1.0rn";
$header .= "Content-Type: application/x-www-form-urlencodedrn";
$header .= "Content-Length: " . strlen($req) . "rnrn";
$fp = fsockopen ('www.paypal.com', 80, $errno, $errstr, 30);

// assign posted variables to local variables
$item_name = $_POST['item_name'];
$item_number = $_POST['item_number'];
$payment_status = $_POST['payment_status'];
$payment_amount = $_POST['mc_gross'];
$payment_currency = $_POST['mc_currency'];
$txn_id = $_POST['txn_id'];
$receiver_email = $_POST['receiver_email'];
$payer_email = $_POST['payer_email'];
$transid=$_POST['txn_id'];
$idUsuario=$_POST['item_number'];
$cantidad=$_POST['mc_gross'];
$creditos=100;

if (!$fp) {
    //CONTROL DE ERRORES; NO SE PUEDE CONECTAR CON PAYPAL
    //NO ES GRAVE, COMO NO LE CONFIRMAMOS LA TRANSACCION
    //ELLOS MISMOS LA REINTENTARÁN MÁS ADELANTE
}else{
    fputs ($fp, $header . $req);
    while (!feof($fp)) {
        $res = fgets ($fp, 1024);
        if (strcmp ($res, "VERIFIED") == 0) {
            //compruebo que no se haya procesado ya la transaccion
            $query="select * from paypal where transid='$transid' and estado=1";
            $rs=$conn->Execute($query);
            $sumar=$rs->recordcount();
            if($sumar==0){
                //LOGEAMOS TODA LA TRANSACCION
                $vars="GET: ".serialize($_GET)."rnPOST: ".serialize($_POST)."";
                $query="insert into paypal (transid, fecha, estado, variables)
                    VALUES ('$transid', now(), 1, '$vars')";
                $rs=$conn->Execute($query);

                //aquí debes hacer ahora tus operaciones
                //para conceder el servicio al usuario: $idUsuario
                //incluso comprobar que idUsuario es válido
            }else{
              //TRANSACCION DUPLICADA, NO HACEMOS NADA
            }
        }else if (strcmp ($res, "INVALID") == 0) {
            //CONTROL DE ERRORES
        }
    }
    fclose ($fp);
}

Ya hemos recibido la confirmación de pago de PayPal, la hemos guardado en nuestra base de datos y le hemos dado a nuestro cliente su servicio, este proceso será distinto para cada aplicación así que no lo explicaremos, haz el tuyo como creas oportuno. Lo que sí te recomiendo es guardar una tabla con todas las transacciones recibidas a modo de log, te servirá para buscar errores o reclamaciones de usuarios.

Cabe señalar que PayPal sólamente lanza este proceso con las transacciones correctas, aquellas se que se han cobrado correctamente, nunca con las erróneas (falta de saldo, tarjeta incorrecta, etc.).

Devolviendo al usuario a nuestra web

Una vez que el usuario ha terminado su transacción en PayPal deberíamos enviarlo de nuevo a nuestra web para que comience a utilizar el servicio por el que ha pagado. Para ello PayPal nos provee del método Retroceso automático que mandará al usuario a la URL que le hayamos especificado indicando los parámetros de la transacción, entre ellos si ha sido válida o no. PayPal, además, ha pensado en todo: no puedo devolver a un usuario a la web de origen sin antes haberle comunicado el éxito de la transacción (el paso anterior). Así el mecanismo de PayPal retrasa el reenvío del usuario unos segundos para intentar que tu servidor ya esté informado de esa transacción. Simplemente genial. Ahora utilizaremos tu código personal de identidad que hemos obtenido al configurar la cuenta en PayPal. Es el parámetro que en el código llamamos $auth_token.

El proceso es parecido a la confirmación de transacciones. Debemos comunicar a PayPal que hemos recibido al petición de vuelta del usuario y que somos nosotros quién lo hacemos, sólo así nos dará los datos de la transacción. De nuevo un método curioso. Para hacerlo, nos indica por GET el identificador de la transacción y debemos devolvérselo junto a nuestro código personal de identidad mediante otra llamada HTTP POST, de este modo nos aseguramos de que somos nosotros quienes solicitamos la información. Si todo ha sido correcto PayPal nos devuelve los datos de la transacción como respuesta a esta llamada. Otra vez genial el sistema.

¿Por qué no hacerlo como en el paso anterior? Sencillo, el método IPN es transparence al usuario, es una llamada interna que hacen los sistemas de PayPal a los tuyos, nadie va a saber que datos se envían, con lo cual puedes utilizar esos datos para confirmar la transacción. En el método de retroceso, esta URL llega al usuario, con lo que podría hacer cosas que no deseamos con los datos, con lo que no nos envían nada en la solicitud, simplemente el identificador de la transacción para que internamente nosotros pidamos los datos validándonos con el código personal.

//read the post from PayPal system and add 'cmd'
$tx_token = $_GET['tx'];
$auth_token = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
$req = 'cmd=_notify-synch';
$req .= "&tx=$tx_token&at=$auth_token";
$header .= "POST /cgi-bin/webscr HTTP/1.0rn";
$header .= "Content-Type: application/x-www-form-urlencodedrn";
$header .= "Content-Length: " . strlen($req) . "rnrn";

$fp = fsockopen ('www.paypal.com', 80, $errno, $errstr, 30);
$isError=0;
if(!$fp) {
    $isError=2;//error HTTP
}else{
    fputs ($fp, $header . $req);
    // read the body data
    $res = '';
    $headerdone = false;
    while (!feof($fp)) {
        $line = fgets ($fp, 1024);
        if (strcmp($line, "rn") == 0) {
            // read the header
            $headerdone = true;
        }else if ($headerdone){
            // header has been read. now read the contents
            $res .= $line;
        }
    }    // parse the data
    $lines = explode("n", $res);
    $keyarray = array();
    if (strcmp ($lines[0], "SUCCESS") == 0) {
        for ($i=1; $i<count($lines);$i++){
            list($key,$val) = explode("=", $lines[$i]);
            $keyarray[urldecode($key)] = urldecode($val);
        }

        $isError=0;//no error
        $nombre = $keyarray['first_name']." ".$keyarray['last_name'];
        $producto = $keyarray['item_name'];
        $amount = $keyarray['payment_gross'];
        $idUsuario=$keyarray['item_number'];
        $cantidad=0+$keyarray['mc_gross'];
        $estado=$keyarray['payment_status'];
        $transid=$keyarray['txn_id'];

        //ahora ya puedes evaluar lo que necesites de tu transacción
        //y termina informando al usuario de que todo ha ido bien y ya tiene su servicio
    }else if (strcmp ($lines[0], "FAIL") == 0) {
        $isError=1; //error de transaccion
    }
}
fclose ($fp);

La respuesta que recibimos es una respuesta HTTP estandar, con lo cual debemos ser conscientes de que vamos a recibir primero todas las cabeceras HTTP de la respuesta, después dos saltos de línea y a continuación la respuesta propiamente dicha. En una petición normal esta respuesta sería el código HTML de tu página, pero en este caso recibimos la lista de parámetros de la transacción, uno por línea y del tipo:

parámetro1=valor1
parámetro2=valor2
...

El código tiene esto en cuenta y, al recoger la respuesta, regenera la lista de parámetros/valores recibidos con lo que tenemos los datos necesarios.
La primera línea va a ser SUCESS ó FAIL, está claro el dato, una indica que la transacción ha sido válida y la otra que no. Obviamente debes informar al usuario de que la operación ha sido correcta y que ya tiene su servicio disponible.

Si has entendido bien todo lo explicado hasta ahora, verás que los sistemas de recepción de notificaciones y retroceso automático son muy similares, de hecho puedes utilizar este último para validar las transacciones de igual modo que con el primero y no necesitarías éste. Pero ¿qué ocurriría si sólo implementas el segundo y el usuario cierra la ventana del pago mientras está en esos segundos de espera antes de reenviarlo a tu web? Simplemente que el usuario no tendría su servicio disponible ya que nunca ha llegado a realizar el proceso del Retroceso automático. Para solucionarlo implementamos los dos. Con el primero aseguramos que la mayoría de transacciones válidas son procesadas y los servicios otorgados al cliente, con la segunda, además de informar al cliente del éxito o fracaso se su operación, tenemos un sistema de redundancia por si el primer procedimiento hubiese fallado. Como en ámbos tenemos el identificador de transacción, simplemente debemos comprobar que esa transacción ya existe y no hacer nada o procesarla si no existe.

Y eso es todo amigos. Con esto hemos aprendido a tener un sistema de compras de servicios seguro y dinámico en PayPal. Cómo habéis podido observar, el procedimiento es bastante complejo en cuanto a configuración y desarrollo, pero es muy interesante el estudio del resultado para tener una idea más amplia de como implementar sistemas seguros.

105 comentarios en “Cobrando por servicios a través de PayPal con PHP

  1. NO SIRVE!!, he estado probandolo, subiendo actualizando los archivos en paypal, el servidor y nada!, ademas el codigo tiene problemas de sintasys, está mal escrito y tiene muchos errores, he tratado lo mejor que pude, en paypal los certificados ya estan bien y por mas que intengo vale queso, le hago clic en el boton comprar y me manda pero a la pagina principal de paypal, esto es una basaura, no sirve.

  2. Hola Jorge,

    Te aseguro que funciona, más que nada por que lo tengo funcionando desde hace año y medio sin ningún problema. El código es el mismo que tengo funcionando, así que si no he copiado y pegado mal algo, debería estar bien.
    Podrías empezar por decir que partes del código has tenido que modificar y, a continuación, mostrarnos tu código de creación de botones para ver porqué no te funciona.

    Un saludo.

  3. Hola Osus,

    Estoy integrando paypal en un web site con tu método, pero una vez configurada la cuenta como indicas y creado el botón, al conectar con paypal, éste me devuelve el siguiente error:

    “No podemos procesar esta transacción, porque hay un problema con la dirección de correo electrónico de PayPal facilitada por el vendedor. Póngase en contacto con el vendedor para resolver el problema. Si este pago se destina a un anuncio de eBay, puede ponerse en contacto con el vendedor mediante el vínculo “Preguntar al vendedor” de la página del anuncio. Una vez que tenga la dirección de correo electrónico correcta, el pago se puede realizar en http://www.paypal.com.”

    Tienes idea de a qué puede ser debido?
    He verificado que el correo indicado en el botón sea el mismo que el de la cuenta de paypal, pero no se que puede ser, pues es la primera vez que integro paypal.

    Gracias de antemano.

  4. Sí que funciona, más que nada porque esa clase es la oficial de PayPal, no es hecha por “alguien externo”, la dan en el soporte oficial de su web. Es cierto que el código aquí mostrado tiene algún error de sintaxis, pero casi seguro que es cosa del blog al postear (comillas, etc etc), para evitar los entities html.

    En fin, que sí que funciona, lo que pasa es que no sabrás configurarlo.

  5. Selphy,

    Así pensándolo no me suena tu error, pero tiene pinta de que pueda ser algún problema con la cuenta de PayPal. ¿Estás segura de que está bien y no tiene ninguna limitación?
    ¿Has revisado que el certificado sea válido?

  6. Hola Osus,
    El certificado es correcto y la configuración supongo que también, pues no pinta muy complicado, jeje. Pero creo que al cliente le falta validar algo de la cuenta, según me ha comentado algo que tarda unos 5 o 6 dias, estoy a la espera de su aviso para volver a probar.
    Ya os contaré de que se trata si realmente ese es el problema.
    Hasta entonces esperaré, para no volverme loca! Deben faltar uno o dos dias como mucho 😉

  7. Buenas tardes,
    Estuve probado tu codigo, pero desde la primera parte al momento de dar click en el botón de pagar con paypal, la entidad me contesta con el mensaje : “No podemos descodificar el Id. de certificado.”

    ¿Sabes que podrá ser?

    Muchas gracias y un saludo.

  8. Hola,

    Yo tengo el mismo problema que Ricardo, no pueden descodificar el ID del certificado. Estoy usando el sandbox de paypal para pruebas, sabes si también funciona ahí?

    Gracias,

    Jose.

  9. Hola, estoy a punto de empezar un sistema similar, quisiera saber si se pueden enviar otros datos al envar la información a paypal y si estos seran devueltos en IPN y al devolver al usuario a nuestro sitio.

    Encontre que existen las variables first_name o last_name por ejemplo… ¿solo seria cuestion de agregarlas al enviar el boton y ya las podria usar en los otros dos scripts? es decir paypal me las pasaria nuevamente?

  10. Bueno estoyusando este ejemplo para crear un sistema de compra dinamico este es el codigo encritado que me genera la clase…

    EL tema es que obtengo el error “No podemos descodificar el Id. de certificado.” y leo que puede ser porque inserte algun salto de linea mal pero la clase me devulve la cadena codificada con los saltos que se ven ya incluidos 😐 ¿es asi como deve verce la cadena o debe ser una cadena sin saltos… que estoy haciendo mal (se que no es dificil de decir :P)

  11. Ya me funciono lo dejo como ayuda aquí:

    la linea del formulario “—–BEGIN PKCS7—–n”.$paypal->encryptButton($paypalParam).”n—–END PKCS7—–”

    es en realidad “—–BEGIN PKCS7—–n”.$paypal->encryptButton($paypalParam).”n—–END PKCS7—–”

    es decir “—–” (guión 5 veces) en vez de “—–”, seguramente fue remplazado cuando se publico, a mi casi me deja loco XD
    además están mal las comillas (“) pero eso se nota mas fácil.

  12. Respecto al error “No podemos descodificar el Id. de certificado.”, quisiera comentar que en mi caso se producía porque estaba usando el paypal_cert_pem.txt para el Sandbox, pero cuando pones el sitio en producción hay que bajarlo de nuevo desde nuestro perfil.

    Por lo demás agradecer a Osus sus explicaciones, ya que me han sido de mucha ayuda. PayPay es un mar de opciones, y a mi me ha costado más transladar lo que quería hacer al lenguaje PayPal que implementarlo.

  13. se ve bueno el tutorial pero como lo integro con con una base de datos en el stio de paypal esta echoo todo un liooo
    y no explica bien, lo podrian hacer ud.
    que tablas nesecitare, estoy medio confundifooo ayuda please
    gracias de ante mano

  14. En primer lugar, muchas gracias por este tutorial, gracias a él he conseguido casi terminar de desarrollar un componente para Joomla usando este sistema.

    Mi problema en cuestión es el siguiente: Me realiza todo de forma correcta, pero cuando leo lo que me manda PayPal, recibo siempre el estado: INVALID, a pesar de que las transacciones se realizan de forma correcta.

    Me pregunto, qué puede estar pasando, ya que la URL de regreso que me muestra lleva incluso un “st=Completed”, este es el texto que me devuelve PayPal, completo:

    HTTP/1.1 200 OK
    Date: Mon, 08 Dec 2008 20:33:17 GMT
    Server: Apache/1.3.33 (Unix) mod_fastcgi/2.4.2 mod_gzip/1.3.26.1a mod_ssl/2.8.22 OpenSSL/0.9.7e
    Set-Cookie: c9MWDuvPtT9GIMyPc3jwol1VSlO=ugWg5Fq17yTNvJw6i9yajRA9gaHl_ZusWGHr1ZCwB912Xkc4kdO5bOGStqqy1wgCqeKx2VZTuDIU0DvRgVjsu6KXPfh072F1jjgLc2_blM6crdOKIgRVmrGjT3qEAh1jXhrBLW%7ckqIf8aaHtDaxudBa7EeqqJbSQuAbfZTagzjImEwsdvJqrVTjfQXS9gCVyBZJTM30FO1WEm%7coS3WUqLXGHHG9FnMnhMAirT8hRnH_UoatwwtKYjtZRJJmKJRZZcECOP7HYJ3yZ-B5rjQM0%7c1228768397; domain=.paypal.com; path=/
    Set-Cookie: cookie_check=yes; expires=Thu, 06-Dec-2018 20:33:17 GMT; domain=.paypal.com; path=/
    Set-Cookie: navcmd=_notify-validate; domain=.paypal.com; path=/
    Set-Cookie: navlns=0; expires=Sun, 03-Dec-2028 20:33:17 GMT; domain=.paypal.com; path=/
    Set-Cookie: Apache=10.191.196.11.158601228768397316; path=/; expires=Sun, 26-Oct-02 14:05:01 GMT
    Connection: close
    Content-Type: text/html; charset=UTF-8

    INVALID

  15. man dime de donde descargaste los certificados…. copio esos q estan hay y cuando los subo a paypal me dice q tiene q ser con formato .pem

  16. #Hibade,
    Te dejo unos enlaces por si ayudan con tu problema:
    http://www.pdncommunity.com/pdn/board/message?board.id=ipn&thread.id=9388
    http://paypaldev.org/topic.asp?TOPIC_ID=5720
    http://paypaldev.org/topic.asp?TOPIC_ID=11377
    http://www.paypaldeveloper.com/pdn/board/message?board.id=ipn&thread.id=8610

    En general, el problema es sólo de notificación, la transacción se ha efectuado correctamente, lo que falla es la notificación. Revisa las urls que te indico por si encuentras el fallo.

    #Roberto,
    no entiendo mucho tu problema.
    ¿Generaste tus propios certificados tal y como indico en el tutorial?

    openssl genrsa -out my-prvkey.pem 1024
    openssl req -new -key my-prvkey.pem -x509 -days 3650 -out my-pubcert.pem

    El certificado a subir a Paypal debe ser el tuyo personal.

  17. Buenas
    Muy buen tutorial, gracias por el esfuerzo.

    Tengo un problemita. Llevo mucho rato buscando y no he conseguido encontrar el porqué.
    Se me crea el botón correctamente, si veo el código fuente de la página veo k me lo ha encriptado pero al apretar el botón para ver que funciona paypal me da el siguiente mensaje: La dirección de correo electrónico para la empresa no se incluye en el objeto binario. Póngase en contacto con el vendedor.

    Si alguien sabe como puedo solucionarlo se lo agradecería mucho.

    Un saludo y gracias por adelantado

  18. hola, estoy creando una web con integracion de paypal. he leido tu manual y estoy perdido en los primeros pasos de creacion de certificado público X.509 ya que en esta parte:

    Las instrucciones detallas las tienes aquí. básicamente necesitas

    el enlace no funciona agradezco tu ayuda

  19. Ya he conseguido solucionar mi problema. Os lo comento por si a alguien le pasa que sepa solucionarlo.
    El problema viene de la clase PayPalEWP. He encontrado otra por internet y con esa me ha funcionado a la primera.

  20. holas, primeramente agradecer por el tuto, pero tengo un problema no se si es con mi certificado o que pero al momento de haber mi boton que veo q si esta encriptado y todo, presiono y me redirige a la pagina de paypal pero mostrandome un error que dice: “No podemos descodificar el Id. de certificado.”, no se cual pueda ser el problema ya que realice los pasos tal como mensionas.

    Epero una manito porfas.

  21. Tengo una duda, cual de los dos ultimos script debo utilizar???, porke primero puse el ipn, con toda la verificacion y luego mostrastes el otro con el token como hago eso???, son los 2 o uno de ellos???, cual seria el indicado???

  22. Hola Kerveros,

    Son dos cosas distintas pero que se relacionan.
    El primer script, si he entendido bien, es la notificación del pago. Este aviso es transparente al usuario, lo hace paypal contra tus sistemas y te indica que la oepración se ha procesado correctamente.

    El segundo script que comentas entiendo que es la vuelta del usuario una vez ha comprado, que en realidad también es una notificación.

    Pero piensa una cosa, ¿qué ocurre si sólo usas el segundo método y el ususario al terminar la compra no vuelve a tu web por el redirect que le marca paypal?

    Son dos procedimientos complementarios, no excluyentes 🙂 .

    Espero haberte ayudado.

    Osus

  23. Hola! En primer lugar muchas gracias por el tutorial claro y util; toda la informacion esta en ingles y se agradece mucho el aporte.

    Tras depurar un poco el codigo y adaptarlo a mi programacion llego a un punto en el que no puedo continuar. En primer lugar he realizado el upgrade de mi cuenta de Pay pal a premium y la he verificado; he creado la clave privada y el certificado publico; he subido mi certificado y descargado el certificado publico de Pay pal.

    Con los certificados en el root de la aplicacion y el id del mismo en $paypal->setCertificateID creo que ya lo deberia tener todo.

    Cuando ejecuto, Pay pal me da un mensaje que pone : “El vendedor no es una cuenta PayPal Premier o Business. Esta función sólo se activa para los titulares de cuenta PayPal Premier o Business.”, cuando si voy a mi cuenta si que me pone que es Premier verificada.

    Podrias darme alguna idea de lo que esta fallando? Muchas gracias de cualquier modo

  24. He resuelto el problema; lo posteo por si a alguien le pasa lo mismo:
    en el parametro business de la variable $paypalParam hay que poner el email de la cuenta Paypal. Yo habia dejado el [email protected] que traia el codigo.

    Todo lo demas funciona muy bien; muchas gracias Osus

  25. Hola q tal saludos, este es un excelente tutorial solo que yo en lugar de botones quiero que el pago se lleve acabo atravez de mi sitio web sin salir de el podrias orientarme un poco, por dond empezar gracias!!!

  26. Muy bueno el tutorial. Bueno yo estoy utilizando un carrito de compra que hice….este boton es para “Comprar Ahora”, mi pregunta es ¿lo puedo implementar en el carrito de compra? es decir, al final para comprar todos lo productos que hay en el carrito.

  27. Estube intentando hacer la transacción, me sale este error:

    “No podemos descodificar el Id. de certificado”

    Ya intente generando un nuevo certificado y una nueva llave privada…y un certificado de paypal….. el id de certificado que me da paypal es de 13 digitos y lo pongo en esta variable:

    $paypal->setCertificateID(“1234567890123”);

    es correcto?

    Gracias por tu ayuda Osus

  28. Ya intente hacer todo lo que comentan en el foro y no logró resolver el problema….. ¿será que no esté bien configurada la extensión php_openssl? lo estoy haciendo desde localhost de mi maquina y tengo XP, el apache lo gestiona el Wamp asi como php, no se si tenga algo que ver.

    Y otra cosa, ya implementado en el host, necesito:
    un certificado ssl?
    una ip dedicada?

    o alguna cosa más? gracias por tu ayuda Osus, esta increible este post, aprendí mucho ya que soy nuevo en esto del e-commerce.

    espero tu respuesta o la de otros…..Gracias de antemano

  29. Hola David,

    No necesitas ni ssl ni ip dedicada, si lo quieres hacer con ssl es decisión tuya, no del protocolo.

    Por otra parte, lo del problema con el certificado, consulta los comentarios más arriba, Ivan indica una posible solución a tu problema.

  30. ya los logre generar por OpenSSL, una duda…

    El certificado paypal es un txt?
    $paypal->setPayPalCertificate(“paypal_cert_pem.txt”);

    o tambien es un .pem?
    $paypal->setPayPalCertificate(“paypal_cert.pem”);

  31. Buenas,

    Excelente tutorial, te debo unas cañas, no veas el tiempo que me has ahorrado buscando opciones por Paypal, queda claro que se puede hacer en sus páginas pero la documentación deja mucho que desear.

    Resumo mis pasos (aunque están todas las soluciones en los comentarios) para que se sepa que a fecha de hoy sigue siendo perfectamente valido (leyendo bien artículo y comentarios así como con un poco de sentido común, of course):

    1.- Depurar el código para limpiar basurilla wordpres (comillas, saltos de línea)

    2.- En el hidden encrypted sustituir las dos rayas que se ven por cinco guiones

    Osus, muchisimas gracias por el tiempo que te has tomado por ofrecernos este tuto, verdaderamente ha sido de gran ayuda.

    Saludos,

    PD: Supongo que los que tenéis blog estáis acostumbrados a los trols pero no me queda otra que sentirme avergonzado por permanecer a las misma raza que el tal Jorge Ortega del comentario despectivo, menos mal que tu ni caso y a lo tuyo 😉

  32. Hola MrLp3,

    Muchísimas gracias por tus comentarios y más aun por tu apoyo 🙂

    Seguro que gracias a tus consejos mucha gente dejará de tener problemas con el copy/paste, eso que llamas “sentido común” 😉

    Un abrazo

  33. Hola,
    lo primero agradeceros muchísimo este tutorial… Está genial. Completo, claro, útil.. Directo para el top ten 🙂
    Tengo una duda: ¿esto es una implementación del expressCheckOut de Paypal o de qué exactamente?

    Muchísimas gracias

  34. Hola que tal, me había desaparecido…encontre cual fue el error aparte de los 5 guiones y comillas. Cuando entraba al recinto de sandbox, me salia un error que paypal no podia decodificar el id de certificado.
    El caso fue que cambia _s-xclick pr _s-click

    Saludos, ahora intentaré adecuar el código para añadir varios productos en un mismo botón. Mi pregunta es ¿se puede?

    Gracias Osus por este foro que nos ha ayudado a muchos, sin duda… Shalom

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *