Wednesday, January 5, 2011

Php Json-RPC source code (server side)

<?php
/**
* Author: James Hu
*Email: techman@navime.net
*/
 
require_once(dirname(__FILE__) . '/debug.php');
 
Error::$ExceptionEnabled = true;
 
class RpcServer {
  //
  //
  private $passcode;
 
  //
  //
  private $public_funcs;

  //
  // 
  public function RpcServer() {
    $this->__construct();
  }
 
  //
  //
  public function __construct() {
    $this->passcode = md5('sunday');
    $this->public_funcs = array('rpc_echo', 'rpc_version');
  }
 
  public function run() {
    try {
      $this->request_handler();
    } catch (Exception $e) {
      // catch all exceptions
      //
      $this->output(false, $e->getMessage());
    }
  }
 
  public function set_passcode($passcode) {
    $this->passcode = md5($passcode);
  }
 
  public function set_public_func($func) {
    if(!preg_match('/^rpc_/i', $func)) $func = "rpc_$func";
    $this->public_funcs[] = $func;
  }
 
  private function request_handler() {
    //
    //
    $this->load_modules();
 
    // more flexible to specify the function name
    //
    $pnames = array('call', 'do', 'method');
 
    // iterate the possible function name
    //
    foreach($pnames as $pname) {
      $func = @$_REQUEST[$pname];
      if(!empty($func)) break;
    }
 
    // check if the rpc call exists
    //
    if(empty($func) || !function_exists("rpc_$func")) {
      throw new Exception("Rpc function does not exist");
    }
 
    $func = "rpc_$func";
 
    if(!in_array($func, $this->public_funcs)) {
      $this->authenticate();
    }
 
    $params = @$_REQUEST['params'];
 
    // extract raw params information
    //
    if(empty($params)) {
      $params = array();
    } else {
      $params = preg_split('/,/', $params);
 
      foreach($params as $k => $param) {
        $params[$k] = $this->json_decode($param);
      }
    }
 
    // get function's parameters
    //
    $funcRef = new ReflectionFunction($func);
    $paramsRef = $funcRef->getParameters();
 
    for($i = 0; $i < count($paramsRef); ++$i) {
      $paramName = $paramsRef[$i]->name;
      if(isset($_REQUEST[$paramName])) {
        for($j = 0; $j < $i; ++$j) {
          if(!isset($params[$j])) $params[$j] = false;
        }
        $params[$i] = $this->json_decode($_REQUEST[$paramName]);
      }
    }
 
    $result = @call_user_func_array($func, $params);
    $this->output(true, $result);
  }
 
  private function json_decode($v) {
    if(preg_match('/^\[.*?\]$/i', $v)) {
      $p = json_decode($v, true);
      if($p) return $p;
    }
 
    return $v;
  }
 
  private function load_modules() {
    if(!file_exists('./modules')) return;
 
    $dir = dir('./modules');
    while(false !== ($entry = $dir->read())) {
      if(preg_match('/.*\.php$/i', $entry) && $entry != 'index.php') {
        require_once("./modules/$entry");
      }
    }
  }
 
  private function output($error, $result) {
    if(@$_REQUEST['format'] == 'raw') {
      die($result);
    } else {
      die(json_encode(array('ok' => $error, 'response' => $result)));
    }
  }
 
  private function authenticate() {
    $passcode = md5(@$_REQUEST['passcode']);
    if($passcode != $this->passcode) {
      throw new Exception('access is denied');
    }
  }
};
 
function rpc_echo() {
  return func_get_args();
}
 
function rpc_version() {
  return "rpc server v1.1";
}
 
?>

No comments:

Post a Comment