Do napisania tego oto tutorialu zmotywowa??y mnie wiele rzeczy po pierwsze w polskim internecie nie ma zbyt wiele na temat p??atno??ci paypal’em. Znalaz??em na kilku forach zapytania na ten temat. Z czego sam jedno napisa??em na forum.php.pl. Drug? przes??ank? kt??ra u??wiadomi??a, ??e paypal zaczyna zdobywa? polski rynek p??atno??ci online jest fakt umowy jak? paypal.com podpisa?? z p??atno??ci.pl i ju?? nied??ugo b?dziemy mogli si? cieszy? p??aceniem za us??ugi i produkty w ten wygodny spos??b. Kolejn? spraw?, kt??ra pokaza??a mi jak bardzo szkodliw? rzecz? mo??e by? nieumiej?tne korzystanie z „Buy Now” (tych nie kodowanych) gdzie wystarczy ze ??r??d??a strony wyci??:
<input type="hidden" name="return" value="url_po_udanej_transakcji" />
by uzyska? dost?p do zasobu kt??ry chcemy kupi?. Nast?pny fakt wyp??yn??? na ??wiat??o dzienne gdy sam pisa??em obs??ug? IPN na Paypal’u i zobaczy??em, ??e nawet tutorial’e i przyk??ady na stronie developer center @ paypal maj? b???dy(mnie szczeg??lnie ineteresowa?? ten do php4). A Koniec ko??c??w w poszukiwaniu gotowych rozwi?za?? tj. klas, funkcji kt??re mog??y by zaspokoi? moje potrzeby. Znalaz??em dwa takie rozwi?zania. Pierwsze z nich na phpclasses.org by??o mocno rozbudowane i zabezpieczone szyfrowaniem. Jednak mia??o jedn? podstawow? wad? wymaga??o „doklejenia” kolejnych 3 du??ych bibliotek. Natomiast drugie z nich po wst?pnych testach okaza??o si? nie dzia??a? tak jak bym chcia??, wi?c postanowi??em napisa? co?? w??asnego.
Tyle s??owem wst?pu teraz przedstawie czego b?dziemy potrzebowa? do wdro??enia p??atno??ci paypal’em na naszej stronie.
Po pierwsze do test??w paypal udost?pnia nam sandbox. ??eby do owej „piaskownicy” uzyska? dost?p trzeba za??o??y? sobie konto na: developer.paypal.com . Po za??o??eniu konta i potwierdzeniu prawdziwo??ci skrzynki e-mail. Mamy mo??liwo??? za??o??enia kont testowych. B?d? nam potrzebne takie dwa: pierwsze buissnes account do testowania p??atno??ci i wygenerowania kodu button??w na, kt??rych b?dziemy testowali nasze rozwi?zania, drugie natomiast kupuj?cego po to by zbada? sam proces dokonywania p??atno??ci.
Uwaga! wa??ne do testowania p??atno??ci na sandbox’ie wymaga bycia zalogowanym na developer.paypal.com
Aby zrozumie? temat bardziej sp??jrzmy na poni??szy schemat.
Dla klienta zasada jest prosta. Rejestruje si? na naszej stronie. Op??aca us??ug? np. abonament na dost?p do poprzednich wyda?? naszego magazynu w plikach pdf po przez klikni?cie Buy Now. Jest przekierowany na strone paypal’a gdzie loguje si? na swoje konto lub p??aci kart? p??atnicz?. Po pozytywnym zako??czeniu transakcji wraca na nasz? stron? z podzi?kowaniami tzw „return”. Paypal gubi ka??d? sesje wi?c nie ma co liczy? na jej odzyskanie po powrocie. Rozwi?zaniem najprostszym jest odes??anie klienta po podzi?kowaniu do formularza logowania.
Serwer paypala opr??cz tego. ??e przeprowadza ca??? transakcje i odpowiedzialno??? za wpisane tam poufne dane takie jak numer karty kredytowej s? po jego stronie. To jeszcze przekazuje nam dane na temat transakcji za po??rednictwem IPN(instant payment notification). Dzieje si? to w nast?puj?cy spos??b. Po dokonaniu wp??aty na paypalu wysy??a do naszego skryptu na adres podany w:
<input type="hidden" name="notify_url" value="url_do_skryptu_obs??uguj?cego_ipn" />
przekazuje nam pule zmiennych metod? POST min.
$invoice = $_POST['invoice']; $receiver_email = $_POST['receiver_email']; $item_name = $_POST['item_name']; $item_number = $_POST['item_number']; $quantity= $_POST['invoice']; $payment_status = $_POST['payment_status']; $pending_reason = $_POST['pending_reason']; $payment_date = $_POST['payment_date']; $payment_gross = $_POST['payment_gross']; $payment_fee = $_POST['payment_fee']; $payment_amount = $_POST['mc_gross']; $payment_currency = $_POST['mc_currency']; $txn_id = $_POST['txn_id']; $txn_type = $_POST['txn_type']; $first_name = $_POST['first_name']; $last_name = $_POST['last_name']; $address_street = $_POST['address_street']; $address_city = $_POST['address_city']; $address_state = $_POST['address_state']; $address_zip = $_POST['address_zip']; $address_country = $_POST['address_country']; $payer_email = $_POST['payer_email']; $address_status = $_POST['address_status']; $payment_type = $_POST['payment_type']; $notify_version = $_POST['notify_version']; $verify_sign =$_POST['verify_sign'];
Dzi?ki tym zmiennym mo??emy po pierwsze rozpozna? czy p??atno??? zosta??a zako??czona powodzeniem:
$_POST['payment_status'] == "succes"
Oraz pozna? bli??ej dane naszego klienta. Jego dane jakie poda?? na naszej stronie mog? si? r????ni? od tych danych jakie widniej? na paypalu. Mo??emy je wykorzysta? jako powi?kszenie naszej bazy do mailing??w z promocjami, b?d?? zachowa? je tylko po to by rejestrowa? sprzeda?? prowadzon? na naszej stronie.
Jednak zanim obs??u??ymy otrzymane ???danie musimy sprawdzi? czy aby na pewno pochodzi z paypal’a. Wystarczy z??o??y? wszystkie zmienne przekazane postem w ci?g znak??w typu zmienna1=5&zmienna2=6&….. itd. Jednak zanim to jednak zrobimy musimy doda? na samym pocz?tku komend?, kt??ra poinformuje paypal, ??e chcemy dokona? potwierdzenia czy takie ???danie zosta??o wys??ane przez paypal czy te?? nie. Zrobimy to nast?puj?cym kodem:
$req = 'cmd=_notify-validate'; //dok??adamy komend? z pro??b? o potwierdzenie tego powiadomienia o p??atno??ci foreach ($_POST as $key => $value) { $value = urlencode($value); $req .= "&$key=$value"; } //zmienna req teraz przechowuje wszystkie zmienne z $_POST w postaci kt??r? opisywa??em wcze??niej
Nast?pnie wystarczy wys??a? takie zapytanie do serwera paypala. S? dwie szko??y wysy??ania, albo fsockopen() albo za pomoc? klasy cURL. Oba s? poprawne. Ja zaprezentuje fragment kodu wykorzystuj?cy pierwsz? z nich.
$header .= "POST /cgi-bin/webscr HTTP/1.0\r\n"; // ustawiamy nag????wki zapytania. $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; $header .= "Content-Length: " . strlen($req) . "\r\n\r\n"; // w tej linii zamieszczamy d??ugo??? naszego zapytania $fp = fsockopen (paypal_adr, 80, $errno, $errstr, 30); //sta??a paypal_adr jest adresem na kt??ry wysy??amy nasze zapytanie z pro??b? o validacje
Sta??a paypal_adr mo??e mie? dwie warto??ci: pierwsz? testow? https://www.sandbox.paypal.com lub drug? ju?? w pe??ni funkcjonaln? https://www.paypal.com czasami pojawia si? problem z https:// poniewa?? niekt??re serwery nie maj? skonfigurowanego portu.
Otwarli??my deskryptor portu $fp. Teraz musimy wys??a? nasze dane do validacji.
if (!$fp) { // sprawdzamy czy wszystko ok z naszym po???czeniem je??eli nie jest to deskryptor przyjmuje warto??? false // tutaj mo??emy napisa? obs??ug? HTTP ERROR } else { fputs ($fp, $header . $req); // je??eli deskryptor jest ok to wysy??amy mu nasze nag????wki po???czone z zapytaniem o validacje powiadomienia
Je??eli ju?? wys??ali??my nasz? pro??be o potwierdzenie ???dania teraz musimy obs??u??y? odpowied?? serwera paypal, kt??ry zwr??ci nam string z informacj? czy wszystko posz??o tak jak powinno czy te?? to odwo??anie by??o tylko pr??b? wy??udzenia od nas towaru.
Zatem zaczynamy od odczytania odpowiedzi do p??ty do p??ki nie dostaniemy znaku ko??ca pliku. Kod kt??ry si? tym zajmie mo??e wygl?da? tak:
while (!feof($fp)) { $res = fgets ($fp, 1024);
Otrzymali??my wi?c ju?? ca??? zawarto??? odpowiedzi i przechowujemy j? w zmiennej $res. Teraz trzeba by by??o sprawdzi? czy ta p??atno??? jest potwierdzona czy te?? nie. Do tego pos??u??y nam funkcja kt??ra por??wnuje binarnie dwa ci?gi znak??w strcmp(). Je??eli oba por??wnywane ci?gi s? identyczne to funkcja zwraca 0. Kod, kt??ry sprawdzi odpowied?? m??g?? by wygl?da? tak:
if (strcmp($res, "VERIFIED")==0) { //Sprawdzamy czy transakcja ma status jako zako??czona if (strcmp ($payment_status, "Completed") == 0) { //je??eli tak to mo??emy spokojnie dalej przetwarza? dane } }else if(strcmp($res, "INVALID")==0){ // mo??emy zarejstrowa? do pliku wszystkie pr??by atak??w na nasz serwis np. tak: $fplog = fopen('ipnlog.txt','a'); fwrite($fplog, gmstrftime ("%b %d %Y %H:%M:%S", time())." -- ".$res." -- ".$req."\n"); fclose($fplog); }
Zatem wiecie ju?? na jakiej zasadzie mo??na obs??ugiwa? IPN otrzymany od paypal’a. Nie taki diabe?? straszny jak si? okazuje. Jednak mi on napsu?? sporo krwi. Ci?g dalszy wkr??tce nast?pi jak tylko znajd? troch? czasu.
Bardzo fajny poradnik. W sumie ju?? na tym spokojnie mo??na oprze? swoje p??atno??ci
wi?c o czym b?dzie druga cz????? 😛
Rozpisa??e?? si?;)
Druga cz???? b?dzie opowiada??a o dowi?zywaniu tabeli p??atno??ci do tabeli produkt??w. No i mo??e b?dzie jaki?? d??u??szy listing z ca??ym ??r??d??em.
Dlaczego Buy Now ma byc takie niebezpieczne? A co ma znajomosc adresu do bezpieczenstwa? Nie mozna zwyczajnie sprawdzic remote address / referer i odrzucac hosty inne niz paypal?
Poniewa?? parametr return z wy???czon? transmisj? danych prowadzi zazwyczaj do udost?pnionego zasobu. ?atwo mo??na to obej??? wyci?gaj?c ten parametr z formularza. Kolejn? kwesti? jest wygoda. Jak np. prowadzimy sprzeda?? wysy??kow? to po co za ka??dym razem logowa? si? na paypalu i sprawdza? czy p??atno??? dotar??a i wszystko jest ok. Trzeba u??atwia? sobie ??ycie :). Pozrawiam.
robie paypal w trybie testowym , i jezeli na poczatku w formularzu
nie dam
to mi nie wraca na wymagana stronke, a jezeli
juz zwroci przez POST wartosci, to w $payment_status
mam wiecznie „pending” zamiast „Completed”.
mam pytanko, czy koniecznie musze ustawiac i nie wiem
czemu nie zwraca mi completed
w profilu ze mam wlaczony IPN, i podawac stronke ..
(np co zrobic w wypadku kiedy z paru stronek
chce sie polaczyc ?)
Czesc,
Bardzo fajny artyku??. Mam ma??e pytanie odno??nie niego.
Mam stronk? do kt??rej loguj? si? u??ytkownicy systemu.
Oferuje im kupno pewnych rzeczy poprzez system paypal.
W jaki sposob zmapowa? dana tranzakcje na danego u??ytkownika ?
Przychodzi mi powiadomienie ze tranzakcja zakonczyla sie pomy??lnie, ale teraz chcia??bym dla danego u??ytkownia od??wie??yc dane na stronce np. ze dokonal zakupu i co kupi??.
Pozdr. Tomek
kerszi: W sandboxie p??atno??ci wykonywane inn? walut? ni?? USD zawsze s? pending, nie wiadomo dla czego mia??em dok??adnie ten sam problem z euro. W produkcyjnej wersji ju?? wszystko jest ok.
Je??eli to jest chocia?? troszk? zbli??one do typowego sklepu internetowego to mo??na to zrobi? tak. (Mowa o rejestrowaniu zam??wie??/koszyka powi?zanych relacja n-1 z tabel? u??ytkownik??w).
Potem mo??esz ustali? jaki to u??ytkownik na podstawie zapytania sql z prost? relacj? lub inner join’em. Tylko musisz zapisywa? i blokowa? zam??wienia ??eby user nie m??g?? zap??aci? tyle samo za wi?cej produkt??w. Jest to proste do napisania.
Je??eli to jest chocia?? troszk? zbli??one do typowego sklepu internetowego to mo??na to zrobi? tak. (Mowa o rejestrowaniu zam??wie??/koszyka powi?zanych relacja n-1 z tabel? u??ytkownik??w).
Potem mo??esz ustali? jaki to u??ytkownik na podstawie zapytania sql z prost? relacj? lub inner join’em. Tylko musisz zapisywa? i blokowa? zam??wienia ??eby user nie m??g?? zap??aci? tyle samo za wi?cej produkt??w. Jest to proste do napisania.
To mi by??o potrzebne! Dzi?kuj?!
??wietny artyku??. Gratulacje dla autora.
Mimo szczerych ch?ci, ci???ko by??o przej??? przez dokumentacje PayPal – jest za du??a, zagmatwana i og??lnie beznadziejna. Nadmieni?, ??e nie jestem ca??kowitym laikiem w temacie – obs??u??y??em Przelewy24, SMS DoaPay, SMS DotPay, SMS OneBip – a przez PayPala przej??? nie mog??em.
Jeszcze raz gratulacje – pewnie wiele osobom u??atwi??e?? ??ycie
tutaj http://phpweby.com/software/php-paypal jest fajna biblioteka PHP do obs??ugi IPN – Paypal.
Dodam co?? od siebie – je??eli sandbox zwraca komu?? VERIFIED to trzeba u??y?:
$paypalurl=’www.sandbox.paypal.com';
$fp = @ fsockopen(‚ssl://’.$this->paypalurl, „443”, $errNum, $errStr, 30);
Dodam co?? od siebie ?? je??eli sandbox nie zwraca komu?? VERIFIED to trzeba u??y?:
$paypalurl=??www.sandbox.paypal.com??;
$fp = @ fsockopen(??ssl://??.$this->paypalurl, ??443??, $errNum, $errStr, 30);
Witam
Artyku?? okaza?? sie bardzo pomocny musia??em tylko troch? zmodyfikow?? kod:
$header = ”;
$header .= „POST /cgi-bin/webscr HTTP/1.0\r\n”;
$header .= „Host: http://www.paypal.com\r\n”;
$header .= „Content-Type: application/x-www-form-urlencoded\r\n”;
$header .= „Content-Length: ” . strlen($req) . „\r\n\r\n”;
i adres wysy??ki:
$paypal_adr = ‚ssl://www.paypal.com';
czyli doda??em linijk? $header .= „Host: http://www.paypal.com\r\n”;
i posz??o a dok??adnie prawie posz??o:)
Wszystko jest w porz?dku w przypadku p??atno??ci EUR ale przy PLN wszystkie wracaj? jako INVALID wie kto?? mo??e dlaczego? Bo ju?? troch? g??upieje.
I druga sprawa po przej??ciu na strone paypala (aby dokonac p??atno??ci) w informacji o zamowieniu nie ma poskich znak??w tylko krzaki
Funkcja wywoluj?ca to chyba to:
function pay(){
#Convert the array to url encode variables
$vars = http_build_query($this->config);
if($this->config[‚production’] == TRUE){
header(‚LOCATION:’.$this->production_url.$vars);
}else{
header(‚LOCATION:’.$this->sandbox_url.$vars);
}
}
Strona sklepu kodowana w utf-8 , nie wiem za bardzo czy do paypala nie powinno byc inne kodowanie albo czy nie trzeba go zadeklarow?? przed wysy??k?;/
Dzi?ki wielkie. Tutorial ma ju?? kilka lat. Pewnie si? troch? pozmienia??o.
Witam. Mi ten skrypt wcale nie dzia??a. Adres testowego formularza to http://ekasiora.pl/ipn/pp.html prosz? o pomoc
Testowy formularz te?? nie dzia??a 😉