API Paypal: come implementare un pagamento online? Le procedure specifiche (4/6)
Proseguiamo con la guida riguardante l’implementazione di pagamenti tramite le API Paypal. Come avrai avuto modo di leggere nei precedenti articoli, in questa guida stiamo realizzando un’applicazione grazie alla quale é possibile attivare degli account a pagamento (istant access, ovvero le risorse sono disponibili immediatamente dopo il pagamento).
Nell’articolo precedente abbiamo concluso la preparazione della classe IPNListener, la quale ci fornisce lo strumento per verificare se è possibile procedere (isReadyTransaction) all’attivazione dell’account.
Come abbiamo visto questa classe sarà utilizzabile in qualunque tipo di applicazione che necessita di un pagamento. Si tratta infatti di una raccolta di tutte le procedure necessarie alla verifica della notifica di pagamento.
Ora dovremo sviluppare il resto, ovvero la classe YIIListener che sarà un’estensione di IPNListener e conterrà i metodi che si occuperanno della creazione dell’account come pure della definizione dei metodi astratti contenuti nella classe parent.
API Paypal: La classe YIIListener per gestire il pagamento online
Creiamo il file YIIListener.php ed iniziamo ad includere IPNListenr.php, a dichiarare la classe e la proprietà $conn che conterrà la risorsa di connessione del database.
<?php require_once 'IPNListener.php'; class YIIListener extends IPNListener { protected $conn;
Ed ora scriviamo il metodo che provvederà alla connessione al database:
protected function dbConnect() { $this->conn = mysql_connect(HOST,DB_USER,DB_PASSWORD) OR die(); mysql_select_db(DB_NAME,$this->conn) OR die(); }
A questo punto implementiamo il metodo astratto isVerifiedAmmount().
Nel nostro caso sarà molto semplice. Come detto abbiamo un solo prodotto ed un solo prezzo.
Verificheremo dunque che il pagato (senza deduzione per le commissioni) corrisponda a quanto abbiamo indicato nella costante AMMOUNT.
protected function isVerifiedAmmount() { if($_POST['mc_gross'] == AMMOUNT) { return TRUE; } return FALSE; }
Ed ora procediamo ad implementare il secondo metodo astratto isNotProcessed(), che si occupa di verificare che la transazione non sia già stata processata. Per fare questo controlleremo la presenza dell’id della transazione (txn_id) nel database:
protected function isNotProcessed() { $this->dbConnect(); $sql = "SELECT * FROM utenti WHERE idTransazione=’$_POST[txn_id]’"; $res = mysql_query($sql, $this->conn); if(mysql_num_rows($res)) { return FALSE; } return TRUE; }
Ora sviluppiamo un piccolo metodo grazie al quale otterremo una password casuale da attribuire al nuovo utente.
protected function getRandPassword() { $result = ""; for($i = 0;$i < 10; $i++) { $chr = rand(40,126); $result .= chr($chr); } return $result; }
Come vedi con questo metodo andiamo a scegliere 10 caratteri casuali compresi tra il carattere 40 ed il carattere 126 del codice ASCII. Partiamo dal 40 in modo da evitare fastidiosi apici e virgolette.
Ora sviluppiamo il metodo sendLoginData() resposabile di inviare all’utente i dati del suo nuovo account. Questo metodo sarà invocato poi all’interno di un altro metodo che si occuperà di inserire il nuovo account nel database.
protected function sendLoginData($password) { if(SIMULATION) { $to = ADMIN_MAIL; $add = "- SIMULAZIONE -"; } else { $to = $_POST['payer_email']; $add = ""; } $subject = "$add Attivazione account su Your Inspiration Images"; $from = NO_REPLY; $message = "Ciao $_POST[first_name] e benvenuto su YII\r\n"; $message .= "Ecco i tuoi dati di autenticazione:\r\n\r\n"; $message .= "Nome utente: $_POST[payer_email] \r\n"; $message .= "Password: $password \r\n\r\n"; $message .= "Your Inspiration Images Team"; mail($to,$subject,$message,"From: noreply<$from>"); }
Anche in questo caso, iniziamo con il verificare se ci trovaimo in ambiente di simulazione. In caso affermativo aggiungiamo la parola simulazione all’oggetto dell’email sempre per non fare confusione. Inoltre, in simulazione, faremo in modo che l’email venga inviata a noi stessi.
Infatti, l’email dell’utente di Sandbox non esiste, o meglio può ricevere messaggi solo dall’interno.
In ogni caso non è utilizzabile. Dunque, per verificare l’effettivo e corretto invo dell’email con i dati di autenticazione, farò in modo che venga inviata a me. Mentre nell’ambiente di produzione sarà correttamente inviata al pagante (payer_email).
Siamo così giunti alla definizione dell’ultimo metodo (insertNewUser) che, dopo aver verificato la bontà della notifica, procederà all’inserimento del nuovo utente nel database ed all’invio dell’email con i dati di autenticazione.
public function insertNewUser() { if($this->isReadyTransaction()) { $password = $this->getRandPassword(); $md5password = md5($password); $sql = "INSERT INTO utenti (nome,cognome,email,username,password,idTransazione) VALUES ('$_POST[first_name]','$_POST[last_name]','$_POST[payer_email]','$_POST[payer_email]','$md5password','$_POST[txn_id]')"; mysql_query($sql,$this->conn); $this->sendLoginData($password); } }
Come prima cosa, chiaramente verificheremo l’esito del metodo isReadyTransaction(). Solo se l’esito è positivo, generiamo una password casule con il metodo getRandPassword().
Creiamo l’hash di questa password da inserire nel database.
Scriviamo la query di inserimento e la eseguiamo.
Ed infine inviamo i dati di autenticazione tramite il metodo sendLoginData() avendo cura di passare la password (in chiaro ovviamente).
Come vedi non ho fatto nessun escape delle stringhe in entrata. Infatti, a questo punto siamo certi (in quanto lo abbiamo verificato) che i dati ci arrivano da PayPal e dunque li considero dati sicuri (non credo proprio che PayPal si diverta ad inviarci delle sql injection).
Non ci resta che instanziare la classe ed invocare questo ultimo metodo. Il risultato finale sarà questo:
<?php require_once 'IPNListener.php'; class YIIListener extends IPNListener { protected $conn; protected function isVerifiedAmmount() { if($_POST['mc_gross'] == AMMOUNT) { return TRUE; } return FALSE; } protected function isNotProcessed() { $this->dbConnect(); $sql = "SELECT * FROM utenti WHERE idTransazione=’$_POST[txn_id]’"; $res = mysql_query($sql, $this->conn); if(mysql_num_rows($res)) { return FALSE; } return TRUE; } protected function dbConnect() { $this->conn = @mysql_connect(HOST,DB_USER,DB_PASSWORD) OR die(); @mysql_select_db(DB_NAME,$this->conn) OR die(); } protected function getRandPassword() { $result = ""; for($i = 0;$i < 10; $i++) { $chr = rand(40,126); $result .= chr($chr); } return $result; } protected function sendLoginData($password) { if(SIMULATION) { $to = ADMIN_MAIL; $add = "- SIMULAZIONE -"; } else { $to = $_POST['payer_email']; $add = ""; } $subject = "$add Attivazione account su Your Inspiration Images"; $from = NO_REPLY; $message = "Ciao $_POST[first_name] e benvenuto su YII\r\n"; $message .= "Ecco i tuoi dati di autenticazione:\r\n\r\n"; $message .= "Nome utente: $_POST[payer_email] \r\n"; $message .= "Password: $password \r\n\r\n"; $message .= "Your Inspiration Images Team"; mail($to,$subject,$message,"From: noreply<$from>"); } public function insertNewUser() { if($this->isReadyTransaction()) { $password = $this->getRandPassword(); $md5password = md5($password); $sql = "INSERT INTO utenti (nome,cognome,email,username,password,idTransazione) VALUES ('$_POST[first_name]','$_POST[last_name]','$_POST[payer_email]','$_POST[payer_email]','$md5password','$_POST[txn_id]')"; mysql_query($sql,$this->conn); $this->sendLoginData($password); } } } $ipn = new YIIListener(); $ipn->insertNewUser(); ?>
Questo è il file al quale dovrà puntare PayPal che avevamo genericamente chiamato lettoreIPN.php. Ora modifichiamolo con il nome e percorso corretto così come descritto all’inizio del secondo articolo di questa guida.
Conclusione
Se hai seguito correttamente gli articoli fino ad ora, il tuo sistema di pagamento realizzato sfruttanto le API PayPal dovrebbe funzionare senza problemi. Potrai eseguire il pagamento con l’utente utente ed il tutto dovrebbe funzionare. Dovrebbe. Nel prossimo articolo procederemo quindi ad un’accurata sessione di test.
Fino ad ora é tutto chiaro? Sei riuscito a seguire e a comprendere i vari passaggi anche se oggettivamente complessi?
28 commenti
Trackback e pingback
[...] This post was mentioned on Twitter by mtx_maurizio, Simone D'Amico. Simone D'Amico said: Come implementare un pagamento online: Le…
[...] Le procedure specifiche [...]
[...] Le procedure specifiche [...]