首先是服务端,服务端有一个主要的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'));
?>

一个PHP写的简单webservice服务端+客户端的更多相关文章

  1. JAVA WEBSERVICE服务端&amp;客户端的配置及调用(基于JDK)

    前言:我之前是从事C#开发的,因公司项目目前转战JAVA&ANDROID开发,由于对JAVA的各种不了解,遇到的也是重重困难.目前在做WEBSERVICE提供数据支持,看了网上相关大片的资料也 ...

  2. AgileEAS.NET SOA 中间件平台.Net Socket通信框架-简单例子-实现简单的服务端客户端消息应答

    一.AgileEAS.NET SOA中间件Socket/Tcp框架介绍 在文章AgileEAS.NET SOA 中间件平台Socket/Tcp通信框架介绍一文之中我们对AgileEAS.NET SOA ...

  3. DelphiXE7中创建WebService(服务端+客户端)

    相关资料: http://www.2ccc.com/news/Html/?1507.html http://www.dfwlt.com/forum.php?mod=viewthread&tid ...

  4. DelphiXE7中创建WebService(服务端+客户端) good

    相关资料:http://www.2ccc.com/news/Html/?1507.html DelphiXE7新建WebService具体操作:1.打开“DelphiXE7”->“File”-& ...

  5. myeclipse-建立webservice服务端和客户端

    一.建立webservice服务端: 1.新建一个web service project,名称为webservice_server截图如下,点击finish. 2.选择工程,点击右键,选择new-&g ...

  6. socket编程,简单多线程服务端测试程序

    socket编程,简单多线程服务端测试程序 前些天重温了MSDN关于socket编程的WSAStartup.WSACleanup.socket.closesocket.bind.listen.acce ...

  7. 基于JAX-WS的Web Service服务端/客户端 ;JAX-WS + Spring 开发webservice

    一.基于JAX-WS的Web Service服务端/客户端 下面描述的是在main函数中使用JAX-WS的Web Service的方法,不是在web工程里访问,在web工程里访问,参加第二节. JAX ...

  8. CXF发布webService服务以及客户端调用

    这篇随笔内容是CXF发布webService服务以及客户端调用的方法 CXF是什么? 开发工作之前需要下载CXF和安装 下载地址:http://cxf.apache.org 安装过程: <1&g ...

  9. react服务端/客户端,同构代码心得

    FKP-REST是一套全栈javascript框架   react服务端/客户端,同构代码心得 作者:webkixi react服务端/客户端,同构代码心得 服务端,客户端同构一套代码,大前端的梦想, ...

随机推荐

  1. 跨应用使用Spoon框架截图的方法

    spoon框架是一个很棒的用例驱动跟测试结果生成加工的框架.但在使用spoon-client时,传入参数需要被测应用的activity实例,跨应用测试会很受限(当然也可能是因为我对android不熟导 ...

  2. Oracl中sql书写技巧

    1.写脚本(1)为什么不直接设置回滚点?因为服务器上数据库是很多人使用的,所以除了自己操作外,有很多人操作.如果设置回滚点时,回滚后,很多人操作都消失了,因此savepoint不可以.但是可以自己书写 ...

  3. 拼图 canvas分割 dom拖拽 pc 移动端

    参考:Canvas drag 实现拖拽拼图小游戏 参考的案例,不支持手机端.总结下实现过程中遇到的小坑. gitHub:https://github.com/WppFrontEnd/puzzle 大概 ...

  4. C#:基于WMI查询USB设备信息 及 Android设备厂商VID列表

    /* ---------------------------------------------------------- 文件名称:WMIUsbQuery.cs 作者:秦建辉 MSN:splashc ...

  5. tshark过滤并保存包特定字段

    1.过滤端口为5001的tcp包,将时间输出 tshark -r h1.pcap -Y "tcp.port==5001" -T fields -e frame.time 时间格式如 ...

  6. CSS 使用推荐

      中文字体css编码转换 微软雅黑 \5FAE\8F6F\96C5\9ED1 或 Microsoft YaHei 黑体 \9ED1\4F53 新宋体 \65b0\5b8b\4f53 宋体 \5b8b ...

  7. POJ 3067 Japan(经典树状数组)

    基础一维树状数组  题意:左边一排 1-n 的城市,右边一排 1-m 的城市,都从上到下依次对应.接着给你一些城市对,表示城市这两个城市相连,最后问你一共有多少个交叉,其中处于城市处的交叉不算并且每个 ...

  8. Apache Shiro系列教程之二:十分钟上手Shiro

    在本教程中,我们会写一个简单的.仅仅输出一些内容命令行程序,从而对Shiro有一个大体的感觉. 一.准备工作 本教程需要Java1.5+,并且我们用Maven生成项目,当然Maven不是必须的,你也可 ...

  9. js 去掉字符串前后空格

    //去左空格; function ltrim(s){ return s.replace(/(^\s*)/g, ""); } //去右空格; function rtrim(s){ r ...

  10. Mac mongodb 配置安装

    简单总结就几条,比较简单配置mongodb. 1,首先下载安装包:百度云下载地址 2,下载之后解压到自己常放的工作目录下,然后开始配置一下你的Mac环境 vim ~/.bash_profile 添加m ...