草庐IT

php - 使用 NuSOAP 生成 WSDL - 返回具有各种类型(整数、字符串、结构数组)的结构

coder 2024-01-01 原文

我想通过使用 NuSOAP 生成 WSDL 通过 SOAP 查询一些东西.
我知道有很多与该主题相关的问题,但我没有成功地根据我的特定问题调整代码。

我成功地生成了仅返回一个结构数组(关联数组)的 WSDL 代码,但是 我更愿意返回一个包含整数变量、字符串变量和数组的对象(结构)结构

所以,这是用于返回结构数组的代码:

<?php

    function getStuffs( $user='', $pass='' ) {
        // here we can check user and pass and do whatever (if it isn't alright, we can throw exception or return NULL or sg. similar)
        // .......

        $stuff_array   = array();
        $stuff_array[] = array( 'id'=>122, 'name'=>'One stuff');
        $stuff_array[] = array( 'id'=>213, 'name'=>'Another stuff');
        $stuff_array[] = array( 'id'=>435, 'name'=>'Whatever stuff');
        $stuff_array[] = array( 'id'=>65, 'name'=>'Cool Stuff');
        $stuff_array[] = array( 'id'=>92, 'name'=>'Wow, what a stuff');    

        return $stuff_array;
    }

    require_once 'nusoap/lib/nusoap.php';
    $server = new soap_server;

    // $myNamespace = $_SERVER['SCRIPT_URI'];
    $myNamespace = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'];

    $server->configureWSDL('MyStuffService', 'urn:' . $myNamespace);
    // $server->wsdl->schemaTargetNamespace = 'http://soapinterop.org/xsd/';

    $server->wsdl->addComplexType(
        // name
        'Stuffs',
        // typeClass (complexType|simpleType|attribute)
        'complexType',
        // phpType: currently supported are array and struct (php assoc array)
        'struct',
        // compositor (all|sequence|choice)
        'all',
        // restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
        '',
        // elements = array ( name = array(name=>'',type=>'') )
        array(
            'id' => array(
                'name' => 'id',
                'type' => 'xsd:int'
            ),
            'name' => array(
                'name' => 'name',
                'type' => 'xsd:string'
            )
        )
    );  

    $server->wsdl->addComplexType(
        // name
        'StuffsArray',
        // typeClass (complexType|simpleType|attribute)
        'complexType',
        // phpType: currently supported are array and struct (php assoc array)
        'array',
        // compositor (all|sequence|choice)
        '',
        // restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
        'SOAP-ENC:Array',
        // elements = array ( name = array(name=>'',type=>'') )
        array(),
        // attrs
        array(
            array(
                'ref' => 'SOAP-ENC:arrayType',
                'wsdl:arrayType' => 'tns:Stuffs[]'
            )
        ),
        // arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string)
        'tns:Stuffs'
    );

    $server->register(
        // string $name the name of the PHP function, class.method or class..method
        'getStuffs',
        // array $in assoc array of input values: key = param name, value = param type
        array(
            'user' => 'xsd:string',
            'pass' => 'xsd:string'
        ),
        // array $out assoc array of output values: key = param name, value = param type
        array(
            'return' => 'tns:StuffsArray'
        ),
        // mixed $namespace the element namespace for the method or false
        'urn:' . $myNamespace,
        // mixed $soapaction the soapaction for the method or false
        'urn:' . $myNamespace . "#getStuffs",
        // mixed $style optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically
        'rpc',
        // mixed $use optional (encoded|literal) or false
        'encoded',
        // string $documentation optional Description to include in WSDL
        'Fetch array of Stuffs ("id", "name").' // documentation
    );

    #$server->wsdl->schemaTargetNamespace = $myNamespace;
    $server->service(isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '');
    exit();

?>

在 C# 控制台应用程序中,在添加名为“StuffService”的 Web 引用后,在可以找到此 PHP 文件的适当 URL 后附加“?wsdl”,此代码有效,我可以完美地查询 stuff_array 值,例如这个:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WebServiceTest
{
    class Program
    {
        static void Main(string[] args)
        {
            StuffService.MyStuffService myService = new StuffService.MyStuffService();

            StuffService.Stuffs[] stuffs = myService.getStuffs("someone", "1234");

            foreach (var stuff in stuffs)
            {
                Console.WriteLine(stuff.id+".: "+stuff.name);
            }

            Console.WriteLine();
            Console.WriteLine("Press a key...");
            Console.ReadKey();
        }
    }
}

这很酷,但是我想开发这段代码来返回这样一个对象:

class ResponseObject {
    public $responseCode = 0;
    public $responseMessage = '';
    public $stuffArray = NULL;
}   

$responseObject = NULL;

function getStuffs( $user='', $pass='' ) {
    global $responseObject;

    $responseObject = new ResponseObject();

    // check stuffs in a simple way now
    if($user != 'someone' && $pass != '1234'){
        $responseObject->responseCode = 2;
        $responseObject->responseMessage = 'Authentication failed';
        return $responseObject;
    }

    $responseObject->stuffArray   = array();
    $responseObject->stuffArray[] = array( 'id'=>122, 'name'=>'One stuff');
    $responseObject->stuffArray[] = array( 'id'=>213, 'name'=>'Another stuff');
    $responseObject->stuffArray[] = array( 'id'=>435, 'name'=>'Whatever stuff');
    $responseObject->stuffArray[] = array( 'id'=>65, 'name'=>'Cool Stuff');
    $responseObject->stuffArray[] = array( 'id'=>92, 'name'=>'Wow, what a stuff');          

    $responseObject->responseCode = 1;
    $responseObject->responseMessage = 'Successful!';
    return $responseObject; 
}

什么是合适的 NuSOAP 代码?
谢谢!! :)

我希望我能阐明我想要实现的目标:返回一个包含一个 int、一个字符串和一个结构数组的结构,但不知道如何为此编写适当的 NuSOAP 代码。这样我可以首先检查 responseCode,并用适当的错误消息处理它或输出 stuffArray 等。

最佳答案

经过长时间的试验,我找到了解决方案!

因此返回一个包含三个成员的结构 - 一个 int responseCode,一个字符串 responseMessage 和一个名为 stuffArray 的结构数组在示例中 - 通过 SOAP 和 NuSOAP (PHP) 如下所示,我在代码中添加了一些注释让它更明确:

<?php

    class ResponseObject {
        public $responseCode = 0;
        public $responseMessage = 'Unknown error!';
        public $stuffArray = NULL;
    }   

    /**
     * @return object
     */ 
    function getStuffs( $user='', $pass='' ) {

        $responseObject = new ResponseObject();

        // check stuffs in a simple way now
        if( !($user == 'someone' and $pass == '1234') ){
            $responseObject->responseCode = 2;
            $responseObject->responseMessage = 'Authentication failed!';
            return $responseObject;
        }

        $responseObject->stuffArray   = array();
        $responseObject->stuffArray[] = array( 'id'=>122, 'name'=>'One stuff');
        $responseObject->stuffArray[] = array( 'id'=>213, 'name'=>'Another stuff');
        $responseObject->stuffArray[] = array( 'id'=>435, 'name'=>'Whatever stuff');
        $responseObject->stuffArray[] = array( 'id'=>65, 'name'=>'Cool Stuff');
        $responseObject->stuffArray[] = array( 'id'=>92, 'name'=>'Wow, what a stuff');          

        $responseObject->responseCode = 1;
        $responseObject->responseMessage = 'Successful!';
        return $responseObject; 
    }

    require_once 'nusoap/lib/nusoap.php';
    $server = new soap_server;

    // $myNamespace = $_SERVER['SCRIPT_URI'];
    $myNamespace = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'];

    $server->configureWSDL(
        // string $serviceName, name of the service
        'MyStuffService',
        // mixed $namespace optional 'tns' service namespace or false
        // 'urn:' . $myNamespace
        $myNamespace
    );

    // $server->wsdl->schemaTargetNamespace = 'http://soapinterop.org/xsd/';
    $server->wsdl->schemaTargetNamespace = $myNamespace;

    $server->wsdl->addComplexType(
        // name
        'Stuffs',
        // typeClass (complexType|simpleType|attribute)
        'complexType',
        // phpType: currently supported are array and struct (php assoc array)
        'struct',
        // compositor (all|sequence|choice)
        'all',
        // restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
        '',
        // elements = array ( name = array(name=>'',type=>'') )
        array(
            'id' => array(
                'name' => 'id',
                'type' => 'xsd:int'
            ),
            'name' => array(
                'name' => 'name',
                'type' => 'xsd:string'
            )
        )
    );  

    $server->wsdl->addComplexType(
        // name
        'StuffsArray',
        // typeClass (complexType|simpleType|attribute)
        'complexType',
        // phpType: currently supported are array and struct (php assoc array)
        'array',
        // compositor (all|sequence|choice)
        '',
        // restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
        'SOAP-ENC:Array',
        // elements = array ( name = array(name=>'',type=>'') )
        array(),
        // attrs
        array(
            array(
                'ref' => 'SOAP-ENC:arrayType',
                'wsdl:arrayType' => 'tns:Stuffs[]'
            )
        ),
        // arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string)
        'tns:Stuffs'
    );


    $server->wsdl->addComplexType(
        // name
        'ResponseObject',
        // typeClass (complexType|simpleType|attribute)
        'complexType',
        // phpType: currently supported are array and struct (php assoc array)
        'struct',
        // compositor (all|sequence|choice)
        'all',
        // restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
        '',
        // elements = array ( name = array(name=>'',type=>'') )
        array
        (
            'responseCode' => array(   'type' => 'xsd:int'),
            'responseMessage' => array(   'type' => 'xsd:string'),
            'stuffArray'   => array(   'type' => 'tns:StuffsArray'
                                            // DON'T UNCOMMENT THE FOLLOWING COMMENTED LINES, BECAUSE THIS WAY IT DOESN'T WORK!!! - Left it in the code not to forget it....
                                            // ,
                                            // 'minOccurs' => '0',
                                            // 'maxOccurs' => 'unbounded'
                                            )
        )
    );

    $server->register(
        // string $name the name of the PHP function, class.method or class..method
        'getStuffs',
        // array $in assoc array of input values: key = param name, value = param type
        array(
            'user' => 'xsd:string',
            'pass' => 'xsd:string'
        ),
        // array $out assoc array of output values: key = param name, value = param type
        array(
            'return' => 'tns:ResponseObject'
        ),
        // mixed $namespace the element namespace for the method or false
        // 'urn:' . $myNamespace,
        $myNamespace,
        // mixed $soapaction the soapaction for the method or false
        // 'urn:' . $myNamespace . "#getStuffs",
        $myNamespace . "#getStuffs",
        // mixed $style optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically
        'rpc',
        // mixed $use optional (encoded|literal) or false
        'encoded',
        // string $documentation optional Description to include in WSDL
        'Fetch array of Stuffs ("id", "name").' // documentation
    );

    // $server->wsdl->schemaTargetNamespace = $myNamespace;

    // function def.: nusoap/lib/class.soap_server.php (236)
    $server->service(isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '');

    //   DON'T UNCOMMENT THE FOLLOWING LINES!! - Don't call these headers explicitly,
    //   everything will be handled in function service() appropriately - I know it by experience that it's not a good choice...
    // output:wsdl
    // header('Content-Type: text/xml;charset=utf-8');
    // header('Content-Type: text/xml');
    // echo $server->wsdl->serialize();

    exit(0);

给这个文件一个名字,例如getStuffComplex.php,然后把这个文件复制到你的网络服务器上的某个地方,记住它的路径。
例如,我本地网络服务器上的一个域名是 http://soap.local,上面提到的 PHP 代码可以在 http://soap.local/getStuffComplex.php 上找到

假设您想要通过 SOAP 客户端从 Visual Studio 2010 下的控制台应用程序调用 C# 代码中的 getStuffs() 函数。在这种情况下,您必须执行以下步骤:

  1. 创建一个新的控制台应用程序项目
  2. 右键单击“引用”-“添加服务引用”
  3. 点击“高级...”
  4. 单击“添加 Web 引用...”
  5. 粘贴之前保存的 PHP 文件的 URL 路径(包含上述内容)并在 URL 字段中附加“?wsdl”字符串。例如在我的例子中:http://soap.local/getStuffComplex.php?wsdl
  6. 单击绿色右箭头(“开始”)或在填写 URL 字段后按 Enter。如果找到 getStuff() 方法,则情况有希望。
  7. 在右侧为引用命名(Web 引用名称),例如 “StuffServiceComplex”(我将在我的代码中使用此名称),然后按 Enter。现在您必须在 “Web 引用” 下看到它。
  8. 将下面的代码复制到 Program.cs 中,然后按 F5 键或单击绿色的“播放”图标对其进行测试。

C#代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Services.Protocols;

namespace WebServiceTestComplex
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                StuffServiceComplex.MyStuffService myService = new StuffServiceComplex.MyStuffService();

                StuffServiceComplex.ResponseObject myRespObject = myService.getStuffs("someone", "1234");

                switch (myRespObject.responseCode)
                {
                    // Everything was OK, results can be output
                    case 1:
                        Console.WriteLine("Everything's OK, let's write the results to the standard output:");
                        foreach (var stuff in myRespObject.stuffArray)
                        {
                            Console.WriteLine("\t"+stuff.id + ".:\t" + stuff.name);
                        }
                        break;
                    // Authentication failed
                    case 2:
                    // Unknown error
                    case 0:
                    default:
                        Console.WriteLine("Error:");
                        Console.WriteLine("\tError code: "+myRespObject.responseCode);
                        Console.WriteLine("\tError message: " + myRespObject.responseMessage);
                        break;
                }

            }
            catch (SoapException e)
            {
                Console.WriteLine("=== SOAP EXCEPTION!! ===");
                Console.WriteLine(e);
            }
            catch (Exception e)
            {
                Console.WriteLine("=== OTHER EXCEPTION!! ===");
                Console.WriteLine(e.ToString());
            }


            Console.WriteLine();
            Console.WriteLine("Press a key...");
            Console.ReadKey();
        }
    }
}

输出:

Everything's OK, let's write the results to the standard output:
        122.:   One stuff
        213.:   Another stuff
        435.:   Whatever stuff
        65.:    Cool Stuff
        92.:    Wow, what a stuff

Press a key...

我希望这对努力将 PHP、SOAP 和 .NET 结合在一起的人有所帮助。

(注意:使用重音符号或任何特殊字母时要注意字符编码。默认情况下,可以使用 ANSI(但字符编码必须相同)。)

关于php - 使用 NuSOAP 生成 WSDL - 返回具有各种类型(整数、字符串、结构数组)的结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6986350/

有关php - 使用 NuSOAP 生成 WSDL - 返回具有各种类型(整数、字符串、结构数组)的结构的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. Ruby 解析字符串 - 2

    我有一个字符串input="maybe(thisis|thatwas)some((nice|ugly)(day|night)|(strange(weather|time)))"Ruby中解析该字符串的最佳方法是什么?我的意思是脚本应该能够像这样构建句子:maybethisissomeuglynightmaybethatwassomenicenightmaybethiswassomestrangetime等等,你明白了......我应该一个字符一个字符地读取字符串并构建一个带有堆栈的状态机来存储括号值以供以后计算,还是有更好的方法?也许为此目的准备了一个开箱即用的库?

  4. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  5. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  6. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  7. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  8. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  9. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  10. ruby-on-rails - unicode 字符串的长度 - 2

    在我的Rails(2.3,Ruby1.8.7)应用程序中,我需要将字符串截断到一定长度。该字符串是unicode,在控制台中运行测试时,例如'א'.length,我意识到返回了双倍长度。我想要一个与编码无关的长度,以便对unicode字符串或latin1编码字符串进行相同的截断。我已经了解了Ruby的大部分unicode资料,但仍然有些一头雾水。应该如何解决这个问题? 最佳答案 Rails有一个返回多字节字符的mb_chars方法。试试unicode_string.mb_chars.slice(0,50)

随机推荐