4

I'm receiving an HTTP Post with the following JSON object:

{"notification":{"version":6.0,"attemptCount":0,"role":"VENDOR","site":"nicholeen","receipt":"********","currency":"USD","transactionType":"TEST","transactionTime":1406070122781,"paymentMethod":"VISA","totalProductAmount":1.00,"totalTaxAmount":0.00,"totalShippingAmount":0.00,"customer":{"shipping":{"firstName":"TEST","lastName":"USER","fullName":"Test User","email":"[email protected]","address":{}},"billing":{"firstName":"TEST","lastName":"USER","fullName":"Test User","email":"[email protected]","address":{}}},"lineItems":[{"itemNo":"1","productTitle":"A passed in title","shippable":false,"recurring":false,"customerProductAmount":1.00,"customerTaxAmount":0.00}]},"verification":"2745A502"}

I need to Convert the "notification" JSON object into a JSON string assigned to a PHP variable without losing any data, including the decimals.

Currently I'm receiving the IPN using $ipn_raw = file_get_contents('php://input');. Then I json_decode the JSON to a PHP variable, then re-encode the notification portion using json_encode. Here's the code:

$ipn_raw = file_get_contents('php://input');
$ipn = json_decode($ipn_raw);
$notification = $ipn['notification'];
$result = json_encode($notification);

However, the result strips some values giving me the following:

{"version":6,"attemptCount":0,"role":"VENDOR","site":"nicholeen","receipt":"********","currency":"USD","transactionType":"TEST","transactionTime":1406095846441,"paymentMethod":"VISA","totalProductAmount":1,"totalTaxAmount":0,"totalShippingAmount":0,"customer":{"shipping":{"firstName":"TEST","lastName":"USER","fullName":"Test User","email":"[email protected]","address":[]},"billing":{"firstName":"TEST","lastName":"USER","fullName":"Test User","email":"[email protected]","address":[]}},"lineItems":[{"itemNo":"1","productTitle":"A passed in title","shippable":false,"recurring":false,"customerProductAmount":1,"customerTaxAmount":0}]}

You can see that version 6.0 is now just version 6, totalProductAmount was 1.00 and is now 1, etc.

How can I do this without any values changing in the result?

Thanks!

Per request, here's some extra background information for why I need everything to be unchanged from the original. Clickbank has given me the following information in order to create the necessary SHA 1 hash to validate the Version 6 IPN I receive from them (see https://support.clickbank.com/entries/22803622-Instant-Notification-Service)

1) Use a JSON library/DSL to extract the “notification” JSON object from the IPN. 2) Convert the "notification" JSON object into a JSON string. The string should begin with a curly brace { and end with a curly brace } as it is a representation of a JSON object. 3) Append the secret key directly onto the string after the end curly brace of the notification object. No spaces or separator characters. 4) SHA 1 hash the string created in step 3. 5) Take the first 8 characters of the hash created in step 4. That’s the value of the "verification" field in the v6 IPN.

If needed I could provide all my code for the rest of the steps, but at this point the only part I'm having problems with is getting the notification object in a string by itself.

6
  • 1
    You do know that 6.0 and 6 are just two different respresentations of the same number. You can even try with PHP: var_dump(6.0 == 6); // will print true Commented Jul 23, 2014 at 6:23
  • Yes, knittl. I know that they are the same representation; however, I need to have the EXACT same output in order to generate a matching SHA 1 hash for another step that I have not mentioned above. Commented Jul 23, 2014 at 6:31
  • Then you should mention every necessary detail in your question ;) What about whitespace in your output? The JSON strings { "v" : 1 } and {"v":1} describe the same object too. Commented Jul 23, 2014 at 6:33
  • I added some background information to the bottom of my question. I'm not sure if whitespace will effect the generation of the SHA1 hash. Commented Jul 23, 2014 at 6:39
  • In crypting algorythm even byte changes upcoming hash Commented Jul 23, 2014 at 6:42

3 Answers 3

2

What you are asking (given the fact that you are hashing the string representation of the JSON object), you'd need to extract the relevant portion of your JSON by string manipulation methods (e.g. regex):

$result = preg_replace(array('^\{[^{]', '[^}]\}$'), '', $in);

This will strip everything up to the second curly brace in the beginning, and everything from the second last curly brace from the end. (But it will obviously only work if your JSON has this exact format, i.e. notification is the only nested object, the first object, and everything that comes after that contains no } (especially the verification code))


There seems to be a "bug" report about this: https://bugs.php.net/bug.php?id=50224, although it seems that stringifying 6.0 is expected behavior and JavaScript does the same thing. Also see this related question: PHP function json_decode decodes float value with zeros after point as int

Sign up to request clarification or add additional context in comments.

6 Comments

That will fail, of course, for nested structures (which OP has)
@AlmaDo: why will it fail for the OP's JSON string? I explicitely mentioned the caveats of this method in my answer.
notification is not the only nested object... You have "customer" as well as a couple others. Is that going to be a problem?
@deggertsen: very likely. Maybe you can adapt the regex. You should also keep in mind that float values cannot represent every decimal value (for instance, 1.1 cannot be exactly represented in binary, you can only store a approximation). If you're feeling funky, you could even write a parser which counts braces and ignores braces inside strings to extract your notification object.
@deggertsen: see my update to my answer. JavaScript behaves the same way as PHP does and represents x.0 values as integer numbers.
|
1

The problem is: both 6.0 and 6 are same floats from viewpoint of values. Thus, while decoding, PHP will lose this decimal format points. So on your first json_decode() call you'll already lose your data about how many decimal points were there.

The way to resolve may be to enclose your values in-place in raw source json with quites, to turn them into strings and store them in PHP in that format. It's like:

$jsonRaw = '{"notification":{"version":6.0,"attemptCount":0,"role":"VENDOR","site":"nicholeen","receipt":"********","currency":"USD","transactionType":"TEST","transactionTime":1406070122781,"paymentMethod":"VISA","totalProductAmount":1.00,"totalTaxAmount":0.00,"totalShippingAmount":0.00,"customer":{"shipping":{"firstName":"TEST","lastName":"USER","fullName":"Test User","email":"[email protected]","address":{}},"billing":{"firstName":"TEST","lastName":"USER","fullName":"Test User","email":"[email protected]","address":{}}},"lineItems":[{"itemNo":"1","productTitle":"A passed in title","shippable":false,"recurring":false,"customerProductAmount":1.00,"customerTaxAmount":0.00}]},"verification":"2745A502"}';

$jsonRaw = preg_replace('/(\b)([0-9]+\.[0-9]+)(\b)/', '$1"$2"$3', $jsonRaw);
$jsonObj = json_decode($jsonRaw);

So now your object will store your values as strings and that won't cause losing of decimal points. Of course, with decoding you'll need to do reverse thing:

$notification = $jsonObj->notification;
$result       = json_encode($notification);
$result       = preg_replace('/"([0-9]+\.[0-9]+)"/', '$1', $result);

But this has a flaw: because you'll lose data about what were actual strings and what were floats. So if your original json contains string like "6.00" and it's intended to be string, such conversion will lose that information and make that value float. So if your data contain such strings in this form, then - yes, it's not the way to go (but then I doubt there is an easy way to go without implementing your own json parser)

2 Comments

Thank you. This is very helpful. Seems like a mess... Version 4 of the clickbank Instant Notification Service was so much easier. Is there a way to do this using javascript and then saving the result to a variable?
I'm not sure what do you want to do in js, but here, the problem is on PHP side (it's PHP parser which strips decimal zeros)
0

For anyone who's interested, here's what I ended up using:

$json_ipn = preg_replace('({"notification":|,"verification"([\s\S]*))', '', $ipn_raw);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.