首先说明一下,这个小程序是我自己用PHP写成的一个简单的webservice系统,包括服务端的程序和客户端的程序,无论是服务端还是客户端在使用起来都非常的简单方便,也可以很方便的移植到自己的项目里,我自己也已经在稍微改造后用在了自己的项目里,应用到生产环境2个多月以来都很稳定,没有出过什么问题。?
这个简单的webservice小程序有以下几个优点:?
1. 简单、易用,几乎没有什么学习成本?
2. 可扩展性很强,因为简单,所以你可以在这个基础上扩展出很多的东西,比如返回的数据格式上可以加上xml的支持等,这个就需要自己动手了?
3. 数据传输量小,服务端到客户端的数据传输采用gzip压缩的方式,极大的减小了数据的体积,我自己做的测试是,一份4.7M的html数据在压缩后只有113K?
4. 有一定的安全性,首先服务端和客户端之间的通讯会有密钥机制,同时又采取限定IP的方式保护了接口的安全。
当然,也有缺点:比如程序过于简单,没有对安全性和数据过过多的校验,这个在应用到生产环境之前一定要记得加强一下;客户端到服务端的请求默认采用get形式,传输的数据量有限,这个我会考虑在以后的改进中改为post,同时数据也采用gzip压缩以后传输。?
好了,言归正传,下面介绍一下代码本身:?
首先是服务端,服务端有一个主要的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?=?//私有静态单例变量??
- private?static?$_instance?=?null;??
- ?????*?构造方法,处理请求参数?
- ?????*/??
- function?__construct(){??
- ????????$this->dealRequest();??
- ????}??
- ?????*?单例运行?
- public?static?function?getInstance(){??
- ????????if(self::$_instance?===?null){??
- ????????????self::$_instance?=?new?self();??
- ????????}??
- return?self::$_instance;??
- ?????*?运行?
- 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($this->service_method['method']));??
- if(is_array($result)){??
- ????????????$result?=?json_encode($result);??
- ????????$result?=?gzencode($result);??
- ????????exit($result);??
- ?????*?检查授权?
- 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']){??
- //ip限制??
- if($this->ip_limit){??
- ????????????$remote_ip?=?$this->getIP();??
- ????????????$intersect?=?array_intersect($remote_ip,$this->ip_allow);??
- if(emptyempty($intersect)){??
- ???????????????? ????????????}??
- return?true;??
- ?????*?获取服务名和方法名?
- function?getApiMethod(){??
- if(strpos($this->request['method'],?'.')?===?false){??
- ????????????$method?=?$this->default_method;??
- ????????????$method?=?$this->request['method'];??
- ????????$tmp?=?explode('.',?$method);??
- ????????$this->service_method?=?array('service'=>$tmp[0],'method'=>$tmp[1]);??
- return?$this->service_method;??
- ?????*?获取和处理请求参数?
- 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');??
- ????????????$this->request['param']?=?json_decode(urldecode($this->request['param']),true);??
- ?????*?获取request变量?
- ?????*?@param?string?$item?
- function?_request($item){??
- return?isset($_REQUEST[$item])???trim($_REQUEST[$item])?:?'';??
- ?????*?设置IP限制?
- ?????*?@param?bool?$limit?
- function?setIPLimit($limit=true){??
- ????????$this->ip_limit?=?$limit;??
- ?????*?获取客户端ip地址?
- function?getIP(){??
- ????????$ip?=?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,并启动服务即可,如:?
?*?server.php?
?*?自定义数据接口的入口?
?*?@filename?server.php?
//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:?
?*?welcome.php?
?*?功能代码?
?*?@filename?welcome.php?
class?welcome{??
function?index(){??
return?'hello?service';??
下面是客户端的主程序:apiClient.php?
?*?apiClient.php?
?*?webservice客户端程序?
?*?@filename?apiClient.php?
class?apiClient{??
function?send($url,$method,$param=array()){??
????????$time?=?time();??
????????$auth?=?md5(md5($time.'|'.$method.'|'.API_AUTH_KEY));??
if(!is_array($param)?||?emptyempty($param)){??
????????????$json_param?=?'';??
????????????$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);??
????????????$content?=?self::gzdecode($content);??
return?$content;??
function?gzdecode($data)?{??
????????$len?=?strlen?(?$data?);??
if?($len?<?18?||?strcmp?(?substr?(?$data,?0,?2?),?"x1fx8b"?))?{??
return?null;???
????????$method?=?ord?(?substr?(?$data,?2,?1?)?);???
????????$flags?=?ord?(?substr?(?$data,?3,0); padding:0px; margin:0px; width:auto; border:0px">//?Flags??
if?($flags?&?31?!=?$flags)?{??
??????????????
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,250); line-height:18px"> ????????$headerlen?=?10;??
????????$extralen?=?0;??
????????$extra?=?"";??
if?($flags?&?4)?{??
//?2-byte?length?prefixed?EXTRA?data?in?header??
if?($len?-?$headerlen?-?2?<?8)?{??
return?false;???
????????????$extralen?=?unpack?(?"v",?2?)?);??
????????????$extralen?=?$extralen?[1];??
if?($len?-?$headerlen?-?2?-?$extralen?<?8)?{??
????????????$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)?{??
????????????$filenamelen?=?strpos?(?substr?(?$data,?8?+?$extralen?),?chr?(?0?)?);??
if?($filenamelen?===?false?||?$len?-?$headerlen?-?$filenamelen?-?1?<?8)?{??
????????????$filename?=?substr?(?$data,?$headerlen,?$filenamelen?);??
????????????$headerlen?+=?$filenamelen?+?1;??
????????$commentlen?=?0;??
????????$comment?=?"";??
if?($flags?&?16)?{??
//?C-style?string?COMMENT?data?in?header??
????????????$commentlen?=?strpos?(?substr?(?$data,?8?+?$extralen?+?$filenamelen?),85); font-weight:bold">if?($commentlen?===?false?||?$len?-?$headerlen?-?$commentlen?-?1?<?8)?{??
//?Invalid?header?format??
????????????$comment?=?substr?(?$data,?$commentlen?);??
????????????$headerlen?+=?$commentlen?+?1;??
????????$headercrc?=?"";??
if?($flags?&?1)?{??
//?2-bytes?(lowest?order)?of?CRC32?on?header?present??
????????????$calccrc?=?crc32?(?substr?(?$data,?$headerlen?)?)?&?0xffff;??
????????????$headercrc?=?unpack?(?"v",250); line-height:18px"> ????????????$headercrc?=?$headercrc?[1];??
if?($headercrc?!=?$calccrc)?{??
//?Bad?header?CRC??
????????????$headerlen?+=?2;??
//?GZIP?FOOTER?-?These?be?negative?due?to?PHP's?limitations??
????????$datacrc?=?unpack?(?"V",?-?8,250); line-height:18px"> ????????$datacrc?=?$datacrc?[1];??
????????$isize?=?unpack?(?"V",?-?4?)?);??
????????$isize?=?$isize?[1];??
//?Perform?the?decompression:??
????????$bodylen?=?$len?-?$headerlen?-?8;??
if?($bodylen?<?1)?{??
//?This?should?never?happen?-?IMPLEMENTATION?BUG!??
????????$body?=?substr?(?$data,?$bodylen?);??
????????$data?=?"";??
if?($bodylen?>?0)?{??
switch?($method)?{??
case?8?:??
??????????????????????
????????????????????$data?=?gzinflate?(?$body?);??
????????????????????break;??
default?:??
//?Unknown?compression?method??
//?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?$data;??
使用起来非常简单,下面是一个调用程序:?
?*?demo.php?
?*?客户端调用示例?
?*?@filename?demo.php?
include_once('../client/apiClient.php');??
$server_uri?=?'http://localhost/webservice/server/server.php';??
print_r(apiClient::send($server_uri,'welcome.index'));??
本文所涉及到的所有代码及主程序我都打包到下面的zip文件中,可以直接下载,有什么疑问可以直接在下面留言回复。?
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|