PHP中的SOAP错误:OperationFormatter遇到无效的消息正文

PHP中的SOAP错误:OperationFormatter遇到无效的消息正文,php,soap,wsdl,soapui,soap-client,Php,Soap,Wsdl,Soapui,Soap Client,原始问题: 我正在尝试从SOAP API wsdl链接获取数据。我的代码如下。但我得到了这个错误。有人能帮忙吗 错误消息:OperationFormatter遇到无效的消息正文。 应找到名为“GetLocalRates”的节点类型“Element”,并且 命名空间。找到名为的节点类型“Element” “soapenv:Envelope”和命名空间 编辑2: $client->\u getTypes结果: $client->\u获取函数结果: 修复:在下面使用,而不是XML信封。谢谢你,马塞尔

原始问题:

我正在尝试从SOAP API wsdl链接获取数据。我的代码如下。但我得到了这个错误。有人能帮忙吗

错误消息:OperationFormatter遇到无效的消息正文。 应找到名为“GetLocalRates”的节点类型“Element”,并且 命名空间。找到名为的节点类型“Element” “soapenv:Envelope”和命名空间

编辑2:

$client->\u getTypes结果:

$client->\u获取函数结果:

修复:在下面使用,而不是XML信封。谢谢你,马塞尔。你是一位伟大的救世主

$requestParams = array( 'credentials' => array('AgentCode' => $acode,
                                               'HashedPassword' => $hpass,
                                               'Username' => $uname),
                  'payincurcode' => $ccode,
                  'transferType' => $ttype
              );

$response = $client->GetLocalRates( $requestParams );

提前感谢您用丢失的数据更新了您的问题。本例是一个本机php示例,展示了如何以面向对象的方式使用soap函数和类型

一,。类型和类别

正如您在类型数组中看到的,有几种类型声明为struct。如果您愿意这样说,可以将结构称为PHP类。因此,让我们从每个结构中生成一个php类

class EzCredentialStruct
{
    public $AgentCode;

    public $HashedPassword;

    public $Username;

    public function getAgentCode() : string
    {
        return $this->AgentCode;
    }

    public function setAgentCode(string $AgentCode) : EzCredentialStruct
    {
        $this->AgentCode = $AgentCode;
        return $this;
    }

    public function getHashedPassword() : string
    {
        return $this->HashedPassword;
    }

    public function setHashedPassword(string $HashedPassword) : EzCredentialStruct
    {
        $this->HashedPassword = $HashedPassword;
        return $this;
    }

    public function getUsername() : string
    {
        return $this->Username;
    }

    public function setUsername(string $Username) : EzCredentialStruct
    {
        $this->Username = $Username;
        return $this;
    }
}

class GetLocalRatesStruct
{
    public $credentials;

    public $payincurcode;

    public $transferType;

    public function getCredentials() : EzCredentialStruct
    {
        return $this->credentials;
    }

    public function setCredentials(EzCredentialStruct $credentials) : GetLocalRatesStruct
    {
        $this->credentials = $credentials;
        return $this;
    }

    public function getPayincurcode() : string
    {
        return $this->payincurcode;
    }

    public function setPayincurcode(string $payincurcode) : GetLocalRatesStruct
    {
        $this->payincurcode = $payincurcode;
        return $this;
    }

    public function getTransferType() : string
    {
        return $this->transferType;
    }

    public function setTransferType(string $transferType) : GetLocalRatesStruct
    {
        $this->transferType = $transferType;
        return $this;
    }
}
这两个类是类型数组中所有结构的示例。所以把你所有的结构写下来作为类。您稍后会注意到好处

二,。Soap客户端和类映射选项

现在,当我们将所使用的Web服务类型声明为类时,我们可以启动soap客户端。使用正确的选项启动soap客户机非常重要。始终将客户端包装在try/catch块中

try {
    $options = [
        'cache_wsdl' => WSDL_CACHE_NONE, 
        'soap_version' => SOAP_1_2,
        'trace' => true,
        'classmap' => [
            'EzCredential' => 'EzCredentialStruct',
            'GetLocalRates' => 'GetLocalRatesStruct',
        ],
    ];

    $wsdl = 'path/to/the/webservice/endpoint?wsdl';

    $client = new \SoapClient(
        $wsdl,
        $options,
    );
} catch (\SoapFault $e) {
    // error handling
}
如您所见,选项数组中有一个类映射键。类映射将类型路由到特定的php类。在本例中,我们只使用前面定义的两个示例类型类。soap客户端现在可以自动创建Web服务所需的xml字符串

三,。把它们放在一起

现在,由于我们已经具备了正确的soap请求所需的一切,我们的代码应该如下所示

$credentials = (new EzCredentialStruct())
    ->setAgentCode($agentCode)
    ->setHashedPassword($hashedPassword)
    ->setUsername($username);

$request = (new GetLocalRatesStruct())
    ->setCredentials($credentials)
    ->setPayincurcode($code)
    ->setTransferType($transferType);

$result = $client->GetLocalRates($request);
结论

乍一看,这种方法可能需要更多的工作。但是对于webservice声明的每个结构,将类型与函数和编程类分开是有意义的。webservice函数的调用将更容易,因为我们只将对象作为参数传递。不再有奇怪的数组构造。一切都在它的位置,可以重复使用


PS:此代码未经测试。不建议在生产中使用它。本代码仅作为示例。它可能包含错误。

首先,reliable和useWSA对于soap客户端类来说是无效的选项。您可以删除它们。此外,请添加选项“trace”=>true。这允许跟踪最后一个请求和响应。在catch块中添加echo$client->\uu getLastResponse;告诉我们,Web服务作为响应返回的确切内容。嗨@Marcel,我已经在我的答案中添加了结果。请看一看。非常感谢您的帮助。回复中明确指出,您的请求正文无效。这一行:$client->getlocalratesnewsoapvar$request,XSD_ANYXML;我想这是错的。GetLocalRates函数可以采用哪种类型作为参数?您可以通过查看$client->\uuuuGetTypes和$client->\uuuGetFunctions找到答案。这些类型声明了您可以通过webservice发送和获取的类型。函数显示函数名,您可以通过webservice使用。每个函数都有参数。这些参数是在类型数组中声明的。@Marcel,非常抱歉。我认为问题在我的XML信封中。但我想不出如何解决这个问题。这是我第一次处理SOAP调用。你能给我一个提示吗。我在我的问题中添加了上述结果。不,问题不是信封节点。这是请求本身。我给你举个例子,你如何解决这个问题。感谢您提供的类型和功能。那真的很有用。
$requestParams = array( 'credentials' => array('AgentCode' => $acode,
                                               'HashedPassword' => $hpass,
                                               'Username' => $uname),
                  'payincurcode' => $ccode,
                  'transferType' => $ttype
              );

$response = $client->GetLocalRates( $requestParams );
class EzCredentialStruct
{
    public $AgentCode;

    public $HashedPassword;

    public $Username;

    public function getAgentCode() : string
    {
        return $this->AgentCode;
    }

    public function setAgentCode(string $AgentCode) : EzCredentialStruct
    {
        $this->AgentCode = $AgentCode;
        return $this;
    }

    public function getHashedPassword() : string
    {
        return $this->HashedPassword;
    }

    public function setHashedPassword(string $HashedPassword) : EzCredentialStruct
    {
        $this->HashedPassword = $HashedPassword;
        return $this;
    }

    public function getUsername() : string
    {
        return $this->Username;
    }

    public function setUsername(string $Username) : EzCredentialStruct
    {
        $this->Username = $Username;
        return $this;
    }
}

class GetLocalRatesStruct
{
    public $credentials;

    public $payincurcode;

    public $transferType;

    public function getCredentials() : EzCredentialStruct
    {
        return $this->credentials;
    }

    public function setCredentials(EzCredentialStruct $credentials) : GetLocalRatesStruct
    {
        $this->credentials = $credentials;
        return $this;
    }

    public function getPayincurcode() : string
    {
        return $this->payincurcode;
    }

    public function setPayincurcode(string $payincurcode) : GetLocalRatesStruct
    {
        $this->payincurcode = $payincurcode;
        return $this;
    }

    public function getTransferType() : string
    {
        return $this->transferType;
    }

    public function setTransferType(string $transferType) : GetLocalRatesStruct
    {
        $this->transferType = $transferType;
        return $this;
    }
}
try {
    $options = [
        'cache_wsdl' => WSDL_CACHE_NONE, 
        'soap_version' => SOAP_1_2,
        'trace' => true,
        'classmap' => [
            'EzCredential' => 'EzCredentialStruct',
            'GetLocalRates' => 'GetLocalRatesStruct',
        ],
    ];

    $wsdl = 'path/to/the/webservice/endpoint?wsdl';

    $client = new \SoapClient(
        $wsdl,
        $options,
    );
} catch (\SoapFault $e) {
    // error handling
}
$credentials = (new EzCredentialStruct())
    ->setAgentCode($agentCode)
    ->setHashedPassword($hashedPassword)
    ->setUsername($username);

$request = (new GetLocalRatesStruct())
    ->setCredentials($credentials)
    ->setPayincurcode($code)
    ->setTransferType($transferType);

$result = $client->GetLocalRates($request);