php - No se puede usar la API de Paypal en un sitio web SSL
curl paypal-sandbox (1)
Tengo un sitio web SSL con integración de Paypal API usando cURL.
Esta es mi clase en PHP incluye archivo:
class paypalApi {
public $username;
public $password;
public $signature;
function post($method, $params, $mode) {
// Method: Required
// Parameters: An array containing the requested parameters
// The request URL
$url = "https://api-3t".$mode.".paypal.com/nvp";
// Version of the API
$version = ''116.0'';
// Construct the query params
// Set the API method, version, and API credentials.
$credentials = array(''METHOD'' => $method, ''VERSION'' => $version, ''USER'' => $this->username, ''PWD'' => $this->password, ''SIGNATURE'' => $this->signature);
$params = array_merge($credentials, $params);
// Set the curl parameters.
if(function_exists(''curl_exec'')) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
// Turn off the server and peer verification (TrustManager Concept).
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
$response = curl_exec($ch);
}
if(empty($response)) {
$opts = array(''http'' =>
array(
''protocol_version'' => ''1.1'',
''method'' => ''POST'',
''header'' => ''Content-type: application/x-www-form-urlencoded'',
''content'' => http_build_query($params)
)
);
$context = stream_context_create($opts);
$response = file_get_contents($url, false, $context);
}
// Parse the response
parse_str($response, $responseArr);
// If the request fails
if(empty($responseArr) || !array_key_exists(''ACK'', $responseArr)) {
global $LNG;
// Mimic a fake response
return array(''L_SHORTMESSAGE0'' => $LNG[''error''], ''L_LONGMESSAGE0'' => $LNG[''payment_error_0''], ''ACK'' => ''REQUEST_FAILED'');
}
return $responseArr;
}
}
Por alguna razón, no funciona, al hacer clic en el botón de pago se lleva al usuario a Paypal, pero después de finalizar el proceso, el usuario regresa al sitio web, la URL parece correcta (por ejemplo, https://example.com/pro&type=successful?token=EC-8BB04791XJ708490K&PayerID=QL54Q696KZCLA
) pero sin realizar el pago.
Probé la caja de arena también, pero no puedo ver ningún error en el archivo de registro de Apache, así que tengo que depurar $response
, por esta razón intenté agregar echo var_dump($response);
antes de analizar la respuesta.
Pero no tengo mucha experiencia en la depuración, y en Chrome no sé dónde verificar la respuesta (en la consola JS no puedo verla)
¿Cómo podría depurar esta respuesta de API para verificar por qué PayPal no permite pagos para mi sitio web? (el sitio web ya está verificado)
ACTUALIZAR
Como autenticación, estoy usando el formato NVP de la firma API con el método SetExpressCheckout
.
Este es el código de mi respuesta:
// Execute SetExpressCheckOut method to create the payment token and PayerID
$paypalResponse = $paypal->post(''SetExpressCheckout'', $params, $PayPalMode);
//Respond according to message we receive from Paypal
if(strtoupper($paypalResponse["ACK"]) == "SUCCESS") {
// Generat the PayPal payment url with the response Token
$paypalurl = ''https://www''.$PayPalMode.''.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=''.$paypalResponse["TOKEN"].'''';
// Redirect to PayPal payment page
header(''Location: ''.$paypalurl);
// Execute DoExpressCheckoutPayment to receive the payment from the user
$paypalResponse = $paypal->post(''DoExpressCheckoutPayment'', $params, $PayPalMode);
// Check if the payment was successful
if(strtoupper($paypalResponse["ACK"]) == "SUCCESS") {
// Verify if the payment is Completed
if($paypalResponse["PAYMENTINFO_0_PAYMENTSTATUS"] == ''Completed'') {
// Execute GetExpressCheckoutDetails to retrieve the transaction details
$params = array(''TOKEN'' => $token);
$paypalResponse = $paypal->post(''GetExpressCheckoutDetails'', $params, $PayPalMode);
// If the GetExpressCheckoutDetails was successful
if(strtoupper($paypalResponse["ACK"]) == "SUCCESS") {
$date = date("Y-m-d H:m:s", strtotime(($_SESSION[''SelectedPlan''] == 1 ? "+1 year" : "+1 month")));
$stmt = $db->prepare(sprintf("INSERT INTO `payments`
(`by`, `payer_id`, `payer_first_name`, `payer_last_name`, `payer_email`, `payer_country`, `txn_id`, `amount`, `currency`, `type`, `status`, `valid`, `time`) VALUES
(''%s'', ''%s'', ''%s'', ''%s'', ''%s'', ''%s'', ''%s'', ''%s'', ''%s'',''%s'', ''%s'', ''%s'', ''%s'')",
$db->real_escape_string($feed->id), $db->real_escape_string($paypalResponse[''PAYERID'']), $db->real_escape_string($paypalResponse[''FIRSTNAME'']), $db->real_escape_string($paypalResponse[''LASTNAME'']), $db->real_escape_string($paypalResponse[''EMAIL'']), $db->real_escape_string($paypalResponse[''SHIPTOCOUNTRYNAME'']), $db->real_escape_string($paypalResponse[''PAYMENTREQUEST_0_TRANSACTIONID'']), $db->real_escape_string($paypalResponse[''AMT'']), $settings[''currency''], $_SESSION[''SelectedPlan''], 1, $date, date("Y-m-d H:m:s")));
// Execute the statement
$stmt->execute();
// Check the affected rows
$affected = $stmt->affected_rows;
// Close the statement
$stmt->close();
// If the pro status has been added
if($affected) {
// Set the pro account to valid
$proAccount = 2;
}
} else {
$TMPL[''error''] = notificationBox(''error'', ''<strong>''.urldecode($paypalResponse[''L_SHORTMESSAGE0''].''</strong>: ''.$paypalResponse[''L_LONGMESSAGE0'']));
}
} else {
$TMPL[''error''] = notificationBox(''error'', ''<strong>''.urldecode($paypalResponse[''L_SHORTMESSAGE0''].''</strong>: ''.$paypalResponse[''L_LONGMESSAGE0'']));
}
} else {
$TMPL[''error''] = notificationBox(''error'', ''<strong>''.urldecode($paypalResponse[''L_SHORTMESSAGE0''].''</strong>: ''.$paypalResponse[''L_LONGMESSAGE0'']));
}
}
EDITAR
Este es mi archivo error.log:
* Hostname was NOT found in DNS cache
* Trying 173.0.82.83...
* Connected to api-3t.sandbox.paypal.com (173.0.82.83) port 443 (#0)
* successfully set certificate verify locations:
* CAfile: none
CApath: /etc/ssl/certs
* SSL connection using ***********************
* Server certificate:
* subject: C=US; ST=California; L=San Jose; O=PayPal, Inc.; OU=PayPal Production; CN=api-3t.sandbox.paypal.com
* start date: 2015-09-16 00:00:00 GMT
* expire date: 2016-10-31 23:59:59 GMT
* issuer: C=US; O=VeriSign, Inc.; OU=VeriSign Trust Network; OU=Terms of use at https://www.verisign.com/rpa (c)10; CN=VeriSign Class 3 Secure Server CA - G3
* SSL certificate verify ok.
> POST /nvp HTTP/1.1
Host: api-3t.sandbox.paypal.com
Accept: */*
Content-Length: 862
Content-Type: application/x-www-form-urlencoded
* upload completely sent off: 862 out of 862 bytes
< HTTP/1.1 200 OK
< Date: Wed, 30 Dec 2015 09:49:59 GMT
* Server Apache is not blacklisted
< Server: Apache
< X-PAYPAL-OPERATION-NAME: SetExpressCheckout
< X-PAYPAL-API-RC:
< Connection: close
< Content-Length: 138
< Paypal-Debug-Id: 7d9949c818525
< Set-Cookie: X-PP-SILOVER=name%3DSANDBOX3.API.1%26silo_version%3D880%26app%3Dappdispatcher_apit%26TIME%3D3349709654; domain=.paypal.com; path=/; Secure; HttpOnly
< Set-Cookie: X-PP-SILOVER=; Expires=Thu, 01 Jan 1970 00:00:01 GMT
< Content-Type: text/plain; charset=utf-8
* Closing connection 0
2nd EDIT
Finalmente pude depurar la respuesta (hubo un problema de redirección)
TOKEN=EC-9F8624569H0752611
BILLINGAGREEMENTACCEPTEDSTATUS=0
CHECKOUTSTATUS=PaymentActionCompleted
TIMESTAMP=2015-12-30T15:41:54Z
CORRELATIONID=19204729b140
ACK=Success
VERSION=116.0
BUILD=18308778
[email protected]
PAYERID=QL54Q696KZCLA
PAYERSTATUS=verified
FIRSTNAME=test
LASTNAME=buyer
COUNTRYCODE=IT
SHIPTONAME=test buyer
SHIPTOSTREET=Via Unit? d/'Italia, 5783296
SHIPTOCITY=Napoli
SHIPTOSTATE=NAPOLI
SHIPTOZIP=80127
SHIPTOCOUNTRYCODE=IT
SHIPTOCOUNTRYNAME=Italy
ADDRESSSTATUS=Unconfirmed
CURRENCYCODE=EUR
AMT=4.00
ITEMAMT=4.00
SHIPPINGAMT=0.00
HANDLINGAMT=0.00
TAXAMT=0.00
INSURANCEAMT=0.00
SHIPDISCAMT=0.00
L_NAME0=Monthly Pro Plan - example subdirectory
L_NUMBER0=cfcd208495d565ef66e7dff9f98764da
L_QTY0=1
L_TAXAMT0=0.00
L_AMT0=4.00
L_DESC0=Monthly Pro Plan - example subdirectory
L_ITEMWEIGHTVALUE0= 0.00000
L_ITEMLENGTHVALUE0= 0.00000
L_ITEMWIDTHVALUE0= 0.00000
L_ITEMHEIGHTVALUE0= 0.00000
PAYMENTREQUEST_0_CURRENCYCODE=EUR
PAYMENTREQUEST_0_AMT=4.00
PAYMENTREQUEST_0_ITEMAMT=4.00
PAYMENTREQUEST_0_SHIPPINGAMT=0.00
PAYMENTREQUEST_0_HANDLINGAMT=0.00
PAYMENTREQUEST_0_TAXAMT=0.00
PAYMENTREQUEST_0_INSURANCEAMT=0.00
PAYMENTREQUEST_0_SHIPDISCAMT=0.00
PAYMENTREQUEST_0_TRANSACTIONID=61M42051UB346361T
PAYMENTREQUEST_0_INSURANCEOPTIONOFFERED=false
PAYMENTREQUEST_0_SHIPTONAME=test buyer
PAYMENTREQUEST_0_SHIPTOSTREET=Via Unit? d/'Italia, 5783296
PAYMENTREQUEST_0_SHIPTOCITY=Napoli
PAYMENTREQUEST_0_SHIPTOSTATE=NAPOLI
PAYMENTREQUEST_0_SHIPTOZIP=80127
PAYMENTREQUEST_0_SHIPTOCOUNTRYCODE=IT
PAYMENTREQUEST_0_SHIPTOCOUNTRYNAME=Italy
PAYMENTREQUEST_0_ADDRESSSTATUS=Unconfirmed
PAYMENTREQUEST_0_ADDRESSNORMALIZATIONSTATUS=None
L_PAYMENTREQUEST_0_NAME0=Monthly Pro Plan - example subdirectory
L_PAYMENTREQUEST_0_NUMBER0=cfcd208495d565ef66e7dff9f98764da
L_PAYMENTREQUEST_0_QTY0=1
L_PAYMENTREQUEST_0_TAXAMT0=0.00
L_PAYMENTREQUEST_0_AMT0=4.00
L_PAYMENTREQUEST_0_DESC0=Monthly Pro Plan - example subdirectory
L_PAYMENTREQUEST_0_ITEMWEIGHTVALUE0= 0.00000
L_PAYMENTREQUEST_0_ITEMLENGTHVALUE0= 0.00000
L_PAYMENTREQUEST_0_ITEMWIDTHVALUE0= 0.00000
L_PAYMENTREQUEST_0_ITEMHEIGHTVALUE0= 0.00000
PAYMENTREQUESTINFO_0_TRANSACTIONID=61M42051UB346361T
PAYMENTREQUESTINFO_0_ERRORCODE=0
Entonces, por mi parte, todo funciona ahora, pero no veo transacciones en Sandbox Paypal. ¿Qué pasa?
Tu proceso parece muy intrincado. Vamos a romper esto
// Execute SetExpressCheckOut method to create the payment token and PayerID
$paypalResponse = $paypal->post(''SetExpressCheckout'', $params, $PayPalMode);
//Respond according to message we receive from Paypal
if(strtoupper($paypalResponse["ACK"]) == "SUCCESS") {
// Generat the PayPal payment url with the response Token
$paypalurl = ''https://www''.$PayPalMode.''.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=''.$paypalResponse["TOKEN"].'''';
// Redirect to PayPal payment page
header(''Location: ''.$paypalurl);
Hasta aquí todo bien. Usted hace su llamada SEC, obtiene su token y pasa el usuario a PayPal. Pero luego esta siguiente parte es confusa
// Execute DoExpressCheckoutPayment to receive the payment from the user
$paypalResponse = $paypal->post(''DoExpressCheckoutPayment'', $params, $PayPalMode);
// Check if the payment was successful
if(strtoupper($paypalResponse["ACK"]) == "SUCCESS") {
Esto no tiene ningún sentido. Acabas de devolver al usuario a PayPal con un header
y estamos llamando a esto con lo que parece ser los mismos datos que pasamos a la llamada SEC. DoExpressCheckoutPayment
requiere que devuelva el token y el usuario acaba de abandonar el sitio para autorizarlo. Esperaría ver su código buscar $_GET[''TOKEN'']
(es decir, el usuario devuelto desde PayPal) y luego crear una nueva solicitud para eso. En este momento, como está escrito su código, solo está encadenando las 3 llamadas en una cadena gigante.
Esto es lo que debería parecer el proceso
-
SetExpressCheckout
- Rebote al usuario a PayPal. Detener el procesamiento -
GetExpressCheckoutDetails
: el usuario ha regresado de PayPal porque tenemos un TOKEN en la cadena de consulta. Ejecutar esta llamada ahora nos permite asegurarnos de que TOKEN sea válido -
DoExpressCheckoutPayment
: siDoExpressCheckoutPayment
es válido, completemos la venta.
Por último, pero no menos importante, no puedes simplemente buscar el éxito . Lea los documentos en ACK . También puede obtener SuccessWithWarning . Cambie su condición de éxito a
if(stripos($paypalResponse["ACK"], "SUCCESS") !== false) {