1

I'm using the json_decode function to decode (and verify a postback from a payment processor). the json object received looks as follow

{
   "notification":{
      "version":6.0,
      "attemptCount":0,
      "role":"VENDOR",
      .....
      "lineItems":[
         {
            "itemNo":"1",
            "productTitle":"A passed in title",
            "shippable":false,
            "recurring":false,
            "customerProductAmount":1.00,
            "customerTaxAmount":0.00
         }
      ]
   },
   "verification":"9F6E504D"
}

The verification works as follows, one takes the notification node and append a secret key. The first eight characters of the SHA1 hash of this string should match the content of the validation node.

However, I noticed that whilst using json_decode, the double value 6.0, 0.00 etc are truncated to integers (6, 0 ,etc). This messes up the string (in terms of it not generating the correct SHA1-hash). Do note, I cannot use the depth limit to prevent decoding of the notification branch, since I need to support PHP 5.0. How can I tackle this issue. The (defect) validation code I wrote is:

  public function IPN_Check(){
    $o = (json_decode($this->test_ipn));
    $validation_string = json_encode($o->notification);
  }
Friso Kluitenberg
  • 1,157
  • 1
  • 14
  • 34
  • Is there any reason why you need `6.0` opposed to `6`? – N.B. Aug 29 '14 at 13:08
  • I don't think there is any built-in function to convert double to int directly in a JSON (or in a JSON string). I'm afraid you'll have to decode your JSON, parse arrays to cast double to integers on concerned values, and re-encode it to JSON to match your hash check later on. – Clément Malet Aug 29 '14 at 13:11
  • 6 gives a different SHA1 hash for verification than 6.0 – Friso Kluitenberg Aug 29 '14 at 13:11
  • @clement malet, it should remain a double. – Friso Kluitenberg Aug 29 '14 at 13:12
  • @FrisoKluitenberg I missunderstood, you want doubles instead of integers ? It's the same, just transform integers into double ? Or I don't get it ? – Clément Malet Aug 29 '14 at 13:14
  • @Clément Malet: The input is a double, it should remain that way after I extract the validation node and apply json_encode again to the notification node. However, currently json_decoding the notifation node, results in an object with that value represented as an integer – Friso Kluitenberg Aug 29 '14 at 13:15
  • So the question is really how to get the textual version of only one part of that JSON, that part being `notification` key of the JSON, correct? – N.B. Aug 29 '14 at 13:18
  • Yes, that is correct. – Friso Kluitenberg Aug 29 '14 at 13:19
  • 1
    In lack of a better method, I'd just use a regex to extract that information and then SHA1 it to check for integrity. As I can't see the entire JSON, I can't suggest the actual expression but it appears you need stuff between `"notification":` and `\n"verification"`. – N.B. Aug 29 '14 at 13:21
  • I fear i should use a regex indeed, – Friso Kluitenberg Aug 29 '14 at 13:27
  • @FrisoKluitenberg Where are you getting this JSON from? I'm wondering if it's possible you could decode and encode the JSON before generating the verification hash the first time, to make sure the JSON is in a canonical form. – Paul Aug 29 '14 at 13:29
  • The hash is from ClickBank IPN 6.0, https://support.clickbank.com/entries/22803622-Instant-Notification-Service . The external server calculates the value of the verification hash before posting it. – Friso Kluitenberg Aug 29 '14 at 13:33

2 Answers2

1

I tried the following:

<?php

var_dump(json_decode('
{
   "notification":{
      "version":6.0,
      "attemptCount":0
   }
}
'));

and got this output:

object(stdClass)#1 (1) {
  ["notification"]=>
  object(stdClass)#2 (2) {
    ["version"]=>
    float(6)
    ["attemptCount"]=>
    int(0)
  }
}

PHP does make a difference between float and int, maybe you could do something like gettype($o->notification[$i]) == 'float' to check whether you need to add a zero using a string.

UPD. PHP does make a difference between float and int, but json_encode() - may not. To be sure, that you encode all values as they are - use json_encode() with JSON_PRESERVE_ZERO_FRACTION parameter, and all your float/double types will be saved correctly.

Coded Monkey
  • 604
  • 7
  • 19
  • Whilst normally serialize is the preffered way to store data types in php. Serialize is PHP specific and does not output json (to my knowledge). I specifically need the output to be in json, to generate the hash. – Friso Kluitenberg Aug 29 '14 at 13:10
0

It looks like ClickBank they always send it in the same format with only the two top level fields "notification" and "verification". So you can just use substr to remove the first 16 characters ({"notification":) and the last 27 characters (,"verification":"XXXXXXXX"}) from the raw JSON and then proceed from there:

$notification = substr($json, 16, -27);
$verification = strtoupper( substr( hash('sha1', $notification . $secret), 0, 8) );
Paul
  • 139,544
  • 27
  • 275
  • 264