【问题标题】:How to deal with backslashes in json strings php如何处理 json 字符串 php 中的反斜杠
【发布时间】:2015-11-10 11:26:42
【问题描述】:

在尝试解码由 json_encode 生成的字符串时,json_encode 和/或 json_decode 似乎有些奇怪:

    $object = new stdClass;
    $object->namespace = 'myCompany\package\subpackage';

    $jsonEncodedString = json_encode($object);
    echo $jsonEncodedString;
    // Result of echo being:
    // {"namespace":"myCompany\\package\\subpackage"}

    $anotherObject = json_decode($jsonEncodedString);
    echo $anotherObject->namespace;
    // Result of echo being:
    // myCompany\package\subpackage


    $yetAnotherObject = json_decode('{"namespace":"myCompany\\package\\subpackage"}');
    // Result should be:
    // myCompany\package\subpackage
    // But returns an invalid string sequence error instead...
    echo json_last_error_msg();

在此之前我从未遇到过问题,因为直到今天我才不得不捕获带有反斜杠的字符串。在查看上面的代码时,我可以使用 PHP 的内置组件进行编码/解码。但是,如果我尝试解码此编码器生成的字符串,我会收到一条错误消息。我已经阅读了诸如“Predefined Constants”之类的文档项目以及诸如“how remove the backslash (“\”) in the json response using php?”之类的其他堆栈问题。但我似乎找不到为什么我无法解码由 json_encode 生成的字符串的原因。我用来测试这段代码的 PHP 版本是 5.5.9。

我知道我可能会因为遗漏某些东西而一无所知,但是如果我尝试在其他地方使用它,我是否应该以不同的方式处理由 json_encode 生成的字符串?

【问题讨论】:

    标签: php json


    【解决方案1】:

    那是因为 PHP 在将双斜杠传递给 json_decode 之前将其转换为单斜杠。您将需要转义双斜杠(我知道这很痛苦)或手动构造对象。

    http://php.net/manual/en/language.types.string.php#language.types.string.syntax.single

    【讨论】:

    • 所以要明确一点,建议是在字符串上执行类似的操作: str_replace() 并在我尝试 json_decode 的字符串中添加一个额外的反斜杠?看起来有点笨拙。
    • 是的,这是一个奇怪的解决方法,但它是最简单的方法。 str_replace( "\\", "\\\\", $input );
    • 这看起来真的很奇怪,因为现在在我清理输入后,我现在必须检查每个字符串是否有反斜杠并进行替换。看起来这不应该是应该在编程级别而是在语言级别处理的事情。好吧,我今天学到了一些东西,谢谢布莱克!
    • PHP 不转换任何东西。您将一种语言用来表示字符串中特殊字符的约定误认为是解析器在运行时通过遵循约定生成的字符序列。 \` is the way to tell the PHP parser you want a ` 在字符串中。
    【解决方案2】:

    您可以使用stripslashes 函数去除破折号,它会工作测试

      $yetAnotherObject = json_decode(stripslashes('{"namespace":"myCompany\\package\\subpackage"}'));
    

    【讨论】:

    • 如果您使用 stripslashes(),那么您将对象内的数据更改为:{"namespace":"myCompanypackagesubpackage"},这是一个不同的值。
    • 来自文档:“返回一个去掉反斜杠的字符串。(\' 变为 ' 等等。)双反斜杠 (\) 被制成一个反斜杠 ()。”所以在这种情况下,它只会去掉两个斜杠之一,但这不是预期的结果。
    【解决方案3】:

    您需要将双反斜杠 \\ 编码为四重反斜杠 \\\\,因为 php 将反斜杠解释为单引号和双引号字符串中的转义字符。这意味着\\ 被视为\

    这个例子说明了正在发生的事情

    <?php
    $str = '{"namespace":"myCompany\\package\\subpackage"}';
    echo $str, PHP_EOL; // \\ seen as \
    $yetAnotherObject = json_decode($str);
    echo json_last_error_msg(), PHP_EOL;
    
    var_dump(json_decode(str_replace('\\', '\\\\', $str)));
    echo json_last_error_msg(), PHP_EOL;
    

    这是输出

    $ php test.php
    {"namespace":"myCompany\package\subpackage"}
    Syntax error
    class stdClass#1 (1) {
      public $namespace =>
      string(28) "myCompany\\package\\subpackage"
    }
    No error
    

    【讨论】:

      【解决方案4】:

      答案就在问题中:

      $jsonEncodedString = json_encode($object);
      echo $jsonEncodedString;
      // Result of echo being:
      // {"namespace":"myCompany\\package\\subpackage"}
      

      您不必去除任何斜线。相反。您必须将回显文本表示为 PHP 源代码。

      $yetAnotherObject = json_decode('{"namespace":"myCompany\\\\package\\\\subpackage"}');
      

      反斜杠 (\) 在 PHP 和 JSON 中都是一个特殊字符。两种语言都使用它来转义字符串中的特殊字符,并且为了在字符串中正确表示反斜杠,您必须在 PHP 和 JSON 中为其添加另一个反斜杠。

      让我们尝试在上面的字符串上完成 PHP 解析器的工作。在左括号之后遇到string enclosed in single quotes。有两个特殊字符需要在单引号字符串中转义:撇号 (') 和反斜杠 (\)。虽然撇号总是需要转义,但 PHP 解释器是宽容的,只要不造成混淆,就允许使用非转义的反斜杠。但是,单引号字符串中反斜杠的正确表示是\\

      传递给函数json_decode()的字符串是

      {"namespace":"myCompany\\package\\subpackage"}
      

      请注意,这是在运行时处理的字符的确切列表,而不是 PHP 或任何其他语言表示的字符串。语言具有表示特殊字符的特殊规则。这只是纯文本。

      上面的文本由函数json_decode() 解释,它期望它是JSON 的一部分。 JSON 是一种小语言,它对字符串中特殊字符的编码有特殊的规则。反斜杠是这些字符之一,当它出现在字符串中时,必须在前面加上另一个反斜杠。 JSON 不宽容;当遇到反斜杠时,它总是将其视为字符串中下一个字符的转义字符。

      json_decode() 在成功解析您传递给它们的 JSON 表示后创建的对象包含一个名为 namespace 的属性,其值为:

      myCompany\package\subpackage
      

      再次注意,这是实际的字符串,而不是任何语言的表示。

      出了什么问题?

      回到你的代码:

      $yetAnotherObject = json_decode('{"namespace":"myCompany\\package\\subpackage"}');
      

      PHP 解析器使用 PHP 规则解释上述代码。它理解json_decode() 函数必须以文本{"namespace":"myCompany\package\subpackage"} 作为参数调用。

      json_decode() 使用它的规则并尝试将上面的文本解释为一段 JSON 表示。 myCompany 之前的引号 (") 告诉它必须将 "myCompany\package\subpackage" 解析为字符串。 package 之前的反斜杠被解释为 p 的转义字符,但 \p 不是 JSON 中字符串的有效转义序列。这就是为什么它拒绝继续并返回NULL

      【讨论】:

      • 如果我想在 javascript 中直接使用 PHP 中的 json_encode 怎么办,比如 JSON.parse('$encoded') 那么它将不起作用。
      • json_encode() 生成的字符串是一个完全有效的 JavaScript 数据定义。像这样的(HTML+PHP 的)片段:let x = &lt;?php json_encode($value); ?&gt;; 生成正确的 JavaScript 片段。没有要解码的内容。
      • 如果你非要,就拿数据库中一个实体的json_encode生成的这个JSON。 {"id":20,"user_id":83,"done_at":null,"created_at":"2020-05-18 23:26:21","updated_at":"2020-05-18 23:26:21","taskable_type":"App\\Entities\\Tasks\\NormalTask","taskable_id":1,"counter":0} 尝试使用 javascript 解析它,它不起作用,因为它有一个 json_encode 已转义的命名空间,但 JSON 并未将其视为已转义!
      • perfectly valid JSON,可以直接用JavaScript code。不要将 JSON 包裹在引号或撇号中!它不会使其成为有效的 JavaScript 字符串。按原样使用它。如果你想使用JSON.parse() 解析它,然后将它写入一个文件,然后从那里读取它。
      • 太棒了,它对我有用!但是我在想我总是需要从PHP解析数据才能将其转换为JS对象,你能不能多说明一下,如果不需要解析数据那么JSON.parse有什么用?
      【解决方案5】:

      请使用PHP原生函数stripslashes

      https://www.php.net/manual/en/function.stripslashes.php

      <?php
      $str = 'myCompany\\package\\subpackage';
      echo stripslashes(json_encode($str));
      //output: myCompany\package\subpackage
      

      【讨论】:

        【解决方案6】:

        不幸的是,当 json_decode() 尝试解码带有双反斜杠 ("\\") 的 JSON 字符串时,它会抛出 JsonException。

        <?php
        var_dump(
            json_decode(
                '{"Server": "\\\\ComputerName\\MainDirectory\\SubDirectory"}',
            false, 512, JSON_THROW_ON_ERROR)
        );
        

        <br />
        <b>Fatal error</b>:  Uncaught JsonException: Syntax error in [...][...]:2
        Stack trace:
        #0 [...][...](2): json_decode('{&quot;Server&quot;: &quot;\\\\C...', false, 512, 4194304)
        #1 {main}
          thrown in <b>[...][...]</b> on line <b>2</b><br />

        为了解决这个问题, 我们可以使用 str_replace() 将这些双反斜杠 ("\\") 转换为四反斜杠 ("\\\\")。

        <?php
        var_dump(
            json_decode(
                str_replace('\\','\\\\','{"Server": "\\\\ComputerName\\MainDirectory\\SubDirectory"}'),
                false, 512, JSON_THROW_ON_ERROR
            )
        );
        
        
        object(stdClass)#1 (1) {
            ["Server"]=>
            string(41) "\\ComputerName\MainDirectory\SubDirectory"
        }
        

        希望这会有所帮助。

        【讨论】:

        • 这是不正确的。首先,在使用 JSON 时不要使用字符串操作。其次,你所说的JsonException 的错误是因为你的 JSON 中的无效转义,在这种情况下是 \M\S。所以这个输入的 JSON 一开始就是畸形的。也许它被错误地编码或复制了?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-03-17
        • 1970-01-01
        • 2016-08-28
        • 2017-12-27
        • 1970-01-01
        • 1970-01-01
        • 2011-11-23
        相关资源
        最近更新 更多