damowang

首先是服务端,服务端有一个主要的class组成:apiServer.php

<?php
/**
 * apiServer.php
 *
 * webservice主类
 *
 * @filename apiServer.php
 * @version  v1.0
 * @update   2011-12-22
 * @author   homingway
 * @contact  homingway@gmail.com
 * @package  webservice
 */
define(\'API_AUTH_KEY\',  \'i8XsJb$fJ!87FblnW\');
class apiServer{
 
    //请求参数
    public $request = array();
 
    //是否ip限制
    public $ip_limit = true;
    //允许访问的IP列表
    public $ip_allow = array(\'127.0.0.1\',\'192.168.0.99\');
 
    public $default_method = \'welcome.index\';
    public $service_method = array();
 
    //私有静态单例变量
    private static $_instance = null;
 
    /**
     * 构造方法,处理请求参数
     */
    private function __construct(){
        $this->dealRequest();
    }
 
    /**
     * 单例运行
     */
    public static function getInstance(){
        if(self::$_instance === null){
            self::$_instance = new self();
        }
        return self::$_instance;
    }
 
    /**
     * 运行
     */
    public function run(){
        //授权
        if(!$this->checkAuth()){
            exit(\'3|Access Denied\');
        }
        $this->getApiMethod();
        include_once(API_SERVICE_PATH.\'/\'.$this->service_method[\'service\'].\'.php\');
        $serviceObject = new $this->service_method[\'service\'];
        if($this->request[\'param\']){
            $result = call_user_func_array(array($serviceObject,$this->service_method[\'method\']),$this->request[\'param\']);
        } else {
            $result = call_user_func(array($serviceObject,$this->service_method[\'method\']));
        }
        if(is_array($result)){
            $result = json_encode($result);
        }
        $result = gzencode($result);
        exit($result);
    }
 
    /**
     * 检查授权
     */
    public function checkAuth(){
        //检查参数是否为空
        if(!$this->request[\'time\'] || !$this->request[\'method\']   || !$this->request[\'auth\']){
            return false;
        }
 
        //检查auth是否正确
        $server_auth = md5(md5($this->request[\'time\'].\'|\'.$this->request[\'method\'].\'|\'.API_AUTH_KEY));
        if($server_auth != $this->request[\'auth\']){
            return false;
        }
 
        //ip限制
        if($this->ip_limit){
            $remote_ip = $this->getIP();
            $intersect = array_intersect($remote_ip,$this->ip_allow);
            if(empty($intersect)){
                return false;
            }
        }
 
        return true;
    }
 
    /**
     * 获取服务名和方法名
     */
    public function getApiMethod(){
        if(strpos($this->request[\'method\'], \'.\') === false){
            $method = $this->default_method;
        } else {
            $method = $this->request[\'method\'];
        }
        $tmp = explode(\'.\', $method);
        $this->service_method = array(\'service\'=>$tmp[0],\'method\'=>$tmp[1]);
        return $this->service_method;
    }
 
    /**
     * 获取和处理请求参数
     */
    public function dealRequest(){
        $this->request[\'time\'] = $this->_request(\'time\');
        $this->request[\'method\'] = $this->_request(\'method\');
        $this->request[\'param\'] = $this->_request(\'param\');
        $this->request[\'auth\'] = $this->_request(\'auth\');
        if($this->request[\'param\']){
            $this->request[\'param\'] = json_decode(urldecode($this->request[\'param\']),true);
        }
    }
 
    /**
     * 获取request变量
     * @param string $item
     */
    private function _request($item){
        return isset($_REQUEST[$item]) ? trim($_REQUEST[$item]) : \'\';
    }
 
    /**
     * 设置IP限制
     * @param bool $limit
     */
    public function setIPLimit($limit=true){
        $this->ip_limit = $limit;
    }
 
    /**
     * 获取客户端ip地址
     */
    public function getIP(){
        $ip = array();
        if(isset($_SERVER[\'REMOTE_ADDR\'])){
            $ip[] = $_SERVER[\'REMOTE_ADDR\'];
        }
        if(isset($_SERVER[\'HTTP_VIA\'])){
            $tmp = explode(\', \',$_SERVER[\'HTTP_X_FORWARDED_FOR\']);
            $ip = array_merge($ip,$tmp);
        }
        $ip = array_unique($ip);
        return $ip;
    }
 
}
?>

然后在服务端的入口文件中调用该class,并启动服务即可,如:

<?php
/**
 * server.php
 *
 * 自定义数据接口的入口
 *
 * @filename server.php
 * @version  v1.0
 * @update   2011-12-22
 * @author   homingway
 * @contact  homingway@gmail.com
 * @package  webservice
 */
 
//API的根目录
define(\'API_PATH\',dirname(__FILE__));
 
//服务目录
define(\'API_SERVICE_PATH\',API_PATH.\'/service\');
define(\'API_LIB_PATH\',  API_PATH.\'/lib\');
 
//服务核心class
include_once(API_LIB_PATH.\'/apiServer.php\');
 
//运行
apiServer::getInstance()->run();
?>

然后创建一个service的目录,里面就是自己的接口class,如welcome.php:

<?php
/**
 * welcome.php
 *
 * 功能代码
 *
 * @filename welcome.php
 * @version  v1.0
 * @update   2011-12-22
 * @author   homingway
 * @contact  homingway@gmail.com
 * @package  webservice
 */
 
class welcome{
 
    public function index(){
        return \'hello service\';
    }
 
}
?>

下面是客户端的主程序:apiClient.php

<?php
/**
 * apiClient.php
 *
 * webservice客户端程序
 *
 * @filename apiClient.php
 * @version  v1.0
 * @update   2011-12-22
 * @author   homingway
 * @contact  homingway@gmail.com
 * @package  webservice
 */
 
define(\'API_AUTH_KEY\',  \'i8XsJb$fJ!87FblnW\');
 
class apiClient{
 
    public static function send($url,$method,$param=array()){
        $time = time();
        $auth = md5(md5($time.\'|\'.$method.\'|\'.API_AUTH_KEY));
        if(!is_array($param) || empty($param)){
            $json_param = \'\';
        } else {
            $json_param = urlencode(json_encode($param));
        }
        $api_url = $url.\'?method=\'.$method.\'&time=\'.$time.\'&auth=\'.$auth.\'&param=\'.$json_param;
        $content = file_get_contents($api_url);
        if(function_exists(\'gzdecode\')){
            $content = gzdecode($content);
        } else {
            $content = self::gzdecode($content);
        }
        return $content;
    }
 
    public static function gzdecode($data) {
        $len = strlen ( $data );
        if ($len < 18 || strcmp ( substr ( $data, 0, 2 ), "\x1f\x8b" )) {
            return null; // Not GZIP format (See RFC 1952)
        }
        $method = ord ( substr ( $data, 2, 1 ) ); // Compression method
        $flags = ord ( substr ( $data, 3, 1 ) ); // Flags
        if ($flags & 31 != $flags) {
            // Reserved bits are set -- NOT ALLOWED by RFC 1952
            return null;
        }
        // NOTE: $mtime may be negative (PHP integer limitations)
        $mtime = unpack ( "V", substr ( $data, 4, 4 ) );
        $mtime = $mtime [1];
        $xfl = substr ( $data, 8, 1 );
        $os = substr ( $data, 8, 1 );
        $headerlen = 10;
        $extralen = 0;
        $extra = "";
        if ($flags & 4) {
            // 2-byte length prefixed EXTRA data in header
            if ($len - $headerlen - 2 < 8) {
                return false; // Invalid format
            }
            $extralen = unpack ( "v", substr ( $data, 8, 2 ) );
            $extralen = $extralen [1];
            if ($len - $headerlen - 2 - $extralen < 8) {
                return false; // Invalid format
            }
            $extra = substr ( $data, 10, $extralen );
            $headerlen += 2 + $extralen;
        }
        $filenamelen = 0;
        $filename = "";
        if ($flags & 8) {
            // C-style string file NAME data in header
            if ($len - $headerlen - 1 < 8) {
                return false; // Invalid format
            }
            $filenamelen = strpos ( substr ( $data, 8 + $extralen ), chr ( 0 ) );
            if ($filenamelen === false || $len - $headerlen - $filenamelen - 1 < 8) {
                return false; // Invalid format
            }
            $filename = substr ( $data, $headerlen, $filenamelen );
            $headerlen += $filenamelen + 1;
        }
 
        $commentlen = 0;
        $comment = "";
        if ($flags & 16) {
            // C-style string COMMENT data in header
            if ($len - $headerlen - 1 < 8) {
                return false; // Invalid format
            }
            $commentlen = strpos ( substr ( $data, 8 + $extralen + $filenamelen ), chr ( 0 ) );
            if ($commentlen === false || $len - $headerlen - $commentlen - 1 < 8) {
                return false; // Invalid header format
            }
            $comment = substr ( $data, $headerlen, $commentlen );
            $headerlen += $commentlen + 1;
        }
 
        $headercrc = "";
        if ($flags & 1) {
            // 2-bytes (lowest order) of CRC32 on header present
            if ($len - $headerlen - 2 < 8) {
                return false; // Invalid format
            }
            $calccrc = crc32 ( substr ( $data, 0, $headerlen ) ) & 0xffff;
            $headercrc = unpack ( "v", substr ( $data, $headerlen, 2 ) );
            $headercrc = $headercrc [1];
            if ($headercrc != $calccrc) {
                return false; // Bad header CRC
            }
            $headerlen += 2;
        }
 
        // GZIP FOOTER - These be negative due to PHP\'s limitations
        $datacrc = unpack ( "V", substr ( $data, - 8, 4 ) );
        $datacrc = $datacrc [1];
        $isize = unpack ( "V", substr ( $data, - 4 ) );
        $isize = $isize [1];
 
        // Perform the decompression:
        $bodylen = $len - $headerlen - 8;
        if ($bodylen < 1) {
            // This should never happen - IMPLEMENTATION BUG!
            return null;
        }
        $body = substr ( $data, $headerlen, $bodylen );
        $data = "";
        if ($bodylen > 0) {
            switch ($method) {
                case 8 :
                    // Currently the only supported compression method:
                    $data = gzinflate ( $body );
                    break;
                default :
                    // Unknown compression method
                    return false;
            }
        } else {
 
        // I\'m not sure if zero-byte body content is allowed.
        // Allow it for now...  Do nothing...
        }
 
        // Verifiy decompressed size and CRC32:
        // NOTE: This may fail with large data sizes depending on how
        //       PHP\'s integer limitations affect strlen() since $isize
        //       may be negative for large sizes.
        if ($isize != strlen ( $data ) || crc32 ( $data ) != $datacrc) {
            // Bad format!  Length or CRC doesn\'t match!
            return false;
        }
        return $data;
    }
}
?>

使用起来非常简单,下面是一个调用程序:

<?php
/**
 * demo.php
 *
 * 客户端调用示例
 *
 * @filename demo.php
 * @version  v1.0
 * @update   2011-12-22
 * @author   homingway
 * @contact  homingway@gmail.com
 * @package  webservice
 */
 
include_once(\'../client/apiClient.php\');
 
$server_uri = \'http://localhost/webservice/server/server.php\';
 
print_r(apiClient::send($server_uri,\'welcome.index\'));
?>

 

分类:

技术点:

相关文章: