Paypal – wst?p

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.

Schemat Dzia??ania IPN w p??atno??ciach paypal.com

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.

19 myśli nt. „Paypal – wst?p

  1. bim

    Bardzo fajny poradnik. W sumie ju?? na tym spokojnie mo??na oprze? swoje p??atno??ci :) wi?c o czym b?dzie druga cz????? 😛

  2. mmx3 Autor wpisu

    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.

  3. Adrian Pawlik

    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?

  4. mmx3 Autor wpisu

    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.

  5. kerszi

    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 ?)

  6. Tomek

    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

  7. mmx3 Autor wpisu

    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.

  8. mmx3 Autor wpisu

    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.

  9. mmx3 Autor wpisu

    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.

  10. wiki_nosi

    ??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

  11. Tomasz

    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);

  12. Tomasz

    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);

  13. Mugol

    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?;/

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

Możesz użyć następujących tagów oraz atrybutów HTML-a: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>