So, currently at work I’ve been rewriting all our Payment Gateways for Your Members. Making them more better Class based an abstracting out the common functions to a base class, to save memory footprint and code etc.
And came across a problem when rewriting the Facebook Credits handler.
The order ID that gets passed around, as well as the Application ID is too long for a 32 Bit PHP installation to handle when treating it as an Integer.
So a number like “239724439419867” was ending up as “1.7592246582797E+14” when stored/processed, or converted to a string.
Now the obvious way to process this is to convert it to a string another way, which is somewhat difficult since before you even start it is in a format that you can’t handle.
The saving grace here is the fact that data is passed to you as a JSON packet (aside from the fact the Order ID is in the $_POST variable and thus a string, so I could of used it from there).
This led to me to look at the JSON packet, which starts as a string but when decoded the large integers are still a larger integer than can be processed (whether you json_decode to a Array or to an Object, the problem persists). So I thought about how to process the raw JSON packet and make sure the order ID, and other large integers are treated as strings.
If you look at a Raw JSON packet you can easily spot whats a string, integer, object or array.
Take this example Facebook Credits JSON Packet, (wrapped for readability):
{"order_id":239724439419867,"buyer":197803678,"app":148748711865470, "receiver":197803678,"amount":5,"update_time":1320075413, "time_placed":1320075408,"data":"","items":[{"item_id":"<item_id>","title":"Post", "description":"A New Purchasable Post", "image_url":"<some url>","product_url":"<some other url>", "price":5,"data":"<data>"}],"status":"<status>"}
- order_id is an integer as it has no ” around it
- status is a string as its surrounded by “
- Items is an array as its surrounded by [, in this case containing a single object, entries/items are comma separated.
So after thinking about this I decided the best way to sort this out was to convert the integers in the raw JSON packet to strings before decoding.
In pseudo code.
Lop off the { and } from the start and end Explode around , array walk each item split on : check if there are no " in the second bit if none wrap in " glue back together
Something alone the lines of:
function largeint($rawjson) { $rawjson = substr($rawjson, 1, -1); $rawjson = explode(',' , $rawjson); array_walk($rawjson, 'strfun'); $rawjson = implode(',', $rawjson); $rawjson = '{', . $rawjson . '}'; $json = json_decode($rawjson); return $json; } function strfun(&$entry, $key) { $data = explode(':', $entry); if (FALSE === strpos($data[1], '"')) { $data[1] = '"' . $data[1] . '"'; $entry = implode(':', $data); } }
I’m not sure in terms of memory footprint if its cheaper to do a substr of $data[1] and check if its a ” or not.
I suppose it could test the string length of the detected integer to see if its invalid/unable to process, but then you would be performing a string function on an integer and again the problem would arise.
But as a block of code is does the job, its obviously not ideal for all situations, since in this case I want the integer as a string, I’m not using it for math, but if I did, we probably need to do some bizarre unpack-ing or something.
Any opinions or improvements give us a comment below 😀