WordPress.org

Make WordPress Core

Opened 4 years ago

Closed 3 years ago

#14933 closed defect (bug) (fixed)

IXR_Server->call() fails when calling method that uses __call()

Reported by: dave1010 Owned by: westi
Milestone: 3.1 Priority: normal
Severity: normal Version: 3.0.1
Component: XML-RPC Keywords: has-patch
Focuses: Cc:

Description

I have a class in a plugin that uses PHP's magic method __call() to add some XMl-RPC callback methods, but IXR_Server->call() throws an IXR_Error as it uses method_exists() instead of is_callable().

method_exists() returns true only if a method is specifically defined (and is visible). is_callable() should be identical to method_exists(), except also return true on any classes with a visible __call() method.

Attachments (2)

class-IXR.php.patch (572 bytes) - added by dave1010 4 years ago.
14933.patch (651 bytes) - added by hakre 4 years ago.

Download all attachments as: .zip

Change History (15)

dave10104 years ago

comment:1 dave10104 years ago

  • Component changed from General to XML-RPC
  • Keywords has-patch added
  • Resolution set to fixed
  • Status changed from new to closed

comment:2 dave10104 years ago

  • Cc dave1010 added

comment:3 dave10104 years ago

  • Resolution fixed deleted
  • Status changed from closed to reopened

Didn't mean to close, sorry

comment:4 josephscott4 years ago

Any reason you aren't using the xmlrpc_methods filter to add new XML-RPC methods? I wrote a simple example on how to do this http://josephscott.org/archives/2008/11/adding-xml-rpc-methods-to-wordpress/

comment:5 josephscott4 years ago

  • Cc josephscott added

comment:6 dave10104 years ago

I am using the xml_rpc filter (inside a class):

// lots of code snipped
class MyXmlRpc {
  public function __construct() {
    add_filter( 'xmlrpc_methods', array($this, 'add_new_xmlrpc_methods') );
  }
  public function add_new_xmlrpc_methods($methods) {
    foreach ($this->methods as $method) {
      $methods[$this->PREFIX . $method] = array($this, $method);
    }
    return $methods;
  }
  public function __call($method, $args) {
    // ... does lots of things with $method and $args here
    return call_user_func_array(array($this, $method), $args);
  }
}

I think I even used your how to :-)

comment:7 hakre4 years ago

Patch does not apply clean against trunk.


call() will only be called if a certain function does not exists by name. So I don't understand your code example, because if so, your call() implementation will fail by call_user_func_array() as $method on $this does not exists and that's why call() will be invoked.

Or do I see something wrong here?

hakre4 years ago

comment:8 hakre4 years ago

same patch against trunk.

comment:9 dave10104 years ago

Thanks for the patch against trunk. I'm still learning SVN.

__call() is called when a method of that name is not visible. I.e. if you have private / protected methods with the same name. This means certain non-public methods can be run, but they are filtered through __call(). In my code I'm also modifying $method in some cases.

Some random examples of what is possible using __call() in this situation:

if (strpos($method, 'secure', 0) !== false) {
  $this->authenticate();
}
if ($args[0] == 7 || date('D') == 'Mon') {
  $method .= '_awesome';
  $args[1]++;
}

I guess I could work around it by sending all XML-RPC requests to 1 method and adding an extra arg, but that's a bit messy.

comment:10 hakre4 years ago

I had missed the protected / private members, my fault. is_callable() looks valid to me. +1.

comment:11 hakre4 years ago

  • Keywords IXR extending xmlrpc removed

comment:12 westi4 years ago

  • Milestone changed from Awaiting Review to 3.1
  • Owner set to westi
  • Status changed from reopened to accepted

comment:13 nacin3 years ago

  • Resolution set to fixed
  • Status changed from accepted to closed

(In [16809]) s/method_exists/is_callable/. props hakre, fixes #14933.

Note: See TracTickets for help on using tickets.