Skip to content
This repository was archived by the owner on May 16, 2018. It is now read-only.
This repository was archived by the owner on May 16, 2018. It is now read-only.

Zend_Rest_Server does not properly handle optional parameters when anonymous (arg1, etc) parameters are passed in #187

@C-Duv

Description

@C-Duv

Note: Issue already reported by Jonathan Csanyi (jcsanyi) on 2010-03-08T17:49:13.000+0000 (see [ZF-9374])(http://framework.zend.com/issues/browse/ZF-9374) but isn't closed there and bug is still present in v1.12.3.

Related issues: #186

When anonymous parameters are passed in, and one or more optional parameters are missing, the default values are not correctly filled in, and the call fails with a 'missing arguments' error message.

Original comments

Posted by Jonathan Csanyi (jcsanyi) on 2010-03-08T17:51:19.000+0000

There was already a unit test for this functionality, but the expected value was incorrectly hard-coded backwards, so the failure was counting as a pass.


Posted by Jonathan Csanyi (jcsanyi) on 2010-03-08T17:53:36.000+0000

Attached patch fixes Zend_Rest_Server, and accompanying unit tests.


Posted by Jonathan Csanyi (jcsanyi) on 2010-03-08T18:00:28.000+0000

'sorry.. original diff had a misleading/incorrect comment. This is the correct diff.


Posted by Claude Duvergier (cduv) on 2010-07-15T03:23:47.000+0000

I agree with Jonathan Csanyi.

I ran into that problem an thought Zend_Rest_Client was the cause as it uses the "arg1" query parameter name when only one argument is passed to the server (see ZF-4910). But is seems that Zend_Rest_Server is guilty.

With the following server PHP code:

class MyServerImpl
{
  public function myMethod ($var)
  {
    $return $var*$var;
  }
  public function myOtherMethod ($var = 3)
  {
    $return $var*$var;
  }
}
$server = new Zend_Rest_Server();
$server->setClass('MyServerImpl');
$server->handle();

The following client PHP code:

$client
  ->myMethod(5)
  ->get();

Issues the following request: server.php?method=myMethod&myMethod=5&arg1=5

Which is handled by Zend_Rest_Server::handle() as

$missing_args[0] = 'var';
$calling_args[1] = 5
=> myMethod(5);

Which is correct.

And the other following client PHP code:

$client
  ->myOtherMethod(5)
  ->get();

Issues the following request: server.php?method=myOtherMethod&myOtherMethod=5&arg1=5

Which is handled by Zend_Rest_Server::handle() as

$missing_args[] = array();
$calling_args[0] = 3;
$calling_args[1] = 5;
=> myOtherMethod(3);

Which is incorrect.

The solution would be to either use 0-based array everywhere, or the given "library/Zend/Rest/Server.php" DIFF file "trunk-correct.diff".

Original attachments

trunk.diff

Index: tests/Zend/Rest/ServerTest.php
===================================================================
--- tests/Zend/Rest/ServerTest.php  (revision 21404)
+++ tests/Zend/Rest/ServerTest.php  (working copy)
@@ -542,9 +542,10 @@

     /**
      * @see ZF-1949
+     * @see ZF-9374
      * @group ZF-1949
      */
-    public function testMissingArgumentsWithDefaultsShouldNotResultInFaultResponse()
+    public function testMissingAnonArgumentsWithDefaultsShouldNotResultInFaultResponse()
     {
         $server = new Zend_Rest_Server();
         $server->setClass('Zend_Rest_Server_Test');
@@ -552,10 +553,38 @@
         $server->handle(array('method' => 'testFunc7', 'arg1' => "Davey"));
         $result = ob_get_clean();
         $this->assertContains('<status>success</status>', $result, var_export($result, 1));
-        $this->assertContains('<response>Hello today, How are you Davey</response>', $result, var_export($result, 1));
+        $this->assertContains('<response>Hello Davey, How are you today</response>', $result, var_export($result, 1));
     }

     /**
+     * @see ZF-9374
+     */
+    public function testMissingZeroBasedAnonArgumentsWithDefaultsShouldNotResultInFaultResponse()
+    {
+        $server = new Zend_Rest_Server();
+        $server->setClass('Zend_Rest_Server_Test');
+        ob_start();
+        $server->handle(array('method' => 'testFunc7', 'arg0' => "Davey"));
+        $result = ob_get_clean();
+        $this->assertContains('<status>success</status>', $result, var_export($result, 1));
+        $this->assertContains('<response>Hello Davey, How are you today</response>', $result, var_export($result, 1));
+    }
+
+    /**
+     * @see ZF-9374
+     */
+    public function testMissingNamesArgumentsWithDefaultsShouldNotResultInFaultResponse()
+    {
+        $server = new Zend_Rest_Server();
+        $server->setClass('Zend_Rest_Server_Test');
+        ob_start();
+        $server->handle(array('method' => 'testFunc7', 'who' => "Davey"));
+        $result = ob_get_clean();
+        $this->assertContains('<status>success</status>', $result, var_export($result, 1));
+        $this->assertContains('<response>Hello Davey, How are you today</response>', $result, var_export($result, 1));
+    }
+
+    /**
      * @group ZF-3751
      */
     public function testCallingUnknownMethodDoesNotThrowUnknownButSpecificErrorExceptionMessage()
Index: library/Zend/Rest/Server.php
===================================================================
--- library/Zend/Rest/Server.php    (revision 21404)
+++ library/Zend/Rest/Server.php    (working copy)
@@ -189,28 +189,35 @@

                     $func_args = $this->_functions[$this->_method]->getParameters();

+                    // calling_args will be a zero-based array of the parameters
                     $calling_args = array();
                     $missing_args = array();
-                    foreach ($func_args as $arg) {
+                    foreach ($func_args as $i => $arg) {
                         if (isset($request[strtolower($arg->getName())])) {
-                            $calling_args[] = $request[strtolower($arg->getName())];
+                            $calling_args[$i] = $request[strtolower($arg->getName())];
                         } elseif ($arg->isOptional()) {
-                            $calling_args[] = $arg->getDefaultValue();
+                            $calling_args[$i] = $arg->getDefaultValue();
                         } else {
                             $missing_args[] = $arg->getName();
                         }
                     }

+                    // anon_args may be zero-based (per docs), or 1-based (per incorrect Zend_Rest_Client @see ZF-9373)
+                    $anon_args = array();
                     foreach ($request as $key => $value) {
                         if (substr($key, 0, 3) == 'arg') {
                             $key = str_replace('arg', '', $key);
-                            $calling_args[$key] = $value;
+                            $anon_args[$key] = $value;
                             if (($index = array_search($key, $missing_args)) !== false) {
                                 unset($missing_args[$index]);
                             }
                         }
                     }

+                    // re-key the anon_args to be zero-based, and add in any values already set in calling_args (optional defaults)
+                    ksort($anon_args);
+                    $calling_args = array_values($anon_args) + $calling_args;
+
                     // Sort arguments by key -- @see ZF-2279
                     ksort($calling_args);

trunk-correct.diff

Index: tests/Zend/Rest/ServerTest.php
===================================================================
--- tests/Zend/Rest/ServerTest.php  (revision 21404)
+++ tests/Zend/Rest/ServerTest.php  (working copy)
@@ -542,9 +542,10 @@

     /**
      * @see ZF-1949
+     * @see ZF-9374
      * @group ZF-1949
      */
-    public function testMissingArgumentsWithDefaultsShouldNotResultInFaultResponse()
+    public function testMissingAnonArgumentsWithDefaultsShouldNotResultInFaultResponse()
     {
         $server = new Zend_Rest_Server();
         $server->setClass('Zend_Rest_Server_Test');
@@ -552,10 +553,38 @@
         $server->handle(array('method' => 'testFunc7', 'arg1' => "Davey"));
         $result = ob_get_clean();
         $this->assertContains('<status>success</status>', $result, var_export($result, 1));
-        $this->assertContains('<response>Hello today, How are you Davey</response>', $result, var_export($result, 1));
+        $this->assertContains('<response>Hello Davey, How are you today</response>', $result, var_export($result, 1));
     }

     /**
+     * @see ZF-9374
+     */
+    public function testMissingZeroBasedAnonArgumentsWithDefaultsShouldNotResultInFaultResponse()
+    {
+        $server = new Zend_Rest_Server();
+        $server->setClass('Zend_Rest_Server_Test');
+        ob_start();
+        $server->handle(array('method' => 'testFunc7', 'arg0' => "Davey"));
+        $result = ob_get_clean();
+        $this->assertContains('<status>success</status>', $result, var_export($result, 1));
+        $this->assertContains('<response>Hello Davey, How are you today</response>', $result, var_export($result, 1));
+    }
+
+    /**
+     * @see ZF-9374
+     */
+    public function testMissingNamesArgumentsWithDefaultsShouldNotResultInFaultResponse()
+    {
+        $server = new Zend_Rest_Server();
+        $server->setClass('Zend_Rest_Server_Test');
+        ob_start();
+        $server->handle(array('method' => 'testFunc7', 'who' => "Davey"));
+        $result = ob_get_clean();
+        $this->assertContains('<status>success</status>', $result, var_export($result, 1));
+        $this->assertContains('<response>Hello Davey, How are you today</response>', $result, var_export($result, 1));
+    }
+
+    /**
      * @group ZF-3751
      */
     public function testCallingUnknownMethodDoesNotThrowUnknownButSpecificErrorExceptionMessage()
Index: library/Zend/Rest/Server.php
===================================================================
--- library/Zend/Rest/Server.php    (revision 21404)
+++ library/Zend/Rest/Server.php    (working copy)
@@ -189,28 +189,35 @@

                     $func_args = $this->_functions[$this->_method]->getParameters();

+                    // calling_args will be a zero-based array of the parameters
                     $calling_args = array();
                     $missing_args = array();
-                    foreach ($func_args as $arg) {
+                    foreach ($func_args as $i => $arg) {
                         if (isset($request[strtolower($arg->getName())])) {
-                            $calling_args[] = $request[strtolower($arg->getName())];
+                            $calling_args[$i] = $request[strtolower($arg->getName())];
                         } elseif ($arg->isOptional()) {
-                            $calling_args[] = $arg->getDefaultValue();
+                            $calling_args[$i] = $arg->getDefaultValue();
                         } else {
                             $missing_args[] = $arg->getName();
                         }
                     }

+                    // anon_args may be 1-based (per docs), or 0-based (per incorrect Zend_Rest_Client @see ZF-9373)
+                    $anon_args = array();
                     foreach ($request as $key => $value) {
                         if (substr($key, 0, 3) == 'arg') {
                             $key = str_replace('arg', '', $key);
-                            $calling_args[$key] = $value;
+                            $anon_args[$key] = $value;
                             if (($index = array_search($key, $missing_args)) !== false) {
                                 unset($missing_args[$index]);
                             }
                         }
                     }

+                    // re-key the anon_args to be zero-based, and add in any values already set in calling_args (optional defaults)
+                    ksort($anon_args);
+                    $calling_args = array_values($anon_args) + $calling_args;
+
                     // Sort arguments by key -- @see ZF-2279
                     ksort($calling_args);


Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions