Skip to content

Instantly share code, notes, and snippets.

@millken
Created August 11, 2010 03:01
Show Gist options
  • Save millken/518403 to your computer and use it in GitHub Desktop.
Save millken/518403 to your computer and use it in GitHub Desktop.
< ?php
//====================================================
// FileName: webremote.php
// Summary: Web Service
// Author: millken
// LastModifed:2009-06-19 9:51
// copyright (c)2009 millken@gmail.com
//====================================================
error_reporting(7);
if ( !function_exists( "json_decode" ) )
{
function json_decode( $content, $assoc = false )
{
include_once( "json.php" );
if ( $assoc )
{
$json = new services_json( SERVICES_JSON_LOOSE_TYPE );
}
else
{
$json = new services_json( );
}
return $json->decode( $content );
}
}
if ( !function_exists( "json_encode" ) )
{
function json_encode( $content )
{
include_once( "json.php" );
$json = new services_json( );
return $json->encode( $content );
}
}
class webRemote {
public $functions = array();
public $debug_str = '';
public $headers = array();
private $config = array();
private $url = '';
private $options;
private $json;
/*
Constructor: __construct
Parameters:
options - array, see options below
Options:
url - url for the RPC calls. Defaults to the current url.
*/
public function __construct($url='',$options = array()) {
$this->url = $url;
$this->options = $options;
$this->options['debuglevel'] = isset($this->options['debuglevel'])?$this->options['debuglevel'] : 0;
$this->options['secret-key'] = isset($this->options['secret-key'])?$this->options['secret-key'] : '123456';
$this->options['connection_timeout'] = isset($this->options['connection_timeout'])?$this->options['connection_timeout'] : 30;
$this->options['response_timeout'] = isset($this->options['response_timeout'])?$this->options['response_timeout'] : 30;
$this->config['secret-key'] = isset($this->config['secret-key'])?$this->config['secret-key']:'123456';
$this->config['allow-ip'] = (isset($this->config['allow-ip']) && is_array($this->config['allow-ip']))?$this->config['allow-ip']:array();
$this->debug('New webRemote object init.');
if($this->options['debuglevel']>1) {
$this->debug('$url='.$this->url);
$this->debug('$options='.print_r($this->options,true));
}
}
public function call($operation,$params='') {
$url = parse_url($this->url);
if(!$url)$this->debug("URL self::$url is not correct.");
if(!isset($url['port'])){
if($url['scheme'] == 'https'){
$url['port'] = 443;
} else {
$url['port'] = 80;
}
}
if(!empty($params)) {
$call['method'] = $operation;
$call['params'] = $params;
$postdata = $this->rc4(json_encode($call),$this->options['secret-key']);
$postdata = 'call='.urlencode(base64_encode($postdata));
}
$this->debug("connect connection_timeout {$this->options['connection_timeout']}, response_timeout {$this->options['response_timeout']}, scheme {$url['scheme']}, host {$url['host']}, port {$url['port']}");
$fp = fsockopen($url['host'], $url['port'], $errno, $errstr, $this->options['connection_timeout']);
$header =$res = $body = '';
if (!$fp) {
$this->debug('Couldn\'t open socket connection to server :'.$this->url.'>Error ('.$errno.'): '.$errstr);
} else {
$this->debug('socket connected');
$out = "POST {$url['path']} HTTP/1.0\r\n";
$out .= "Host: {$url['host']}\r\n";
$out .= "Content-type: application/x-www-form-urlencoded\r\n";
$out .= "Content-Length: " . strlen($postdata) . "\r\n";
$out .= "Connection: Close\r\n\r\n";
$out .= $postdata;
if($this->options['debuglevel']>1) {
$this->debug("sent date:\n".$out);
}
fwrite($fp, $out);
socket_set_timeout( $fp, $this->options['response_timeout']);
while(!feof($fp)) {
$res .= fgets($fp,4096);
}
fclose($fp);
if($res) {
$separator = '/\r\n\r\n|\n\n|\r\r/';
list($header,$body) = preg_split($separator, $res, 2);
$this->headers = $header;
unset($header,$res,$out,$postata);
$body = rtrim($body,"\r\n");
$this->debug("response header:\n".print_r($this->headers,true));
$this->debug("response body:\n".print_r($body,true));
}else{
$this->debug("response is empty");
}
}
$body = json_decode($body,true);
return $body;
}
public function register($function) {
$this->functions[] = $function;
}
public function config($cfg=array()) {
$this->config['secret-key'] = isset($cfg['secret-key'])?$cfg['secret-key']:'123456';
$this->config['allow-ip'] = isset($cfg['allow-ip'])?$cfg['allow-ip']:array();
}
public function error($errno, $errstr){
$this->response(array('error' => $errstr));
}
private function debug($string) {
if($this->options['debuglevel']>0) {
$tod = gettimeofday();
$sec = $tod['sec'];
$usec = $tod['usec'];
$this->debug_str .= strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec) .'>' . get_class($this) . ": $string\n";
}
}
public function getDebug() {
if($this->debug_str == '') {
return 'Incorrect model.';
}else{
return nl2br($this->debug_str);
}
}
private function response($data){
die(json_encode($data));
}
public function service(){
global $_POST;
set_error_handler(array($this, 'error'), E_ALL);
if(!empty($_POST['call'])) {
try {
if($this->config['allow-ip']) {
if(getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) {
$onlineip = getenv('HTTP_CLIENT_IP');
} elseif(getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) {
$onlineip = getenv('HTTP_X_FORWARDED_FOR');
} elseif(getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) {
$onlineip = getenv('REMOTE_ADDR');
} elseif(isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
$onlineip = $_SERVER['REMOTE_ADDR'];
}
preg_match("/[\d\.]{7,15}/", $onlineip, $onlineipmatches);
$onlineip = $onlineipmatches[0] ? $onlineipmatches[0] : 'unknown';
unset($onlineipmatches);
if(!in_array($onlineip,$this->config['allow-ip'])) throw new Exception("your ip has been banned .");
}
$call = $this->rc4(base64_decode($_POST['call']),$this->config['secret-key']);
$call = json_decode($call, true);
if(!is_array($call) || empty($call)) throw new Exception("secret-key is not correct.");
$method = $call['method'];
$params = $call['params'];
$callback = null;
if (is_string($method)){ // function
if(!in_array($method, $this->functions)) throw new Exception("Function $function is not registered.");
$callback = $method;
}
if(!is_callable($callback, false, $callable)) throw new Exception("Method is not callable.");
$result = call_user_func($callback, $params);
$this->response($result);
} catch (Exception $e) {
$this->error(1, $e->getMessage());
}
}
restore_error_handler();
}
private function rc4($pt, $key='') {
$s = range(0, 255);
$ct = '';
for ($j=$i=0; $i<256; $i++) {
$j = ($j + $s[$i] + ord($key[$i % strlen($key)])) % 256;
$x = $s[$i];
$s[$i] = $s[$j];
$s[$j] = $x;
}
for ($i=$j=$y=0; $y<strlen($pt); $y++) {
$i = ($i + 1) % 256;
$j = ($j + $s[$i]) % 256;
$x = $s[$i];
$s[$i] = $s[$j];
$s[$j] = $x;
$ct .= $pt[$y] ^ chr($s[($s[$i] + $s[$j]) % 256]);
}
return $ct;
}
}
? >
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment