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>