Server端+Client端
上篇用了wsdl这个写不用wsdl的.
声明:很简单!!!!!!
参考了如下:
http://blog.111cn.net/phphot/archive/
类文件
<?php
/**
* 实现业务逻辑的类,此类是一个普通类
*
*/
class Basic {
/**
* 返回一个字符串:Hello World!
*
* @return string
*/
public function returnString($test){
return "Hello World!".$test;
}
}
?>
Server
<?php
/**
* Web Service的Server端,包含类文件。
*/
require_once("basic.php");
/**
* 创建Server对象
*/
$arrOptions = array(''uri''=>''checkAPI''); //设置命名空间
$objSoapServer = new SoapServer(null,$arrOptions);
/**
* 注册Basic类的所有方法
*/
$objSoapServer->setClass("Basic");
/**
* 处理请求
*/
$objSoapServer->handle();
?>
Client
<?php
/**
* Client端,首先创建Client对象
*/
$arrOptions = array(''uri''=>''checkAPI'', //设置命名空间
''location''=>''http://localhost/user/soaptest.php'', //设置Server地址
''trace''=>true);
$objSoapClient = new SoapClient(null,$arrOptions);
/**
* 远程调用
*/
$test=''ok123'';
try{
$strReturn = $objSoapClient->returnString($test);
}catch(Exception $e){
}
/**
* 打印结果
*/
echo $strReturn;
?>
Server端+Client端+WSDL
声明:很简单!!!!!!
参考了如下:
先建Server,然后使用wsdl工具来生成wsdl,我用的是zend development environment,
在zde中的tools中的wsdl generator wizard
第一页是名字,和输出地址(输出后直接挪过去就OK)
第二页是类和地址,类挑上勾,URL那里添server那个文件的地址
第三页 finish
别忘了拷那个wsdl过去...
记得server引用的那个类文件里不要有输出.
一共有两个需要添地址的地方
一个是wsdl中的描述http://127.0.0.1/test/CulculatorServer.php
一个是client中的连接http://127.0.0.1/test/Culculator.wsd
类文件
<?php
/**
* @name Culculator.php
* @date Fri Jan 25 12:43:40 CST 2008
* @copyright 马永占(MyZ)
* @author 马永占(MyZ)
* @link http://blog.111cn.net/mayongzhan/
*/
class Culculator
{
/**
* 求和
*
* @param float $x
* @param float $y
* @return float
*/
public function add($x, $y)
{
return $x + $y;
}
}
?>
Server
<?php
/**
* @name CulculatorServer.php
* @date Fri Jan 25 12:44:04 CST 2008
* @copyright 马永占(MyZ)
* @author 马永占(MyZ)
* @link http://blog.111cn.net/mayongzhan/
*/
include(''./Culculator.php'');
$server = new SoapServer(''./Culculator.wsdl'');
$server->setClass(''Culculator'');
$server->handle();
?>
Client
<?php
/**
* @name CulculatorClient.php
* @date Fri Jan 25 12:43:54 CST 2008
* @copyright 马永占(MyZ)
* @author 马永占(MyZ)
* @link http://blog.111cn.net/mayongzhan/
*/
$soap = new SoapClient(''http://127.0.0.1/test/Culculator.wsdl'');
echo $soap->add(1, 2);
?>
WSDL
<?xml version=''1.0'' encoding=''UTF-8''?>
<!-- WSDL file generated by Zend Studio. -->
<definitions name="math" targetNamespace="urn:math" xmlns:typens="urn:math" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/">
<message name="add">
<part name="x" type="xsd:float"/>
<part name="y" type="xsd:float"/>
</message>
<message name="addResponse">
<part name="addReturn" type="xsd:float"/>
</message>
<portType name="CulculatorPortType">
<operation name="add">
<documentation>
求和
</documentation>
<input message="typens:add"/>
<output message="typens:addResponse"/>
</operation>
</portType>
<binding name="CulculatorBinding" type="typens:CulculatorPortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="add">
<soap:operation soapAction="urn:CulculatorAction"/>
<input>
<soap:body namespace="urn:math" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</input>
<output>
<soap:body namespace="urn:math" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</output>
</operation>
</binding>
<service name="mathService">
<port name="CulculatorPort" binding="typens:CulculatorBinding">
<soap:address location="http://127.0.0.1/test/CulculatorServer.php"/>
</port>
</service>
</definitions>
fsockopen
以socket方式打开一个连接
我最常用的是模拟post
这个是小李挖掘的到的...不错
至于要模拟get方式....直接file_get_content就行了.
代码见后面
stream_socket_client, 代码见后面
这个和fsockopenfsockopen一样.以socket方式打开一个连接,只是参数不同
stream_socket_server
建立一个socket server端, 代码见后面
如果是建立的是tcp的server 就用stream_socket_accept进行通讯
如果是建立的是udp的server 就用stream_socket_recvfrom和stream_socket_sendto进行通讯,而且stream_socket_server中需要加个参数STREAM_SERVER_BIND
还有个socket扩展,这个是最基础的建立socket,但是从
这里就不介绍了.
---------------------------- stream_socket client---------------------------
<?php
/**
* @name test.php
* @date Sun Jan 27 00:49:00 CST 2008
* @copyright 马永占(MyZ)
* @author 马永占(MyZ)
* @link http://blog.111cn.net/mayongzhan/
*/
$xport = "tcp";
$port = "8001";
$ip = "127.0.0.1";
$address = "{$xport}://{$ip}:{$port}";
$fp = stream_socket_client($address, $errno, $errstr, 1);
if (!$fp) {
echo "$errstr ($errno)<br /> ";
} else {
fwrite($fp, " ");
echo fread($fp, 1024);
fclose($fp);
}
?>
---------------------------- streamSocketServer---------------------------
<?php
/**
* @name test2.php
* @date Sun Jan 27 00:45:57 CST 2008
* @copyright 马永占(MyZ)
* @author 马永占(MyZ)
* @link http://blog.111cn.net/mayongzhan/
*/
header("Content-type: text/html;charset=utf-8");
//设置不超时.服务端当然不能超时
set_time_limit(0);
//得到可用socket
$xportlist = stream_get_transports();
echo "transports: ";
foreach ($xportlist as $value) {
echo "{$value} ";
}
//定义一些东西
$xport = "tcp";
$port = "8001";
$address = "{$xport}://
//建立socketserver
if ($xport==''tcp'') {
$socket = stream_socket_server($address, $errno, $errstr);
}
elseif ($xport==''udp'') {
$socket = stream_socket_server($address, $errno, $errstr, STREAM_SERVER_BIND);
}
if (!$socket) {
echo "{$errstr} ({$errno}) ";
}
else {
echo "listening {$xport}:{$port} ... ";
if ($xport==''tcp'') {
//许可一个socket连接,-1超时
while ($conn = stream_socket_accept($socket,-1)) {
//得到访问的端口
$peer = stream_socket_get_name($conn,true);
echo "$peer ";
fwrite($conn, ''The local time is '' . date("Y-m-d H:i:s "));
fclose($conn);
}
}
elseif ($xport==''udp'') {
do {
//得到访问的端口
$pkt = stream_socket_recvfrom($socket, 1, 0, $peer);
echo "$peer ";
stream_socket_sendto($socket, date("Y-m-d H:i:s "), 0, $peer);
} while ($pkt !== false);
}
//关闭socket
fclose($socket);
}
?>
---------------------------- fsockopen(post)---------------------------
<?php
/**
* @name test.php
* @date Sat Jan 26 23:01:23 CST 2008
* @copyright 马永占(MyZ)
* @author 马永占(MyZ)
* @link http://blog.111cn.net/mayongzhan/
*/
/**
* php 发送POST请求
*
* @param string $url 提交到的地址
* @param array $data 要提交的参数 array(''a''=>'''',''b''=>'''');
* @return string
*/
function virtualPost($url, $data) {
$url = parse_url($url);
if (!$url) return "URL不能解析";
if (!isset($url[''port''])) $url[''port''] = "";
if (!isset($url[''query''])) $url[''query''] = "";
$encoded = "";
while (list($k,$v) = each($data)) {
$encoded .= ($encoded ? "&" : "");
$encoded .= rawurlencode($k)."=".rawurlencode($v);
}
//$fp = stream_socket_client($url[''host''].":".($url[''port''] ? $url[''port''] : 80));
$fp = fsockopen($url[''host''], $url[''port''] ? $url[''port''] : 80);
if (!$fp) return "不能打开到$url[host]的连接";
//发送
fputs($fp, sprintf("POST %s%s%s HTTP/1.0 ", $url[''path''], $url[''query''] ? "?" : "", $url[''query'']));
fputs($fp, "Host: $url[host] ");
fputs($fp, "Content-type: application/x-www-form-urlencoded ");
fputs($fp, "Content-length: " . strlen($encoded) . " ");
fputs($fp, "Connection: close ");
fputs($fp, "$encoded ");
//接受
$line = fgets($fp,1024);
if (!eregi("^HTTP/1.. 200", $line)) return "返回结果错误";
//滤掉空行
$results = "";
$inheader = 1;
while(!feof($fp)) {
$line = fgets($fp,1024);
//把剩余的头信息过滤掉
if ($inheader && ($line == " " || $line == " ")) {
$inheader = 0;
}elseif (!$inheader) {
$results .= $line;
}
}
fclose($fp);
return $results;
}
echo virtualPost(''http://127.0.0.1/test/test2.php'',array(myz=>''马永占''));
?>
一、问题起源
稍大一些的网站,通常都会有好几个服务器,每个服务器运行着不同功能的模块,使用不同的二级域名,而一个整体性强的网站,用户系统是统一的,即一套用户名、密码在整个网站的各个模块中都是可以登录使用的。各个服务器共享用户数据是比较容易实现的,只需要在后端放个数据库服务器,各个服务器通过统一接口对用户数据进行访问即可。但还存在一个问题,就是用户在这个服务器登录之后,进入另一个服务器的别的模块时,仍然需要重新登录,这就是一次登录,全部通行的问题,映射到技术上,其实就是各个服务器之间如何实现共享 SESSION 数据的问题。
二、PHP SESSION 的工作原理
在解决问题之前,先来了解一下 PHP SESSION 的工作原理。在客户端(如浏览器)登录网站时,被访问的 PHP 页面可以使用 session_start() 打开 SESSION,这样就会产生客户端的唯一标识 SESSION ID(此 ID 可通过函数 session_id() 获取/设置)。SESSION ID 可以通过两种方式保留在客户端,使得请求不同的页面时,PHP 程序可以获知客户端的 SESSION ID;一种是将 SESSION ID 自动加入到 GET 的 URL 中,或者 POST 的表单中,默认情况下,变量名为 PHPSESSID;另一种是通过 COOKIE,将 SESSION ID 保存在 COOKIE 中,默认情况下,这个 COOKIE 的名字为 PHPSESSID。这里我们主要以 COOKIE 方式进行说明,因为应用比较广泛。
那么 SESSION 的数据保存在哪里呢?当然是在服务器端,但不是保存在内存中,而是保存在文件或数据库中。默认情况下,php.ini 中设置的 SESSION 保存方式是 files(session.save_handler = files),即使用读写文件的方式保存 SESSION 数据,而 SESSION 文件保存的目录由 session.save_path 指定,文件名以 sess_ 为前缀,后跟 SESSION ID,如:sess_c72665af28a8b14c0fe11afe3b59b51b。文件中的数据即是序列化之后的 SESSION 数据了。如果访问量大,可能产生的 SESSION 文件会比较多,这时可以设置分级目录进行 SESSION 文件的保存,效率会提高很多,设置方法为:session.save_path="N;/save_path",N 为分级的级数,save_path 为开始目录。当写入 SESSION 数据的时候,PHP 会获取到客户端的 SESSION_ID,然后根据这个 SESSION ID 到指定的 SESSION 文件保存目录中找到相应的 SESSION 文件,不存在则创建之,最后将数据序列化之后写入文件。读取 SESSION 数据是也是类似的操作流程,对读出来的数据需要进行解序列化,生成相应的 SESSION 变量。
三、多服务器共享 SESSION 的主要障碍及解决办法
通过了解 SESSION 的工作原理,我们可以发现,在默认情况下,各个服务器会各自分别对同一个客户端产生 SESSION ID,如对于同一个用户浏览器,A 服务器产生的 SESSION ID 是 30de1e9de3192ba6ce2992d27a1b6a0a,而 B 服务器生成的则是 c72665af28a8b14c0fe11afe3b59b51b。另外,PHP 的 SESSION 数据都是分别保存在本服务器的文件系统中。
在PHP开发中对比起Cookie,Session 是存储在服务器端的会话,相对安全,并且不像 Cookie 那样有存储长度限制,本文简单介绍 Session 的使用。
由于 Session 是以文本文件形式存储在服务器端的,所以不怕客户端修改 Session 内容。实际上在服务器端的 Session 文件,PHP 自动修改 Session 文件的权限,只保留了系统读和写权限,而且不能通过 ftp 修改,所以安全得多。PHPChina 开源社区门户k%W%e2CY
对于 Cookie 来说,假设我们要验证用户是否登陆,就必须在 Cookie 中保存用户名和密码(可能是 md5 加密后字符串),并在每次请求页面的时候进行验证。如果用户名和密码存储在数据库,每次都要执行一次数据库查询,给数据库造成多余的负担。因为我们并不能 只做一次验证。为什么呢?因为客户端 Cookie 中的信息是有可能被修改的。假如你存储 $admin 变量来表示用户是否登陆,$admin 为 true 的时候表示登陆,为 false 的时候表示未登录,在第一次通过验证后将 $admin 等于 true 存储在 Cookie,下次就不用验证了,这样对么?错了,假如有人伪造一个值为 true 的 $admin 变量那不是就立即取的了管理权限么?非常的不安全。
而 Session 就不同了,Session 是存储在服务器端的,远程用户没办法修改 Session 文件的内容,因此我们可以单纯存储一个 $admin 变量来判断是否登陆,首次验证通过后设置 $admin 值为 true,以后判断该值是否为 true,假如不是,转入登陆界面,这样就可以减少很多数据库操作了。而且可以减少每次为了验证 Cookie 而传递密码的不安全性了(Session 验证只需要传递一次,假如你没有使用 SSL 安全协议的话)。即使密码进行了 md5 加密,也是很容易被截获的。
当然使用 Session 还有很多优点,比如控制容易,可以按照用户自定义存储等(存储于数据库)。我这里就不多说了。
Session 在 php.ini 是否需要设置呢?一般不需要的,因为并不是每个人都有修改 php.ini 的权限,默认 Session 的存放路径是服务器的系统临时文件夹,我们可以自定义存放在自己的文件夹里,这个稍后我会介绍。
开始介绍如何创建 Session。非常简单,真的。
启动 Session 会话,并创建一个 $admin 变量:
<?php
// 启动 Session
session_start();
// 声明一个名为 admin 的变量,并赋空值。
$_SESSION["admin"] = null;
?>
如果你使用了 Seesion,或者该 PHP 文件要调用 Session 变量,那么就必须在调用 Session 之前启动它,使用 session_start() 函数。其它都不需要你设置了,PHP 自动完成 Session 文件的创建。
执行完这个程序后,我们可以到系统临时文件夹找到这个 Session 文件,一般文件名形如:sess_4c83638b3b0dbf65583181c2f89168ec,后面是 32 位编码后的随机字符串。用编辑器打开它,看一下它的内容:
admin|N;
一般该内容是这样的结构:
变量名|类型:长度:值;
并用分号隔开每个变量。有些是可以省略的,比如长度和类型。
我们来看一下验证程序,假设数据库存储的是用户名和 md5 加密后的密码:
<?php
// 表单提交后...
$posts = $_POST;
// 清除一些空白符号
foreach ($posts as $key => $value)
{
$posts[$key] = trim($value);
}
$password = md5($posts["password"]);
$username = $posts["username"];
$query = "SELECT `username` FROM `user` WHERE `password` = ''$password''";
// 取得查询结果
$userInfo = $DB->getRow($query);
if (!empty($userInfo))
{
if ($userInfo["username"] == $username)
{
// 当验证通过后,启动 Session
session_start();
// 注册登陆成功的 admin 变量