目录

安装soap扩展

## 下载
wget -O php7.1.26.tar.gz http://cn2.php.net/get/php-7.1.26.tar.gz/from/this/mirror

## 解压
tar xvf php7.1.26.tar.gz 

## 进入扩展目录
cd php-7.1.26/

## 配置
./configure --enable-soap=shared

## 编译so文件
make

## 复制so文件到PHP扩展目录中
sudo cp modules/soap.so /usr/lib/php/20160303/

如果configure过程中提示报错:

error: xml2-config not found. Please check your libxml2 installation
sudo apt-get install libxml2-dev

什么是SOAP

SOAP 是简单对象访问协议的首字母缩写。它是一种基于 XML 的消息传递协议,用于在计算机之间交换信息。SOAP 是 XML 规范的一个应用程序。SOAP 是一种旨在通过 Internet 进行通信的通信协议。

SOAP 可以扩展 HTTP 以进行 XML 消息传递。

SOAP 为 Web 服务提供数据传输。

SOAP 可以交换完整的文档或调用远程过程。

SOAP 可用于广播消息。

SOAP 与平台和语言无关。

SOAP 是定义发送信息的方式为 XML 方式。

SOAP 使客户端应用程序能够轻松连接到远程服务并调用远程方法。

SOAP 扩展主要用来处理 RPC 形式的 Web Services。不过,你也可以使用文本形式的 WSDL 文件配合 WSDL 模式的服务端和客户端。

关于更多介绍:SOAP Web 服务介绍 - SegmentFault 思否

php的SOAP扩展

SoapClient 类

这个类用来使用 Web Services。SoapClient 类可以作为给定 Web Services 的客户端。 它有两种操作形式:

  • WSDL 模式
  • Non-WSDL 模式

在 WSDL 模式中,构造器可以使用 WSDL 文件名作为参数,并自动从 WSDL 中提取使用服务时所需要的信息。

Non-WSDL 模式中使用参数来设置使用服务时所需要的信息。这个类有许多可以用来使用服务的有用的方法。其中 SoapClient::__soapCall() 是最重要的。这个方法可以用来调用服务中的某个操作。

SoapServer 类

这个类可以用来提供 Web Services。与 SoapClient 类似,SoapServer 也有两种操作模式:WSDL 模式和 non-WSDL模式。这两种模式的意义跟 SoapClient 的两种模式一样。在 WSDL 模式中,服务实现了 WSDL 提供的接口;在 non-WSDL 模式中,参数被用来管理服务的行为。

在 SoapServer 类的众多方法中,有三个方法比较重要。它们是 SoapServer::setClass()、SoapServer::addFunction() 和 SoapServer::handle()。

SoapServer::setClass()方法设定用来实现 Web Services 的类。SoapServer::setClass 所设定的类中的所有公共方法将成为 Web Services 的操作(operation)。

SoapServer::addFunction() 方法用来添加一个或多个作为 Web Services 操作(operation)的函数。

SoapServer:: handle() 方法指示 Web Services 脚本开始处理进入的请求。Web Services 脚本是用 PHP 脚本写的一个或多个 SoapServer 对象的实例。尽管你可以有不止一个的 SoapServer 对象,但通常的习惯是一个脚本只拥有一个 SoapServer 实例。在调用 SoapServer::handle() 方法之前,Web Services 脚本会使用设置在 SoapServer 对象实例上的任何信息来处理进入的请求和输出相应的内容。

SoapFault 类

这个类从 Exception 类继承而来,可以用来处理错误。SoapFault 实例可以抛出或获取 Soap 错误的相关信息并按程序员的要求处理。

SoapHeader 类

这个类可以用来描述 SOAP headers。它只是一个只包含构造器方法的数据容器。

SoapParam 类

SoapParam 也是一个只包含构造器方法的数据容器。这个方法可以用来描述传递给 Web Services 操作的参数。在 non-WSDL 模式中这是一个很有用的类,可以用来传递所期望格式的参数信息。

SoapVar 类

SoapVar 也是一个只包含构造器的低级类,与 SoapHeader 和 SoapParam 类相似。这个类可以用来给一个Web Services 操作传递编码参数。这个类对 non-WSDL 中传递类型信息是非常有用的。

注:SoapParam 和 SoapVar 主要用来封装用于放入 SOAP 请求中的数据,他们主要在 non-WSDL 模式下使用。事实上,在 WSDL 模式下,SOAP 请求的参数可以通过数组方式包装,SOAP 扩展会根据 WSDL 文件将这个数组转化成为 SOAP 请求中的数据部分,所以并不需要这两个类。而在 non-WSDL 模式下,由于没有提供 WSDL 文件,所以必须通过这两个类进行包装。

SoapHeader 类用来构造 SOAP 头,SOAP 头可以对 SOAP 的能力进行必要的扩展。SOAP 头的一个主要作用就是用于简单的身份认证。

WSDL VS. non-WSDL 模式

Web Services 有两种实现模式:契约先行(Contract first)模式和代码先行(Code first)模式。

契约先行模式使用了一个用 XML 定义的服务接口的WSDL文件。WSDL 文件定义了服务必须实现或客户端可以使用的接口。SoapServer 和 SoapClient 的 WSDL 模式就基于这个概念。

在代码先行模式中,首先要先写出实现服务的代码。然后在大多数情况下,代码会产生一个契约(可以借助一些工具生成),换种说法,一个 WSDL 文件。接着客户端在使用服务的时候就可以使用那个 WSDL 来获得服务的接口及其他信息。尽管如此,PHP5 的扩展并没有从代码输出一个 WSDL 的实现,考虑到这种情况,可以在 non-WSDL 模式下使用 SoapServer 和 SoapClient。

范例

SOAP服务端

SOAPHandler.php


class SOAPHandler
{

    /**
     * 检查$_SERVER中的PHP_AUTH_USER
     */
    public function check(){
        if ($_SERVER['PHP_AUTH_USER'] != 'jm' || $_SERVER['PHP_AUTH_PW'] != 'chinese') {
            header('WWW-Authenticate: Basic realm="NMG Terry"');
            header('HTTP/1.0 401 Unauthorized');
            exit();
        }        
    }
    
    /**
     * 检查header中的Authorization: Basic am06Y2hpbmVzZQ==
     * @param type $auth
     * @throws SOAPFault
     */
    public function auth($auth)
    {
        if ($auth->string[0] != 'jm' || $auth->string[1] != 'chinese') {
            throw new SOAPFault('Server', 'No Permission From Server');
        }
    }

    // 域名链接字符串
    public function domainLink($domain = '',$url="")
    {
        return "<a href=".$url.">".$domain."</a>";
    }
    
    public function getServerInfo(){
        return $_SERVER;//array
    }
    

}

soapServer.php


require 'SOAPHandler.php';
$handler = new SOAPHandler();

$handler->check();

// no wsdl mode
try {
    $serverUri = "soap/soapServer";
    $config = array(
        'uri' => $serverUri
    );
    $server = new SOAPServer(null, $config);
    $server->setObject($handler);//设置处理请求的对象,也可以使用setClass设置处理请求的类
    $server->handle();//开始处理请求
} catch (SOAPFault $f) {
    echo "Error:".$f->getMessage();
}

SOAP客户端


$serverLocation = "http://demo.130.com/FunctionsReference/soap/soapServer.php";
$serverUri = "soap/soapServer";
$config = [
            'location' => $serverLocation,
            'uri' => $serverUri,
            'login' => 'jm',//[PHP_AUTH_USER] => jm | [PHP_AUTH_PW] => chinese  | Authorization: Basic am06Y2hpbmVzZQ==
            'password' => 'chinese',
            'trace' => true
];

try{
 
    $auth = ['jm', 'chinese'];
 
    // no wsdl
    $client = new SOAPClient(null, $config);
    
    $header = new SOAPHeader("soap/header", 'auth', $auth, false,SOAP_ACTOR_NEXT);//SOAP_ACTOR_NEXT:soap服务端接收到请求并进入handle处理后,会调用对应的auth方法,并传递$auth参数
    $client->__setSoapHeaders([$header]);
 
    $link1 = $client->domainLink("9ong",'www.9ong.com');
    $link2 = $client->__soapCall('domainLink', ['9ong', 'www.9ong.com']);
 
    echo $link1.'<br />';
    echo $link2.'<br />';
    print_r($client->getServerInfo());
    print_r($client->__getLastRequestHeaders());
    

}catch(SOAPFault $e){
    echo "ERROR:".$e->getMessage();
}

输出

<a href=www.9ong.com>9ong</a>
<a href=www.9ong.com>9ong</a>
Array
(
    
    [HTTP_AUTHORIZATION] => Basic am06Y2hpbmVzZQ==
    [HTTP_CONTENT_LENGTH] => 587
    [HTTP_SOAPACTION] => "soap/soapServer#getServerInfo"
    [HTTP_CONTENT_TYPE] => text/xml; charset=utf-8
    [HTTP_USER_AGENT] => PHP-SOAP/7.1.26
    ...
    [DOCUMENT_ROOT] => /var/www/html/php-shiyanchang
    [DOCUMENT_URI] => /FunctionsReference/soap/soapServer.php
    [REQUEST_URI] => /FunctionsReference/soap/soapServer.php
    [SCRIPT_NAME] => /FunctionsReference/soap/soapServer.php
    [CONTENT_LENGTH] => 587
    [CONTENT_TYPE] => text/xml; charset=utf-8
    [REQUEST_METHOD] => POST
    [QUERY_STRING] => 
    [SCRIPT_FILENAME] => /var/www/html/php-shiyanchang/FunctionsReference/soap/soapServer.php
    [PATH_INFO] => 
    [FCGI_ROLE] => RESPONDER
    [PHP_SELF] => /FunctionsReference/soap/soapServer.php
    [PHP_AUTH_USER] => jm
    [PHP_AUTH_PW] => chinese

)
POST /FunctionsReference/soap/soapServer.php HTTP/1.1
Host: demo.130.com
Connection: Keep-Alive
User-Agent: PHP-SOAP/7.1.26
Content-Type: text/xml; charset=utf-8
SOAPAction: "soap/soapServer#getServerInfo"
Content-Length: 587
Authorization: Basic am06Y2hpbmVzZQ==


关于soapHeader的用途

$header = new SOAPHeader("soap/header", 'auth', $auth, false,SOAP_ACTOR_NEXT);//SOAP_ACTOR_NEXT:soap服务端接收到请求并进入handle处理后,会调用对应的auth方法,并传递$auth参数

上面的范例中,我们看到handler中的auth方法在server端接收到请求后就会执行,这个是为什么呢?我们看鸟哥怎么说的:

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

还有人在用SOAP吗

zhuzhibin   2020-01-10 20:48:58 +08:00
我之前对接过。。自己封装了一层 W ebservice SOAP 来处理请求, 有点不太习惯了,因为都是基于 xml 描述,现在大多数都是 json 了,还是挺难受的


Tn5ohB1Yecdk3qCK   2020-01-10 18:39:39 +08:00
天气,电视节目 等等好像都是用的 webservice


	    
CHENJIAJIE   2020-01-10 18:35:55 +08:00
电视端的节目媒资注入都是用 webservice


murmur   2020-01-10 17:03:18 +08:00
我们的一些老接口还是 webservice,新接口已经让外包商用 json 了


		    
zhuzhibin   2020-01-10 20:48:58 +08:00
我之前对接过。。自己封装了一层 W ebservice SOAP 来处理请求, 有点不太习惯了,因为都是基于 xml 描述,现在大多数都是 json 了,还是挺难受的

	    
Revenant   2020-01-10 23:45:34 +08:00
医保平台接口都还是走 WebService 的形式呢

	    
yangsh   2020-01-10 23:15:44 +08:00
有,我们 现在的产品内部还在广泛的使用 webservice


	    
jiashun   2020-01-11 10:36:27 +08:00
国家电网内的异构系统集成基本上都是走 ESB,各服务厂商提供 WebService 集成接口在 ESB 上进行注册。
至于“WebService 的连接超时,和读取超时问题”,调用 webservice 接口的时候可以使用 soap 工具类,设置连接超时和读取超时参数; webservice 接口调用也可以使用 http 的方式,根据 wsdl 描述来手工拼装 webservice 报文,用 http 工具类进行 http 请求。


cway   2020-01-11 12:43:37 +08:00
很多 SAP ERP 系统都还是用 WebService 呢
国企最多


	    
hantsy   2020-01-11 12:20:25 +08:00   ❤️ 1
@fox0001 1. SOA 是企业开发为目标的产物。2 SOA 很大程度上想解决各应用服务器供应的技术上互操作问题,SUN,IBM,还 MS 都是在 SOAP,SOA 付出很出。结果很多东西还是各自为政(如 MS 有很多扩展没办法在 Java 平台用,SUN 有业务流程上有 JBI,与 BPEL 不兼容,IBM 搞了自己的 SCA ),没有达到预期的效果。

CHYK   2020-01-10 16:10:13 +08:00
有,仅在单位内网的项目上,对外则是微服务了。