'', 'token'=>'', 'orderID'=>''); var $expressCheckoutData = array(); var $expressCheckoutDataAgg = array(); //vanno comunque attivate sul profilo del ricevente pagamento: https://www.paypal.com/merchantnotification/ipn/preference/edit, default per tnx è https://www.tnx.it/?defaultPayPalIpnUrl=cambiamiNelPannelloPayPalOViaApi //simulazione qui: https://developer.paypal.com/dashboard/ipnSimulator var $attivaIpn = false; //credenziali smart buttons var $apiUrl = 'https://api.paypal.com/'; var $clientId = 'AZ5iXj6a5M_QZHVYZ78yXFZv0spTfVhd0VGh0XA5VAbr7n2zFf3fQz8XIjI385THSxKTNk44NuL3Gv6C'; var $secret = 'EJRG_EJUT4soJHxu2RzEQ_spbAKbrzlHLhr5uluY-rr6dJT5GM7MraG4vNw3ejOm5dR0owmmYv63p88i'; //urbano bruni: // var $clientId = 'AV1lHfBQcchAuq15GqLo2GKBlim_C2UyrYPBDVriGxy7rJApWD1qJlchIZ5LwjIzokIdTXWBEhWNAEX0'; // var $secret = 'EO6GusGbI3bERIHziTW6_1jhZ51w4cJLCwtO4K1mOJ6k-xmm6EpjeAiinDDLL_ff3rVxt0WY5F_FYgMI'; var $mostraLoading = false;//mostra una pagina con la loaddingImg, utile nel caso si arrivi da un link diretto (pagamento ordinalo da app), altrimenti la schermata rimane bianca fino al completamento della prima comunicazione con i server paypal function demoInfo(){ $return = ''; // if($this->preferisci_carta) $return .= "ATTENZIONE: il paramtro che attiva l'atterraggio sulla pagina dei dati della carta non funziona su sandbox, ma funziona in produzione (ultimo test 28/4/2016). "; $return .= 'Per il pagamento usare utente: cliente@tnx.it, password: cliente@tnx.it '; if($this->usaSmartButtons) $return .= 'oppure carta 371449635398431 (altre qui 3d secure qui)'; else $return .= 'oppure carta 4111111111111111'; $return .= ' con scadenza e cvv casuali. Area venditore su www.sandbox.paypal.com utente: negoziotnx@tnx.it, password: negoziotnx.'; return $return; } function setValuta($currencyCode){ $this->valuta = $currencyCode; } function auto(){ $this->indiLingua(); if($this->demo){ //$this->debug = true; $this->account_venditore = "negoziotnx@tnx.it"; //Smart Buttons $this->apiUrl = 'https://api.sandbox.paypal.com/'; $this->clientId = 'ARhzOyG-m5Tl1HNALqsDp7oWMFFXslwlAa_Y9vcpr7Uah62FmZX3ZC4cvKcqSYUBDerdeBn3hzjHMKaB'; $this->secret = 'ENF5fYN_Bsd1SZIvV0YVFgsIOX7kgM9fD1x8be2e7Uc1dl8PRyoiD6syVFVVvrJY3sdNP-2ddT4ynvn-'; } else if($this->account_venditore == "negoziotnx@tnx.it"){ $this->account_venditore = ''; trigger_error("Tentativo di pagamento su negoziotnx@tnx.it, l'account non esiste, ma il pagamento andrebbe a buon fine, svuoto"); } $bloccaRedirect = false; if(!$this->account_venditore){ trigger_error("Indirizzo account PayPal non configurato, il pagamento arriverà a TNX"); if(is_local()) $bloccaRedirect = true; } else $this->account_venditore = trim($this->account_venditore);//con spazi il pagamento viene accettato e finisce in un limbo if($this->usaCartaAdvanced) $this->usaSmartButtons = true; switch($_GET[$this->step_var]){ default: if($this->webViewFix && !$_GET['webViewFixContent']){ //carico la pagina di paypal dentro un frame a cui imposto imposto io l'altezza //in questa maniera si riescono ad aggirare i problemi nell'uso di vh dentro le webview di titanium //CI SONO PERO' ALTRI PROBLEMI: //- PAYPAL CERCA DI MODIFICARE L'URL DELLA FINESTRA CONTENITORE, CHROME LO BLOCCCA (LA PRIMA VOLTA L'HA CONSENTITO, MA NEI TEST SUCCESSIVI NO) E LA PROCEDURA SI INTERROMPE //- DENTRO WEBVIEW SEMBRA RIUSCIRE A FARE IL REDIRECT, QUINDI DI NUOVO IL PROBLEMA VH CON PAGINA BIANCA CON //il codice sotto non è completo, ci sarebbe da monitorare l'src del frame (quindi da verificare la compatibilità di questa operazione) e cambiare l'url della pagina contenitore in modo da poter essere monitorata dal codice delle app $this->pulisciOutput(); $url = "http".(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off' ? 's' : '')."://".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI']; $url .= strpos($url, "?") !== false ? "&" : "?"; $url .= "webViewFixContent=1"; echo ' '; die; } if($this->usaSmartButtons){ if(function_exists("mod_pc_salva_servizio")) mod_pc_salva_servizio("paypal"); $agg = ''; if($this->importo >= 30 && $this->importo <= 2000) $agg .= '&enable-funding=paylater'; if($this->usaCartaAdvanced) $agg .= '&components=buttons,card-fields'; $this->Procedura->iniziato($this->nome_metodo); //'&locale='.($this->lingua=='IT'?'it_IT':'en_US'). NON FUNZIONA $url = 'www.paypal.com/sdk/js?client-id='.$this->clientId.'¤cy=EUR&disable-funding=sofort,mybank'.$agg; mod_pc_salva_servizio($url, "script"); $di = $this->demo ? $this->demoInfo() : ''; if($di) $di = '
'.$di.'
'; //https://developer.paypal.com/sdk/js/reference/ return '
'. $this->Procedura->riepilogoPagamentoHtml(). $di. '
'. ($this->usaCartaAdvanced ? '
'.$this->Procedura->htmlentities($this->Procedura->testo_oppure_paga_con_carta).'

':''). '
'; } if($this->mostraLoading){ return "
Procedura->classeDivContainer."\">".$this->Procedura->loadingImg."
" ."" // ."Procedura->genera_link_agg(array($this->step_var=>"redirect"))."\">Clicca per pagare" ; } //continua a redirect case 'redirect': $this->Procedura->iniziato($this->nome_metodo); $response = $this->SetExpressCheckout(); $token = $response['TOKEN']; if($response['L_ERRORCODE0'] == '10412'){ $e = "Questo pagamento risulta essere già stato completato sui server di PayPal"; // trigger_error($e); return $this->Procedura->errore($e); } else if(in_array($response['L_ERRORCODE0'], ['11068'/*Seller restriction*/, '10002'/*Account is locked or inactive*/]) && method_exists($this->Procedura, "autoDisattivaMetodo")){ return $this->Procedura->errore($this->Procedura->autoDisattivaMetodo($this->Procedura->metodo_scelto, $response['L_SHORTMESSAGE0'].": ".$response['L_LONGMESSAGE0'])); } else if(!$token){ trigger_error("Paypal non ha inviato il token per avviare il pagamento ".print_r($response, true), E_USER_ERROR); return $this->Procedura->errore("Problema di comunicazione con i server di PayPal, riprova tra poco"); } //https://developer.paypal.com/docs/integration/direct/payment-experience/?mark=_express-checkout#flow-configuration //https://developer.paypal.com/docs/api/payment-experience/v1/?mark=landing_page_type#definition-flow_config $url = $this->demo ? "https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&useraction=commit&token=".$token : "https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&useraction=commit&token=".$token ; if($this->debug/*$this->demo*/ || $bloccaRedirect){ return '



Qui l\'utente viene automaticamente reindirizzato a '.$url.'



'; } else{ $this->Procedura->redirect($url); return; } case 'redirect': $this->Procedura->iniziato($this->nome_metodo); $response = $this->SetExpressCheckout(); $token = $response['TOKEN']; if($response['L_ERRORCODE0'] == '10412'){ $e = "Questo pagamento risulta essere già stato completato sui server di PayPal"; // trigger_error($e); return $this->Procedura->errore($e); } else if(!$token){ trigger_error("Paypal non ha inviato il token per avviare il pagamento ".print_r($response, true), E_USER_ERROR); return $this->Procedura->errore("Problema di comunicazione con i server di PayPal, riprova tra poco"); } //https://developer.paypal.com/docs/integration/direct/payment-experience/?mark=_express-checkout#flow-configuration //https://developer.paypal.com/docs/api/payment-experience/v1/?mark=landing_page_type#definition-flow_config $url = $this->demo ? "https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&useraction=commit&token=".$token : "https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&useraction=commit&token=".$token ; if($this->debug/*$this->demo*/ || $bloccaRedirect){ return '



Qui l\'utente viene automaticamente reindirizzato a '.$url.'



'; } else{ $this->Procedura->redirect($url); return; } case 'capture': mailtnx($_SERVER['TNX_SERVER_ID']=='demo'?'c@localhost':"carlo@tnx.it", "Casistica non utilizzata", __FILE__.":".__LINE__."\n".print_r(array($_REQUEST, $_SERVER), true)); break; case 'test': $res = $this->request("v2/checkout/orders/"); break; case 'createOrder': //https://developer.paypal.com/docs/api/orders/v2/ $config = [ "intent" => "CAPTURE", "purchase_units" => [[ "custom_id" => $this->identificativo, "invoice_id" => $this->getInvoiceNumber(), "description" => $this->descrizione, "amount" => [ "value" => number_format($this->importo, 2, ".", ""), "currency_code" => "EUR" ], "payee" => [ "email_address" => $this->account_venditore ] ]], ]; //per testare errore 3d secure, attivare sotto e usare 4868719796782421 01/26 123 // $config["payment_source"] = [ // 'card' => [ // 'attributes' => [ // 'verification' => [ // 'method' => "SCA_ALWAYS" // ] // ] // ] // ]; $res = $this->request("v2/checkout/orders", $config); if(!$res["id"]) mailtnx($_SERVER['TNX_SERVER_ID']=='demo'?'c@localhost':"carlo@tnx.it", "Errore PayPal Carta Advanced", __FILE__.":".__LINE__."\n".print_r(array($res, $config, $_REQUEST, $_SERVER), true)); // print_r_tnx($res, $_SERVER['REMOTE_ADDR'] == '192.168.0.177') || die; $this->pulisciOutput(); die($res["id"]); case 'return_ok': return $this->Procedura->concluso(); case 'ipn': $ch = curl_init($this->demo ? 'https://ipnpb.sandbox.paypal.com/cgi-bin/webscr' : 'https://ipnpb.paypal.com/cgi-bin/webscr'); curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POSTFIELDS, 'cmd=_notify-validate&'.http_build_query($_POST)); curl_setopt($ch, CURLOPT_FORBID_REUSE, true); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close')); $res = curl_exec($ch); if($err = curl_error($ch) || $res != 'VERIFIED'){ if($res && $res != 'VERIFIED') $err = $res; $this->Procedura->comunicazione_s2s($this->identificativo, "Errore verifica IPN: $err\n".print_r($_POST, true)); } else{ if(in_array($_POST['txn_type'], ['recurring_payment', 'recurring_payment_profile_created']) && method_exists($this->Procedura, "ricorrenzaPayPal")) $this->Procedura->ricorrenzaPayPal($_POST); $this->Procedura->comunicazione_s2s($this->identificativo, "IPN verificata: ".print_r($_POST, true)); } return; case 'debug': print_r_tnx($this->GetExpressCheckoutDetails(), true); die; case 's2s'://in realtà è il return url dell'utente ma il pagamento viene eseguito ora tramite s2s if($this->usaSmartButtons){ $response = $this->request("v2/checkout/orders/".$_GET['orderID']."/capture"); $pagamento = $response["purchase_units"][0]["payments"]["captures"][0]; // $ok = $response["status"] == "COMPLETED";//NO! questo è COMPLETED anche se il pagamento è FAILED! $status = $pagamento["status"]; $ok = $status == "COMPLETED"; $identificativo = $ok ? $pagamento["custom_id"] : $this->identificativo; // if(!$response["payer"]) mailtnx($_SERVER['TNX_SERVER_ID']=='demo'?'c@localhost':"carlo@tnx.it", "Esito pagamento diretto con carta PayPal", __FILE__.":".__LINE__."\n".print_r(array($response), true)); // else mailtnx($_SERVER['TNX_SERVER_ID']=='demo'?'c@localhost':"carlo@tnx.it", "Esito pagamento smart button PayPal: ".$status, __FILE__.":".__LINE__."\n".print_r(array($response), true)); if($this->logFullDetails || !$ok){ $body = ""; foreach($response as $k=>$v) $body .= "\n| $k:\t$v"; $this->Procedura->comunicazione_s2s($identificativo, $body); } if($ok){ $info = "ID operazione: ".$response["id"].", ID pagamento: ".$pagamento["id"].", Status: ".$pagamento["status"].", Importo: ".$pagamento["amount"]["value"]." ".$pagamento["amount"]["currency_code"].", "; if($response["payer"]) $info .= "Account PayPal: ".$response["payer"]["email_address"]." ".$response["payer"]["name"]["given_name"]." ".$response["payer"]["name"]["surname"]." payer_id: ".$response["payer"]["payer_id"]; else $info .= "Pagamento diretto con carta senza account PayPal"; $this->Procedura->comunicazione_s2s($identificativo, $info); $this->Procedura->confermato($identificativo, $response); $url = $this->Procedura->genera_link_agg(array($this->step_var=>"return_ok", 'orderID'=>'')); if($this->debug || $bloccaRedirect){ return 'Qui l\'utente viene automaticamente reindirizzato a '.$url.''; } else{ $this->Procedura->redirect($url); return; } } else{ $message = $status; if(!$message) $message = $response["details"][0]["description"]; if(!$message) $message = $response["message"]; return $this->Procedura->errore($message); } } if($this->abbonamento){ // mail("c@localhost", "Debug", print_r(array($_GET, $_POST), true)); $details = $this->CreateRecurringPaymentsProfile(); $identificativo = $this->identificativo; if($details['PROFILEID']){ $this->Procedura->comunicazione_s2s($identificativo, "Profilo pagamenti ricorrenti creato: ".$details['PROFILEID']." ".$details['PROFILESTATUS']); //l'esito è pending comunque chiamo confermato $this->Procedura->confermato($identificativo, $details); //evito errori di refresh (doppia esecuzione confermato viene comunque evitata da $res != true) $url = $this->Procedura->genera_link_agg(array($this->step_var=>"return_ok", 'token'=>'')); if($this->debug || $bloccaRedirect){ return 'Qui l\'utente viene automaticamente reindirizzato a '.$url.''; } else{ $this->Procedura->redirect($url); return; } } else{ $body = ""; foreach($details as $k=>$v) $body .= "\n| $k:\t$v"; $this->Procedura->comunicazione_s2s($identificativo, $body); trigger_error("Abbonamento PayPal non creato: ".print_r($details, true), E_USER_ERROR); return $this->Procedura->errore($res['L_SHORTMESSAGE0']); } } else if($_GET['token']){ $doPaymentRes = $this->DoExpressCheckoutPayment(); //da DoExpressCheckoutPayment non ricevo PAYMENTREQUEST_0_CUSTOM, quindi devo fare questa seconda chiamata //vedi: http://stackoverflow.com/questions/18192535/paymentrequest-n-invnum-in-doexpresscheckoutpayment $detailsRes = $this->GetExpressCheckoutDetails(); $identificativo = $detailsRes['PAYMENTREQUEST_0_CUSTOM']; // if($doPaymentRes['PAYMENTINFO_0_ACK'] == "Success"){//nel 10/2018 in seguito a un pagamento saltato per un errore nella chiamata DoExpressCheckoutPayment ("GnuTLS recv error (-54): Error in the pull function") ho iniziato a basarmi sui dati di GetExpressCheckoutDetails (a posteriori mi rendo conto che le due chiamate hanno la stessa probabilità di fallire) - 02/2025 è successo 4 volte che GetExpressCheckoutDetails dava ok e DoExpressCheckoutPayment inveve no, ho aggiunto PAYMENTINFO_0_ACK al trigger_error per capire meglio $isOk = $detailsRes['CHECKOUTSTATUS'] == "PaymentActionCompleted"; if($this->logFullDetails || !$isOk || $doPaymentRes['PAYMENTINFO_0_ACK'] != "Success"){ if($isOk && $doPaymentRes['PAYMENTINFO_0_ACK'] != "Success"){ $isOk = false; trigger_error("La chiamata DoExpressCheckoutPayment ha restituito esisto [".$doPaymentRes['PAYMENTINFO_0_ACK']."/".$doPaymentRes['ACK']."], ma da GetExpressCheckoutDetails la transazione risulta andata a buon fine, loggo tutto e considero fallito il pagamento"); } $body = "DoExpressCheckoutPayment:"; foreach($doPaymentRes as $k=>$v) $body .= "\n| $k:\t$v"; $body .= "\nGetExpressCheckoutDetails:"; foreach($detailsRes as $k=>$v) $body .= "\n| $k:\t$v"; $this->Procedura->comunicazione_s2s($identificativo?$identificativo:$this->identificativo, $body); } if($isOk){ $this->Procedura->comunicazione_s2s($identificativo, "ID risposta: ".$detailsRes['CORRELATIONID']);//CORRELATIONID: The ID unique to this response message. PayPal recommends you log this ID. $this->Procedura->comunicazione_s2s($identificativo, "ID pagamento: ".$detailsRes['PAYMENTREQUEST_0_TRANSACTIONID']);//CORRELATIONID: The ID unique to this response message. PayPal recommends you log this ID. $this->Procedura->comunicazione_s2s($identificativo, $detailsRes['CHECKOUTSTATUS']." ".$detailsRes['AMT']." ".$detailsRes['CURRENCYCODE']." ".$detailsRes['EMAIL']." ".$detailsRes['FIRSTNAME']." ".$detailsRes['LASTNAME']); //qui c'è anche $detailsRes['PAYMENTREQUEST_0_TRANSACTIONID']; $this->Procedura->confermato($identificativo, $detailsRes);//i dettagli li uso in qualche personalizzazione di confermato() //evito errori di refresh (doppia esecuzione confermato viene comunque evitata da $doPaymentRes != true) $url = $this->Procedura->genera_link_agg(array($this->step_var=>"return_ok", 'token'=>'', 'PayerID'=>'')); if($this->debug || $bloccaRedirect){ return 'Qui l\'utente viene automaticamente reindirizzato a '.$url.''; } else{ $this->Procedura->redirect($url); return; } } else{ if($doPaymentRes['L_SHORTMESSAGE0']) return $this->Procedura->errore($doPaymentRes['L_SHORTMESSAGE0']); else return $this->Procedura->incerto(); } } else $this->Procedura->comunicazione_s2s($this->identificativo, "Chiamata pagina s2s senza token"); case 'cancel': //devo togliere il parametro token che paypal appende (altrimenti mi rimane nelle varie pagine se l'utente riprova) $url = $this->Procedura->genera_link_agg(array($this->step_var=>"", 'token'=>'', $this->Procedura->metodo_var=>'')); if($this->debug){ return 'Qui l\'utente viene automaticamente reindirizzato a '.$url.''; } else{ $this->Procedura->redirect($url); return; } case 'return_ko': return $this->Procedura->annulla(); case 'error_ajax': $postedJson = json_decode(file_get_contents("php://input")); mailtnx($_SERVER['TNX_SERVER_ID']=='demo'?'c@localhost':"carlo@tnx.it", "Errore paypal", __FILE__.":".__LINE__."\n".print_r(array($postedJson, $_REQUEST, $_SERVER), true)); $this->pulisciOutput(); die; case 'error': // mailtnx($_SERVER['TNX_SERVER_ID']=='demo'?'c@localhost':"carlo@tnx.it", "Pagina error paypal (controllare se c'è errore specifico da mostrare al cliente)", __FILE__.":".__LINE__."\n".print_r(array($postedJson, $_REQUEST, $_SERVER), true)); return $this->Procedura->errore(); } } function request($url, $data = [], $method = 'POST'){ $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $this->apiUrl.$url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); $tokenUrl = "v1/oauth2/token"; if(!$this->accessToken && $url != $tokenUrl){ $res = $this->request($tokenUrl, "grant_type=client_credentials"); if(!$res['access_token']){ trigger_error("Accss token non ricevuto ".print_r($res, true)); return; } else $this->accessToken = $res['access_token']; } $headers = []; if($url == $tokenUrl) curl_setopt($ch, CURLOPT_USERPWD, $this->clientId.":".$this->secret); else $headers[] = 'Authorization: Bearer '.$this->accessToken; if(!is_string($data)){ $headers[] = 'Content-Type: application/json'; $data = json_encode($data); if($data == "[]") $data = "{}";//se passo un array vengono settati altri header! } curl_setopt($ch, CURLOPT_POSTFIELDS, $data); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); // mailtnx( // $_SERVER['TNX_SERVER_ID']=='demo'?'c@localhost':"carlo@tnx.it", // "Debug ".microtime(true), __FILE__.":".__LINE__."\n".print_r(array( // 'url' => $this->apiUrl.$url, // 'method' => $method, // 'userpwd' => $url == $tokenUrl?$this->clientId.":".$this->secret:null, // 'headers' => $headers, // 'data' => $data, // ), true) // ); return json_decode(curl_exec($ch), true); } function indiLingua(){ switch($GLOBALS['DATI']["lang"]) { case "ita": $this->lingua = "IT"; break; case "fra": $this->lingua = "FR"; break; case "spa": $this->lingua = "ES"; break; case "ger": $this->lingua = "DE"; break; default: $this->lingua = "GB"; break; } } function merchantApiCall($method, $post){ if(!$post) $post = array(); $post = array_merge( array( //https://www.paypal.com/businessprofile/mytools/apiaccess/firstparty/signature "USER" => $this->demo?"negoziotnx_api1.tnx.it":"info_api1.tnx.it", "PWD" => $this->demo?"1376322655":"HBXXHK7CYNF5CTH9", "SIGNATURE" => $this->demo?"AFcWxV21C7fd0v3bYYYRCpSSRl31ATPQ3eH.O-bIW-YQGMRzOppjZaeG":"Aske7HoHl8zPMYtKAVFvv.nsLJ7UAJWnoiVQNFt--lIgeiP1u5Fvr1fE", //https://developer.paypal.com/webapps/developer/docs/classic/release-notes/ //ho dato un occhiata veloce fino alla 204 e non dovrebbe esserci cambiamenti particolari //quindi si sarebbe compatibili, ma neanche si userebbe le nuove feature "VERSION" => "104.00", "METHOD" => $method, ), $post ); $ch=curl_init(); //curl_setopt($curl, CURLOPT_SSLVERSION,6); // 6 is TLS 1.2 curl_setopt($ch,CURLOPT_URL,$this->demo?"https://api-3t.sandbox.paypal.com/nvp":"https://api-3t.paypal.com/nvp"); curl_setopt($ch,CURLOPT_RETURNTRANSFER,true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post));//se passo un array vengono settati altri header e non funziona! if($this->debug){ curl_setopt($ch, CURLOPT_VERBOSE, 1); $r = fopen("php://output", 'a'); curl_setopt($ch, CURLOPT_STDERR, $r); $GLOBALS["DATI"]["OUTPUT_HEADER"] = "NO";//fopen("php://output" sembra mandare degli header altrimenti da errore } $res = curl_exec($ch); if($res === false){ trigger_error("Errore di comunicazione con i server di PayPal: ".curl_error($ch), E_USER_ERROR); } parse_str($res, $response); curl_close($ch); //The magic_quotes_gpc setting affects the output of this function, as parse_str() uses the same mechanism that PHP uses to populate the $_GET, $_POST, etc. variables. foreach($response as $k=>$v){ if(is_string($v)) $response[$k] = stripslashes($v); else $response[$k] = print_r($v, true); } if($this->debug){ echo '
';
			echo '$post:
'; print_r($post); echo '$response:
'; print_r($response); //echo '
'; //non chiudo perchè va in output il dump della richiesta } if($response['ACK'] != "Success"){ //qui ci passa anche in caso di pagamento non autorizzato //trigger_error("Errore $method (merchant Api PayPal): ".$response['L_SHORTMESSAGE0']. " | ". $response['L_LONGMESSAGE0'], E_USER_ERROR); } return $response; } function SetExpressCheckout(){ $post = array_merge($this->getExpressCheckouData(), array( "SOLUTIONTYPE" => "Sole", "LANDINGPAGE" => $this->preferisci_carta ? "Billing" : "Login", "LOCALECODE" => $this->lingua, "NOSHIPPING" => intval(!$this->richiedi_indirizzo_spedizione),//ci sarebbe anche il valore 2 per forzare l'indirizzo passandolo con i parametri giusti... "ALLOWNOTE" => intval($this->richiedi_note),//ci sarebbe anche il valore 2 per forzare l'indirizzo passandolo con i parametri giusti... "RETURNURL" => $this->Procedura->genera_link_agg(array($this->step_var=>"s2s")), //viene usato anche per il bottone "TORNA AL SITO" che paypal mostra se uno pigia back essere tornato sul notro sito, quindi non va bene return_ko altrimetni viene registrato "pagamento annullato" //"URL of the original page on your website where the buyer initially chose PayPal as a payment type." //era $this->Procedura->genera_link_agg(array($this->step_var=>"return_ko")), "CANCELURL" => $this->Procedura->genera_link_agg(array($this->step_var=>"cancel")),//sono obbligato a passare da una pagina apposita perchè paypal ci appende il token )); if($this->logo_venditore_url){ if(!mt_rand(0,9)){//controllo esistenza logo $ch = curl_init($this->logo_venditore_url); curl_setopt($ch, CURLOPT_NOBODY, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, TNX_SECURE_CURL); curl_exec($ch); $retcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);// $retcode >= 400 -> not found, $retcode = 200, found. curl_close($ch); if($retcode != 200) trigger_error("Logo venditore per Paypal non trovato: ".$this->logo_venditore_url); } $post['HDRIMG'] = $this->logo_venditore_url; } return $this->merchantApiCall("SetExpressCheckout", $post); } function ignoreSetupError(){ if(in_array($_GET[$this->step_var], array('ipn'))) return true; return false; } function descrizionePulita(){ //richiedono 127 single-byte alphanumeric characters. //ma qui https://developer.paypal.com/docs/classic/api/NVPAPIOverview/ //dicono "The PayPal API assumes that all data in requests is in Unicode, specifically, the Unicode (or UCS) Transformation Format, 8-bit encoding form (UTF-8)." return substr(strip_tags($this->descrizione), 0, 127); } function getExpressCheckouData(){ //https://developer.paypal.com/webapps/developer/docs/classic/api/merchant/SetExpressCheckout_API_Operation_NVP/ //questa parte deve essere uguale in SetExpressCheckout e DoExpressCheckoutPayment $return = array( "PAYMENTREQUEST_0_SELLERPAYPALACCOUNTID" => $this->account_venditore,//nessario eprchè le credenziali api sono tnx e i soldi vanno a altri ); if($this->abbonamento){ $return = array_merge($return, array( 'L_BILLINGTYPE0' => "RecurringPayments", 'PAYMENTREQUEST_0_AMT' => "0",//Set this field to 0 if the transaction does not include a one-time purchase such as when you set up a billing agreement for a recurring payment that is not immediately charged. // 'PAYMENTREQUEST_0_NOTIFYURL' => $this->Procedura->genera_link_agg(array($this->step_var=>"s2s")),//funziona solo con DoExpressCheckoutPayment... 'L_BILLINGAGREEMENTDESCRIPTION0' => $this->descrizionePulita(),//For example, buyer is billed at "9.99 per month for 2 years". )); if($this->attivaIpn) $return['NOTIFYURL'] = $this->Procedura->genera_link_agg(array( $this->step_var=>"ipn" )); } else{ $return = array_merge($return, array( "PAYMENTREQUEST_0_PAYMENTACTION" => "Sale", "PAYMENTREQUEST_0_AMT" => number_format($this->importo, 2, ".", ""), "PAYMENTREQUEST_0_CURRENCYCODE" => $this->valuta, //"PAYMENTREQUEST_0_PAYMENTREQUESTID" => "123545",//PROBABILMENTE SERVE QUANDO FACCIO TRANSAZIONI ORDER/AUTORIZATION. se lo setto non fa più funzionare i controlli di PAYMENTREQUEST_0_INVNUM (sparisce proprio) "PAYMENTREQUEST_0_INVNUM" => $this->getInvoiceNumber(), "PAYMENTREQUEST_0_CUSTOM" => $this->identificativo,//Lo uso per il s2s. Non blocca l'ordine duplicato. Compare SOLO nel resoconto venditore come "personalizzato" "PAYMENTREQUEST_0_DESC" => $this->descrizionePulita(), ), $this->expressCheckoutDataAgg); } return $return; } function getInvoiceNumber(){ //paypal blocca i pagamenti di fatture già pagate //PayPal recommends using this field to associate transactions with your internal tracking IDs or invoice numbers; populating the invoice ID field will help you pull transaction information at a later date using only your internal ID. return $this->identificativoUnivoco ? substr($this->identificativo, 0, 255) : $this->uniqueID(256); } function GetExpressCheckoutDetails(){ $post = array_merge($this->getExpressCheckouData(), array("TOKEN" => $_GET['token'])); return $this->merchantApiCall("GetExpressCheckoutDetails", $post); } function DoExpressCheckoutPayment(){ //https://developer.paypal.com/docs/classic/api/merchant/DoExpressCheckoutPayment_API_Operation_NVP/ $post = array_merge($this->getExpressCheckouData(), array( "PAYERID" => $_GET['PayerID'], "TOKEN" => $_GET['token'], )); if($this->attivaIpn) $post['PAYMENTREQUEST_0_NOTIFYURL'] = $this->Procedura->genera_link_agg(array( $this->step_var=>"ipn", "PayerID" => '', "token" => '', )); $response = $this->merchantApiCall("DoExpressCheckoutPayment", $post); // mail("c@localhost", "Debug", print_r(array($response, $_REQUEST), true)); // if($response['PAYMENTINFO_0_ACK'] == "Success") return true; // else return $response; } function CreateRecurringPaymentsProfile(){ //https://developer.paypal.com/docs/archive/nvp-soap-api/merchant/create-recurring-payments-profile-nvp/ $post = array_merge(array( 'PROFILESTARTDATE' => strftime("%FT%TZ"),//nella documentazione è richiesta UTC/GMT *format* (php gmstrftime) ma pare sia legata ai settaggi dell'account, vedi errore attivazione piadinapiu_it tra mezzanotte e l'una ([L_SHORTMESSAGE0] => Start Date should be greater than current date [L_LONGMESSAGE0] => Subscription start date should be greater than current date) e https://www.paypal-community.com/t5/Buying-with-PayPal/Payment-date-different-from-actual-date/m-p/400192#M2509 'DESC' => $this->descrizionePulita(), "TOKEN" => $_GET['token'], "CURRENCYCODE" => $this->valuta, ), $this->abbonamento); return $this->merchantApiCall("CreateRecurringPaymentsProfile", $post); } //PRIMO TEST IN DISUSO CAUSA MANCANZA DI PERSONALIZZAZIONE RIEPILOGO ORDINE (vedi T:\lavori\ecomm paypal\Appunti Carlo.odt) /* function getAdaptivePaymentsPaymentUrl(){ $ch=curl_init(); curl_setopt($ch,CURLOPT_URL,$this->demo?"https://svcs.sandbox.paypal.com/AdaptivePayments/Pay":"https://svcs.paypal.com/AdaptivePayments/Pay"); // curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch,CURLOPT_RETURNTRANSFER,1); curl_setopt($ch, CURLOPT_HEADER, false);//esclude gli header dall'output curl_setopt($ch, CURLOPT_HTTPHEADER, array( // Sandbox API credentials for the API Caller account "X-PAYPAL-SECURITY-USERID: ".($this->demo?"negozio_api1.tnx.it":"info_api1.tnx.it"), "X-PAYPAL-SECURITY-PASSWORD: ".($this->demo?"1370356653":"HBXXHK7CYNF5CTH9"), "X-PAYPAL-SECURITY-SIGNATURE: ".($this->demo?"AhRhIGqL5d6rjS4IBLdmDN5cR8TYAoJhWO-U49A1CSUoZ.Nd0ebiZKwd":"Aske7HoHl8zPMYtKAVFvv.nsLJ7UAJWnoiVQNFt--lIgeiP1u5Fvr1fE"), "X-PAYPAL-APPLICATION-ID: ".($this->demo?"APP-80W284485P519543T":"APP-38M15417N4146200W"), // Input and output formats "X-PAYPAL-REQUEST-DATA-FORMAT: JSON",//NV/JSON "X-PAYPAL-RESPONSE-DATA-FORMAT: JSON" )); $payload = array( "actionType" => "PAY", "currencyCode" => "EUR", "receiverList" => array( "receiver" => array( array( "amount" => number_format($this->importo, 2, ".", ""), "email" => $this->account_venditore ) ) ), "memo" => $this->descrizione, //"trackingId" => "questo deve essere univoco se no non crea il pagamento", "returnUrl" => $this->genera_link_agg(array($this->step_var=>"return_ok")), "cancelUrl" => $this->genera_link_agg(array($this->step_var=>"return_ko")), "ipnNotificationUrl" => $this->genera_link_agg(array($this->step_var=>"s2s")), "requestEnvelope" => array( "errorLanguage" => "en_US", "detailLevel" => "ReturnAll" ) ); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload)); if($this->debug){ curl_setopt($ch, CURLOPT_VERBOSE, 1); $r = fopen("php://output", 'w+'); curl_setopt($ch, CURLOPT_STDERR, $r); curl_setopt($ch, CURLOPT_VERBOSE, true); } $response = curl_exec($ch); curl_close($ch); $response = json_decode($response); if($this->debug){ ?>
$response:
'; //non chiudo perchè va in output il dump della richiesta } if($response->responseEnvelope->ack != "Success"){ trigger_error("Errore creazione pagamento su PayPal: ".$response->error[0]->message, E_USER_ERROR); } return $this->demo ? "https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_ap-payment&paykey=".$response->payKey : "https://www.paypal.com/cgi-bin/webscr?cmd=_ap-payment&paykey=".$response->payKey ; } */ } ?>