您的位置:首页 > 编程语言 > PHP开发

分享一个PHP写的简单webservice服务端+客户端

2015-01-15 16:47 633 查看


分享一个PHP写的简单webservice服务端+客户端

首先说明一下,这个小程序是我自己用PHP写成的一个简单的webservice系统,包括服务端的程序和客户端的程序,无论是服务端还是客户端在使用起来都非常的简单方便,也可以很方便的移植到自己的项目里,我自己也已经在稍微改造后用在了自己的项目里,应用到生产环境2个多月以来都很稳定,没有出过什么问题。 

这个简单的webservice小程序有以下几个优点: 

1. 简单、易用,几乎没有什么学习成本 

2. 可扩展性很强,因为简单,所以你可以在这个基础上扩展出很多的东西,比如返回的数据格式上可以加上xml的支持等,这个就需要自己动手了 

3. 数据传输量小,服务端到客户端的数据传输采用gzip压缩的方式,极大的减小了数据的体积,我自己做的测试是,一份4.7M的html数据在压缩后只有113K 

4. 有一定的安全性,首先服务端和客户端之间的通讯会有密钥机制,同时又采取限定IP的方式保护了接口的安全。 

当然,也有缺点:比如程序过于简单,没有对安全性和数据过过多的校验,这个在应用到生产环境之前一定要记得加强一下;客户端到服务端的请求默认采用get形式,传输的数据量有限,这个我会考虑在以后的改进中改为post,同时数据也采用gzip压缩以后传输。 

好了,言归正传,下面介绍一下代码本身: 

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

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(emptyempty($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代码  


<?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代码  


<?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代码  


<?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) || emptyempty($param)){  

            $json_param = '';  

        } else {  

            $json_param = urlencode(json_encode($param));  

        }  

        $api_url = $url.'?method='.$method.'&time='.$time.'&auth='.$auth.'¶m='.$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代码  


<?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'));  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  php webservice json