Zend Framework

Zend_Json_Encoder creates invalid JSON for Zend_Json_Decoder

Details

  • Type: Bug Bug
  • Status: Resolved Resolved
  • Priority: Blocker Blocker
  • Resolution: Fixed
  • Affects Version/s: 1.10.0, 1.10.1, 1.10.2
  • Fix Version/s: 1.10.6
  • Component/s: Zend_Json
  • Labels:
    None

Description

This piece of JSON was created with Zend_Json_Encoder::encode

{"_className":"fgSDK_Types_TTrip","IDuser":1,"Smoker":"flex","NumberPlate":"WI-EN 89","Places":2,"Contactlandline":"0221 54899","Contactmobile":"0175 54899","Description":"ich fahre nach k\u00f6ln","ClientIP":"192.168.1.20","Triptype":"offer","Routings":{"className":"fgSDK_Types_TRoutingCollection",0:{"className":"fgSDK_Types_TRouting","Origin":{"className":"fgSDK_Types_TPlace","Address":"K\u00f6ln, Deutschland","Accuracy":4,"CountryCode":"DE","CountryName":"Deutschland","Longitude":6.9599115,"Latitude":50.9406645,"Placetype":"geo","LatLonBox":{"className":"fgSDK_Types_TLatLonBox","North":51.0530233,"South":50.8280335,"East":7.2160303,"West":6.7037927}},"Destination":{"className":"fgSDK_Types_TPlace","Address":"Hamburg, Deutschland","Accuracy":4,"CountryCode":"DE","CountryName":"Deutschland","Longitude":9.9921962,"Latitude":53.5534074,"Placetype":"geo","LatLonBox":{"_className":"fgSDK_Types_TLatLonBox","North":53.6593331,"South":53.4472158,"East":10.248315,"West":9.7360774}},"RoutingIndex":-1}}}

During Decoding using Zend_Json_Decoder::decode this exception is thrown:

Message: Missing key in object encoding: {"_className":"fgSDK_Types_TTrip","IDuser":1,"Smoker":"flex","NumberPlate":"WI-EN 89","Places":2,"Contactlandline":"0221 54899","Contactmobile":"0175 54899","Description":"ich fahre nach köln","ClientIP":"192.168.1.20","Triptype":"offer","Routings":{"className":"fgSDK_Types_TRoutingCollection",0:{"className":"fgSDK_Types_TRouting","Origin":{"className":"fgSDK_Types_TPlace","Address":"Köln, Deutschland","Accuracy":4,"CountryCode":"DE","CountryName":"Deutschland","Longitude":6.9599115,"Latitude":50.9406645,"Placetype":"geo","LatLonBox":{"className":"fgSDK_Types_TLatLonBox","North":51.0530233,"South":50.8280335,"East":7.2160303,"West":6.7037927}},"Destination":{"className":"fgSDK_Types_TPlace","Address":"Hamburg, Deutschland","Accuracy":4,"CountryCode":"DE","CountryName":"Deutschland","Longitude":9.9921962,"Latitude":53.5534074,"Placetype":"geo","LatLonBox":{"_className":"fgSDK_Types_TLatLonBox","North":53.6593331,"South":53.4472158,"East":10.248315,"West":9.7360774}},"RoutingIndex":-1}}}
Stack trace:

#0 D:\server\lib\zend1.10\Zend\Json\Decoder.php(174): Zend_Json_Decoder->_decodeObject()
#1 D:\server\lib\zend1.10\Zend\Json\Decoder.php(219): Zend_Json_Decoder->_decodeValue()
#2 D:\server\lib\zend1.10\Zend\Json\Decoder.php(174): Zend_Json_Decoder->_decodeObject()
#3 D:\server\lib\zend1.10\Zend\Json\Decoder.php(156): Zend_Json_Decoder->_decodeValue()
#4 D:\dev\web[REMOVED]\service.[REMOVED]\trunk\application\controllers\TripController.php(38): Zend_Json_Decoder::decode('{"__className":...')
#5 D:\server\lib\zend1.10\Zend\Controller\Action.php(513): TripController->putAction()
#6 D:\server\lib\zend1.10\Zend\Controller\Dispatcher\Standard.php(289): Zend_Controller_Action->dispatch('putAction')
#7 D:\server\lib\zend1.10\Zend\Controller\Front.php(954): Zend_Controller_Dispatcher_Standard->dispatch(Object(Zend_Controller_Request_Http), Object(Zend_Controller_Response_Http))
#8 D:\server\lib\zend1.10\Zend\Application\Bootstrap\Bootstrap.php(97): Zend_Controller_Front->dispatch()
#9 D:\server\lib\zend1.10\Zend\Application.php(366): Zend_Application_Bootstrap_Bootstrap->run()
#10 D:\dev\web[REMOVED]\service.[REMOVED]\trunk\public\index.php(76): Zend_Application->run()
#11 {main}

Activity

Hide
Ben Scholzen added a comment -

Could you please provide the source data (array/object) for debugging?

Show
Ben Scholzen added a comment - Could you please provide the source data (array/object) for debugging?
Hide
Robert added a comment -

Please see the attached files.

You need to extract the ZIP file (required types)

in the zend.php you can see the object creation and structure.

Do you need anything else?

br
robert

Show
Robert added a comment - Please see the attached files. You need to extract the ZIP file (required types) in the zend.php you can see the object creation and structure. Do you need anything else? br robert
Hide
Robert added a comment -

Hi again,

sorry but its the first issue which I'm reported here.

What are the next steps?
Is there a quick FIX available?

Can sombody here help in a short term?

br
robert

Show
Robert added a comment - Hi again, sorry but its the first issue which I'm reported here. What are the next steps? Is there a quick FIX available? Can sombody here help in a short term? br robert
Hide
Matthew Weier O'Phinney added a comment -

Fixes to issues are prioritized by severity; that said, they're also going to occur based on availability of the contributors/maintainers of the components in question. The easier it is for a contributor to reproduce the issue, the easier it will be for them to work on it.

Is there any chance you can simplify the reproduce case further?

Show
Matthew Weier O'Phinney added a comment - Fixes to issues are prioritized by severity; that said, they're also going to occur based on availability of the contributors/maintainers of the components in question. The easier it is for a contributor to reproduce the issue, the easier it will be for them to work on it. Is there any chance you can simplify the reproduce case further?
Hide
Robert added a comment -

I attached already this 2 Files, including only a few files to reproduce the issue.
It should be very very easy to reproduce and debug it.

For my client SOA architecture this functionality is key.

Is there a timeframe which I can communicate anyhow?

br

Show
Robert added a comment - I attached already this 2 Files, including only a few files to reproduce the issue. It should be very very easy to reproduce and debug it. For my client SOA architecture this functionality is key. Is there a timeframe which I can communicate anyhow? br
Hide
Núria Aloy added a comment -

This bug is related to the fact that one of the classes is an instance of Iterator. In that case the encoder iterates the object itself instead of its variables to produce the JSON string.

It can be reproduced in the following scenarios:

class A implements Iterator {
    
    protected $_stack;
    
    public function __construct(array $array)
    {
        $this->_stack = $array;
    }
    
    public function rewind() {
        reset($this->_stack);
    }

    public function current() {
        return current($this->_stack);
    }

    public function key() {
        return key($this->_stack);
    }

    public function next() {
        return next($this->_stack);
    }

    public function valid() {
        return $this->current() !== false;
    }
}

$a = new A(array("foo"));
$encoded = Zend_Json_Encoder::encode($a);
$decoded = Zend_Json_Decoder::decode($encoded);
// Exception 'Zend_Json_Exception' with message 'Missing key in object encoding: {"__className":"A",0:"foo"}'
class B extends ArrayIterator
{
    
}
$b = new B(array("foo"));
$encoded = Zend_Json_Encoder::encode($b);
$decoded = Zend_Json_Decoder::decode($encoded);
// Exception 'Zend_Json_Exception' with message 'Missing key in object encoding: {"__className":"B",0:"foo"}'
Show
Núria Aloy added a comment - This bug is related to the fact that one of the classes is an instance of Iterator. In that case the encoder iterates the object itself instead of its variables to produce the JSON string. It can be reproduced in the following scenarios:
class A implements Iterator {
    
    protected $_stack;
    
    public function __construct(array $array)
    {
        $this->_stack = $array;
    }
    
    public function rewind() {
        reset($this->_stack);
    }

    public function current() {
        return current($this->_stack);
    }

    public function key() {
        return key($this->_stack);
    }

    public function next() {
        return next($this->_stack);
    }

    public function valid() {
        return $this->current() !== false;
    }
}

$a = new A(array("foo"));
$encoded = Zend_Json_Encoder::encode($a);
$decoded = Zend_Json_Decoder::decode($encoded);
// Exception 'Zend_Json_Exception' with message 'Missing key in object encoding: {"__className":"A",0:"foo"}'
class B extends ArrayIterator
{
    
}
$b = new B(array("foo"));
$encoded = Zend_Json_Encoder::encode($b);
$decoded = Zend_Json_Decoder::decode($encoded);
// Exception 'Zend_Json_Exception' with message 'Missing key in object encoding: {"__className":"B",0:"foo"}'
Hide
Joel Clermont added a comment -

ZF-9416.patch includes a test that demonstrates this bug. The problem relates to the fact that ArrayIterator gets encoded as an object in JSON, which requires a string key for each value. However, when an array without keys is encoded it is an array in JSON, which does not have keys. I'm not sure what the proper behavior should be. Do we convert numeric keys to strings and preserve it as an object? Do we embed an array within the JSON object and follow the same rules for encoding arrays?

Show
Joel Clermont added a comment - ZF-9416.patch includes a test that demonstrates this bug. The problem relates to the fact that ArrayIterator gets encoded as an object in JSON, which requires a string key for each value. However, when an array without keys is encoded it is an array in JSON, which does not have keys. I'm not sure what the proper behavior should be. Do we convert numeric keys to strings and preserve it as an object? Do we embed an array within the JSON object and follow the same rules for encoding arrays?
Hide
Joel Clermont added a comment - - edited

I think the proper behavior is demonstrated by json_encode:

$iteratorA = new ArrayIterator(array('foo'));
$encoded = json_encode($iteratorA);
var_dump($encoded);

This produces:

string(11) "{"0":"foo"}"

I am going to follow this behavior in Zend_Json::encode and add the numeric keys as strings for safety.

Show
Joel Clermont added a comment - - edited I think the proper behavior is demonstrated by json_encode:
$iteratorA = new ArrayIterator(array('foo'));
$encoded = json_encode($iteratorA);
var_dump($encoded);
This produces:
string(11) "{"0":"foo"}"
I am going to follow this behavior in Zend_Json::encode and add the numeric keys as strings for safety.
Hide
Joel Clermont added a comment -

In the sample code, it is calling Json_Encoder and Json_Decoder directly. A better approach is to use Json::encode and Json::decode. This way, if you have json support in PHP it will use the native functions json_encode and json_decode. Not only is it faster, but this bug does not occur. The bug only exists in the internal class Json_Encoder (which I will soon fix).

Show
Joel Clermont added a comment - In the sample code, it is calling Json_Encoder and Json_Decoder directly. A better approach is to use Json::encode and Json::decode. This way, if you have json support in PHP it will use the native functions json_encode and json_decode. Not only is it faster, but this bug does not occur. The bug only exists in the internal class Json_Encoder (which I will soon fix).
Hide
Joel Clermont added a comment -

ZF-9416-2.patch fixes the bug and includes a better unit test. I fixed the bug by using the internal _encodeString function for keys within an object, since JSON requires that object keys always be strings. This handles the encoding of numeric keys in the same way as the native json_encode feature now. Unit test now passes. Should be ready to commit.

Show
Joel Clermont added a comment - ZF-9416-2.patch fixes the bug and includes a better unit test. I fixed the bug by using the internal _encodeString function for keys within an object, since JSON requires that object keys always be strings. This handles the encoding of numeric keys in the same way as the native json_encode feature now. Unit test now passes. Should be ready to commit.
Hide
Joel Clermont added a comment -

Unit test written to demonstrate the problem and prove that the patch fixes it. Please use the ZF-9416-2.patch file.

Show
Joel Clermont added a comment - Unit test written to demonstrate the problem and prove that the patch fixes it. Please use the ZF-9416-2.patch file.
Hide
Ralph Schindler added a comment -

Was not resolved in code (yet).

Show
Ralph Schindler added a comment - Was not resolved in code (yet).
Hide
Ralph Schindler added a comment -

Resolved in r22452 in trunk and in r22453 in release branch 1.10 with patch "-2" from above.

Show
Ralph Schindler added a comment - Resolved in r22452 in trunk and in r22453 in release branch 1.10 with patch "-2" from above.

People

Vote (0)
Watch (3)

Dates

  • Created:
    Updated:
    Resolved: