【问题标题】:Convert nested json object into a php string without stripping values将嵌套的 json 对象转换为 php 字符串而不剥离值
【发布时间】:2014-07-23 23:57:08
【问题描述】:

我正在接收带有以下 JSON 对象的 HTTP Post:

{"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":"testuser@somesite.com","address":{}},"billing":{"firstName":"TEST","lastName":"USER","fullName":"Test User","email":"testuser@somesite.com","address":{}}},"lineItems":[{"itemNo":"1","productTitle":"A passed in title","shippable":false,"recurring":false,"customerProductAmount":1.00,"customerTaxAmount":0.00}]},"verification":"2745A502"}

我需要将“通知”JSON 对象转换为分配给 PHP 变量的 JSON 字符串,而不会丢失任何数据,包括小数。

目前我使用$ipn_raw = file_get_contents('php://input'); 接收IPN。 然后我将 JSON json_decode 为 PHP 变量,然后使用 json_encode 重新编码通知部分。代码如下:

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

但是,结果去掉了一些值,给了我以下信息:

{"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":"testuser@somesite.com","address":[]},"billing":{"firstName":"TEST","lastName":"USER","fullName":"Test User","email":"testuser@somesite.com","address":[]}},"lineItems":[{"itemNo":"1","productTitle":"A passed in title","shippable":false,"recurring":false,"customerProductAmount":1,"customerTaxAmount":0}]}

您可以看到版本 6.0 现在只是版本 6,totalProductAmount 是 1.00 现在是 1,等等。

如何在结果中不改变任何值的情况下做到这一点?

谢谢!

根据要求,这里有一些额外的背景信息,说明为什么我需要所有内容都与原始内容保持一致。 Clickbank 为我提供了以下信息,以便创建必要的 SHA 1 哈希来验证我从他们那里收到的第 6 版 IPN(请参阅https://support.clickbank.com/entries/22803622-Instant-Notification-Service

1) 使用 JSON 库/DSL 从 IPN 中提取“通知”JSON 对象。 2) 将“通知”JSON 对象转换为 JSON 字符串。该字符串应以大括号 { 开头并以大括号 } 结尾,因为它是 JSON 对象的表示形式。 3) 将密钥直接附加到通知对象末尾大括号之后的字符串上。没有空格或分隔符。 4) SHA 1 散列在步骤 3 中创建的字符串。 5) 取第 4 步中创建的哈希的前 8 个字符。这就是 v6 IPN 中“验证”字段的值。

如果需要,我可以为其余步骤提供我的所有代码,但在这一点上,我唯一遇到的问题是将通知对象单独保存在一个字符串中。

【问题讨论】:

  • 您知道6.06 只是同一个数字的两个不同表示。您甚至可以尝试使用 PHP:var_dump(6.0 == 6); // will print true
  • 是的,knittl。我知道它们是相同的表示;但是,我需要有完全相同的输出才能为我上面没有提到的另一个步骤生成匹配的 SHA 1 哈希。
  • 那么你应该在你的问题中提到每一个必要的细节;)你的输出中的空白呢? JSON 字符串 { "v" : 1 }{"v":1} 也描述了同一个对象。
  • 我在问题的底部添加了一些背景信息。我不确定空格是否会影响 SHA1 哈希的生成。
  • 在加密算法中,即使是字节也会改变即将到来的哈希

标签: php json


【解决方案1】:

您要问什么(鉴于您正在散列 JSON 对象的 string 表示),您需要通过字符串操作方法(例如,正则表达式)提取 JSON 的相关部分):

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

这将删除开头的第二个花括号的所有内容,以及末尾倒数第二个花括号的所有内容。 (但它显然只有在你的 JSON 具有这种精确格式时才有效,即通知是唯一的嵌套对象、第一个对象,以及之后的所有内容都不包含 }(尤其是验证码))


似乎有一个关于此的“错误”报告:https://bugs.php.net/bug.php?id=50224,尽管字符串化6.0 似乎是预期的行为,而 JavaScript 也会做同样的事情。另请参阅此相关问题:PHP function json_decode decodes float value with zeros after point as int

【讨论】:

  • 当然,对于嵌套结构(OP 具有),这将失败
  • @AlmaDo:为什么 OP 的 JSON 字符串会失败?我在回答中明确提到了这种方法的注意事项。
  • 通知不是唯一的嵌套对象...您有“客户”以及其他几个。这会是个问题吗?
  • @deggertsen:很有可能。也许您可以调整正则表达式。您还应该记住,浮点值不能代表每个十进制值(例如,1.1 不能以二进制精确表示,您只能存储一个近似值)。如果你觉得很时髦,你甚至可以编写一个解析器来计算大括号并忽略字符串中的大括号来提取你的通知对象。
  • @deggertsen:查看我对答案的更新。 JavaScript 的行为方式与 PHP 相同,并将 x.0 值表示为整数。
【解决方案2】:

问题是:从价值观的角度来看,6.06 都是相同的浮点数。因此,在解码时,PHP 会丢失这个十进制格式点。因此,在您第一次拨打json_decode() 时,您已经丢失了有关小数点位数的数据。

解决的方法可能是将您的值原位包含在原始源 json 中,并使用相当,将它们转换为字符串 并以该格式将它们存储在 PHP 中。就像:

$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":"testuser@somesite.com","address":{}},"billing":{"firstName":"TEST","lastName":"USER","fullName":"Test User","email":"testuser@somesite.com","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);

所以现在您的对象会将您的值存储为字符串,这不会导致小数点丢失。当然,解码时你需要做相反的事情:

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

但这有一个缺陷:因为你会丢失关于什么是实际字符串和什么是浮点数的数据。因此,如果您的原始 json 包含像 "6.00" 这样的 string 并且它应该是字符串,那么这种转换将丢失该信息并使该值浮动。因此,如果您的数据以这种形式包含此类字符串,那么 - 是的,这不是要走的路(但我怀疑有一种简单的方法可以在不实现自己的 json 解析器的情况下使用)

【讨论】:

  • 谢谢。这很有帮助。看起来一团糟……clickbank 即时通知服务的第 4 版要容易得多。有没有办法使用 javascript 来做到这一点,然后将结果保存到变量中?
  • 我不确定你想在 js 中做什么,但在这里,问题出在 PHP 方面(它是去除小数点零的 PHP 解析器)
【解决方案3】:

对于任何感兴趣的人,这是我最终使用的:

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

【讨论】:

    猜你喜欢
    • 2021-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-16
    • 2021-12-06
    • 2013-11-04
    • 1970-01-01
    • 2018-12-25
    相关资源
    最近更新 更多