【问题标题】:Prevent quoting of certain values with PHP json_encode()防止使用 PHP json_encode() 引用某些值
【发布时间】:2016-09-18 07:20:58
【问题描述】:

当使用 PHP 的 json_encode 将数组编码为 JSON 字符串时,有没有办法阻止函数在返回的字符串中引用特定值?我问的原因是因为我需要 javascript 将对象中的某些值解释为实际变量名称,例如现有 javascript 函数的名称。

我的最终目标是使用输出的 json 作为 ExtJS Menu 组件的配置对象,因此引用所有内容的事实阻止我成功设置子项的“处理程序”(单击事件处理函数)等属性数组。

【问题讨论】:

    标签: php json


    【解决方案1】:

    我们所做的是(这也是Zend_Json::encode() 所做的),是使用一个特殊的marker 类,它将Javascript 表达式封装在一个特殊的类中。然后编码递归遍历我们的待编码数组,用一些字符串替换所有 marker 实例。使用内置的json_encode() 后,我们只需进行字符串替换,将每个特殊字符串替换为相应marker 实例的__toString() 值。

    您可以直接使用Zend_Json(如果可能的话)或检查how they do it 并根据您的需要调整代码。

    【讨论】:

      【解决方案2】:

      Bill 的函数几乎可以工作了,只需要添加 is_assoc() 函数即可。

      但是当我整理这个时,我把它清理了一下。这对我来说似乎很有效:

      <?php
      
      /**
       * JSObject class.
       */
      
      class JSObject {
          var $jsexp = 'JSEXP:';
      
          /**
           * is_assoc function.
           *
           * Determines whether or not the object is an associative array
           * 
           * @access public
           * @param mixed $arr
           * @return boolean
           */
          function is_assoc($arr) {
              return (is_array($arr) && count(array_filter(array_keys($arr),'is_string')) == count($arr));
          }
      
          /**
           * Encode object
           *
           * Encodes the object as a json string, parsing out items that were flagged as objects so that they are not wrapped in double quotes.
           *
           * @param     array   $properties
           * @return    string
           */
          function encode($properties = array()) {
      
              $is_assoc = $this->is_assoc($properties);
      
              $enc_left  = $is_assoc ? '{' : '[';
              $enc_right = $is_assoc ? '}' : ']';
      
              $outputArray = array();
      
              foreach ($properties as $prop => $value) {
      
                  if ((is_array($value) && !empty($value)) || (is_string($value) && strlen(trim(str_replace($this->jsexp, '', $value))) > 0) || is_int($value) || is_float($value) || is_bool($value)) {
      
                      $output = (is_string($prop)) ? $prop.': ' : '';
      
                      if (is_array($value)) {
                          $output .= $this->encode($value);
                      }
                      else if (is_string($value)) {
                          $output .= (substr($value, 0, strlen($this->jsexp)) == $this->jsexp) ?  substr($value, strlen($this->jsexp))  : json_encode($value);
                      }
                      else {
                          $output .= json_encode($value);
                      }
      
      
                      $outputArray[] = $output;
                  }
              }
      
              $fullOutput = implode(', ', $outputArray);
      
              return $enc_left . $fullOutput . $enc_right;
          }
      
          /**
           * JS expression
           *
           * Prefixes a string with the JS expression flag
           * Strings with this flag will not be quoted by encode() so they are evaluated as expressions
           *
           * @param   string  $str
           * @return  string
           */
          function js($str) {
              return $this->jsexp.$str;
          }
      }
      

      【讨论】:

        【解决方案3】:

        不,json_encode 不能这样做。然后你需要手动构造你的 JS 表达式

        $json = "{'special':" . json_encode($string) . " + js_var,"
              .  "'value': 123}";
        

        (尝试仍将 json_encode 用于固定值部分,如上例。)

        【讨论】:

        • 是的,这就是我害怕的,因为这是一个多维数组,子数组的深度未知,这将使手工构建这个json字符串变得很痛苦:-(跨度>
        • 编写自己的小型 json 编码器并不复杂。只需让它链接到 PHP 为普通值(字符串和数字)提供的 json_encode,并让它为任何对象调用 __toString(这样你就可以抛出你自己的 JS 表达式)。您可能不需要数组支持甚至递归。 (但全部手写可能是最简单的选择。)
        【解决方案4】:

        json_encode 函数不提供任何控制引号的功能。引号也是 JavaScript 在 JavaScript 端正确形成对象所必需的。

        为了使用返回值在 JavaScript 端构造对象,请使用 json_encoded 字符串在您的关联中设置标志。

        例如:

        json_encode( array( "click_handler"=> "FOO" ) );
        

        AJAX 中的 JavaScript 端:

        if( json.click_handler == "FOO" ) {
          json.click_handler = Your_Handler;
        }
        

        完成这些步骤后,您可以将对象传递到某个地方。

        【讨论】:

          【解决方案5】:

          我的快速修复是这样的:

          $myobject->withquotes = 'mystring';
          $myobject->withoutquotes = '##noquote## mystring ##noquote##';
          

          以后

          str_replace(array('"##noquote## ', ' ##noquote##"'), '', json_encode($myobject))
          

          结果是这样的

          {"withquotes":"mystring","withoutquotes":mystring}
          

          【讨论】:

            【解决方案6】:

            这就是我最终做的事情,这与我认为上面 Stefan 建议的非常接近:

            class JSObject
            {
                var $jsexp = 'JSEXP:';
            
                /**
                 * Encode object
                 * 
                 * 
                 * @param     array   $properties
                 * @return    string 
                 */
                function encode($properties=array())
                {
                    $output    = '';
                    $enc_left  = $this->is_assoc($properties) ? '{' : '[';
                    $enc_right = ($enc_left == '{') ? '}' : ']';
            
                    foreach($properties as $prop => $value)
                    {
                        //map 'true' and 'false' string values to their boolean equivalent
                        if($value === 'true')  { $value = true; }
                        if($value === 'false') { $value = false; }
            
                        if((is_array($value) && !empty($value)) || (is_string($value) && strlen(trim(str_replace($this->jsexp, '', $value))) > 0) || is_int($value) || is_float($value) || is_bool($value))
                        {
                            $output .= (is_string($prop)) ? $prop.': ' : '';
            
                            if(is_array($value))
                            {
                                $output .= $this->encode($value);
                            }
                            else if(is_string($value))
                            {
                                $output .= (substr($value, 0, strlen($this->jsexp)) == $this->jsexp) ?  substr($value, strlen($this->jsexp))  : '\''.$value.'\'';
                            }
                            else if(is_bool($value))
                            {
                                $output .= ($value ? 'true' : 'false');
                            }
                            else
                            {
                                $output .= $value;
                            }
            
                            $output .= ',';
                        }
                    }
            
                    $output = rtrim($output, ',');
                    return $enc_left.$output.$enc_right;
                }
            
                /**
                 * JS expression
                 * 
                 * Prefixes a string with the JS expression flag
                 * Strings with this flag will not be quoted by encode() so they are evaluated as expressions
                 * 
                 * @param   string  $str
                 * @return  string
                 */
                function js($str)
                {
                    return $this->jsexp.$str;
                }
            }
            

            【讨论】:

              【解决方案7】:

              在 Stefan Gehrig 的带领下,我把这个粗糙的小班放在一起。下面的例子。使用过mark方法的一定要记得使用serialize方法,否则标记会一直存在于最终的json中。

              class json_extended {
              
                  public static function mark_for_preservation($str) {
                      return 'OINK' . $str . 'OINK'; // now the oinks will be next to the double quotes
                  }
              
                  public static function serialize($stuff) {
                      $json = json_encode($stuff);
                      $json = str_replace(array('"OINK', 'OINK"'), '', $json);
                      return $json;
                  }
              }
              
              
              $js_arguments['submitHandler'] = json_extended::mark_for_preservation('handle_submit');
              
              <script>
              $("form").validate(<?=json_extended::serialize($js_arguments)?>);
              // produces: $("form").validate({"submitHandler":handle_submit});
              function handle_submit() {alert( 'Yay, pigs!'); }
              </script>
              

              【讨论】:

                猜你喜欢
                • 2018-07-16
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2022-07-08
                • 2019-05-14
                • 2015-11-16
                • 2016-05-21
                • 1970-01-01
                相关资源
                最近更新 更多