/** * make it look to the component as if it is receiving * a request for a method invocation and check the response * is correct */ public function testWrapperAndProxy() { $_SERVER['HTTP_HOST'] = 'localhost'; $_SERVER['REQUEST_METHOD'] = 'POST'; $_SERVER['SCRIPT_FILENAME'] = 'TestService.php'; $_SERVER['REQUEST_URI'] = 'http://localhost/TestService.php'; $_SERVER['CONTENT_TYPE'] = 'application/json-rpc'; SCA_JsonRpcServer::$test_request = $this->request; SCA_JsonRpcClient::$store_test_request = true; SCA_JsonRpcClient::$test_response = $this->email_response; ob_start(); SCA::initComponent("TestService.php"); $out = ob_get_contents(); ob_end_clean(); $this->assertContains($this->response, $out); $this->assertContains(SCA_JsonRpcClient::$test_request, $this->email_request); }
/** * Call the remote JSON service method using CURL to * send the HTTP request * * @param string $method_name Method name * @param array $arguments Arguments * * @return mixed */ public function __call($method_name, $arguments) { // check that the requested method exists $method = null; foreach ($this->methods as $methods_entry) { if ($methods_entry->name == $method_name) { $method = $methods_entry; } } if ($method == null) { throw new SCA_RuntimeException("Trying to call {$method_name} on remote service " . "using JSONRPC and the method cannot be found. " . "The remote service has the following interface " . $this->smd_file); } // collect useful information about the method $return_type = $method->return->type; // construct the JSON request $json_request = "{\"id\":" . $this->id . ","; // increment the id so we get a unique id for calls from this client // its done up here so that we don't resuse IDs in this session // regardless of what happens to the call // TODO - is this sufficient? $this->id = $this->id + 1; $json_request = $json_request . "\"method\":\"{$method_name}\","; $json_request = $json_request . "\"params\":["; // convert all the arguments into JSON strings $argument_id = 0; foreach ($arguments as $argument) { if ($argument == null) { $json_request = $json_request; } else { if (is_object($argument)) { $json_request = $json_request . $this->json_das->encode($argument); } else { if (is_array($argument)) { throw new SCA_RuntimeException("Argument {$argument_id} to {$method_name} of type array found. " . "Arguments must be either primitives or SDOs"); } else { $json_request = $json_request . json_encode($argument); } } } $argument_id += 1; if ($argument_id < count($arguments)) { $json_request = $json_request . ","; } } $json_request = $json_request . "],\"version\":\"1.0\"}"; // some debugging // file_put_contents("json_messages.txt", // "Request at JSONRPC client = " . $json_request . "\n", // FILE_APPEND); if (self::$store_test_request == false) { // send this string to the service url $request = curl_init($this->service_url); curl_setopt($request, CURLOPT_POST, true); curl_setopt($request, CURLOPT_POSTFIELDS, $json_request); curl_setopt($request, CURLOPT_HEADER, false); curl_setopt($request, CURLOPT_RETURNTRANSFER, true); $header = array("User-Agent: SCA", "Content-Type: application/json-rpc", "Accept: application/json-rpc"); curl_setopt($request, CURLOPT_HTTPHEADER, $header); // Do the POST $response = curl_exec($request); // TODO probably need a better way of detecting PHP errors at the far end if (strchr($response, '<b>Fatal error</b>') !== false || strchr($response, '<b>Parse error</b>') !== false) { throw new SCA_RuntimeException('Bad response from jsonrpc call: ' . $response); } // Get info about the response $response_http_code = curl_getinfo($request, CURLINFO_HTTP_CODE); // close the session curl_close($request); // some debugging // file_put_contents("json_messages.txt", // "Response at JSONRPC client = " . $response . "\n", // FILE_APPEND); // test the response status if ($response == null || $response == false) { throw new SCA_RuntimeException("JSONRPC call to {$this->service_url} for method " . "{$method_name} failed "); } // test the response status if ($response_http_code != 200) { throw new SCA_RuntimeException("JSONRPC call to {$this->service_url} for method " . "{$method_name} failed with HTTP response code " . $response_http_code); } } else { self::$test_request = $json_request; $response = self::$test_response; } // decode the response $json_response = json_decode($response); $id = $json_response->id; // test to make sure that the id on the response matches // the id on the request if ($id != $this->id - 1) { throw new SCA_RuntimeException("JSONRPC call to {$this->service_url} for method " . "{$method_name} failed as the id of the response {$id} " . "does not match id of the request " . ($this->id - 1)); } // test to see if there is an error in the response message if (isset($json_response->error)) { $error = $json_response->error; if ($error != null) { throw new SCA_RuntimeException("JSONRPC call to {$this->service_url} for method " . "{$method_name} failed. The JSON error field contained " . '"' . $error . '"'); } } else { // decode the response based on its type. $result = $json_response->result; $return_object = null; if (is_object($result)) { // decode the complex object into an SDO. The return type // has come from the SMD. If XSD files // have also been specified then we guess the namespace // of the return type based on the matching the return // type name from the SMD with the type names from the // XSD $return_namespace = $this->_guessReturnTypeNamespace($return_type); $return_object = $this->json_das->decodeFromPHPObject($result, $return_type, $return_namespace); } else { if (is_array($result)) { throw new SCA_RuntimeException("JSONRPC call to {$this->service_url} for method " . "{$method_name} failed. Result of type array found. " . "Return types must be either primitives or SDOs"); } else { // do nothing in this case. The json_decode method // call has done all the work for us for primitive // types and null $return_object = $result; } } } return $return_object; }