Sei sulla pagina 1di 9

Pagina 1 di 9

02/03/11 - Come implementare un pagamento online: Le procedure generali (3/6)

Nell'articolo precedente di questa serie abbiamo visto, ragionando con una logica ad
oggetti, quello che dovremo realizzare ora nella pratica. In questo articolo vedremo
come implementare la classe parent (che chiameremo IPNListener). Questa classe
la potremo utilizzare per qualsiasi nostro progetto che prevede
l'implementazione di un pagamento.

Come prima cosa però, creiamo un file di configurazione denominato pp_config.php


in questo modo:

Array<?phpArray//systemArraydefine("SIMULATION",
1);Arraydefine("SIMULATION_URL",
"www.sandbox.paypal.com");Arraydefine("PRODUCTION_URL",
"www.paypal.com");Arraydefine("PRIMARY_PAYPAL_EMAIL",
"email@sito.com");Arraydefine("PRIMARY_SANDBOX_EMAIL",
"admin_1284367352_biz@bluewin.ch");ArrayArray//dbArraydefine("
HOST", "localhost");Arraydefine("DB_USER",
"root");Arraydefine("DB_NAME",
"paypal");Arraydefine("DB_PASSWORD",
"*******");ArrayArray//messagesArraydefine("ADMIN_MAIL",
"maurizio.tarchini@bluewin.ch");Arraydefine("NO_REPLY",
"no_reply@site.com");ArrayArraydefine("AMMOUNT",
50);Array?>Array

La prima costante definisce se stiamo utilizzando il nostro sistema in simulazione o


Pagina 2 di 9

in produzione. In questo modo dovremo solo modificare questo parametro quando


passeremo da una circostanza all'altra.
In effetti si potrebbe anche fare automaticamente, infatti tra i vari parametri che
riceviamo possiamo trovare test_ipn che sarà impostato a 1 se siamo in Sandbox o
a 0 se stiamo lavorando con PayPal. Ma qualcosa dentro di me mi dice che è
meglio impostare manualmente (non lo dico ironicamente, non penso che possa
creare dei problemi, ma ugualmente non mi fido).
La seconda e la terza costante definiscono l'url dell'ambiente di simulazione e
dell'ambiente reale, di produzione. Vedremo in seguito come utilizzarle.
La quarta costante definisce il mio account primario di commerciante (reale) mentre
la quinta definisce l'account primario nell'ambiente di simulazione.
Possiamo disporre infatti di diversi indirizzi email nel nostro account PayPal (o
Sandbox), ma solo uno sarà il primario. Per verificare quale sia:

• vai in Sandbox;
• seleziona l'account amministrativo;
• loggati all'account amministrativo;
• clicca su profilo;
• clicca su email

Se hai creato l'account come descritto nel primo articolo, sarà anche l'unico indirizzo
email.
Seguono i dati di connessione al database, il mio email, l'email di risposta per i
messaggi di sistema, ed infine il costo del servizio.

La classe IPNListener

Creiamo ora un nuovo file denominato IPNListener.php, nel quale inizieremo ad


includere il file di configurazione e a dichiarare la classe (astratta) IPNListener.
Pagina 3 di 9

Array<?phpArrayrequire_once 'pp_config.php';ArrayArrayabstract
class IPNListenerArray{Array

Il primo metodo che implementeremo sarà sendReport(). Questo metodo invia un


messaggio all'amministratore con alcuni dati della transazione nel caso in cui la
verifica incontri problemi.

Arrayprivate function sendReport()Array{Array


if(SIMULATION)Array {Array $add = "- SIMULAZIONE
-";Array }Array elseArray {Array $add =
"";Array }Array //messaggio all'amministratoreArray
$subject = "$add Problema IPN";Array $message = "Si è
verificato un problema nella seguente
transazione:\r\n\r\n";Array $message .= "Nome: " .
$_POST['first_name'] . ' ' . $_POST['last_name'] .
"\r\n";Array $message .= "email: " . $_POST['payer_email']
. "\r\n";Array $message .= "id transazione: " .
$_POST['txn_id'] . "\r\n";Array $message .= "oggetto: " .
$_POST['transaction_subject'];ArrayArray
mail(ADMIN_MAIL,$subject,$message,"From: " . NO_REPLY);Array
return;Array }Array

Come vedi, se rilevo che si tratta di una simulazione, aggiungerò all'oggetto


dell'email la parola simulazione, evitando così di fare confusione.

Ora andremo ad implementare il metodo isVerifiedIPN.


Per verificare la legittimità di una notifica devo procedere in questo modo:

• Ricevere la richiesta (POST) da PayPal.


• Creare una richiesta contenente gli stessi valori nello stesso
ordine: (chiave=valore&chiave=valore...) preceduti da un valore
aggiuntivo: cmd=_notify-validate.
• Aprire una connessione (socket) con PayPal (o con Sandbox se
siamo in simulazione)
• Inviare questa richiesta
• PayPal (o Sandbox) risponderà VERIFIED se la richiesta è
legittima o INVALID se non lo è.
Pagina 4 di 9

Se la risposta sarà VERIFIED, la notifica è legittima.


In pratica, alla ricezione di una notifica, contattiamo PayPal e chiediamo: "Ciao, ho
appena ricevuto questa notifica, me l'hai mandata tu?".

Per implementare questo metodo utilizzerò un codice standard di PayPal, al quale


apporteremo qualche modifica.

Iniziamo a scrivere il metodo:

Arrayprivate function isVerifiedIPN()Array{Array $req =


'cmd=_notify-validate';Array foreach ($_POST as $key =>
$value)Array {Array $value =
urlencode(stripslashes($value));Array $req .=
"&$key=$value";Array }Array

Come vedi inseriremo i valori nella variabile $req. Iniziamo con l'inserire il parametro
aggiuntivo (cmd=_notify-validate) ed in seguito con un ciclo foreach scorriamo
l'array POST ed inseriamo le coppie chiave valore nella variabile $req.

A questo punto siamo pronti per preparare gli headers della richiesta che faremo a
PayPal. Ma siccome in questi headers è anche contenuto l'url (che sarà PayPal in
produzione o Sandbox in simulazione), prima verifichiamo appunto in che
circostanza siamo.

Arrayif(SIMULATION)Array{Array $url =
SIMULATION_URL;Array}ArrayelseArray{Array $url =
PRODUCTION_URL;Array}Array

Ora predisponiamo gli headers ed apriamo il soket.

Array$header = "POST /cgi-bin/webscr


HTTP/1.0\r\n";Array$header .= "Host:
$url:443\r\n";Array$header .= "Content-Type:
application/x-www-form-urlencoded\r\n";Array$header .=
"Content-Length: " . strlen($req) . "\r\n\r\n";ArrayArray$fp =
fsockopen ("ssl://$url", 443, $errno, $errstr, 30);Array
Pagina 5 di 9

A questo punto possiamo inviare la richiesta e leggerne il risultato:

Arrayif (!$fp)Array{Array // HTTP ERRORArray // $errstr


- $errnoArray $this->sendReport();Array return
FALSE;Array}ArrayelseArray{Array fputs ($fp, $header .
$req);Array while (!feof($fp))Array {Array $res =
fgets ($fp, 1024);Array if (strcmp($res, "VERIFIED") ==
0)Array {Array fclose ($fp);Array
return TRUE;Array }Array else if (strcmp ($res,
"INVALID") == 0)Array {Array //se la
procedura non è legittima invia un email
all'amministratoreArray $this->sendReport();Array
fclose ($fp);Array return FALSE;Array
}Array }Array}Array

All'inizio, controlliamo che il soket sia stato veramente aperto. In caso contrario
troveremo delle indicazioni nelle variabili $errstr e $errno. Nota che stamparle a
video sarà perfettamente inutile; questa pagina infatti non sarà visualizzata da
nessuno. Eventualmente è possibile farci recapitare tramite email i valori di queste
variabili.
Noi semplicemente, utilizzeremo il metodo sendReport() che ci indicherà che la
notifica di una certa transazione ha avuto dei problemi. In seguito potremo verificare
dall'account di PayPal se vi è stato veramente il pagamento; se è tutto ok potremo
attivare manualmente l'account.

A questo punto verifichiamo la risposta. Se è VERIFIED il metodo ritorna TRUE,


altrimenti ritornerà FALSE, dopo avere inviato un email all'amministratore.

Quindi implementiamo i due metodi molto simili per verificare che la transazione sia
completa (isCompleted) e che l'email corrisponda all'email primario di PayPal (
isPrimaryEmail)

Arrayprivate function isCompleted()Array{Array


if(trim($_POST['payment_status']) === "Completed")Array
{Array return TRUE;Array }Array return
FALSE;Array}ArrayArrayprivate function
isPrimaryPayPalEmail()Array{Array if(SIMULATION)Array
{Array $email = PRIMARY_SANDBOX_EMAIL;Array }Array
elseArray {Array $email =
Pagina 6 di 9

PRIMARY_PAYPAL_EMAIL;Array }ArrayArray
if(trim($_POST['receiver_email']) === $email)Array {Array
return TRUE;Array }Array return FALSE;Array}Array

Come puoi vedere sono molto semplici. Nota che nel secondo metodo,
verifichiamo se si tratta di una simulazione o meno e a dipendenza dell'esito
procediamo con il confronto del giusto email.
Andiamo ora ad inserire i due metodi astratti, in questo modo:

Arrayabstract protected function


isVerifiedAmmount();Arrayabstract protected function
isNotProcessed();Array

Ricordo che li dichiariamo astratti in quanto la loro implementazione sarà diversa


probabilmente in ogni circostanza. Ma sappiamo comunque che ci servono e
che dovremo implementarli.

Ed ora non ci resta che definire il metodo che darà l'ok per l'attivazione dell'account
(in questo caso, più in generale darà l'autorizzazione a procedere).
Questo metodo dovrà verificare che tutti i controlli abbiano dato esito positivo.

Arrayprotected function isReadyTransaction()Array{Array


if($this->isVerifiedIPN() ANDArray
$this->isPrimaryPayPalEmail() ANDArray
$this->isNotProcessed() ANDArray
$this->isVerifiedAmmount() ANDArray
$this->isCompleted())Array {Array return
TRUE;Array }Array return FALSE;Array}Array

Bene. Abbiamo completato la nostra classe parent, che ora ti riporto:

Array<?phpArrayrequire_once 'pp_config.php';ArrayArrayabstract
class IPNListenerArray{Array private function
isVerifiedIPN()Array {Array $req =
'cmd=_notify-validate';Array foreach ($_POST as $key =>
$value)Array {Array $value =
urlencode(stripslashes($value));Array $req .=
"&$key=$value";Array }ArrayArray //Modificando
la costante SIMULATION nel file di configurazioneArray
//è possibile passare dall'ambiente di simulazione a quello di
produzioneArray if(SIMULATION)Array {Array
$url = SIMULATION_URL;Array }Array
elseArray {Array $url = PRODUCTION_URL;Array
}ArrayArray $header = "POST /cgi-bin/webscr
HTTP/1.0\r\n";Array $header .= "Host:
$url:443\r\n";Array $header .= "Content-Type:
application/x-www-form-urlencoded\r\n";Array $header .=
"Content-Length: " . strlen($req) . "\r\n\r\n";ArrayArray
$fp = fsockopen ("ssl://$url", 443, $errno, $errstr,
30);ArrayArray if (!$fp)Array {Array
// HTTP ERRORArray // $errstr - $errnoArray
$this->sendReport();Array return FALSE;Array
}Array elseArray {Array fputs
($fp, $header . $req);Array while (!feof($fp))Array
{Array $res = fgets ($fp,
1024);Array if (strcmp($res, "VERIFIED") ==
0)Array {Array fclose
($fp);Array return TRUE;Array
}Array else if (strcmp ($res, "INVALID") ==
0)Array {Array //se la
procedura non è legittima invia un email
all'amministratoreArray
$this->sendReport();Array fclose
($fp);Array return FALSE;Array
}Array }Array }Array }ArrayArray
private function sendReport()Array {Array
if(SIMULATION)Array {Array $add = "-
SIMULAZIONE -";Array }Array elseArray
{Array $add = "";Array }Array
//messaggio all'amministratoreArray $subject = "$add
Problema IPN";Array $message = "Si è verificato un
problema nella seguente transazione:\r\n\r\n";Array
$message .= "Nome: " . $_POST['first_name'] . ' ' .
$_POST['last_name'] . "\r\n";Array $message .= "email:
" . $_POST['payer_email'] . "\r\n";Array $message .=
"id transazione: " . $_POST['txn_id'] . "\r\n";Array
$message .= "oggetto: " .
$_POST['transaction_subject'];ArrayArray
mail(ADMIN_MAIL,$subject,$message,"From: " . NO_REPLY);Array
Pagina 7 di 9

return;Array }ArrayArray private function


isCompleted()Array {Array
if(trim($_POST['payment_status']) === "Completed")Array
{Array return TRUE;Array }Array
return FALSE;Array }ArrayArray private function
isPrimaryPayPalEmail()Array {ArrayArray
if(SIMULATION)Array {Array $email =
PRIMARY_SANDBOX_EMAIL;Array }Array elseArray
{Array $email = PRIMARY_PAYPAL_EMAIL;Array
}ArrayArray if(trim($_POST['receiver_email']) ===
$email)Array {Array return TRUE;Array
}Array return FALSE;Array }ArrayArray abstract
protected function isVerifiedAmmount();Array abstract
protected function isNotProcessed();ArrayArray protected
function isReadyTransaction()Array {Array
if($this->isVerifiedIPN() ANDArray
$this->isPrimaryPayPalEmail() ANDArray
$this->isNotProcessed() ANDArray
$this->isVerifiedAmmount() ANDArray
$this->isCompleted())Array {Array
return TRUE;Array }Array return
FALSE;Array }Array}Array?>Array

Conclusione

In questo articolo abbiamo visto come realizzare una classe estremamente


riutilizzabile. IPNListener fornisce tutti gli strumenti di base per procedere alle
verifiche di una notifica ed è utilizzabile indifferentemente in simulazione ed in
produzione.
Nel prossimo articolo estenderemo questa classe completandola con i metodi
specifici che ci permetteranno di aggiungere il nuovo utente a pagamento avvenuto.
L'applicazione sta iniziando a prendere forma; sei pronto per lo sprint finale?

Articoli di questa guida

1. Preparazione
2. Chiarirsi le idee
3. Le procedure generali
4. Le procedure specifiche
Pagina 8 di 9

5. Testare l'applicazione
6. Creare dinamicamente i pulsanti di pagamento

Author : Yong Mook Kim

Website : http://www.mkyong.com/blog/adsense-daemon-wordpress-plugin/ -->

Potrebbero piacerti anche