异步PHP SOAP服务器在响应之前发送Acknowledgment消息?

时间:2018-05-09 14:02:18

标签: php soap

我不确定如何做到这一点。我写的SOAP服务的规范说它甚至在响应请求的请求响应之前就需要发回一条确认消息。

这是如何在PHP中完成的?我没有看到如何做到这一点的例子。

来自要求doc:

  

Integration Partner向供应商发送一条确认消息   对于每个SubmitInv消息请求。单个确认消息   也是供应商从每个人发送给集成合作伙伴的   RequestInv消息响应

这不是标准的TCP确认响应。它是一个自定义SOAP格式的响应,它是对收到请求的确认。参见下面的示例。

在询问供应商之后:

  

他们声称这是一个遗留系统,它是为了处理而编写的   那个流动。他们现在不能改变它。我跟他说过   20多年的编程,我从未见过任何SOAP系统需要ACK。   他声称这与必须“等待”回应有关。   显然他们不明白如何妥善处理无国籍人   处理

我已经尝试使用FoxVSky下面概述的PHP Output Buffering函数来实现它,它在SOAP事务中不起作用。 此外,标准的SOAP库,PHP内置的库,以及Zend SOAP库都有这样的功能。

示例:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
               xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
    <PAddRs>
      <RqUID>f11958c8-3fde-42ca-bd94-94fdfca316ef</RqUID>
      <PKey>46dba062-2105-4851-831f-a1d364741329</PKey>
      <AppStatus>
        <AppStatusCode>Accept</AppStatusCode>
      </AppStatus>
    </PAddRs>
  </soap:Body>
</soap:Envelope>

3 个答案:

答案 0 :(得分:4)

好的,我已经在我的SOAP服务中实现了确认消息,这是从客户端调用它的方式:

<?php
require_once __DIR__ . '/vendor/autoload.php';
$options = array();
$options['cache_wsdl'] = WSDL_CACHE_NONE;
$options['soap_version'] = SOAP_1_2;
$client = new Zend\Soap\Client("http://localhost/soap/server.php?wsdl", $options);

try {
    // Currently loading example request
    $xml = simplexml_load_file('RequestExample.xml');
    $t_xml = new DOMDocument();
    $t_xml->loadXML($xml->asXML());
    $xml = $t_xml->saveXML($t_xml->documentElement);
    $response = $client->ReqInv($xml);
} catch (Exception $e) {
    $response = 'Exception: '. $e. "\n"; 
}
echo $response;    

我的服务:

<?php
require_once __DIR__ . '/vendor/autoload.php';
require(__DIR__ . '/PTResp.php');

use Zend\Soap\AutoDiscover;
use Zend\Soap\Server;
use Zend\Soap\Wsdl;

class PT {
    /**
     * function ReqInv
     * Function to return the inventory for the passed request.
     * 
     *  @param string $request 
     *  @return string
     */
    function ReqInv($request) {
        $pt = new PTResp($request);
        return $pt->toString();
    }   
}

if (isset($_GET['wsdl'])) {
    $wsdl = new AutoDiscover();
    $wsdl->setUri('http://localhost/soap/server.php');
    $wsdl->setClass('PT');
    $wsdl->handle();
} else {
    $server = new Zend\Soap\Server('http://localhost/soap/server.php?wsdl');
    $server->setClass('PT');
    $server->setEncoding('ISO-8859-1');
    $server->handle();
}

我的班级(在PTResp.php中):

class PT {

    function __construct($xml) {
        $this->m = new Mustache_Engine;
        $this->xml = @simplexml_load_string($xml);
        $this->xml->registerXPathNamespace(<my namespace info>);
        $this->SendAck();
        $this->BuildResponse();
    } // function __construct

    /*
    * This is the function that is actually called to return the response to the client.
    */
    function toString() {
        $domxml = new DOMDocument('1.0');
        $domxml->preserveWhiteSpace = false;
        $domxml->formatOutput = true;
        $domxml->loadXML($this->response);
        $this->response = $domxml->saveXML($domxml->documentElement);
        return $this->response;
    } // function toString    

    function SendAck() {        
        $this->Status = "Accept";
        $xml_post_string = $this->m->render(
        '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
            <soap:Body>
                <ProcurementAddRs xmlns=MyNamespaceInfo">
                    <RqUID>{{RqUID}}</RqUID>
                    <PKey>{{PKey}}</PKey>
                    <ApplicationStatus>
                        <ApplicationStatusCode>{{Status}}</ApplicationStatusCode>
                    </ApplicationStatus>
                </ProcurementAddRs>
            </soap:Body>
        </soap:Envelope>', array("RqUID" =>$this->RqUID, "PKey"=>$this->PKey, "Status"=>$this->Status));
        $url = 'http://localhost/soap/gotit.php'; // in this test, it writes the response to a file. I will be sending it to the endpoint from here
        $this->curl_post_async($url, $xml_post_string);
    } // function SendAck

    function curl_post_async($url, $post_string){
        $parts=parse_url($url);

        $fp = fsockopen($parts['host'],
            isset($parts['port'])?$parts['port']:80,
            $errno, $errstr, 30);

        $out = "POST ".$parts['path']." HTTP/1.1\r\n";
        $out.= "Host: ".$parts['host']."\r\n";
        $out.= "Content-Type: text/xml\r\n";
        $out.= "Content-Length: ".strlen($post_string)."\r\n";
        $out.= "Connection: Close\r\n\r\n";
        if (isset($post_string)) $out.= $post_string;
        fwrite($fp, $out);
        fclose($fp);
    } // function curl_post_async  

    function BuildResponse() {
        $this-response = "<XML response that is built goes here>";
    }

}

答案 1 :(得分:0)

您可以使用PHP Output Control Functions

这是我的示例用法

soapserver.php:

<?php

$data = file_get_contents('php://input');
$fp = fopen('data.txt', 'a');
fwrite($fp, json_encode($data));
fwrite($fp, "\n");

class MySoapServer {

    public function addNumbers($num1, $num2) {
        return $num1 + $num2;
    }

}

$options = array('uri' => 'http://test.local/');
$server = new SoapServer(NULL, $options);
$server->setClass('MySoapServer');

ob_end_clean();
header("Connection: close\r\n");
ignore_user_abort(true);
ob_start();
$server->handle();
$soapXml = ob_get_contents();
$size = ob_get_length();
// Flush (send) the output buffer and turn off output buffering
ob_end_clean();
ob_start();
header("Content-Length: $size");
echo $soapXml;
ob_end_flush();
// Unless both are called !
flush();
// Continue do another process after sent message
//example
sleep(10);
fwrite($fp, "Test Writing\n");
fclose($fp);

&GT;

soapclient.php:

<?php

// client
$options = array(
    'location' => 'http://test.local/stack/soapserver.php',
    'uri' => 'http://test.local/stack/soapserver.php'
);

$client = new SoapClient(NULL, $options);
echo $client->addNumbers(3, 5); //  8

您将立即在broswer中看到回复8。 10秒后,您会在文件data.txt

中看到Test Writing

答案 2 :(得分:0)

如果您正在编写SOAP服务,为什么不简单地使用SoapServerhandle()方法?你不应该真正实现TCP握手(发送ACK),什么不能。我非常确定这些类/方法都会为您处理。

缺乏背景,所以这是我最好的猜测。