Prevent quoting of certain values with PHP json_encode()

后端 未结 7 1391
广开言路
广开言路 2021-01-06 01:21

When using PHP\'s json_encode to encode an array as a JSON string, is there any way at all to prevent the function from quoting specific values in the returned string? The r

相关标签:
7条回答
  • 2021-01-06 01:34

    Following the lead of Stefan Gehrig I put this rough little class together. Example below. One must remember to use the serialize method if one has used the mark method, otherwise the markers will persist in the final 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>
    
    0 讨论(0)
  • 2021-01-06 01:39

    No, json_encode can't do that. You need to construct your JS expression by hand then:

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

    (Try to still use json_encode for fixed value parts, like in above example.)

    0 讨论(0)
  • 2021-01-06 01:45

    The json_encode function does not provide any functionality for controlling the quotes. The quotes are also necessary for JavaScript to properly form the object on the JavaScript side.

    In order to use the returned value to construct an object on the JavaScript side, use the json_encoded string to set flags in your association.

    For example:

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

    JavaScript side in the AJAX:

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

    After these steps you can pass your object off somewhere.

    0 讨论(0)
  • 2021-01-06 01:47

    This is what I ended up doing, which is pretty close to what Stefan suggested above I think:

    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;
        }
    }
    
    0 讨论(0)
  • 2021-01-06 01:49

    What we do is (and that's what Zend_Json::encode() does too), is to use a special marker class that encapsulates Javascript expressions in a special class. The encoding then walks recursively through our array-to-be-encoded, replaces all marker instances with some string. After using the built-in json_encode() we simply do a string replace to replace each special string with the __toString() value of the respective marker instance.

    You can either use Zend_Json directly (if that's possible) or check how they do it and adapt the code to your needs.

    0 讨论(0)
  • 2021-01-06 01:56

    Bill's function almost worked, it just needed the is_assoc() function added.

    But while I was sorting this out, I cleaned it up a bit. This seems to work quite well for me:

    <?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;
        }
    }
    
    0 讨论(0)
提交回复
热议问题