PHP项目SOAP与WebService

wen PHP项目 2

PHP项目中的SOAP与WebService详解

基本概念

SOAP(Simple Object Access Protocol)

PHP项目SOAP与WebService

  • 基于XML的协议
  • 使用WSDL描述服务
  • 支持多种传输协议(HTTP、SMTP等)
  • 重量级、标准化程度高

WebService

  • 跨平台、跨语言的远程调用技术
  • SOAP和REST是两种主要实现方式
  • 面向服务架构(SOA)的实现

PHP中的SOAP支持

PHP通过soap扩展提供SOAP支持,主要包含:

  • SoapClient:客户端类
  • SoapServer:服务端类
  • SoapFault:异常处理类

实战示例

服务端实现 (server.php)

<?php
// 定义服务类
class CalculatorService {
    public function add($a, $b) {
        return $a + $b;
    }
    public function subtract($a, $b) {
        return $a - $b;
    }
    public function multiply($a, $b) {
        return $a * $b;
    }
    public function divide($a, $b) {
        if ($b == 0) {
            throw new SoapFault("Server", "Division by zero");
        }
        return $a / $b;
    }
}
// 创建SOAP服务器
$options = array(
    'uri' => 'http://localhost/soap',
    'soap_version' => SOAP_1_2,
    'cache_wsdl' => WSDL_CACHE_NONE
);
$server = new SoapServer(null, $options);
$server->setClass('CalculatorService');
$server->handle();
?>

客户端实现 (client.php)

<?php
try {
    $options = array(
        'location' => 'http://localhost/server.php',
        'uri' => 'http://localhost/soap',
        'trace' => true,
        'soap_version' => SOAP_1_2
    );
    $client = new SoapClient(null, $options);
    // 调用服务
    $result = $client->add(10, 20);
    echo "Addition: 10 + 20 = " . $result . "\n";
    $result = $client->subtract(50, 30);
    echo "Subtraction: 50 - 30 = " . $result . "\n";
    $result = $client->multiply(6, 7);
    echo "Multiplication: 6 * 7 = " . $result . "\n";
    try {
        $result = $client->divide(10, 0);
    } catch (SoapFault $e) {
        echo "Error: " . $e->getMessage() . "\n";
    }
    // 查看请求和响应
    echo "\nRequest:\n" . $client->__getLastRequest() . "\n";
    echo "\nResponse:\n" . $client->__getLastResponse() . "\n";
} catch (Exception $e) {
    echo "Error: " . $e->getMessage();
}
?>

WSDL方式实现

生成WSDL (calculator.wsdl)

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
             xmlns:tns="http://localhost/soap"
             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
             targetNamespace="http://localhost/soap">
    <types>
        <xsd:schema targetNamespace="http://localhost/soap">
            <xsd:element name="add">
                <xsd:complexType>
                    <xsd:sequence>
                        <xsd:element name="a" type="xsd:float"/>
                        <xsd:element name="b" type="xsd:float"/>
                    </xsd:sequence>
                </xsd:complexType>
            </xsd:element>
            <xsd:element name="addResponse">
                <xsd:complexType>
                    <xsd:sequence>
                        <xsd:element name="result" type="xsd:float"/>
                    </xsd:sequence>
                </xsd:complexType>
            </xsd:element>
        </xsd:schema>
    </types>
    <message name="addRequest">
        <part name="parameters" element="tns:add"/>
    </message>
    <message name="addResponse">
        <part name="parameters" element="tns:addResponse"/>
    </message>
    <portType name="CalculatorPortType">
        <operation name="add">
            <input message="tns:addRequest"/>
            <output message="tns:addResponse"/>
        </operation>
    </portType>
    <binding name="CalculatorBinding" type="tns:CalculatorPortType">
        <soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
        <operation name="add">
            <soap:operation soapAction=""/>
            <input>
                <soap:body use="literal"/>
            </input>
            <output>
                <soap:body use="literal"/>
            </output>
        </operation>
    </binding>
    <service name="CalculatorService">
        <port name="CalculatorPort" binding="tns:CalculatorBinding">
            <soap:address location="http://localhost/server.php"/>
        </port>
    </service>
</definitions>

使用WSDL的服务端

<?php
class CalculatorWSDL {
    public function add($a, $b) {
        return $a + $b;
    }
}
$server = new SoapServer("calculator.wsdl");
$server->setClass('CalculatorWSDL');
$server->handle();
?>

复杂数据类型处理

<?php
class UserService {
    public function getUser($id) {
        return array(
            'id' => $id,
            'name' => 'John Doe',
            'email' => 'john@example.com',
            'age' => 30
        );
    }
    public function createUser($userData) {
        // 处理用户数据
        return true;
    }
}
// 客户端调用
$client = new SoapClient("user.wsdl");
$user = $client->getUser(1);
echo $user->name; // 输出: John Doe
?>

错误处理与调试

<?php
class SOAPHandler {
    public function secureMethod($param) {
        try {
            if (empty($param)) {
                throw new Exception("参数不能为空");
            }
            return "处理成功: " . $param;
        } catch (Exception $e) {
            throw new SoapFault("Client", $e->getMessage());
        }
    }
}
// 客户端错误处理
try {
    $client = new SoapClient("service.wsdl", array(
        'exceptions' => true,
        'trace' => true,
        'connection_timeout' => 30
    ));
    $result = $client->secureMethod("");
} catch (SoapFault $e) {
    echo "SOAP错误: " . $e->faultcode . ": " . $e->faultstring;
    echo "\n详细错误: " . $e->detail;
    // 调试信息
    if ($client) {
        echo "\n请求内容:\n" . $client->__getLastRequestHeaders();
        echo "\n" . $client->__getLastRequest();
        echo "\n响应内容:\n" . $client->__getLastResponseHeaders();
        echo "\n" . $client->__getLastResponse();
    }
}
?>

安全考虑

<?php
class SecureService {
    private $validTokens = array('token123', 'token456');
    public function authenticate($token) {
        if (!in_array($token, $this->validTokens)) {
            throw new SoapFault("Client", "无效的认证令牌");
        }
        return true;
    }
    public function secureOperation($token, $data) {
        if (!$this->authenticate($token)) {
            throw new SoapFault("Client", "认证失败");
        }
        // 数据验证
        if (!is_numeric($data)) {
            throw new SoapFault("Client", "数据类型错误");
        }
        return $data * 2;
    }
}
// 客户端使用HTTPS
$options = array(
    'location' => 'https://secure.server.com/service.php',
    'uri' => 'https://secure.server.com/soap',
    'stream_context' => stream_context_create(array(
        'ssl' => array(
            'verify_peer' => true,
            'cafile' => '/path/to/certificate.crt',
            'verify_depth' => 5
        )
    ))
);
?>

SOAP与REST对比

特性 SOAP REST
协议 基于XML的协议 使用HTTP协议
状态 有状态或无状态 无状态
性能 较慢(XML解析) 较快(JSON格式)
安全性 内置WS-Security 依赖HTTPS
缓存 不支持 支持
复杂度
适用场景 企业级应用、金融系统 移动应用、Web API

最佳实践

  1. 使用WSDL: 明确接口定义
  2. 错误处理: 完善的异常捕获
  3. 性能优化:
    • 使用WSDL缓存
    • 压缩SOAP消息
    • 使用持久连接
  4. 安全加固:
    • HTTPS传输
    • 输入验证
    • 认证授权
  5. 日志记录: 记录请求和响应

性能优化示例

<?php
// 使用缓存配置
ini_set('soap.wsdl_cache_enabled', '1');
ini_set('soap.wsdl_cache_dir', '/tmp/soap_cache');
ini_set('soap.wsdl_cache_ttl', '86400'); // 24小时缓存
$client = new SoapClient("service.wsdl", array(
    'compression' => SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP,
    'keep_alive' => true,
    'cache_wsdl' => WSDL_CACHE_BOTH
));
?>

SOAP在PHP项目中适合企业级应用,特别是需要严格契约、安全性和事务支持的场景,但在轻量级应用或移动端场景,REST API可能是更好的选择。

抱歉,评论功能暂时关闭!