'PPConnectionException' exception is thrown in PayPal adaptive Payment 'Pay' request - php

I have integrated PayPal adaptive payments in my one of the WordPress plugin. My functionality is fully ready and was working well till yesterday. However, when I started with a final testing, I got stuck with this exception -
PPConnectionException Object ( [url:PPConnectionException:private] => https://svcs.sandbox.paypal.com/AdaptivePayments/Pay [data:PPConnectionException:private] => [message:protected] => error:1408F10B:SSL routines:SSL3_GET_RECORD:wrong version number
........) //I am just pasting necessary piece of error to understand the problem
I have used this library - https://github.com/paypal/adaptivepayments-sdk-php
I am testing it under sandbox environment.
The problem seems to have with OpenSSL or cURL.
I searched for the solution a lot but did not find any helpful answer.
I am also pasting a sample code below (this is for 'parallel' payment method, but neither this nor other methods work) -
require_once('../PPBootStrap.php');
require_once('../Common/Constants.php');
define("DEFAULT_SELECT", "- Select -");
if(isset($_POST['receiverEmail'])) {
$receiver = array();
/*
* A receiver's email address
*/
for($i=0; $i<count($_POST['receiverEmail']); $i++) {
$receiver[$i] = new Receiver();
$receiver[$i]->email = $_POST['receiverEmail'][$i];
/*
* Amount to be credited to the receiver's account
*/
$receiver[$i]->amount = $_POST['receiverAmount'][$i];
/*
* Set to true to indicate a chained payment; only one receiver can be a primary receiver. Omit this field, or set it to false for simple and parallel payments.
*/
$receiver[$i]->primary = $_POST['primaryReceiver'][$i];
}
$receiverList = new ReceiverList($receiver);
}
$payRequest = new PayRequest(new RequestEnvelope("en_US"), $_POST['actionType'], $_POST['cancelUrl'], $_POST['currencyCode'], $receiverList, $_POST['returnUrl']);
// Add optional params
if($_POST["memo"] != "") {
$payRequest->memo = $_POST["memo"];
}
$service = new AdaptivePaymentsService(Configuration::getAcctAndConfig());
try {
/* wrap API method calls on the service object with a try catch */
$response = $service->Pay($payRequest);
} catch(Exception $ex) {
require_once '../Common/Error.php';
/*******
***************************************************
PLEASE NOTE: the code is breaking here, an exception is thrown
***************************************************
*******/
exit;
}
$_POST data are passed from another file.
I have integrated the above code in my plugin (in WordPress way). In fact, if I run above functionality directly in a separate PHP file, even that does not work. So, its clear that the problem is something else. The problem seem to have with connection with PayPal and my server.
I am not getting, all the things were working till yesterday, but suddenly has stopped working. Also, nothing has been updated related to openssl, cURL or PHP on my server.
Any help would be greatly appreciated. Thanks !!!
EDIT:
Changing the openssl version number solves the issue. However, I am still concerned which among version number 1 and 4 is proper and will work in future.
Also, is there any security issue concerned when changing the value from 3 to something else?
If anyone could clarify this, it would be great. Thanks again.

I had the same problem. Seems as though PayPal made some changes yesterday in response to a security issue. Downloading the new version of PayPal PHP SDK that was just released should fix it
https://github.com/paypal/rest-api-sdk-php/releases/tag/v0.13.1

When I make any of the following change in the PPHttpConfig.php file, it works -
CURLOPT_SSLVERSION => 4
OR
CURLOPT_SSLVERSION => 1
2 doesn't work and 3 throws exception.
I am keeping version number 1 for now as I can see the version number 3 is replaced by 1 in the link shared by #Phil
I have also edited my answer for one more small query. If anyone could answer that, it would be great.

The security issue is the now infamous POODLE attack which makes SSLv3 totally insecure.
From the cURL source, you can see what the values mean (// comments mine):
enum {
CURL_SSLVERSION_DEFAULT, // 0, probably good
CURL_SSLVERSION_TLSv1, // 1, works
CURL_SSLVERSION_SSLv2, // 2, insecure
CURL_SSLVERSION_SSLv3, // 3, insecure
CURL_SSLVERSION_LAST /* never use, keep last */ // 4
};
Thus 1 means TLSv1 and as the comment says "never use", 1 is probably better than 4, and maybe 0 is better than 1 because it may try to use TLSv1 (or TLSv1.x or whatever comes default in future cURL versions).
However, I haven't tested 0 on multiple systems, and using the "default" SSL / TLS protocol version might mean SSLv3 instead of the latest and greatest and thus could not work, so YMMV.

Related

Google Plus API - Cannot Handle Token Prior to Certain Date

I implemented a login functionality using Google Plus API. It was working fine until we moved the deployment timezone. The problem below started appearing from time to time even though the server time has been adjusted properly:
Cannot handle token prior to 2018-02-01T06:30:07+0000
This was implemented in PHP and using the SDK for Google Plus. Has anyone encountered this before and resolved it properly?
This worked for me as well. I had to go into my vendor folder that composer generates for me in vendor\google\apiclient\src\Google\AccessToken\Verify.php and look for a function getJwtService() which should look exactly like this
private function getJwtService()
{
$jwtClass = 'JWT';
if (class_exists('\Firebase\JWT\JWT')) {
$jwtClass = 'Firebase\JWT\JWT';
}
if (property_exists($jwtClass, 'leeway')) {
// adds 1 second to JWT leeway
// #see https://github.com/google/google-api-php-client/issues/827
$jwtClass::$leeway += 1;
}
return new $jwtClass;
}
Then I changed the value of the $jwtClass::$leeway += 1; to $jwtClass::$leeway += 200; due to my timezone. I was about 2mins 30 seconds behind. Beware this comes with security vulnerabilities.
While the answer provided by richard4s works well but it's not a good practice to edit files in vendor directory as they are created by composer and would typically be outside your project's Git/Svn repo. The Google_Client accepts custom jwt object as a parameter to it's constructor. So here's a proper way to fix this:
$jwt = new \Firebase\JWT\JWT;
$jwt::$leeway = 5; // adjust this value
// we explicitly pass jwt object whose leeway is set to 5
$this->client = new \Google_Client(['jwt' => $jwt]);
Copied from this article.
This error appears to occur when the server's clock is a few seconds behind Auth servers clock. You probably have a slight skew between the clock on the server that mints the tokens and the clock on the server that's validating the token if the iat or nbf is in the future, then the token isn't yet valid.
One solution would be to use a small leeway, like this:
JWT::$leeway = 5; // Allows a 5 second tolerance on timing checks
see issue 1172

Send file attachment with SendGrid PHP (sendgrid-php library)

When I try to send an attachment using the SendGrid PHP library (https://github.com/sendgrid/sendgrid-php), the function fails (white screen). Removing the "setAttachment" line makes it work again.
Here is my code:
require "sendgrid-php/sendgrid-php.php";
function sendgrid() {
$recips = array("me#mydomain.ca");
$categories = array("test");
$sendgrid = new SendGrid("API key removed");
$email = new SendGrid\Email();
$email
->setSmtpapiTos($recips)
->setFrom('mailroom#mydomain.ca')
->setSubject('Testing Sendgrid')
->setText('Hello World! Testing...')
->setHtml('<strong>Hello World!</strong>')
->setCategories($categories)
->setAttachment('test.txt')
;
//$sendgrid->send($email);
$res = $sendgrid->send($email);
var_dump($res);
}
sendgrid();
As far as I can tell, I'm following the documentation, but I wonder if I haven't formatted the path to the file correctly. "Test.txt" is in the same directory as the file that contains the above code.
Can anyone offer any suggestions?
try this
->setAttachment(realpath(dirname(__FILE__)).DIRECTORY_SEPARATOR.'test.txt');
this doesn't really belong here but as of April 17th 2019 SendGrid broke their postfix mechanism and enforced v3 PHP client without "proper" documentation. And I mean: nothing is properly documented so (since this post came up top of google when I typed in SendGrid - here goes)
so if you see this.. do not panic this post will help u
invalid authentication method - declined because you are using basic authentication with 2FA enabled. to fix, update to using an API key or disable 2FA and switch to using IP Access Management for security.
Some problems with the docs
SendGrids docs on v3 are (in my opinion)
declarative rather than informative (a functional declaration rather than technical information)
cripplingly wrong (wild goose chase of circular links)
out of date (with nothing to alert you)
missing essential components (so won't work out of the box with no hint as to why) ....
for example : (just a flavour) here we see "they" (SendGrid) simply took out \SendGrid\Email() and replaced it with \SendGrid\Mail\Mail() in their code base but didn't update their docs - so their posted examples will not work. - it's very minor as a change - but as written the callers are different and they never updated their examples.. with everything else they omitted it is making very hard work of a easy thing.
i.e. THIS EXAMPLE WORKS v3
$sendgrid = new SendGrid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
$email = new \SendGrid\Mail\Mail();
$email->setFrom("test#example.com", "Example User");
$email->setSubject("Sending with SendGrid is Fun");
$email->addTo("bigman#getme.com", "Example User");
$email->addContent(
"text/plain", "and easy to do anywhere, even with PHP"
);
$email->addContent(
"text/html", "<strong>and easy to do anywhere, even with PHP</strong>"
);
//optional (seems to be bullet proof, pdf, png, etc) to attach a file<START>
$att1 = new \SendGrid\Mail\Attachment();
$att1->setContent(file_get_contents("/path/to/some/test_attach.txt"));
$att1->setType("application/octet-stream");
$att1->setFilename(basename("/path/to/some/test_attach.txt"));
$att1->setDisposition("attachment");
$email->addAttachment($att1);
//optional to attach a file</END>
try {
$response = $sendgrid->send($email);
print $response->statusCode() . "\n";
print_r($response->headers());
print $response->body() . "\n";
}
catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}`
TO UPGRADE TO v3 SEND GRID PHP CLIENT without composer on PHP 5.6
if you're like me and hate composer (don't even get me started) THE GOOD NEWS IS you can get SendGrid to work so- just so you know .. almost everything "they" (SendGrid) direct you to online is going to struggle to help you
After April 17th 2019 SendGrid said you NEED to use v3 YOU WILL NEED PHP 5.6. (rightly or wrongly PHP 5.4 is the ceiling of redhat/centos at time of writing) and YOU CANNOT USE postfix anymore (despite them never specifically saying this nor labeling their postfix examples v2 max, i.e. disabled as of 17th April 2019)
So as of 17th April 2019
-> you have to use v3
-> you have to use the PHP client... (no postfix)
-> you have to upgrade to 5.6
-> you **DO NOT** have to use composer (but if you don't you need to pay attention, see below)
ALSO -> (IMPORTANT) you are stuck with the client or the curl at v3 (they don't simply say this) no postfix. forget it. also re: the Curl mechanism (while it does work with 5.4) carries a) no documentation on using attachments AND b) utilizes illegal json_encoding PHP cannot output ( PHP cannot give "{[{}]}" it's always "{"0":[{}]}")
but regardless not only MUST you use the SendGrid PHP client at 5.6 PHP (again no, server postfix option) you still need to know you need TWO projects: "php-http-client-master" and "sendgrid-php-master" (BOTH repos) and this is undocumented: then you need to do the following: and the /lib/loader.php in "sendgrid-php-master" needs these two lines adding at the end
require_once '/your/path/to/php-http-client-master/lib/Client.php';
require_once '/your/path/to/php-http-client-master/lib/Response.php';
you also need to add this (sadly more sloppiness from SendGrid)
require_once __DIR__ . '/mail/TypeException.php';
Incidentally I also edited sendgrid-php-master\sendgrid-php.php to this
<? php
require __DIR__ . '/lib/loader.php';
?>
theoretically adding composer would mean you could probably avoid all this but for some servers this is out of the question (implementing composer on a different branch of my PHP project took 3 weeks - I am not repeating this) since composer introduces a breaking change in the way PHP handles includes and class autoloading
PS: I have alerted SendGrid to all of this you may well find that this is cleared up pretty fast

get last bitcoin price bitstamp

My goal is fairly simple, this is a PHP file and I included it into my header because I want to display the last bitcoin price using bitstamp.net not any other bitcoin exchange prices.
<?php
function getprice($url){
$decode = file_get_contents($url);
return json_decode($decode, true);
}
$btcUSD = getPrice('https://www.bitstamp.net/api/ticker/ '); //bitstamp
$btcPrice = $btcUSD["last"];
$tempround = round($btcPrice, 2);
$btc_Display = "$".$tempround;
?>
Well, this seems to work, but some times upon refreshing the page I get an error.
Warning: file_get_contents(https://www.bitstamp.net/api/ticker/ ):
failed to open stream: HTTP request failed! HTTP/1.1 400 BAD_REQUEST
in C:\xampp\htdocs\hidden\btcprice.php on line 3
The error doesn't happen often its very random in timing, but what does it mean and how can I prevent it?
It took me a while to get the error because I don't know what is causing it. I'm curious how to prevent it, am I leaving something out? I used a guide to learn how to do this that got the last bitcoin price from btc-e, but I don't want to use btc-e. I have to use bitstamp last price.
Also no JavaScript is allowed (or should I say I'm trying to avoid JavaScript for this little project) and I don't understand PHP OOP stuff, so please no examples in that.
Your code is working for me. The w3.org defines 400 as follows:
The request could not be understood by the server due to malformed
syntax. The client SHOULD NOT repeat the request without
modifications.
However, that can happen when you use a Web-Api. Espacially Api's from Bitcoin-exchanges can be pretty unstable and answer with errors from time to time, according to my own experience. How RobotMind already mentioned, you should put a
try
{
}
catch
{
}
around the getPricefunction.
Another option is to use Curl. This way you can easily access the Status-Code and react accordingly if an error should happen.

Youtube API v3 missing "creation date" in request

I'm trying to make Youtube v3 Data API work on my website.
I shamelessly copied this code from google's code samples, and it is not working. The error message showed is this:
An client error occurred: All cacheable requests must have creation dates.
I previously had issues with API keys as I forgot almost everything about APIs in general and I just thought this sample would have been useful to remember things. I managed to generate the appropriate key and now I know for sure it isn't the real problem.
Sadly Google didn't find posts related to this issue, except two links to the actual Php Library that I implemented in my site to make everything work. By looking at it closely I noticed a developer comment that could be useful.
$rawDate = $resp->getResponseHeader('date');
$parsedDate = strtotime($rawDate);
if (empty($rawDate) || false == $parsedDate) {
// We can't default this to now, as that means future cache reads
// will always pass with the logic below, so we will require a
// date be injected if not supplied.
throw new Google_Exception("All cacheable requests must have creation dates.");
}
I can understand english pretty well but I really don't know what to do now.
I even tried to add some sort of date in the request in my code, but it isn't working (you can laugh):
// Call the search.list method to retrieve results matching the specified
// query term.
$searchResponse = $youtube->search->listSearch('id,snippet', array(
'q' => $_GET['q'],
'maxResults' => $_GET['maxResults'],
'date' => strtotime(),
));
An client error occurred: (list) unknown parameter: 'date'
Any tips? Thank you in advance
EDIT: I know, this PHP library is currently in beta, but there must be some workaround.
EDIT 2: I found a temporary work around. I inverted the logic gate of that 'if' in the Php Library and now it works. But I don't like doing this, and I won't mark this as solved. At least if you know the reason of the bug please explain it to me, I'm really interested.

How do I implement Direct Identity based OpenID authentication with Zend OpenID

I'm using the Zend framework and the openid selector from http://code.google.com/p/openid-selector/ - however I find I can't login using sites like Google and Yahoo as they use direct identity based login system whereby one is just redirected to a url as opposed to entering a unique url of their own for authentication.
I've checked out many options and hacks but none of them seem to work. How can i get this to work here btw - how is it implemented at stack overflow? I could really use all the help here guys..
Edit
Well the issue here is that from what I have noticed is that the Zend OpenID class doesn't support OpenID 2.0 the thing is that a typical open ID providor gives you a unique url such as your-name.openid-providor.com or openid-providor.com/your-name and the Zend OpenId class just parses through that url and then redirects you to the providor website where upon authentication you are redirected back.
In the case of Yahoo and google - you don't enter a unique url instead you are redirected to the providors login site and upon login and authentication you are redirected back - so basically whats happeining is that the zend_openID object when it parses to tell who the providor is it fails to tell from the general url itself. Like when you click on teh Google link it redirects you to https://www.google.com/accounts/o8/id
Its more an issue with the zend openid object here and there isn't any help on zend related forums - so I was wondering if someone had already hacked or had an alteration I could make to the class to accomplish this. Sorry if I'm missing something but I'm kinda new to this and programming with open ID and have just started to get my feet wet.
Thanks for the follow up - I did check into RPX a while back and they do have a php class but I wasnt able to check it out plus I really just want to for now get the code selector used as on stackoverflow to work with Yahoo and Google authentication. There has to be some kind of way to tweak the parsing which the Zend OpenID class uses as it runs a series of regular expression checks to make a discovery.
Little late to the game but I was able to get this working with some hacks I found around the interwebs.
First. Yahoo. To get Yahoo working all I had to do was change the JavaScript to use me.yahoo.com instead of just yahoo.com and it worked perfectly with the version of the Zend Framework I'm using. Unfortunately Google still wasn't, so some hacking was in order.
All of these changes go in Zend/OpenId/Consumer.php
First, in the _discovery method add the following on the series of preg_match checks that starts at around line 740.
} else if (preg_match('/<URI>([^<]+)<\/URI>/i', $response, $r)) {
$version = 2.0;
$server = $r[1];
I added this right before the return false; statement that's in the else {} block.
Second, in the _checkId method you'll need to add 3 new blocks (I haven't dug around enough to know what causes each of these three cases to be called, so I covered all to be on the safe side.
Inside the $version <= 2.0 block, you'll find an if/else if/else block. In the first if statement ($this->_session !== null) add this to the end:
if ($server == 'https://www.google.com/accounts/o8/ud') {
$this->_session->identity = 'http://specs.openid.net/auth/2.0/identifier_select';
$this->_session->claimed_id = 'http://specs.openid.net/auth/2.0/identifier_select';
}
In the else if (defined('SID') block add this to the end:
if ($server == 'https://www.google.com/accounts/o8/ud') {
$_SESSION['zend_openid']['identity'] = 'http://specs.openid.net/auth/2.0/identifier_select';
$_SESSION['zend_openid']['claimed_id'] = 'http://specs.openid.net/auth/2.0/identifier_select';
}
And then after the else block (so outside the if/else if/else block all together, but still inside the $version <= 2.0 block) add this:
if ($server == 'https://www.google.com/accounts/o8/ud') {
$params['openid.identity'] = 'http://specs.openid.net/auth/2.0/identifier_select';
$params['openid.claimed_id'] = 'http://specs.openid.net/auth/2.0/identifier_select';
}
Link to the bug in Zend Framework Issue Tracker
I need to use Google's OpenID stuff, and I tried Steven's code and couldn't get it to work as-is. I've made some modifications.
The _discovery change method is still the same:
Zend/OpenId/Consumer.php, line 765, add:
} else if (preg_match('/<URI>([^<]+)<\/URI>/i', $response, $r)) {
$version = 2.0;
$server = $r[1];
The rest is different, though:
Zend/OpenId/Consumer.php, line 859 (after making the above change), add:
if (stristr($server, 'https://www.google.com/') !== false) {
$id = 'http://specs.openid.net/auth/2.0/identifier_select';
$claimedId = 'http://specs.openid.net/auth/2.0/identifier_select';
}
This is right before:
$params['openid.identity'] = $id;
$params['openid.claimed_id'] = $claimedId;
And to get it to return the ID, once authorized:
Zend/Auth/Adapter/OpenId.php, line 278:
if(isset($_REQUEST['openid_identity']))
{
$this->_id = $_REQUEST['openid_identity'];
$id = $this->_id;
}
This is right before:
return new Zend_Auth_Result(
Zend_Auth_Result::SUCCESS,
$id,
array("Authentication successful"));
Note that I have not thoroughly tested this code. The code below is even more shakey.
I have spent more time and I've gotten it to work with my Google Apps domain with the following changes, in addition to the above:
Zend/OpenId/Consumer.php, line 734
$discovery_url = $id;
if(strpos($discovery_url, '/', strpos($discovery_url, '//')+2) !== false) {
$discovery_url = substr($discovery_url, 0, strpos($discovery_url, '/', strpos($discovery_url, '//')+2));
}
$discovery_url .= '/.well-known/host-meta';
$response = $this->_httpRequest($discovery_url, 'GET', array(), $status);
if ($status === 200 && is_string($response)) {
if (preg_match('/Link: <([^><]+)>/i', $response, $r)) {
$id = $r[1];
}
}
This is right after:
/* TODO: OpenID 2.0 (7.3) XRI and Yadis discovery */
I believe that was the only change I had to make. I'm pretty sure there's supposed to be some checking involved with the above for security reasons, but I haven't looked far enough into it to see what they would be.
Going over all the advice provided - I've decided to ditch using the zend_openid class [ sorry about that zend ] and instead I've switched to using JanRains OpenID library. Its taken a few hours to get it up and running with my project but atleast its working like a breeze. Had to make a lot of hacking and a bit of code spill over to get it working but its worth it.
I couldn't use any of Zend adapters with Zend-Auth to settle this new code library in as the library did the authentication on its own. SO I hacked and made a generic adapter that just returned a filled zend_result set to the Auth object thus I authenticate using my library and merely store the result in the Auth object pulling a bit of a fast one one the Zend-Auth object rather than have to rewrite my code again.
The library is available at http://openidenabled.com/php-openid/
Thanks for all the help guys.
I'm dealing with similar issues. I'm planning on using RPX now with Zend Framework. Maybe I'll write an adapter. Just to let you know.
Info: 'RPS now' provides an all-in-one interface and UI for user registration with
facebook
Google
Yahoo
mySpaceID
Windows LiveID
OpenID
aol
I'm pretty sure that Yahoo only works with OpenID 2.0. If you want to support Yahoo users, you're going to have to upgrade to a library with 2.0 support. That's going to be a matter of more than tweaking some parsing.
Did you check out the manual -- Zend_OpenId_Consumer basics? Check out 38.2.2 on that page and let me know if this helps, because it should.
Specifically, I don't know if Google offers OpenID. I know that Yahoo worked because I've tried it a while back.
Thanks for the information. I started by using JanRain's library, but I have problems with getting Simple Registration to work: I have not succeeded in getting any data that way. And there is no documentation on using Attribute Exchange. :(
So, I found and was trying Zend/OpenId, but had the same problem as you: no Yahoo!, Google and who knows what else support. Reading this, it seems I'll have to get back to JanRain; RPX is not an option in my case as it's a third party service.

Categories