jakoch / PHPTracRPC

A PHP library to interact with the Trac Bugtracker API via remote procedure calls.
4 stars 2 forks source link

Issue with empty "attr" data arrays when calling Trac XML-RPC methods in JSON #2

Closed mmr99869 closed 8 years ago

mmr99869 commented 8 years ago

Hi everyone,

I had an issue with PHPTracRPC when creating Trac tickets. Specifically, when I have an empty "attr" data array:

$ticket_data = array();
$ticket_data['summary'] = 'The ticket summary text';
$ticket_data['desc'] = 'The ticket description text';
$ticket_data['attr'] = array();
$ticket_data['notify'] = false;

$credentials = array('username' => 'theuser', 'password' => 'thepassword');
$trac = new TracRPC('http://trac.example.com/login/jsonrc', $credentials);
$trac->setMultiCall(true);  
$ticket = $trac->getTicketUpdate('create','',$ticket_data);
$trac->doRequest();
$ticket = $trac->getResponse($ticket);

If executed, the above code will produce the following JSON error response:

{
    "result": null,
    "error": {
        "name": "JSONRPCError",
        "message": "'list' object has no attribute 'iteritems'",
        "code": -32603
    },
    "id": 1
}

I analyzed a little bit the PHPTracRPC code and I found the problem when encoding the request in JSON. It seems that empty "attr" data array produces "[]" instead of "{}":

if (is_array($this->request) === true) {
    $this->request = json_encode(array_pop($this->request)); // it produces "[]"
    $this->request = str_replace(':', ': ', $this->request);
    $this->request = str_replace(',', ', ', $this->request);
}

The produced $ticket_data JSON request is:

{
    "method": "system.multicall",
    "params": [
        {
            "method": "ticket.create",
            "params": [
                "The ticket summary text",
                "The ticket description text",
                [],
                false
            ],
            "id": 1
        }
    ],
    "id": 1
}

When changing "[]" to "{}" the problem dissappears. When using a keyed and filled "attr" data array the problem also dissappears.

Maybe this is a bug?

jakoch commented 8 years ago

Hey, thank you for reporting the issue.

I think we need to force the creation of an empty object by using JSON_FORCE_OBJECT, e.g.

json_encode(array_pop($this->request), JSON_FORCE_OBJECT);

This should generate {} instead of [] for the empty $ticket_data['attr'] = array();

Please modify the code (https://github.com/jakoch/PHPTracRPC/blob/master/lib/TracRPC.php#L1177) and give me a feedback, if this works for you.

mmr99869 commented 8 years ago

Hi jakoch,

I tried what you explained about forcing the creation of an empty object inside TracRPC.php:

$this->request = json_encode(array_pop($this->request), JSON_FORCE_OBJECT);

However, it did not work. The generated JSON object contains the following:

{
    "method": "system.multicall",
    "params": {
        "0" : {
            "method": "ticket.create",
            "params": {
                "0" : "The ticket summary text",
                "1" : "The ticket description text",
                "2" : {},
                "3" : false
            },
            "id": 1
        }
    },
    "id": 1
}

When sending the request, Trac returns a JSON error:

{
    "result": null,
    "error": {
        "name": "JSONRPCError",
        "message": "JsonProtocolException details : 'unicode' object has no attribute 'get'",
        "code": -32700
    },
    "id": 1
}

For now, what is working for me is to keep the old json_encode(...) code and adding a validation after it:

$this->request = json_encode(array_pop($this->request));
// (...)
$this->request = str_replace('[]', '{}', $this->request);
jakoch commented 8 years ago

Thank you for providing your solution. I've applied your patch and released a new version. https://github.com/jakoch/PHPTracRPC/releases/tag/1.0.0

I hope the issue is resolved. Closing.