Vender suscripciones con PayPal
Buscando en la red sobre el poder que tiene perl que, aunque Uds. no lo crean es inmenso, encontré el siguiente tutorial desarrollado por Uriel Lizama en el cual nos da las pautas para vender membrecÃas de forma sencilla mediante PayPal, cuyo servicio se puede configurar en menos de una hora en nuestro sitio.
Tu cuenta en PayPal
Como es lógico lo primero que tienes que hacer es crear tu cuenta en PayPal, es realmente muy sencillo y puedes crearla en el siguiente link:
https://www.paypal.com/row/mrb/pal=EC6ML8VKFAJ6E
Una vez que hayas creado tu cuenta de PayPal ahora podemos empezar a configurar todo.
Creando tu área de miembros….
Normalmente cuando vendemos membrecÃas a nuestro sitio lo que hacemos es crear un área especial en donde solamente pueden entrar miembros. Para poder accesar, nuestros miembros deben de usar una clave y contraseña la cual les es proporcionada una vez que hayan hecho el pago de su membrecÃa, les recomiendo el siguiente tutorial en donde puedes conocer como configurar su propio directorio protegido:
http://perlenespanol.baboonsoftware.com/archives-tut/000165.html
Una vez que ya hayas probado que tu directorio protegido funciona de manera correcta, ahora es momento configurar nuestra interface con PayPal.
Usando el IPN de PayPal
Vender membrecÃas con PayPal es sumamente sencillo, todo lo que tenemos que hacer es crear una vÃa de comunicación entre PayPal y nuestro servidor. PayPal se encarga de dar de alta y de baja a nuestros usuarios dependiendo del término de sus membrecÃas, por lo que una vez que hayamos configurado todo ya no nos tenemos que preocupar.
La forma en que PayPal se comunica con nuestro servidor para avisarnos que hay que dar de alta o de baja un usuario es por medio de una tecnologÃa que se llama IPN.
El IPN o Instant Paymen Notification de PayPal es el medio por el cual PayPal se comunicará de manera automática e instantánea con tu sitio para notificar de cambios. A continuación podrán ver un gráfico que te muestra cómo funciona esto:
¿Cómo funciona el IPN?
1. El pago de un usuario o un refund activa el IPN.
2. PayPal hace un post de con campos de un FORM HTML al URL que pongas en tu perfil. Este POST es el corazón de IPN. Dentro de la notificación vienen incluidas la información de pago de tu cliente (como nombre del cliente y monto de pago).
3. Tu servidor debe entonces validar la notificación para asegurarse que es legÃtima.
Para configurar el URL de nuestro IPN debemos de accesar a nuestra cuenta de PayPal.
Ahà nos debemos de dirigir a Profile, ahà bajo Selling Preferences encontraremos una liga que dice Instant Payment Notification Preferences.
Muy bien, ahà debemos de ingresar el URL de nuestro CGI de IPN y activarlo. Dependiendo del lugar en donde quieras poner tu CGI es el URL que debes de poner, por ejemplo:
“http://www.misitio.com/cgi-bin/paypal.cgi”
Creando nuestro programa de IPN
Ahora vamos a la parte más delicada de todo el proceso, que es la creación de nuestro programa de IPN. Este programa es el CGI que se va a encargar de realizar la comunicación de PayPal y de llevar a cabo las tareas de alta y de baja de nuestros miembros.
Recuerda que este CGI es el cual diste de alta en tu Perfil de PayPal, asà que recuerda guardarlo en el mismo URL.  Nuestro CGI consta de varias partes, primero recibimos los datos, luego verificamos que los datos realmente provengan de PayPal y finalmente decidimos que hacer de acuerdo con los datos que PayPal nos ha enviado.
Como siempre, primero empezamos con la cabeza de nuestro CGI, usando el pragma strict y cargando los módulos necesarios.  Recuerda cambiar la primera lÃnea del script #!/usr/bin/perl con el path de Perl en tu servidor.
#!/usr/bin/perl
use strict;
# Cargamos los Módulos
use CGI::Carp;
use CGI qw(:standard escapeHTML);
use LWP::UserAgent;
# CGI.pm versioning issue
$CGI::USE_PARAM_SEMICOLONS = 0;
Después lo que vamos a hacer es configurar nuestras variables globales, estas las debes de customizar de acuerdo a tu información personal:
# URL a PayPal
my $PAYPAL_URL = 'http://www.paypal.com/cgi-bin/webscr';
Â
#Archivo .htpasswd
my $HTPASSWD = '/home/ruta/a/mi/.htpasswd';
Â
# Dirección de nuestro sendmail
my $SENDMAIL_PATH = '/usr/sbin/sendmail';
Â
# Dirección donde queremos las notificaciones de error
my $ADMIN_EMAIL = 'notificaciones@misitio.com';
Â
# Nuestro Email de la cuenta de PayPal
my @PAYMENT_EMAILS = ('pagos@misitio.com');
# -------------------------------------------------------------------
Veamos con cuidado cada una de las variables.
$PAYPAL_URL �sta variable no la debes de modificar, a menos que estés bajo un servidor https, si ese es el caso entonces debes de conectarte a PayPal por medio de https (https://www.paypal.com/cgi-bin/webscr).
$HTPASSWD Aquà debes de poner la ruta completa a tu archivo .htpasswd, recuerda que lo debes de tener configurado.
$SENDMAIL_PATH El CGI va a estar configurado para mandarte mails de cualquier error que pueda haber durante el proceso. Aquà debes de poner la ruta al sendmail de tu servidor.
$ADMIN_EMAIL Email donde quieres recibir las notificaciones de errores que pudieron haber surgido en el CGI. Es muy importante que pongas un mail que cheques constantemente, pues de esta manera podrás revisar en caso de cualquier error.
@PAYMENT_EMAILS Cuando activas tu cuenta en PayPal tu cuenta es el email que registraste, aquà lo debes de poner. Es muy importante que lo pongas bien, de lo contrario todas las transacciones serán rechazadas.
Explorando dentro del script de IPN
Después de definir todas las variables, iniciamos el proceso llamando a nuestra subrutina principal main().
sub main {
        # Verificamos el IPN
       if (verificar_ipn()) {
          # Ha sido verificado vamos a procesarlo
          procesar_ipn();
       }
        # IPN was successfully processed
       respuesta(1);
}
Â
La subrutina principal es muy sencilla, lo primero que hacemos es verificar el IPN, si es correcto entonces los procesamos llamando a la subrutina procesar_ipn(), finalmente damos la respuesta.
La verificación del IPN es sumamente importante, pues nos permite comprobar que PayPal fue el que realmente mandó la notificación. Si no tuviéramos la comprobación, cualquiera podrÃa mandar notificaciones y dar de alta membrecÃas no permitidas.Â
sub verificar_ipn {
   # Nuevo UserAgent
   my $ua = new LWP::UserAgent;
   # Creamos el request
   my $req = new HTTP::Request(”POST”, $PAYPAL_URL);
      $req->content_type(”application/x-www-form-urlencoded”);
      $req->content(query_string() . “&cmd=_notify-validate”);
    # Recibimos la respuesta
   my $resp = $ua->request($req);
    # Checamos si fue exitosa la respuesta
   if (($resp->is_success) && ($resp->content eq “VERIFIED”)) {
       return 1;
   } else {
       # Intentamos identificar el error
       if (($resp->is_success) && ($resp->content eq “INVALID”)) {
           procesar_error(”La notificación recibida no fue de PayPal “.
            “- El mensaje fue ignorado “, “verificación de IPN”, 0, 0);
       } else {
           procesar_error(”La notificación no pudo ser procesada”,
            “verificación de IPN”, 1, 0);
       }
       return undef;
   }Â
}
Lo que estamos haciendo es mandando a PayPal todos los campos recibidos incluyendo el campo cmd=_notify-validate que le indica a PayPal que estamos pidiendo una verificación. Entonces PayPal nos va a regresar una respuesta, ya sea VERIFIED indicando que la notificación si fue enviada por ellos o INVALID indicando que la notificación no salió de PayPal.
Si la respuesta es correcta entonces seguimos con el proceso, de lo contrario llamamos a nuestra subrutina procesar_error(); que es la encargada de manejar todos los errores que surjan durante el proceso.
Seguimos con el procesamiento de nuestro IPN por medio de la subrutina procesar_ipn():
sub procesar_ipn {
        # Nueva membresÃa
       if ((param(”txn_type”) eq “subscr_signup”) && (verificar_cuenta())) {
               # agregamos el usuario
               activar_usuario(param(”username”),param(”password”));
       } elsif (param(”txn_type”) eq “subscr_eot”) {
               # eliminamos al usuario
               desactivar_usuario(param(”username”));
       } else {
               # ignoramos el mensaje
       }Â
}
La subrutina se encarga de ver que es lo que PayPal está notificando. Para hacer esto checa el campo txn_type. En este caso si el campo tiene un valor de subscr_signup entonces significa que PayPal está notificando una nueva membresÃa, en cuyo caso activamos al usuario llamando a la subrutina activar_usuario(), al llamar la subrutina manda dos variables como argumentos el username y el password, los cuales fueron proporcionados por medio de PayPal de manera automática y que el usuario usará para ingresar a la página protegida.
En caso de que el campo tenga un valor de subscr_eot, entonces PayPal nos está notificando que la cuenta debe de ser desactivada, por lo que llamamos a la subrutina desactivar_usuario(), y enviamos a la subrutina el campo username como argumento.
Si te das cuenta cuando vamos a dar de alta un usuario antes pedimos verificar la cuenta, esto lo puedes ver en la siguiente lÃnea:
if ((param(”txn_type”) eq “subscr_signup”) && (verificar_cuenta())) {
La subrutina verificar_cuenta() se encarga de verificar si el pago fue hecho a una de tus cuentas, recuerda que esto lo configuras en la variable @PAYMENT_EMAILS. Esto es muy importante para evitar dar de alta membrecÃas que no te corresponden, aunque esto es muy poco probable, vale la pena comprobarlo:
Â
sub verificar_cuenta {
    # validamos que el pago se haya realizado a nuestra cuenta
   my $valid = undef;
    for my $pay_mail (@PAYMENT_EMAILS) {
       if (param(”receiver_email”) eq $pay_mail) {
           $valid = 1;
           last;
       }
   }
   if (!$valid){
       procesar_error(”Se recibió un IPN de una cuenta que no es tuya “.
                       “- El mensaje fue ignorado.”, “validación de email “, 0, 0);
       return undef;
   }
 return 1;Â
}
Ahora vamos a checar nuestras subrutinas encargadas de dar de alta y de baja a nuestros usuarios. Primero demos un vistazo a la subrutina encargada de dar de alta a los usuarios:
sub activar_usuario{Â
my $user = shift;
my $pass = shift;
#Verificamos que el usuario no exista ya
my $existe = undef;
 open my $in, ‘<’, $HTPASSWD
  or procesar_error(”No se pudo abrir archivo .htpasswd – $!”,
                      “abrir htpasswd”, 0, 1);
   while(my $line = <$in>){
       my ($auser,$apass) = split(/\:/, $line);
           if($auser eq $user){
               $existe = 1;
               last;
           }
    }
close $in;
 if($existe){
   # El usuario si existe, mandamos error
   procesar_error(”El usuario $user ya existe “.
     “- No se ha hecho ninguna acción”, “crear usuario”, 0, 1);
   return 1;
}else{
   # Introducimos el usuario a nuestro .htpasswd
   open my $out, ‘>>’, $HTPASSWD
       or procesar_error(”No se pudo abrir archivo .htpasswd – $!”,
                          ”abrir htpasswd”, 0, 1);
       print {$out} $user . “:” . $pass;
       print {$out} “\n”;
   close $out;
   return 1;
}Â
}
Es sumamente sencillo lo que hacemos, primero recibimos el username y pass enviados al llamar la subrutina. Después de ello abrimos nuestro .htpasswd y checamos si no existe ya el username que queremos dar de alta, en caso de que exista notificamos acerca de esto y ya no realizamos ninguna acción.
Si el usuario aún no existe, entonces introducimos el nuevo usuario y contraseña dentro de nuestro .htpasswd, ya a partir de ese momento podrá tener nuestro usuario acceso a la página protegida.
Como podrás ver no hay necesidad de encriptar la contraseña, pues PayPal ya nos manda la contraseña encriptada. Seguimos ahora con la subrutina encargada de desactivar la cuenta:
sub desactivar_usuario{
my $user = shift;
open my $in, ‘<’, $HTPASSWD
  or procesar_error(”No se pudo abrir archivo .htpasswd – $!”,
                     “abrir htpasswd”, 0, 1);
my @usuarios = <$in>;
close $in;
 # Introducimos el usuario a nuestro .htpasswd
   open my $out, ‘>’, $HTPASSWD
         or procesar_error(”No se pudo abrir archivo .htpasswd – $!”,
                            “abrir htpasswd”, 0, 1);
       for my $linea_usuario(@usuarios){
           chomp($linea_usuario);
           my($auser,$apass) = split(/\:/, $linea_usuario);
          if($auser ne $user){
               print {$out} $linea_usuario, “\n”;
           }
       }
   close $out;
 return 1;
}
De igual manera recibimos el username que queremos eliminar como argumento. Abrimos el archivo .htpasswd y guardamos todo el contenido en el array @usuarios, después volvemos a abrir nuestro archivo pero ahora vamos a sustituir todo el contenido. Hacemos una iteración a través de nuestro array y escribimos en el archivo todas las lÃneas excepto aquellas donde el username sea el que queremos eliminar.
Listo, a partir de ese momento el usuario ya no podrá tener acceso a nuestra página protegida. Ahora vamos a crear la subrutina encargada de hacer las notificaciones de error:
sub procesar_error {
       # sends notification that an error has occured
       my $err_str = shift;
       my $action = shift;
       my $kill = shift;
       my $req_action = shift;
     my $message = “El siguiente error fue encontrado al intentar hacer la $action:”;
       $message .= “\n\t$err_str\n\n\n”;
       $message .= “Información del Usuario\n”;
       $message .= “\tUsername: ” . param(”username”) . “\n”;
       $message .= “\tEmail: ” . param(”payer_email”) . “\n”;
       $message .= “\tNúmero de Suscripción: ” . param(”subscr_id”) . “\n”;
       $message .= “\tTipo de Transacción: ” . param(”txn_type”) . “\n”;
       my $subject = “Error de Suscripción”;
       if ($req_action) {
               $subject .= ” – Necesita una acción”;
       } else {
               $subject .= ” – No se necesita realizar nada”;
       }
       # if an email is not specified write to error_log only
       if (($ADMIN_EMAIL) && ($SENDMAIL_PATH)) {
            if (!open(SENDMAIL, “|$SENDMAIL_PATH -t”)) {
                   carp “Unable to open sendmail pipe.”;
           }
            print SENDMAIL “To: $ADMIN_EMAIL\n”;
           print SENDMAIL “From: $ADMIN_EMAIL\n”;
           print SENDMAIL “Subject: $subject\n”;
           print SENDMAIL “Content-type: text/plain\n\n”;
           print SENDMAIL “$message”;
            if (!close(SENDMAIL)) {
               carp “Unable to close sendmail pipe.”;
           }
       }
     # put it into the error log
       if ($kill) {
               # IPN will retry
               respuesta(0);
               croak $message;
       } else {
               carp $message;
       }
}
 La subrutina actúa de acuerdo a los siguientes argumentos recibidos:
Â
       my $err_str = shift;
       my $action = shift;
       my $kill = shift;
       my $req_action = shift;
Â
El primero es la descripción del error, sigue la acción en la cual se encontró el error, después viene $kill que indica si debe de terminarse en ese momento el CGI y después viene si se necesita alguna acción de parte de uno.
Se crea un reporte y se manda a la dirección de correo configurada al principio del CGI.
Finalmente viene la subrutina que va a dar la respuesta final de nuestro script, al cual llamamos respuesta():
sub respuesta {
       # handle the http reponse
       my $is_success = shift;
       if ($is_success) {
               print header(-status=>(’204 No Content’));
       }
       else {
               print header(-status=>(’500 Internal Server Error’));
       }
}
Si vemos, en caso de que haya algún error el script va a regresar un error 500 usando el http-status, de lo contrario un código 204. Esto es muy importante, pues PayPal seguirá mandando la notificación hasta que el script regrese un código exitoso. Eso es todo, nuestro script está completo y listo para utilizarse, ahora todo lo que nos falta es crear el botón de compra.
Con nuestro script de IPN ya tenemos todo listo para empezar a vender nuestras membrecÃas. Ahora necesitamos hacer el botón de compra. El botón de compra de PayPal es más bien un formulario por medio del cual llamamos a PayPal con todos los argumentos que definen el tipo de compra que van a realizar nuestros usuarios.
Hacer los botones es sumamente sencillo usando la fábrica de botones de PayPal. Lo que vamos a hacer es entrar a nuestra cuenta de PayPal y ahà en la barra de botones de arriba vamos a cliquear sobre Merchant Tools.
Ahà debes de buscar la liga que dice Subscriptions & Recurring Payments bajo el apartado Key Features. Se te va a mostrar la fábrica de botones. Ahà podemos poner todas las caracterÃsticas de nuestra membrecÃa, el nombre, la descripción, el término de la misma, ya sea en dÃas, meses o años, etc.
Es muy importante que al crear tu botón cheques que tengas activada la opción Subscriptions Password Management para que PayPal se encargue de la administración de tus usuarios.
Una vez que hayas creado el botón copia el código que fue generado de manera automática y ponlo en tu página de suscripción.
Haciendo Pruebas
Es muy sencillo realizar pruebas para ver que todo funcione de manera correcta.
Lo que puedes hacer es crear un membrecÃa que cueste $0.01 y que tenga una duración de un dÃa. Entonces realiza la compra de la membrecÃa como si fueras un cliente. Esto te va a servir para checar que los usuarios se están dando de alta automáticamente y aparte al dÃa siguiente podrás ver si realmente se dio de baja el usuario.
Ya después de hacer las pruebas necesarias y estar seguro que todo funciona bien, entonces ya puedes poner a la venta tus membrecÃas.
Como en todo trabajo que involucre inversión, les recomiendo hacer todas las pruebas de control de este script y asà se aseguran no tener futuros malos momentos. También pueden descargar el script completo desde:
http://perlenespanol.baboonsoftware.com/tutoriales/misc/ipn_paypal.zip
Añadir este post a:


[...] ellos, la gente de la Técnica, van un poco mas allá. Ahora nos proponen utilizar PayPal para vender membresias y yo dirÃa cualquier otra cosa que se les pegue la gana. Si les sobra un [...]
Pingback by De la vida y algo mas…. :: Loja en YouTube :: July :: 2007 | July 29, 2007