2017-09-28 12 views
1

PHPの組み込みのSoapServerを使用して2つの異なる配列を含む応答を返す際に問題があります。私のfruitvegetablesの配列は重複しているとPHPは思っています(そうではありません)。このレスポンスでは、Wrapperクラスを使用して、PHPの__get()という魔法のオーバーロードメソッドを使用しています。これは問題の一部であると思われます。PHP 7.x SoapServerが重複しない配列に対してXML参照(href = "#ref1"など)を返すのはなぜですか?

私のコードは、5.3、5.4、5.5および5.6のPHPのバージョンでは完全に正常に動作し、正しいSOAP XML応答を生成します。

<?xml version="1.0" encoding="UTF-8"?> 
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://test-uri/"> 
<SOAP-ENV:Body> 
    <ns1:fooResponse> 
     <result> 
      <fruit> 
       <item>apple</item> 
       <item>orange</item> 
       <item>banana</item> 
      </fruit> 
      <vegetables> 
       <item>carrots</item> 
       <item>broccoli</item> 
      </vegetables> 
     </result> 
    </ns1:fooResponse> 
</SOAP-ENV:Body> 
</SOAP-ENV:Envelope> 

まったく同じコードPHPのバージョン7.0、7.1および7.2RC2は以下を生成します

<?xml version="1.0" encoding="UTF-8"?> 
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://test-uri/"> 
<SOAP-ENV:Body> 
    <ns1:fooResponse> 
     <result> 
      <fruit id="ref1"> 
       <item>apple</item> 
       <item>orange</item> 
       <item>banana</item> 
      </fruit> 
      <vegetables href="#ref1"/> 
     </result> 
    </ns1:fooResponse> 
</SOAP-ENV:Body> 
</SOAP-ENV:Envelope> 

私の質問は、あるはなぜPHP 7.xのはfruitsを考えるとん:fruitコレクションに戻って指し、vegetablesコレクション内の参照が含まれている予期しないXML、 vegetablesはまったく同じものなので、XML参照が返されますか? 7.xバージョンで動作が変わるのはなぜですか?ラッパークラスと__get()メソッドの使用を継続し、以前のバージョンのPHPと同じ応答を実現するにはどうすればよいですか?

これは、私の検証可能な例です。一つのPHPファイルに含まれています。コマンドライン(不要Webサーバ)から直接実行することができます:

$wsdl = <<<WSDL 
<?xml version="1.0" encoding="utf-8"?> 
<definitions name="SoapArrayTest" 
        xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
        xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" 
        xmlns:tns="http://test-uri/" 
        xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
        xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
        xmlns="http://schemas.xmlsoap.org/wsdl/" 
        targetNamespace="http://test-uri/" 
    > 
    <types> 
    <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://test-uri/"> 
     <complexType name="Baz"> 
     <sequence> 
      <element name="fruit" type="tns:StringArray"/> 
      <element name="vegetables" type="tns:StringArray"/> 
     </sequence> 
     </complexType> 
     <element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="BazElement" type="tns:Baz"/> 
     <complexType name="StringArray"> 
     <sequence> 
      <element name="item" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/> 
     </sequence> 
     </complexType> 
     <element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="StringArrayElement" type="tns:StringArray"/> 
    </schema> 
    </types> 
    <message name="fooRequest"> 
    </message> 
    <message name="fooResponse"> 
    <part name="result" type="tns:Baz"/> 
    </message> 
    <portType name="TestPortType"> 
    <operation name="foo"> 
     <input message="tns:fooRequest"/> 
     <output message="tns:fooResponse"/> 
    </operation> 
    </portType> 
    <binding name="TestBinding" type="tns:TestPortType"> 
    <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> 
    <operation name="foo"> 
     <soap:operation soapAction="#foo" style="rpc"/> 
     <input /> 
     <output > 
     <soap:body parts="result" use="literal" namespace="http://test-uri/" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> 
     </output> 
    </operation> 
    </binding> 
    <service name="TestService"> 
    <port name="TestPort" binding="tns:TestBinding"> 
     <soap:address location="http://example.com"/> 
    </port> 
    </service> 
</definitions> 
WSDL; 

class Wrapper 
{ 
    private $object; 

    public function __construct($object) 
    { 
    $this->object = $object; 
    } 

    public function __get($property) 
    { 
    $value = $this->object->$property; 
    return $value; 
    } 
} 

function foo() 
{ 
    $baz = new stdClass(); 
    $arr1 = array("apple", "orange", "banana"); 
    $baz->fruit = $arr1; 
    $arr2 = array("carrots", "broccoli"); 
    $baz->vegetables = $arr2; 
    $bar = new Wrapper($baz); 
    return $bar; 
} 

$fname = tempnam (__DIR__, "wsdl"); 
$f = fopen($fname,"w"); 
fwrite($f,$wsdl); 
fclose($f); 

$server = new SoapServer($fname, array('cache_wsdl' => WSDL_CACHE_NONE, 'soap_version' => SOAP_1_1)); 
$server->addFunction("foo"); 

$soapRequest = <<<XML 
<?xml version="1.0" encoding="utf-8"?> 
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="blah" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> 
    <SOAP-ENV:Body> 
    <ns1:foo> 
    </ns1:foo> 
    </SOAP-ENV:Body> 
</SOAP-ENV:Envelope> 
XML; 


$server->handle($soapRequest); 

更新:

  • この同様の質問PHP SoapClient creating XML references for identical elements, makes it unacceptable for serviceに対する解決策は動作しません。私の要素は同じではありません。私の要素が同じであれば、私はXMLの参考文献でOKです。
  • 、2つの別々のStringArray構造を含むようにWSDLを変更すると、私は(それが動作しませんでした)このように私の配列に「アイテム」を追加しようとした
  • を動作しません:

    function foo() 
    { 
        $baz = new stdClass(); 
    
        $fruits = array("item" => array("apple", "orange", "banana")); 
        $baz->fruit = $fruits; 
    
        $veggies = array("item" => array("carrots", "broccoli")); 
        $baz->vegetables = $veggies; 
    
        $bar = new Wrapper($baz); 
        return $bar; 
    } 
    
  • 私ができます私はこれで満足していないが

    function foo() 
    { 
        $baz = new stdClass(); 
    
        $fruits = new stdClass(); 
        $fruits->item = array("apple", "orange", "banana"); 
        $baz->fruit = $fruits; 
    
        $veggies = new stdClass(); 
        $veggies->item = array("carrots", "broccoli"); 
        $baz->vegetables = $veggies; 
    
        $bar = new Wrapper($baz); 
        return $bar; 
    } 
    

    :このようなitemプロパティを持つオブジェクトを使用してPHP 7.xで問題を修正。 PHP 7.xで配列を使うのがなぜうまくいかないのかまだ分かりません。

+0

、あなたはそれを使用していますか? $ classmap = array( '会議' => '会議'); $ server = new SoapServer( 'soap。wsdl '、array(' classmap '=> $ classmap)); $ server-> setClass( "MySoapServer"); $ server-> handle(); – Marco

+1

'stdClass'またはclassmapオプションのクラスを使用すると、問題はなくなります(質問の最新の更新を参照)。問題は、オブジェクトの代わりに配列が使用されている場合です。なぜ、5.xで動作するのか、7.xでは動作しないのかを知る必要があります。たぶん私のコードが壊れていて、PHP 5.xがもっと寛容でした。 –

+0

それはもっと寛容だったからですが、PHPには多くの特徴が書かれていません。あなたは私の他の答えを試しましたか?私はこれが原因だと思います、あなたはそれをテストできますか? – Marco

答えて

0

あなたのxsdは、正確には必要ではないようです。シーケンス(配列)として一つの要素を定義するには、この内部のようなものが必要バズ定義:

<xs:element name="fruits"> 
<xs:complexType> 
    <xs:sequence> 
    <xs:element name="fruit" maxOccurs="unbounded"/> 
    </xs:sequence> 
</xs:complexType> 

<xs:element name="vegetables"> 
<xs:complexType> 
    <xs:sequence> 
    <xs:element name="vegetable maxOccurs="unbounded"/> 
    </xs:sequence> 
</xs:complexType> 

PHPはclassmappingを定義するオプションがあり

Reference

+1

動作しません。 '<= "REF1" 果物のID>リンゴオレンジバナナ<野菜てhref = "#ref1の"/><これは、返されたXMLが若干異なっている以外、同じ問題です/ ns1:fooResponse> ' –

関連する問題