/** * Executes a method. * A method is a function which you have previously exposed using expose_function. * * @param string $method Method, e.g. "foo.bar" * * @return GenericResult The result of the execution. * @throws APIException|CallException * @access private */ function execute_method($method) { global $API_METHODS; // method must be exposed if (!isset($API_METHODS[$method])) { $msg = elgg_echo('APIException:MethodCallNotImplemented', array($method)); throw new APIException($msg); } // function must be callable $function = elgg_extract('function', $API_METHODS[$method]); if (!$function || !is_callable($function)) { $msg = elgg_echo('APIException:FunctionDoesNotExist', array($method)); throw new APIException($msg); } // check http call method if (strcmp(get_call_method(), $API_METHODS[$method]["call_method"]) != 0) { $msg = elgg_echo('CallException:InvalidCallMethod', array($method, $API_METHODS[$method]["call_method"])); throw new CallException($msg); } $parameters = get_parameters_for_method($method); // may throw exception, which is not caught here verify_parameters($method, $parameters); $serialised_parameters = serialise_parameters($method, $parameters); // Execute function: Construct function and calling parameters $serialised_parameters = trim($serialised_parameters, ", "); // Sadly we probably can't get rid of this eval() in 2.x. Doing so would involve // replacing serialise_parameters(), which does a bunch of weird stuff we need to // stay BC with 2.x. There are tests for a lot of these quirks in ElggCoreWebServicesApiTest // particularly in testSerialiseParametersCasting(). $arguments = eval("return [{$serialised_parameters}];"); if ($API_METHODS[$method]['assoc']) { $argument = array_combine(_elgg_ws_get_parameter_names($method), $arguments); $result = call_user_func($function, $argument); } else { $result = call_user_func_array($function, $arguments); } $result = elgg_trigger_plugin_hook('rest:output', $method, $parameters, $result); // Sanity check result // If this function returns an api result itself, just return it if ($result instanceof GenericResult) { return $result; } if ($result === false) { $msg = elgg_echo('APIException:FunctionParseError', array($function, $serialised_parameters)); throw new APIException($msg); } if ($result === NULL) { // If no value $msg = elgg_echo('APIException:FunctionNoReturn', array($function, $serialised_parameters)); throw new APIException($msg); } // Otherwise assume that the call was successful and return it as a success object. return SuccessResult::getInstance($result); }
/** * Executes a method. * A method is a function which you have previously exposed using expose_function. * * @param string $method Method, e.g. "foo.bar" * * @return GenericResult The result of the execution. * @throws APIException|CallException * @access private */ function execute_method($method) { global $API_METHODS; // method must be exposed if (!isset($API_METHODS[$method])) { $msg = elgg_echo('APIException:MethodCallNotImplemented', array($method)); throw new APIException($msg); } // function must be callable $function = null; if (isset($API_METHODS[$method]["function"])) { $function = $API_METHODS[$method]["function"]; // allow array version of static callback if (is_array($function) && isset($function[0], $function[1]) && is_string($function[0]) && is_string($function[1])) { $function = "{$function[0]}::{$function[1]}"; } } if (!is_string($function) || !is_callable($function)) { $msg = elgg_echo('APIException:FunctionDoesNotExist', array($method)); throw new APIException($msg); } // check http call method if (strcmp(get_call_method(), $API_METHODS[$method]["call_method"]) != 0) { $msg = elgg_echo('CallException:InvalidCallMethod', array($method, $API_METHODS[$method]["call_method"])); throw new CallException($msg); } $parameters = get_parameters_for_method($method); // may throw exception, which is not caught here verify_parameters($method, $parameters); $serialised_parameters = serialise_parameters($method, $parameters); // Execute function: Construct function and calling parameters $serialised_parameters = trim($serialised_parameters, ", "); // @todo remove the need for eval() $result = eval("return {$function}({$serialised_parameters});"); $result = elgg_trigger_plugin_hook('rest:output', $method, $parameters, $result); // Sanity check result // If this function returns an api result itself, just return it if ($result instanceof GenericResult) { return $result; } if ($result === false) { $msg = elgg_echo('APIException:FunctionParseError', array($function, $serialised_parameters)); throw new APIException($msg); } if ($result === NULL) { // If no value $msg = elgg_echo('APIException:FunctionNoReturn', array($function, $serialised_parameters)); throw new APIException($msg); } // Otherwise assume that the call was successful and return it as a success object. return SuccessResult::getInstance($result); }
public function testSerialiseParameters() { // int and bool $this->registerFunction(); $parameters = array('param1' => 1, 'param2' => 0); $s = serialise_parameters('test', $parameters); $this->assertIdentical($s, ',1,false'); // string $this->registerFunction(false, false, array('param1' => array('type' => 'string'))); $parameters = array('param1' => 'testing'); $s = serialise_parameters('test', $parameters); $this->assertIdentical($s, ",'testing'"); // test string with " in it $this->registerFunction(false, false, array('param1' => array('type' => 'string'))); $parameters = array('param1' => 'test"ing'); $s = serialise_parameters('test', $parameters); $this->assertIdentical($s, ',\'test"ing\''); // test string with ' in it $this->registerFunction(false, false, array('param1' => array('type' => 'string'))); $parameters = array('param1' => 'test\'ing'); $s = serialise_parameters('test', $parameters); $this->assertIdentical($s, ",'test\\'ing'"); // test string with \ in it $this->registerFunction(false, false, array('param1' => array('type' => 'string'))); $parameters = array('param1' => 'test\\ing'); $s = serialise_parameters('test', $parameters); $this->assertIdentical($s, ",'test\\ing'"); // test string with \' in it $this->registerFunction(false, false, array('param1' => array('type' => 'string'))); $parameters = array('param1' => "test\\'ing"); $s = serialise_parameters('test', $parameters); $this->assertIdentical($s, ",'test\\\\'ing'"); // test\\'ing // test string reported by twall in #1364 $this->registerFunction(false, false, array('param1' => array('type' => 'string'))); $parameters = array('param1' => '{"html":"<div><img src=\\"http://foo.com\\"/>Blah Blah</div>"}'); $s = serialise_parameters('test', $parameters); $this->assertIdentical($s, ",'{\"html\":\"<div><img src=\\\"http://foo.com\\\"/>Blah Blah</div>\"}'"); // float $this->registerFunction(false, false, array('param1' => array('type' => 'float'))); $parameters = array('param1' => 2.5); $s = serialise_parameters('test', $parameters); $this->assertIdentical($s, ',2.5'); // indexed array of strings $this->registerFunction(false, false, array('param1' => array('type' => 'array'))); $parameters = array('param1' => array('one', 'two')); $s = serialise_parameters('test', $parameters); $this->assertIdentical($s, ",array('0'=>'one','1'=>'two')"); // associative array of strings $this->registerFunction(false, false, array('param1' => array('type' => 'array'))); $parameters = array('param1' => array('first' => 'one', 'second' => 'two')); $s = serialise_parameters('test', $parameters); $this->assertIdentical($s, ",array('first'=>'one','second'=>'two')"); // indexed array of strings $this->registerFunction(false, false, array('param1' => array('type' => 'array'))); $parameters = array('param1' => array(1, 2)); $s = serialise_parameters('test', $parameters); $this->assertIdentical($s, ",array('0'=>'1','1'=>'2')"); // test unknown type $this->registerFunction(false, false, array('param1' => array('type' => 'bad'))); $parameters = array('param1' => 'test'); $this->expectException('APIException'); $s = serialise_parameters('test', $parameters); }
/** * Executes a method. * A method is a function which you have previously exposed using expose_function. * * @param string $method Method, e.g. "foo.bar" * * @return GenericResult The result of the execution. * @throws APIException, CallException * @access private */ function execute_method($method) { global $API_METHODS, $CONFIG; // method must be exposed if (!isset($API_METHODS[$method])) { $msg = elgg_echo('APIException:MethodCallNotImplemented', array($method)); throw new APIException($msg); } // function must be callable if (!isset($API_METHODS[$method]["function"]) || !is_callable($API_METHODS[$method]["function"])) { $msg = elgg_echo('APIException:FunctionDoesNotExist', array($method)); throw new APIException($msg); } // check http call method if (strcmp(get_call_method(), $API_METHODS[$method]["call_method"]) != 0) { $msg = elgg_echo('CallException:InvalidCallMethod', array($method, $API_METHODS[$method]["call_method"])); throw new CallException($msg); } $parameters = get_parameters_for_method($method); if (verify_parameters($method, $parameters) == false) { // if verify_parameters fails, it throws exception which is not caught here } $serialised_parameters = serialise_parameters($method, $parameters); // Execute function: Construct function and calling parameters $function = $API_METHODS[$method]["function"]; $serialised_parameters = trim($serialised_parameters, ", "); // @todo document why we cannot use call_user_func_array here $result = eval("return {$function}({$serialised_parameters});"); // Sanity check result // If this function returns an api result itself, just return it if ($result instanceof GenericResult) { return $result; } if ($result === false) { $msg = elgg_echo('APIException:FunctionParseError', array($function, $serialised_parameters)); throw new APIException($msg); } if ($result === NULL) { // If no value $msg = elgg_echo('APIException:FunctionNoReturn', array($function, $serialised_parameters)); throw new APIException($msg); } // Otherwise assume that the call was successful and return it as a success object. return SuccessResult::getInstance($result); }
public function testSerialiseParametersCasting() { $types = ['int' => [["0", 0], ["1", 1], [" 1", 1]], 'bool' => [["0", false], [" 1", true], [" false", false], ["true", false]], 'float' => [["1.65", 1.65], [" 1.65 ", 1.65]], 'array' => [[["2 ", " bar"], [2, "bar"]], [["' \""], ["' \\\""]]], 'string' => [[" foo ", "foo"]]]; foreach ($types as $type => $tests) { foreach ($tests as $test) { set_input('param', $test[0]); $this->registerFunction(false, false, ['param' => ['type' => $type]]); $serialized = serialise_parameters('test', ['param' => get_input('param')]); $serialized = trim($serialized, ", "); // evaled $value = eval("return {$serialized};"); $this->assertEqual($value, $test[1]); } } }