php+soap

php soap编码转换

在给CHINAZ资讯(dedecms)做同步bbsmax passport登陆api时,因为bbsmax使用utf-8编码,而资讯这边用的是GBK编码,导致乱码。开始想自己转码,但有点麻烦。后面想SOAP既然用来针对不同平台,那肯定也包括编码问题,就又认真看了PHP手册,介绍里虽然没有提到,却发现Examples里有,访问很简单。

$client = new SoapClient("some.wsdl", array('encoding'=>'GBK'));   

只要这么简单,剩下的PHP自己帮忙实现了!

通过SoapHeader实现身份认证

之前一直抱怨php的soap很傻,在client端有设置header的方法,在server端却没有取header的方法。那是很傻很天真,直接用正则表达式从soap信封的header中提取header信息。
最近由于有项目要发布webservice,重新燃起对soap的兴趣,看了w3的英文文档,那是个云里雾里。收集了一些资料,做了一个关于saop header进行身份认证的实验。
在这个实验中,假定soap client用一个字符串作为身份认证的标识,soap server取到这个字符串后,对其进行辨认,如果与期望相符合,认证通过,如果不符,抛出soapFault。
理论就不多说了,我也不懂,直接上代码
client.php
<?php
$cli = new SoapClient(null, array('uri' => 'http://127.0.0.1/namespace/', 'location' => 'http://localhost/server.php', 'trace' => true));
$h = new SoapHeader('http://127.0.0.1/namespace/', 'auth', '123456789', false, SOAP_ACTOR_NEXT);
$cli->__setSoapHeaders(array($h));
try {
    echo $cli->say();
} catch (Exception $e) {
    echo $e->getMessage();
}

server.php
<?php
class Server{
   public function auth($a)
    {
        if($a != '123456789'){
            throw new SoapFault('Server', '您无权访问');
        }
    }
    function say()
    {
        return 'Hi';
    }
}

$srv = new SoapServer(null, array('uri' => 'http://localhost/namespace'));
$srv->setClass('Server');
$srv->handle();

以上代码就实现了认证的功能,最关键的地方就是SoapHeader的构造。soapHeader有五个构造参数,

Namespace    无用

Name    鉴别身份标识的函数或者方法名

Data    存放标识身份的字符串

mustUnderstand    是否必须处理该header

actor    处理该header的角色(不是太理解)

注意看红色的一行,构造了一个soapHeader,header的名称为"auth",data为"123456789",mustUnderstand为false,actor为SOAP_ACTOR_NEXT
注意观察server.php中的server类有一个方法"auth",刚好与header的名称对应,方法auth的参数$u,就是soapHeader的data,soapServer接收到这个请求会,先调用auth方法,并把"123456789"作为参数传递给该方法。
mustUnderstand参数为false时,即便没有auth这个方法,say方法也会被调用,但是如果它为true的话,如果auth方法不存在,就会返回一个Soapfault告知该header没有被处理。
actor参数指名那些role必须处理该header,这儿我理解得不是太透彻,不好说。
大概就这样,关键点在于SoapHeader的构造。
soap官方:http://www.w3.org/TR/soap12-part1/

[]使用SoapHeader实现Soap请求验证

在PHP的Soap Extension中, 对于SoapServer来说, 并没有方法可用得到/处理客户端发送的SoapHeader信息.
网上也有很多人认为, 只能通过读取POST过来的请求XML文件, 分析, 才能得到客户端发送过来的SoapHeader.但, 其实在SoapServer端, 其实是有一种办法, 可用把SoapHeader当作一个请求来处理, 从而获取到客户端提交的SoapHeader信息.

假设客户端代码如下:

 

<?php

/*

* 保存用户名和密码的载体

*/

class SoapUserInfo {

/**

* @var char $name

*/

 public $name;

/**

* @var char $password

*/

public $password;

public function __construct($l, $p) {

    $this->Password = $p;

    $this->Username = $l;

}

}

?>

然后客户端生成SoapHeader

<?php

$soap_header = new SoapHeader("http://www.laruence.com", 'Authorise'

, new SoapUserInfo('laruence', 'password'), false, SOAP_ACTOR_NEXT);

?>

也许细心的同学会注意到4个参数FALSE5个参数SOAP_ACTOR_NEXT, 这是什么呢? 我最后再讲.

然后, 创建客户端, 绑定SoapHeader

<?php

$client = new SoapClient($wsdl);

$client->__setSoapHeaders(array($soap_header));

$client->__soapCall('request', array());

?>

现在, 客户端已经发起了请求, 请求中也包含了SoapHeader, 其中有了我们验证需要的用户名/密码信息.

那么, 在服务端, 该如何做呢?

<?php

$server = new SoapServer('laruence.wsdl');

$server->setClass('InterfaceClass');

$server->handle();

?>

关键的地方就在, 服务端接收请求以后, 会实例化一个处理类, 然后分析SoapHeader, 接着就会调用InterfaceClass::Authorise这个方法(Authorise是我们请求头中的变量名), 所以, 我们就可用在InterfaceClass类中, 定义个Authorise方法, 并在这个方法中对SoapHeader中的信息做验证.

然后, 请求体(Soap body)中的方法被调用, 因为不论Authorise方法返回什么(除非exit), 请求体中的方法一定会被调用, 所以要寻找个变量记录验证的结果.

<?php

class InterfaceClass {

/**

* @var bool $authorized

*/

private $authorized = FALSE;

/*

* Authentication function

*

* @param string username

* @param string password

*/

public function Authentication($username, $password) {

    $this->authorized = validateUser($username, $password);

}

/*

* Test method

*/

public function request(){

    if ($this->authorized) {

        //验证成功, 继续处理.

    } else {

        //验证失败, 拒绝请求.

    }

}

}

?>

当然, 对于网上说的另外一种方法, 通过分析请求的XML文件, 也可以:

<?php

class InterfaceClass {

/**

* @var bool $authorized

*/

private $authorized = FALSE;

function __construct() {

    $xml = file_get_contents('php://input');

    //分析xml, 获得SoapHeader数据, 验证

}

}

?>

Must Understand

这个参数指明了, 是否服务端必须要了解SoapHeader, 如果这个参数为真, 而服务端并不能识别响应的Header, 则会引发一个Soap Fault(Header not understood).

SOAP_ACTOR_NEXT

actor指明了SoapHeader要传递给谁, 被谁处理.

SOAP_ACTOR_NEXT的意思就是, 下一个接受到这个请求头的Service, 在本文的例子中只有一个Server,当然也就没有关系了.

在SoapServer的构造函数中, 我们可以指明一个Server的Actor, 比如:

<?php

$server = new SoapServer($wsdl, array('actor' => 'laruence'));

?>

这样, 我们就可以在Client的SoapHeader中, 通过设置actor是laruence, 来让指定的Server来获得我们设置的头部的信息.

php SOAP实现Web 服务例子

php

 先要开启php_soap模块

一。

方法1
服务器端 文件叫 server.php
<?php
$soap = new SoapServer(null,array('uri'=>"http://10.10.10.24/"));//输入本台服务器的ip地址
$soap->addFunction('say');                                   //添加输出函数
$soap->addFunction(SOAP_FUNCTIONS_ALL);   //不要忘了这个
$soap->handle();                                                   //注意
function say($sth){
   return $sth;
}

?>

客户端 输出的是 hello world
<?php
try {
   $client = new SoapClient(null,
       array('location' =>"http://10.10.10.24/server.php",'uri'=> "http://10.10.10.24/")
   );
   echo $client->say("hello world");
} catch (SoapFault $fault){
   echo "Error: ",$fault->faultcode,", string: ",$fault->faultstring;
}
?>

 二。

服务器端文件server.php:
<?php
$classmap = array();
//注意和实例一的不同
$soap = new SoapServer(null,array('uri'=>"http://10.10.10.24/", "classmap" => $classmap));
$soap->setClass('Myclass');
$soap->handle();
class Myclass {
   function say($someword){
      return $someword;
   }
}
?>
客户端 输出的是 xyz world

<?
try {
        $client = new SoapClient(null,
          array('location' =>"http://www.xiao688.com/server.php",'uri'=> "http://www.xiao688.com/")
       );
   var_dump($client);
   echo $client->say("xyz world");
} catch (SoapFault $fault){
       echo "Error: ",$fault->faultcode,", string: ",$fault->faultstring;
}

 

php soap实例

php提供了一个专门用于soap操作的扩展库,使用该扩展库后 可以直接在php中进行soap操作。下面将介绍soap的基本操作。
一、soap扩展的使用方法
php的soap扩展库通过soap协议实现了客服端与服务器端的数据交互操作。从php5.0后,php就自带了soap的支持。使用 soap扩展库首先需要修改php安装目录下的配置文件php.ini 来激活soap扩展库。 在php.ini文件中找到如下所示的一行代码,去掉前面的注释(;)。 ;extension=php_soap.dll 修改后,重启web服务器即可激活soap扩展。在soap扩展库中,主要 包括三种对象。
1、SoapServer
SoapServer用于创建php服务器端页面时定义可被调用的函数及返回 响应数据。创建一个SoapServer对象的语法格式如下:

 $soap = new SoapServer($wsdl,$array); 

其中,$wsdl为shoap使用得wsdl文件,wsdl是描述Web Service的一种 标准格式,若将$wsdl设置为null,则表示不使用wsdl模式。$array是 SoapServer的属性信息,是一个数组。

  

SoapServer对象的addFunction方法是用来声明哪个函数可以被客户端调用, 语法格式如下:

$soap->addFunction($function_name); 

其中,$soap是一个SoapServer对象,$function_name是需要被调用的函数名。

 

 SoapServer对象的handle方法用来处理用户输入并调用相应的函数,最后返回 给客户端处理的结果。语法格式如下: 

$soap->handle([$soap_request]); 

其中,$soap是一个SoapServer对象,$soap_request是一个可选参数,用来表示 用户的请求信息。如果不指定$soap_request,则表示服务器将接收用户的全部 请求。 

 

2、SoapCliet 

SoapClient用于调用远程服务器上的SoapServer页面,并实现了对相应函数的调用 。创建一个SoapClient对象的语法格式如下:
$soap = new SoapClient($wsdl,$array); 

其中,参数$wsdl和$array与SoapServer相同。 创建SoapClient对象后,调用服务端页面中的函数相当于调用了SoapClient的方法, 创建语法如下:

$soap->user_function($params);
其中,$soap是一个SoapClient对象,user_function是服务器端要调用的函数,$params 是要传入函数的参数。 


3、SoapFault
SoapFault用于生成soap访问过程中可能出现的错误。创建一个soapFault对象的语法格式

 如下:
$fault = new SoapFault($faultcode,$faultstring);
其中,$faultcode是用户定义的错误代码,$faultstring是用户自定义的错误信息。soapFault 对象会在服务器端页面出现错误时自动生成,或者通过用户自行创建SoapFault对象时生成。对于 Soap访问时出现的错误,客户端可通过捕捉SoapFalut对象来获得相应的错误信息。 在客户端捕获SoapFault对象后,可以通过下面的代码获得错误代码和错误信息。
$fault->faultcode;//错误代码 

$fault->faultstring;//错误信息
其中,$fault是在前面创建的SoapFault对象。 

目前的PHP AJAX 库很多,如:SAJAX、JPSPAN、xajax 、AJASON、flxAJAX、AjaxAC等
server端的代码: server.php

<?php

 //声明一个函数add() ,并返回它的值 

function add($a,$b){

return $a+$b;

}

//实例化一个SoapServer对象, 并将add函数注册成为其方法 

$server = new SoapServer(null,array('uri'=>'http://localhost/')); //指定server端代码的URI(资源标志符) 

$server->addFunction("add"); $server->handle(); ?>

然后使用client端的代码来调用server端的代码: client的代码也很简单: 如下:
这个是client端的代码client.php
<?php 

//建立一个参数数组,存储要访问的提供soap服务的计算机的地址与程序

$arrOptions=array( 'uri'=>'http://localhost/','location'=>'http://localhost/soap/server.php',

//注意: 这个location指定的是server端代码在服务器中的具体位置, 我的是在本地根目录下的soap目录中

,'trace'=>true, );

$soapObject = new SoapClient(null,$arrOptions); //实例化客户端对象 echo $soapObject->add(20,30); //调用服务器端的函数add并返回值50

 ?>

 

php5+ webservice (php soap webservice)

SOAP简单对象访问协议

  (SOAP:Simple Object Access Protocol)

  简单对象访问协议(SOAP)是一种轻量的、简单的、基于 XML 的协议,它被设计成在 WEB 上交换结构化的和固化的信息。 SOAP 可以和现存的许多因特网协议和格式结合使用,包括超文本传输协议( HTTP),简单邮件传输协议(SMTP),多用途网际邮件扩充协议(MIME)。它还支持从消息系统到远程过程调用(RPC)等大量的应用程序。

  SOAP 包括四个部分:

  SOAP 封装:它定义了一个框架 , 该框架描述了消息中的内容是什么,谁应当处理它以及它是可选的还是必须的。

  SOAP 编码规则:它定义了一种序列化的机制,用于交换应用程序所定义的数据类型的实例。

  SOAP RPC 表示:它定义了用于表示远程过程调用和应答的协定。

  SOAP 绑定:定义了一种使用底层传输协议来完成在节点间交换SOAP封装的约定。

  SOAP 消息基本上是从发送端到接收端的单向传输,但它们常常结合起来执行类似于请求 / 应答的模式。所有的 SOAP 消息都使用 XML 编码。一条 SOAP 消息就是一个包含有一个必需的 SOAP 的封装包,一个可选的 SOAP 标头和一个必需的 SOAP 体块的 XML 文档。

  把 SOAP 绑定到 HTTP 提供了同时利用 SOAP 的样式和分散的灵活性的特点以及 HTTP 的丰富的特征库的优点。在 HTTP 上传送 SOAP 并不是说 SOAP 会覆盖现有的 HTTP 语义,而是 HTTP 上的 SOAP 语义会自然的映射到 HTTP 语义。在使用 HTTP 作为协议绑定的场合中, RPC 请求映射到 HTTP 请求上,而 RPC 应答映射到 HTTP 应答。然而,在 RPC 上使用 SOAP 并不仅限于 HTTP 协议绑定。

  SOAP也可以绑定到TCP和UDP协议上。   

WSDL 简介

  Web Services Description Language的缩写,是一个用来描述Web服务和说明如何与Web服务通信的XML 语言。 

用php5+ 做 webservice

1,首先要设置服务器环境。

  修改php.ini

  得添加 extension=php_soap.dll (加载soap 内置包)

  修改 soap.wsdl_cache_enabled=1  改为 soap.wsdl_cache_enabled=0

  

2,写soap 服务端。(用 Zend Studio For Eclipse 编写)

  2.1, 写一个用来提供给客户端用的类文件 ( DizzyLion.php )

  Class DizzyLion {

                      / **

                      * 求和函数

                      * @param float $p_a

                      * @param float $p_b

                      * @return float            

                      * /

                   Public function sum($p_a, $p_b){

                          Return $p_a + $p_b;

                   }

 }

说明:写上函数的标准注释有利于下面做wsdl的工作。

2.2, 生成wsdl 文件。(dizzylion.wsdl)如果这个你能手写,那你真是太强了。我用zend studio 生成的。

       我用的Zend Studio for Eclipse 6.1

       选'File'->'Export'->'PHP'->'WSDL File'

       在"Generate WSDL File" 的窗口中。

       Configuration name 取自己想设的名字;File name 指定要生成wsdl文件(dizzylion.wsdl);Exported files 中"Add"添加刚刚的 DizzyLion.php类文件;在 classer url 就会出现DizzyLion.php的所有类, 勾选 DizzyLion. 在 url 写入 server.php的WEB访问URL如:http://localhot/server.php。点"finish"就好了。如果有上面的标准注释这里就不用再去设置wsdl里对应参数类型之类了。

2.3, 写Soap 服务端文件 (server.php)

       <?php

              Require './DizzyLion.php';

              $server = new SoapServer('./dizzylion.wsdl');

              $server->setClass('DizzyLion');

              $server->handle();

         ?>

3, 写Soap客户端。(client.php)

<?php

   $soap = new SoapClient('./dizzylion.wsdl'); //如果是远程,那当然写dizzylion.wsdl的URL了。

   echo $soap->sum(1.1,  3.1);

?>

  运行client.php 得到 4.2 .

 

 

php soap 开发文档

一.必备知识

1.wsdl(web服务标记语言)

       WSDL(网络服务描述语言,Web Services Description Language)是一门基于 XML 的语言,用于描述 Web Services 以及如何对它们进行访问。

      具体参考请访问下面网址

      http://www.w3school.com.cn/wsdl/index.asp

  

2.soap

      SOAP 是一种简单的基于 XML 的协议,它使应用程序通过 HTTP 来交换信息。

      具体参考请访问下面网址

      http://www.w3school.com.cn/soap/index.asp

3.php扩展

具体参考请访问下面网址

http://php.net/manual/en/book.soap.php

  

二. php soap开发模式

1. working in swdl mode(契约先行(Contract first)模式)

  契约先行模式使用了一个用XML定义的服务接口的WSDL文件。WSDL文件定义了服务必须实现或客户端必须使用的接口。SoapServer和SoapClient的WSDL模式就基于这个概念。也就是用soap通讯的时候必须先有一个定义过的服务接口,才能进行通讯。

   

2. working in non-swdl mode(代码先行(Code first)模式)

   在代码先行模式中,首先要先写出实现服务的代码。然后在大多数情况下,代码会产生一个契约,换种说法,一个WSDL。接着客户端在使用服务的时候就可以使用那个WSDL来获得服务的接口。尽管如此,PHP5的扩展并没有从代码输出一个WSDL的规定,考虑到这种情况,可以在non-WSDL模式下使用 SoapServer和SoapClient。也就是说在soap通讯的时候并不需要一个预先定义过的服务接口,代码会自动的产生。

  

三.参考例子:

  下面介绍如何使用WSDL模式和non-WSDL模式来实现服务和客户端。相对而言,使用WSDL模式来实现服务和客户端会比较容易。

  

1. noWSDL模式实现

  

服务端 server.php

<?php

class test

{

      /**

       *

       * @return string

       */

      function show()

      {

           return 'hello world!';

      }

}

#####################################################

$server = new SoapServer(null, array('uri' => "http://test-uri/"));

$server->setClass('test');

$server->handle();

?>

  

客户端 client.php

<?

$soap=new SoapClient(null, array(

'location' =>'http://soapserver_url/server.php',

                                                  'uri' => "http://test-uri/"));  

                                                                     

print_r($soap->__getFunctions());

echo $soap->show();

?>

  

2. WSDL模式实现

第一步:编写服务端类文件

class..php

<?php

class test

{

      /**

       *

       * @return string

       */

      function show()

      {

           return 'hello world!';

      }

}

?>

  

第二步:将类文件生成 wsdl文件server.wsdl。

     由于wsdl文件编写比较复杂,所以我们用第三方工具生成。我们以zend studio为例子演示:

 Tools ==> WSDL Generator ==> Configration name : test; WSDL file name: server

 ==>NEXT ==> 点击 + ==> 选择上面的创建的class.php ==> 这时候会看到一个 classes?? : URL Location的映射,保留 test类前面的勾,并将其url 设置为 SOAP Server的url:http://soapserver_url/server.php ==>点击Finish,ZDE就会创建一个非常漂亮的WSDL了?? 工作基本上完成了.

  

第三步:服务端编写:

<?php

require ' class..php ';  //引入类文件

  

$server = new SoapServer('server.wsdl');

$server->setClass('test');

$server->handle();

?>

  

第四步:客户端编写

$soap = new SoapClient('http:// soapserver_url/server.wsdl');

  

print_r($soap->__getFunctions());

echo $soap->show();

  

  

      以上两个例子只是一个简单的soap服务编写,已经可以满足大部分需要。如果需要更加高级的功能请参考其他方面的资料。

三.出现的问题。

1.在方法中对属性的赋值在其他方法中不起作用。

      比如在客户端调用服务端某个方法对某个属性赋值。

在其他方法里就不能用。但在 __construct 方法中对属性的赋值是可以个在其他方法中使用的。

2. 提示 Client] looks like we got no XML document错误。

      服务器端文件在<?php ?> 标签前后都不要有任何数据包括空格,空行。

posted @ 2013-02-22 10:34  糖糖果  阅读(548)  评论(0编辑  收藏  举报