1

石鹸を使用するアプリケーションを構築しています。

WSDL の生成には Zend_Soap_Autodiscover を使用し、リクエストの処理には SoapClient と SoapServer を使用しています。

私が抱えている問題は、サーバーとクライアントの両方が SOAP バージョン 1.1 に設定されていても、クライアントが VersionMismatch を返し続けることです。

この問題を解決する方法がわかりません。しばらくの間、立ち往生しています。したがって、どんな助けも大いに感謝します。

クライアントで更新メソッドを呼び出そうとしています:

public function update() {
    $this->_soap = Soap_Client_General::getInstance();
    try {
        $this->_soap->fetchNewVersion();
    } catch (Exception $e) {
        var_dump($e);
    }
}

しかし、これは私に次のダンプを与えています:

object(SoapFault)#12 (10) {
  ["message":protected]=>
  string(13) "Wrong Version"
  ["string":"Exception":private]=>
  string(0) ""
  ["code":protected]=>
  int(0)
  ["file":protected]=>
  string(59) "/path/app/library/Update/Client.php"
  ["line":protected]=>
  int(27)
  ["trace":"Exception":private]=>
  array(4) {
    [0]=>
    array(6) {
      ["file"]=>
      string(59) "/path/app/library/Update/Client.php"
      ["line"]=>
      int(27)
      ["function"]=>
      string(6) "__call"
      ["class"]=>
      string(10) "SoapClient"
      ["type"]=>
      string(2) "->"
      ["args"]=>
      array(2) {
        [0]=>
        string(15) "fetchNewVersion"
        [1]=>
        array(0) {
        }
      }
    }
    [1]=>
    array(6) {
      ["file"]=>
      string(59) "/path/app/library/Update/Client.php"
      ["line"]=>
      int(27)
      ["function"]=>
      string(15) "fetchNewVersion"
      ["class"]=>
      string(10) "SoapClient"
      ["type"]=>
      string(2) "->"
      ["args"]=>
      array(0) {
      }
    }
    [2]=>
    array(6) {
      ["file"]=>
      string(55) "/path/app/application.class.php"
      ["line"]=>
      int(25)
      ["function"]=>
      string(6) "update"
      ["class"]=>
      string(13) "Update_Client"
      ["type"]=>
      string(2) "->"
      ["args"]=>
      array(0) {
      }
    }
    [3]=>
    array(6) {
      ["file"]=>
      string(39) "/path/index.php"
      ["line"]=>
      int(24)
      ["function"]=>
      string(2) "go"
      ["class"]=>
      string(11) "Application"
      ["type"]=>
      string(2) "->"
      ["args"]=>
      array(0) {
      }
    }
  }
  ["previous":"Exception":private]=>
  NULL
  ["faultstring"]=>
  string(13) "Wrong Version"
  ["faultcode"]=>
  string(15) "VersionMismatch"
  ["faultcodens"]=>
  string(41) "http://schemas.xmlsoap.org/soap/envelope/"
}

サーバーのソープ処理は、Zend Framework アプリケーションの SOAP モジュールで行われています。このモジュールのすべてのコントローラーは、基本コントローラー クラスから拡張されます。

My_Controller_Base_Soap

<?php

class My_Controller_Base_Soap extends My_Controller_Base {

    protected $_uri;

    public function __construct(\Zend_Controller_Request_Abstract $request, \Zend_Controller_Response_Abstract $response, array $invokeArgs = array()) {
        parent::__construct($request, $response, $invokeArgs);

        $this->_uri = $this->view->serverUrl() . $this->view->baseUrl('soap/');

        //Disable Layout
        $this->_helper->layout()->disableLayout();
        $this->_helper->viewRenderer->setNoRender();

        Application_Model_Log::log('Soap Module Called: ' . implode('-', $request->getParams()) . ' from: '. $_SERVER['REMOTE_ADDR'] , 'soap');
    }

    //Generates WSDL for given class
    protected function handleWSDL($classname) {
        $autodiscover = new Zend_Soap_AutoDiscover();
        $autodiscover->setClass($classname);
        $autodiscover->handle();
    }

    //Handles the soap requests for the giving location and classname
    protected function handleSOAP($loc, $classname) {
        try {
            $options = array('uri' => 'urn:' . $classname,
                'location' => $loc,
                'soap_version' => SOAP_1_1,
                'cache_wsdl' => WSDL_CACHE_NONE);

            $server = new SoapServer(null, $options);
            $server->setClass($classname);
            $server->handle();
        } catch (Exception $e) {
            Application_Model_Log::log('SoapException: ' . $e->getMessage(), 'soap');
        }
    }

}

上記のクラスは My_Controller_Base から拡張され、さらに My_Controller_Base は Zend_Controller_Action から拡張されます

石鹸/GeneralController

<?php
class Soap_GeneralController extends My_Controller_Base_Soap {

    const CLASS_OBJECT = 'Soap_Model_General';

    public function indexAction() {
        $this->handleSOAP($this->view->baseUrl('soap/general/wsdl'), self::CLASS_OBJECT);
    }

    public function wsdlAction() {

        $this->handleWSDL(self::CLASS_OBJECT);
    }

}

Zend_Soap_Autoloader はクラスを使用して、wsdl 生成のベースを以下に基づいています。

Soap_Model_General

<?php
class Soap_Model_General extends Soap_Model_Base_Abstract{

    /**
     * Retrieve new Version
     * 
     * @return string
     */
    public function fetchNewVersion(){

        if (!$this->_authenticated)
            throw new SOAPFault("Not Authenticated.", 401);

    }
}

このクラスは、認証メソッドを含む抽象基本クラスから拡張されます。

Soap_Model_Base_Abstract

<?php
abstract class Soap_Model_Base_Abstract {

    /**
     * This property represents authentication status
     * @var boolean 
     */
    protected $_authenticated = false;

    /**
     * The site object
     * @var Application_Model_Website 
     */
    protected $_website;

    /**
     * Authenticates the SOAP request. (This one is the key to the authentication, it will be called upon the server request)
     *
     * @param array
     * @return array
     */
    public function authenticate($login) {
        if (!empty($login->siteid) && !empty($login->hash)) {


            //Determain if credentials are correct
            $found = false;
            $website = Application_Model_Website::find($login->siteid);
            if ($website instanceof Application_Model_Site) {
                //Is the authentication hash is correct? (siteid, secretkey and remote ip correct?)
                $hash = md5($website->id . $website->secretkey . $website->ip);
                if ($hash == $login->hash) {
                    $found = true;
                }
            }
            //Verify the send IP
            if ($found && $website->ip == $_SERVER['REMOTE_ADDR']) {
                //Accept authentication
                $this->_authenticated = true;
                //set Application_Model_Site to site property
                $this->_website = $website;
                return true;
            } else {
                throw new SOAPFault("Incorrect credentials.", 401);
            }
        } else {
            throw new SOAPFault("Invalid authentication format. Values may not be empty and are case-sensitive.", 401);
        }
    }

}

基本的に、WSDL にアプローチすると、完全に生成された WSDL が得られます。

次に、クライアントをサーバーに接続します。

クライアントのコードは次のとおりです。

Soap_Client_General

<?php
class Soap_Client_General extends Soap_Client_Abstract {

    private static $instance = NULL;

    public static function getInstance() {
        //get config
        $config = Zend_Registry::get('config');

        $wsdl = $config->general->server->general . '/wsdl/';

        if (!self::$instance) {
            return parent::getInstance($wsdl);
        }
        return self::$instance;
    }

}

Soap_Client_Abstract

<?php
abstract class Soap_Client_Abstract {

    private function __construct() {

    }

    /**
     * Return client instance or create intitial
     *
     * @return SoapClient
     * @access public
     */
    public static function getInstance($wsdl) {
        $ns = "auth";
        $config = Zend_Registry::get('config');

        $siteid         = $config->general->siteid;
        $secretkey      = $config->general->secretkey;
        $hash           = md5($siteid . $secretkey . $_SERVER['SERVER_ADDR']);
        //Create our Auth Object to pass to the SOAP service with our values
        $auth->siteid   = $siteid;
        $auth->hash     = $hash;
        $auth_vals      = new SoapVar($auth, SOAP_ENC_OBJECT);

        //The 2nd variable, 'authenticate' is a method that exists inside of the SOAP service 
        $authenticate = new SoapHeader($ns, 'authenticate', $auth_vals, false);

        $client = new SoapClient($wsdl, array('cache_wsdl' => WSDL_CACHE_NONE, 'soap_version' => SOAP_1_1));

        $client->__setSoapHeaders(array($authenticate));
        return $client;
    }

    private function __clone() {

    }

}

十分な情報を提供できたことを願っています。そして、この件について何か方向性を教えていただければ幸いです。

4

0 に答える 0