I use the RPC style engine to achieve what I think you need. Disclaimer I have successfully implemented this scheme in JS + PHP and JS + Python, so it works. But it can be unsafe. You must take all necessary verification steps to ensure that it is safe (especially wrt for encoding / SQL injections and XSS attacks).
The idea is to have one PHP script that processes RPC requests, getting the method name and its argument via GET and POST, and outputs JSON back to the Javascript side.
For example, on the client side:
API.rpc('getItemById', 1532, function(item) { console.log(item); });
will write
Object (ID = 1532, name = "Foo", regardless = "bar")
on the console.
Communication Protocol Used:
- the client sends an HTTP request to the RPC script handler using either GET or POST. Limitations are that the "method" must always be provided in GET and that all arguments must be URL encoded. Otherwise, all arguments are specified as key = value pairs and can be part of a request (GET) or payload (POST)
- the server always responds with HTTP 200 (otherwise it means a very unpleasant thing has happened). It responds only with JSON data. The returned object has at least 2 members.
- the success member is always present and indicates whether the call was successful, i.e. that exception was not thrown
- if successful, the 'ret' members contain the return value of the function
- If an exception is thrown, the 'message' member contains an exception message (I prefer to send all the backtracking here, but this is certainly not suitable for sensitive environments)
(1) On the javascript side (assuming jQuery, coding, as I think, so this could be a mistake):
API = function() { this.rpc = function(method, args, callback) { return $.ajax({ url: 'rpcscript.php?method='+encodeURIComponent(args.method), data: args, type: 'post',
Then you can add shortcuts like syncRPC () to make synchronous calls, etc.
(2) On the PHP side (slightly modified startup code):
class MyAPI { function getItemById($id) { // Assuming the $db is a database connection returning eg an associative array with the result of the SQL query. Note the (int) typecast to secure the query - all defensive measures should be used as usual. return $db->query("SELECT * FROM item WHERE id = ".(int)$id.";"); } } class RemoteProcedureCall { function __construct() { $this->api = new MyAPI(); } function serve() { header("Content-Type: application/json; charset=utf-8"); try { if (!isset($_GET['method'])) throw new Exception("Invalid parameters"); $methodDesc = array($this->api, $_GET['method']); if (!method_exists($methodDesc[0], $methodDesc[1]) || !is_callable($methodDesc)) throw new Exception("Invalid parameters"); $method = new ReflectionMethod($methodDesc[0], $methodDesc[1]); $params = array(); foreach ($method->getParameters() as $param) { // The arguments of the method must be passed as $_POST, or $_GET if (isset($_POST[$param->getName()])) // OK, arg is in $_POST $paramSrc = $_POST[$param->getName()]; elseif (!in_array($param->getName(),array('action','method')) && isset($_GET[$param->getName()]) && !isset($paramSrc[$param->getName()])) // 'action' and 'method' are reserved $_GET arguments. Arguments for the RPC method // can be any other args in the query string, unless they are already in $_POST. $paramSrc = $_GET[$param->getName()]; if (!isset($paramSrc)) { // If the argument has a default value (as specified per the PHP declaration // of the method), we allow the caller to use it - that is, not sending the // corresponding parameter. if ($param->isDefaultValueAvailable()) $p = $param->getDefaultValue(); else throw new Exception("Invalid parameters"); } else { $p = $paramSrc; } $params[$param->getName()] = $p; unset($paramSrc); } $ret = $method->invokeArgs($db, $params); echo json_encode(array('success' => true, 'ret' => $ret)); } catch (Exception $e) { echo json_encode(array('success' => false, 'message' => $e->getMessage()."\n".$e->getBacktrace())); } } }; $rpc = RemoteProcedureCall(); $rpc->serve();
There are many assumptions for specific applications, including the types of exclusions that can be selected, reserved keywords, etc.
In any case, I hope this will be a good starting point for your problem.