一个PHP写的简单webservice服务端+客户端
首先是服务端,服务端有一个主要的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.'¶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
/**
* 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服务端+客户端的更多相关文章
- eclipse使用CXF3.1.*创建webservice服务端客户端以及客户端手机APP(二)
eclipse使用CXF3.1.*创建webservice服务端客户端以及客户端手机APP(二) 接上篇博客,本篇博客主要包含两个内容: 4.使用Android studio创建webservice客 ...
- eclipse使用CXF3.1.*创建webservice服务端客户端以及客户端手机APP(一)
eclipse使用CXF3.1.*创建webservice服务端客户端以及客户端手机APP(一) 本篇博客主要包含五个内容: 1.CXF换将搭建以及eclipse配置CXF. 2.eclipse创建w ...
- 手写内网穿透服务端客户端(NAT穿透)原理及实现
Hello,I'm Shendi. 这天心血来潮,决定做一个内网穿透的软件. 用过花生壳等软件的就知道内网穿透是个啥,干嘛用的了. 我们如果有服务器(比如tomcat),实际上我们在电脑上开启了服务器 ...
- JAVA WEBSERVICE服务端&客户端的配置及调用(基于JDK)
前言:我之前是从事C#开发的,因公司项目目前转战JAVA&ANDROID开发,由于对JAVA的各种不了解,遇到的也是重重困难.目前在做WEBSERVICE提供数据支持,看了网上相关大片的资料也 ...
- AgileEAS.NET SOA 中间件平台.Net Socket通信框架-简单例子-实现简单的服务端客户端消息应答
一.AgileEAS.NET SOA中间件Socket/Tcp框架介绍 在文章AgileEAS.NET SOA 中间件平台Socket/Tcp通信框架介绍一文之中我们对AgileEAS.NET SOA ...
- WebService 服务端客户端 实例 HTTPRIO (一) SOAP WSDL
Delphi中WebService包含的组件解释(有7个) (1) THTTPRIO-------:使用Http消息来调用远程使用SOAP的接口对象 (2) THTTPReqResp- ...
- DelphiXE7中创建WebService(服务端+客户端)
相关资料: http://www.2ccc.com/news/Html/?1507.html http://www.dfwlt.com/forum.php?mod=viewthread&tid ...
- DelphiXE7中创建WebService(服务端+客户端) good
相关资料:http://www.2ccc.com/news/Html/?1507.html DelphiXE7新建WebService具体操作:1.打开“DelphiXE7”->“File”-& ...
- PHP写webservice服务端
1) WebService技术介绍 WebService是一种跨编程语言和跨操作系统平台的远程调用技术.仅仅有通过Web Service,client和server才可以自由的用HTTP进行通信.不论 ...
随机推荐
- 8个免费实用的C++GUI库(转载)
C++标准中并没有包含GUI,这也使得C++开发图形化界面需要依赖于第三方的库.实际上,图形界面恰恰是C++的强项,小到平常使用的各类桌面软件,大到魔兽世界这样的游戏,都是C++擅长的地方.C++ ...
- 一次非常有意思的sql优化经历
补充:看到这么多朋友对sql优化感兴趣,我又重新补充了下文章的内容,将更多关于sql优化的知识分享出来, 喜欢这篇文章的朋友给个赞吧,哈哈,欢迎交流,共同进步. 2015-4-30补充:非常感觉编辑的 ...
- 微信小程序剖析【下】:运行机制
在上一篇<微信小程序「官方示例代码」浅析[上]>中,我们只是简单的罗列了一下代码,这一篇,让我们来玩点刺激的——就是看看IDE的代码,了解它是怎么运行的. 还好微信的开发团队在软件工程的实 ...
- 12.C#yield return和yield break及实际应用小例(六章6.2-6.4)
晚上好,各位.今天结合书中所讲和MSDN所查,聊下yield关键字,它是我们简化迭代器的关键. 如果你在语句中使用了yield关键字,则意味着它在其中出现的方法.运算符或get访问器是迭代器,通过使用 ...
- 年前辞职-WCF入门学习(5)
前言 第五集比较简单,视频也只有7分多钟,但是用处还是挺大的.下面我会介绍. 本来想第六集一起介绍的,后来发现第六集内容比较多,有半个多小时,就不一起了.网站规定6小时内只能发布一篇文章到首页,,那我 ...
- Photoshop之渐变工具使用
最上面两个游标控制不透明度 下面两个控制渐变位置 点击游标可以设置颜色 基于每个游标进行操作
- 创建Car类,实例化并调用Car类计算运输的原料量是否足够
package dx; public class Car { //构造类 public Car() { System.out.println("Car的构造类"); } //构造类 ...
- struts2理解
(1) Struts2(一)---struts2的环境搭建及实例 (2) struts2(二)---ModelDriven模型驱动 (3) Struts2属性驱动与模型驱动 (4)
- href="javascript:void(0)"
javascript:是伪协议,表示url的内容通过javascript执行.void(0)表示不作任何操作,这样会防止链接跳转到其他页面.这么做往往是为了保留链接的样式,但不让链接执行实际操作,具体 ...
- jQuery的查找
children([expr])概述 :取得一个包含匹配的元素集合中每一个元素的所有子元素的元素集合.可以通过可选的表达式来过滤所匹配的子元素.注意:parents()将查找所有祖辈元素,而child ...