json_decode Preservation of Type - php

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);
}

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.

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) );

Related

Get token balance with Ethereum RPC?

how display balance of token through Ethereum RPC?
$id = 0;
$data = array();
$data['jsonrpc'] = '2.0';
$data['id'] = $id++;
$data['method'] = 'eth_call';
$data['params'] = [['from' => '0x0...', 'to' => '0x0...', 'data' => 'contract byte code here 0x0...'], 'latest'];
$ch = curl_init();
...
Return:
{"jsonrpc":"2.0","id":0,"result":"0x"}
What to do next? Call contract method balanceOf? How to do that?
To get token balance with eth_call you need to and data parameter. to is contract address, here we need to generate the data parameter. As the doc eth_call says,
data: DATA - (optional) Hash of the method signature and encoded
parameters. For details see Ethereum-Contract-ABI
Take this EOS token transaction as a example.
Contract address:0x86fa049857e0209aa7d9e616f7eb3b3b78ecfdb0
Token Holder address:0x0b88516a6d22bf8e0d3657effbd41577c5fd4cb7
You can see the contract code here.
contract ERC20 {
function totalSupply() constant returns (uint supply);
function balanceOf( address who ) constant returns (uint value);
function allowance( address owner, address spender ) constant returns (uint _allowance);
function transfer( address to, uint value) returns (bool ok);
function transferFrom( address from, address to, uint value) returns (bool ok);
function approve( address spender, uint value ) returns (bool ok);
event Transfer( address indexed from, address indexed to, uint value);
event Approval( address indexed owner, address indexed spender, uint value);
}
Function Selector
>>> from web3 import Web3
>>> Web3.sha3("balanceOf(address)")
HexBytes('0x70a08231b98ef4ca268c9cc3f6b4590e4bfec28280db06bb5d45e689f2a360be')
Take the first four bytes 70a08231
Argument Encoding
address: equivalent to uint160, except for the assumed interpretation
and language typing.
int: enc(X) is the big-endian two's complement encoding of X,
padded on the higher-order (left) side with 0xff for negative X and
with zero bytes for positive X such that the length is a multiple of
32 bytes.
Padding the 20 bytes token address to 32 bytes with 0 to token holder address:
0000000000000000000000000b88516a6d22bf8e0d3657effbd41577c5fd4cb7
Then concat the function selector and encoded parameter, we get data parameter:
0x70a082310000000000000000000000000b88516a6d22bf8e0d3657effbd41577c5fd4cb7
Make the request with:
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"to": "0x86fa049857e0209aa7d9e616f7eb3b3b78ecfdb0", "data":"0x70a082310000000000000000000000000b88516a6d22bf8e0d3657effbd41577c5fd4cb7"}, "latest"],"id":67}' -H "Content-Type: application/json" http://127.0.0.1:8545/
here is the curl result (You may get different answer here, as there may be some transaction with this address done after my polling the request)
{"jsonrpc":"2.0","id":67,"result":"0x00000000000000000000000000000000000000000000014a314d9ff9b20b9800"}
You can change convert hex format balance to decimal
>>> 0x00000000000000000000000000000000000000000000014a314d9ff9b20b9800
6090978215900000000000
Check the result,
When calling a Solidity contract function, in general, data should be the following, encoded as a hex string:
The "function selector," which is the first four bytes of the keccak-256 hash of the signature of the function you're calling.
The ABI-encoded arguments to the function you're calling.
The function signature for an ERC20 token's balanceOf is balanceOf(address). The keccak-256 hash is 70a08231b98ef4ca268c9cc3f6b4590e4bfec28280db06bb5d45e689f2a360be, so the first four bytes are 70a08231.
The function only takes a single parameter: the address of the account whose balance you're trying to look up. To ABI-encode it, simply left-pad it with zeros until it's 32 bytes long. Since addresses are 20 bytes, this means adding 12 bytes of zeros (or 24 characters in hex).
So the full data field should be "0x70a08231" + "000000000000000000000000" + address.
May I recommend a proper ERC20 library for PHP that I have developed myself.
https://www.furqansiddiqui.com/libraries/erc20-php/
https://github.com/furqansiddiqui/erc20-php
sample code to retrieve balance:
<?php
$geth = new EthereumRPC('127.0.0.1', 8545);
$erc20 = new \ERC20\ERC20($geth);
// Pass ERC20 contract address as argument below
$token = $erc20->token('0xd26114cd6EE289AccF82350c8d8487fedB8A0C07');
var_dump($token->name()); # string(8) "OMGToken"
var_dump($token->symbol()); # string(3) "OMG"
var_dump($token->decimals()); # int(18)
var_dump($token->balanceOf('0x...')); // Enter ethereum address here
For token transaction you need to use eth_sendTransaction.

PHP inet_ntop() is acting differently on real VPS

I deployed my application on a VPS and It works fine expect the inet_ntop() function. On my local web server it's working fine with no error message.
I store the IP addresses in a binary(16) column. Before I would store them into the database I convert them. My last login IP is: 4e43b7, in binary numbers: 00110100 01100101 00110100 00110011 01100010 00110111 and the readable format: 78.92.67.183. So it run with a warning message on the VPS: Warning: inet_ntop(): Invalid in_addr value in home/...
What's wrong? According to the PHP doc the function works on PHP 5.1 or higher and a VPS has 5.5, but I am using 5.6. Can version differences cause problem? This line causes the warning:
$ip = inet_ntop($datas['ip_address'];
As per the manual:
When BINARY values are stored, they are right-padded with the pad value to the specified length. The pad value is 0x00 (the zero byte).
so you're not pulling out a 32bit IPv4 address. You're pulling out an 16x8bit = 128bit value, and feeding that to inet_ntop().
As Marc B noted, your BINARY column is being right-padded with zeroes which is then throwing off your decoding. There's not a super good way of handling this, particularly within just MySQL.
However, IPv6 has a built-in method of encapsulating IPv4 addresses, 6to4. Using this you can store v4 and v6 addresses side-by-side in a way that's maintainable and easy to deal with.
function fourToSix($addr) {
$haddr = str_pad(dechex(ip2long($addr)), 8, '0', STR_PAD_LEFT);
$v6 = sprintf('2002:%s::', implode(':', str_split($haddr, 2)));
return $v6;
}
function sixToFour($addr) {
return long2ip(hexdec(implode('', array_slice(explode(':', $addr), 1, 4))));
}
function isSixToFour($addr) {
return explode(':', $addr)[0] == '2002';
}
$v4 = '10.1.2.3';
$v6 = '2002:0a:01:02:03::';
var_dump(
fourToSix($v4),
isSixToFour($v6),
sixToFour($v6),
bin2hex(inet_pton($v6))
);
Output:
string(18) "2002:0a:01:02:03::"
bool(true)
string(8) "10.1.2.3"
string(32) "2002000a000100020003000000000000"
edit
Example store:
$stmt = $dbh->prepare('INSERT INTO table (id, addr) VALUES(?, ?);');
// convert IP if it is v4
if( ip2long($ip_addr) !== false ) {
$ip_addr = fourToSix($ip_addr);
}
$stmt->execute(1, inet_pton($ip_addr));
Example retrieve:
$addr_raw = $dbh->query('SELECT addr FROM table WHERE id=1')->fetch(PDO::FETCH_ASSOC)['addr'];
$addr_str = inet_ntop($addr_raw);
if( isSixToFour($addr_str) ) {
printf("IPv4 address is: %s\n", sixToFour($addr_str));
} else {
printf("IPv6 address is: %s\n", $addr_str);
}

PHP JSON Google Definitions - accessing a value

EDIT#4: json_decode is failing and returning null on a seemingly valid json string. See below for more info
I am new to JSON/JSONP and I'm running into constant trouble accessing the values in the returned JSON with PHP. I have stripped the JSONP callback without issue using code I found on this board. I am getting a JSONP result from http://www.google.com/dictionary/json?callback=a&sl=en&tl=en&q=love and struggling to access the first result for the meaning. It's a quite complex result, and I need to access the first meaning (in the node "text") from the below JSON result.
http://pastebin.com/hBTeBTUL
My best attempt was:
if (isset($json->primaries[1]->entries[1]->terms[1]->text))
The above was the best I could do, I just keep getting errors trying to return that text node saying it is undefined. I'd prefer to work with objects rather than associative arrays too, if possible, so please avoid telling me to set it to return assoc array.
Any help would be greatly appreciated. I'm really stuck :P
EDIT:
$json->primaries[1]->entries[1]->terms[0]->text didn't seem to work either. Here is the complete script. Ignore the $params array as it is not used, was going to use it to generate the query.
The script has been edited since when I first posted, I had an invalid JSON object, but the error seems to be fixed as it will now parse through JSON formatters.
The error i'm getting trying to print the value out is
PHP Notice: Trying to get property of non-object in /home/outil2/Plugins/GDefine.php on line 23
EDIT#2: added json_decode which was in my original solution, but got lost in the second version
<?php
class GDefine extends Plugin {
public static $enabled = TRUE;
public function onReceivedData($data) {
if ($data["message"][0] == ".def") {
$params = array (
"callback" => "a",
"sl" => "en",
"tl" => "en",
"q" => $data["message"][1]
);
$jsonp = file_get_contents(
"http://www.google.com/dictionary/json?callback=a&sl=en&tl=en&q=" . $data["message"][1]);
$json = json_decode(substr($jsonp, 2, strlen($jsonp)-12));
var_dump($json);
print_r($json->primaries[1]->entries[1]->terms[0]->text);
if (isset($json->primaries[1]->entries[1]->terms[0]->text)) {
$text = $this->bold("Google Definition: ");
$text .= $this->teal($json->primaries[1]->entries[1]->terms[0]->text);
$this->privmsg($data["target"], $text);
} else {
$this->privmsg($data["target"], "error error error");
}
}
}
}
EDIT #3: this is the string I'm trying to json_decode, after using substr to remove the callback function, but am getting a NULL value returned on var_dump($json)
{"query":"love","sourceLanguage":"en","targetLanguage":"en","primaries":[{"type":"headword","terms":[{"type":"text","text":"love","language":"en","labels":[{"text":"Noun","title":"Part-of-speech"}]},{"type":"phonetic","text":"/lÉv/","language":"und"},{"type":"sound","text":"http://www.gstatic.com/dictionary/static/sounds/de/0/love.mp3","language":"und"}],"entries":[{"type":"related","terms":[{"type":"text","text":"loves","language":"und","labels":[{"text":"plural"}]}]},{"type":"meaning","terms":[{"type":"text","text":"An intense feeling of deep affection","language":"en"}],"entries":[{"type":"example","terms":[{"type":"text","text":"babies fill parents with intense feelings of \x3cem\x3elove\x3c/em\x3e","language":"en"}]},{"type":"example","terms":[{"type":"text","text":"their \x3cb\x3e\x3cem\x3elove\x3c/em\x3e for\x3c/b\x3e their country","language":"en"}]}]},{"type":"meaning","terms":[{"type":"text","text":"A deep romantic or sexual attachment to someone","language":"en"}],"entries":[{"type":"example","terms":[{"type":"text","text":"it was \x3cem\x3elove\x3c/em\x3e at first sight","language":"en"}]},{"type":"example","terms":[{"type":"text","text":"they were both \x3cb\x3ein \x3cem\x3elove\x3c/em\x3e with\x3c/b\x3e her","language":"en"}]},{"type":"example","terms":[{"type":"text","text":"we were slowly \x3cb\x3efalling in \x3cem\x3elove\x3c/em\x3e\x3c/b\x3e","language":"en"}]}]},{"type":"meaning","terms":[{"type":"text","text":"A personified figure of \x3cem\x3elove\x3c/em\x3e, often represented as Cupid","language":"en"}]},{"type":"meaning","terms":[{"type":"text","text":"A great interest and pleasure in something","language":"en"}],"entries":[{"type":"example","terms":[{"type":"text","text":"his \x3cb\x3e\x3cem\x3elove\x3c/em\x3e for\x3c/b\x3e football","language":"en"}]},{"type":"example","terms":[{"type":"text","text":"we share a \x3cb\x3e\x3cem\x3elove\x3c/em\x3e of\x3c/b\x3e music","language":"en"}]}]},{"type":"meaning","terms":[{"type":"text","text":"Affectionate greetings conveyed to someone on one\x27s behalf","language":"en"}]},{"type":"meaning","terms":[{"type":"text","text":"A formula for ending an affectionate letter","language":"en"}],"entries":[{"type":"example","terms":[{"type":"text","text":"take care, lots of \x3cem\x3elove\x3c/em\x3e, Judy","language":"en"}]}]},{"type":"meaning","terms":[{"type":"text","text":"A person or thing that one \x3cem\x3eloves\x3c/em\x3e","language":"en"}],"entries":[{"type":"example","terms":[{"type":"text","text":"she was \x3cb\x3ethe \x3cem\x3elove\x3c/em\x3e of his life\x3c/b\x3e","language":"en"}]},{"type":"example","terms":[{"type":"text","text":"their two great \x3cem\x3eloves\x3c/em\x3e are tobacco and whiskey","language":"en"}]}]},{"type":"meaning","terms":[{"type":"text","text":"A friendly form of address","language":"en"}],"entries":[{"type":"example","terms":[{"type":"text","text":"it\x27s all right, \x3cem\x3elove\x3c/em\x3e","language":"en"}]}]},{"type":"meaning","terms":[{"type":"text","text":"Used to express affectionate approval for someone","language":"en"}],"entries":[{"type":"example","terms":[{"type":"text","text":"don\x27t fret, there\x27s a \x3cem\x3elove\x3c/em\x3e","language":"en"}]}]},{"type":"meaning","terms":[{"type":"text","text":"(in tennis, squash, and some other sports) A score of zero; nil","language":"en"}],"entries":[{"type":"example","terms":[{"type":"text","text":"\x3cem\x3elove\x3c/em\x3e fifteen","language":"en"}]},{"type":"example","terms":[{"type":"text","text":"he was down two sets to \x3cem\x3elove\x3c/em\x3e","language":"en"}]}]}]},{"type":"headword","terms":[{"type":"text","text":"love","language":"en","labels":[{"text":"Verb","title":"Part-of-speech"}]},{"type":"phonetic","text":"/lÉv/","language":"und"},{"type":"sound","text":"http://www.gstatic.com/dictionary/static/sounds/de/0/love.mp3","language":"und"}],"entries":[{"type":"related","terms":[{"type":"text","text":"loved","language":"und","labels":[{"text":"past participle"}]},{"type":"text","text":"loves","language":"und","labels":[{"text":"3rd person singular present"}]},{"type":"text","text":"loving","language":"und","labels":[{"text":"present participle"}]},{"type":"text","text":"loved","language":"und","labels":[{"text":"past tense"}]}]},{"type":"meaning","terms":[{"type":"text","text":"Feel a deep romantic or sexual attachment to (someone)","language":"en"}],"entries":[{"type":"example","terms":[{"type":"text","text":"do you \x3cem\x3elove\x3c/em\x3e me?","language":"en"}]}]},{"type":"meaning","terms":[{"type":"text","text":"Like very much; find pleasure in","language":"en"}],"entries":[{"type":"example","terms":[{"type":"text","text":"I\x27d \x3cem\x3elove\x3c/em\x3e a cup of tea, thanks","language":"en"}]},{"type":"example","terms":[{"type":"text","text":"I just \x3cem\x3elove\x3c/em\x3e dancing","language":"en"}]},{"type":"example","terms":[{"type":"text","text":"a fun-\x3cem\x3eloving\x3c/em\x3e girl","language":"en"}]}]}]}]}
I json_decode that and it returns NULL :(
You're trying to access an object that doesn't exist. Your code:
if (isset($json->primaries[1]->entries[1]->terms[1]->text)) // Doesn't exist
There's no terms[1] in entries[1] in primaries[1]. There's just 1 item; terms[0]. I think this will work for example:
if (isset($json->primaries[1]->entries[1]->terms[0]->text))
The first item in the array is indexed by 0 not 1, maybe that's your mistake.
Edit:
You also need to decode the JSON, change:
$json = substr($jsonp, 2, strlen($jsonp)-12);
to:
$json = json_decode(substr($jsonp, 2, strlen($jsonp)-12));
Edit:
You need to escape some unescaped characters in the JSON as well. Add this to your code:
Change:
$json = json_decode(substr($jsonp, 2, strlen($jsonp)-12));
to:
$json = substr($jsonp, 2, strlen($jsonp) - 12);
$json = str_replace("\\", "\\\\", $json);
$json = json_decode($json);

How can I convert a query string into a a shorter alphanumeric string (and convert it back again) in PHP?

I want to store the query string of the current URL as a shorter alphanumeric string with the ability to convert it back to the original query string.
For example:
inputType=timeline&count=50&hashtag=%23li&filterspecifiedhashtag=1&filterhashtagsend=1&filterscreennames=1&extracturl=1&deshortifyurl=1&filterurls=1
I want to be able to use the resultant alphanumeric string as a filename.
I want to avoid using MYSQL or storing values in a text file.
Is there a way to convert to an alphanumeric string as well as being able to convert it back to the original query string? I am not very knowledgeable about hashing but wondering whether some kind of "two way hashing" technique could work?
What you are seeking is not a hash - since hash is a one-way function in common case.
Here is a possible solution - use both base64 encryption and something like parameters map, so you will able to get shorter file name because you'll not store parameters names, only values:
class Holder
{
const NAME_PARAM_DELIMIER = '|';
public static function getParametersMap()
{
return [
0 => 'count',
1 => 'deshortifyurl',
2 => 'extracturl',
3 => 'filterhashtagsend',
4 => 'filterscreennames',
5 => 'filterspecifiedhashtag',
6 => 'filterurls',
7 => 'hashtag',
8 => 'inputType',
];
}
public static function getParamsByName($sName, $bReturnAsArray=true)
{
$rgParams = #array_combine(self::getParametersMap(), explode(self::NAME_PARAM_DELIMIER, base64_decode($sName)));
if(!is_array($rgParams))
{
return null;
}
return $bReturnAsArray?$rgParams:http_build_query($rgParams);
}
public static function getNameByParams($sQuery)
{
parse_str($sQuery, $rgParams);
ksort($rgParams);
return base64_encode(join(self::NAME_PARAM_DELIMIER, array_values($rgParams)));
}
}
$sQuery = 'inputType=timeline&count=50&hashtag=%23li&filterspecifiedhashtag=1&filterhashtagsend=1&filterscreennames=1&extracturl=1&deshortifyurl=1&filterurls=1';
$sName = Holder::getNameByParams($sQuery);
$rgData = Holder::getParamsByName($sName);
var_dump($sName); //NTB8MXwxfDF8MXwxfDF8I2xpfHRpbWVsaW5l
var_dump($rgData);
Also note that base64 will produce "=" symbols - I am not sure that it is allowed on all file systems (I'm using Reiser, so it's ok in my case)
You can use base64_encode() and base64_decode(), but if you want it as a filename, you'll likely hit filename length limit of filesystem (255 chars for ext3). If it's possible you hit this limit, you can use each X chars as directory name, and create full path.

Extract Data from a Website using PHP

I am trying to get PHP to extract the TOKEN (the uppercase one), USERID (uppercase), and the USER NAME (uppercase) from a web page with the following text.
{
"rsp":{
"stat":"ok",
"auth":{
"token":"**TOKEN**",
"perms":"read",
"user":{
"id":"**USERID**",
"username":"**USER NAME**",
"fullname":"**NAME OF USER**"
}
}
}
}
(This is from the RTM api, getting the authentication token of the user).
How would I go about doing this? Thanks!
EDIT:
how would i get task name "Buy Milk!" & the due date of the task"2011-02-28T.." using json_decode and php here? Thanks!
{
"rsp":{
"stat":"ok",
"tasks":{
"rev":"REV_NUMBER",
"list":{
"id":"ID_NUMBER",
"taskse­­ries":{
"id":"ID_NUMBER",
"created":"2010-11-16T00:01:50Z",
"modified":"2011-02-28T05:09:36Z",
"name":"Buy Milk!",
"source":"js",
"url":"",
"location_id":"",
"rrule":{
"every":"1",
"$t":"FREQ=W­­EEKLY;INTERVAL=1"
},
"tags":[
],
"participants":[
],
"notes":[
],
"task":{
"id":"ID_NUMBER" ­­,
"due":"2011-02-28T05:00:00Z",
"has_due_time":"0",
"added":"2011-02-21T05:04:49Z",
"completed":"",
"deleted":"",
"priority":"2",
"postponed":"0",
"estima­­te":""
}
}
}
}
}
}
As Delan suggested, use json_decode. Here is an example of how you would use json_decode to extract the information you require.
// your json string
$string = '{"rsp":{"stat":"ok","auth":{"token":"**TOKEN**","perms":"read","user":{"id":"**USERID**","username":"**USER NAME**","fullname":"**NAME OF USER**"}}}}';
// parse json string to an array
$array = json_decode($string, true);
// auth token
echo $array['rsp']['auth']['token'];
// user details
echo $array['rsp']['auth']['user']['id'];
echo $array['rsp']['auth']['user']['username'];
echo $array['rsp']['auth']['user']['fullname'];
UPDATE I've updated the code to use json_decode's $assoc parameter to convert from an object to an assoc array.
ANOTHER UPDATE To answer your updated question..
how would i get task name "Buy Milk!" & the due date of the task"2011-02-28T.." using json_decode and php here? Thanks!
This code would work to get the values that you want.
//string(9) "Buy Milk!"
echo $array['rsp']['tasks']['list']['taskseries']['name'];
// string(20) "2011-02-28T05:00:00Z"
echo $array['rsp']['tasks']['list']['taskseries']['task']['due'];
This code isn't ideal, but it gets the job done for you.
If the string is JSON, json_decode in PHP will do the trick. It's was implemented in PHP 5.2.0.
http://www.php.net/manual/en/function.json-decode.php

Categories