Make WordPress Core

Opened 13 years ago

Closed 13 years ago

#14933 closed defect (bug) (fixed)

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

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


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 13 years ago.
14933.patch (651 bytes) - added by hakre 13 years ago.

Download all attachments as: .zip

Change History (15)

#1 @dave1010
13 years ago

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

#2 @dave1010
13 years ago

  • Cc dave1010 added

#3 @dave1010
13 years ago

  • Resolution fixed deleted
  • Status changed from closed to reopened

Didn't mean to close, sorry

#4 @josephscott
13 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

#5 @josephscott
13 years ago

  • Cc josephscott added

#6 @dave1010
13 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 :-)

#7 @hakre
13 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?

13 years ago

#8 @hakre
13 years ago

same patch against trunk.

#9 @dave1010
13 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) {
if ($args[0] == 7 || date('D') == 'Mon') {
  $method .= '_awesome';

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.

#10 @hakre
13 years ago

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

#11 @hakre
13 years ago

  • Keywords IXR extending xmlrpc removed

#12 @westi
13 years ago

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

#13 @nacin
13 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.