1<?php
2//
3// +----------------------------------------------------------------------+
4// | PHP Version 4                                                        |
5// +----------------------------------------------------------------------+
6// | Copyright (c) 1997-2018 The PHP Group                                |
7// +----------------------------------------------------------------------+
8// | This source file is subject to version 2.02 of the PHP license,      |
9// | that is bundled with this package in the file LICENSE, and is        |
10// | available through the world-wide-web at                              |
11// | http://www.php.net/license/2_02.txt.                                 |
12// | If you did not receive a copy of the PHP license and are unable to   |
13// | obtain it through the world-wide-web, please send a note to          |
14// | license@php.net so we can mail you a copy immediately.               |
15// +----------------------------------------------------------------------+
16// | Authors: Shane Caraveo <Shane@Caraveo.com>                           |
17// +----------------------------------------------------------------------+
18
19require_once 'DB.php'; // PEAR/DB
20require_once 'client_round2_params.php';
21require_once 'test.utility.php';
22require_once 'config.php';
23
24error_reporting(E_ALL ^ E_NOTICE);
25
26class Interop_Client
27{
28    // database DNS
29    var $DSN = "";
30
31    var $baseURL = "";
32
33    // our central interop server, where we can get the list of endpoints
34    var $interopServer = "http://www.whitemesa.net/wsdl/interopInfo.wsdl";
35
36    // our local endpoint, will always get added to the database for all tests
37    var $localEndpoint;
38
39    // specify testing
40    var $currentTest = 'base';      // see $tests above
41    var $paramType = 'php';     // 'php' or 'soapval'
42    var $useWSDL = 0;           // 1= do wsdl tests
43    var $numServers = 0;        // 0 = all
44    var $specificEndpoint = ''; // test only this endpoint
45    var $testMethod = '';       // test only this method
46    var $skipEndpointList = array(); // endpoints to skip
47    var $nosave = 0;
48    var $startAt = ''; // start in list at this endpoint
49    // debug output
50    var $show = 1;
51    var $debug = 0;
52    var $showFaults = 0; // used in result table output
53
54    // PRIVATE VARIABLES
55    var $dbc = NULL;
56    var $totals = array();
57    var $tests = array('base','GroupB', 'GroupC');
58    var $paramTypes = array('php', 'soapval');
59    var $endpoints = array();
60    var $html = 1;
61
62    function Interop_Client() {
63        global $interopConfig;
64        $this->DSN = $interopConfig['DSN'];
65        $this->baseURL = $interopConfig['baseURL'];
66        //$this->baseURL = 'http://'.$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF']);
67        // set up the database connection
68        $this->dbc = DB::connect($this->DSN, true);
69        // if it errors out, just ignore it and rely on regular methods
70        if (DB::isError($this->dbc)) {
71            echo $this->dbc->getMessage();
72            $this->dbc = NULL;
73        }
74        // set up local endpoint
75        $this->localEndpoint['base'] = (object)array(
76                                'endpointName'=>'PHP ext/soap',
77                                'endpointURL'=>$this->baseURL.'/server_round2_base.php',
78                                'wsdlURL'=>$this->baseURL.'/interop.wsdl.php'
79                              );
80        $this->localEndpoint['GroupB'] = (object)array(
81                                'endpointName'=>'PHP ext/soap',
82                                'endpointURL'=>$this->baseURL.'/server_round2_groupB.php',
83                                'wsdlURL'=>$this->baseURL.'/interopB.wsdl.php'
84                              );
85        $this->localEndpoint['GroupC'] = (object)array(
86                                'endpointName'=>'PHP ext/soap',
87                                'endpointURL'=>$this->baseURL.'/server_round2_groupC.php',
88                                'wsdlURL'=>$this->baseURL.'/echoheadersvc.wsdl.php');
89    }
90
91    function _fetchEndpoints(&$soapclient, $test) {
92        $this->_getEndpoints($test, 1);
93
94        // retrieve endpoints from the endpoint server
95        $endpointArray = $soapclient->__soapCall("GetEndpointInfo",array("groupName"=>$test),array('soapaction'=>"http://soapinterop.org/",'uri'=>"http://soapinterop.org/"));
96        if (is_soap_fault($endpointArray) || PEAR::isError($endpointArray)) {
97            if ($this->html) print "<pre>";
98            print $soapclient->wire."\n";
99            print_r($endpointArray);
100            if ($this->html) print "</pre>";
101            print "\n";
102            return;
103        }
104
105        // add our local endpoint
106        if ($this->localEndpoint[$test]) {
107          array_push($endpointArray, $this->localEndpoint[$test]);
108        }
109
110        if (!$endpointArray) return;
111
112        // reset the status to zero
113        $res = $this->dbc->query("update endpoints set status = 0 where class='$test'");
114        if (DB::isError($res)) {
115            die ($res->getMessage());
116        }
117        if (is_object($res)) $res->free();
118        // save new endpoints into database
119        foreach($endpointArray as $k => $v){
120            if (array_key_exists($v->endpointName,$this->endpoints)) {
121                $res = $this->dbc->query("update endpoints set endpointURL='{$v->endpointURL}', wsdlURL='{$v->wsdlURL}', status=1 where id={$this->endpoints[$v->endpointName]['id']}");
122            } else {
123                $res = $this->dbc->query("insert into endpoints (endpointName,endpointURL,wsdlURL,class) values('{$v->endpointName}','{$v->endpointURL}','{$v->wsdlURL}','$test')");
124            }
125            if (DB::isError($res)) {
126                die ($res->getMessage());
127            }
128            if (is_object($res)) $res->free();
129        }
130    }
131
132    /**
133    *  fetchEndpoints
134    * retrieve endpoints interop server
135    *
136    * @return boolean result
137    * @access private
138    */
139    function fetchEndpoints($test = NULL) {
140        // fetch from the interop server
141        try {
142            $soapclient = new SoapClient($this->interopServer);
143            if ($test) {
144                $this->_fetchEndpoints($soapclient, $test);
145            } else {
146                foreach ($this->tests as $test) {
147                    $this->_fetchEndpoints($soapclient, $test);
148                }
149                $test = 'base';
150            }
151        } catch (SoapFault $fault) {
152            if ($this->html) {
153                echo "<pre>$fault</pre>\n";
154            } else {
155                echo "$fault\n";
156            }
157            return NULL;
158        }
159        // retrieve all endpoints now
160        $this->currentTest = $test;
161        $x = $this->_getEndpoints($test);
162        return $x;
163    }
164
165    /**
166    *  getEndpoints
167    * retrieve endpoints from either database or interop server
168    *
169    * @param string base (see local var $tests)
170    * @param boolean all (if false, only get valid endpoints, status=1)
171    * @return boolean result
172    * @access private
173    */
174    function getEndpoints($base = 'base', $all = 0) {
175        if (!$this->_getEndpoints($base, $all)) {
176            return $this->fetchEndpoints($base);
177        }
178        return TRUE;
179    }
180
181    /**
182    *  _getEndpoints
183    * retrieve endpoints from database
184    *
185    * @param string base (see local var $tests)
186    * @param boolean all (if false, only get valid endpoints, status=1)
187    * @return boolean result
188    * @access private
189    */
190    function _getEndpoints($base = "", $all = 0) {
191        $this->endpoints = array();
192
193        // build sql
194        $sql = "select * from endpoints ";
195        if ($base) {
196            $sql .= "where class='$base' ";
197            if (!$all) $sql .= "and status=1";
198        } else
199        if (!$all) $sql .= "where status=1";
200        $sql .= " order by endpointName";
201
202
203        $db_ep = $this->dbc->getAll($sql,NULL, DB_FETCHMODE_ASSOC );
204        if (DB::isError($db_ep)) {
205            echo $sql."\n";
206            echo $db_ep->getMessage();
207            return FALSE;
208        }
209        // rearange the array
210        foreach ($db_ep as $entry) {
211            $this->endpoints[$entry['endpointName']] = $entry;
212        }
213
214        if (count($this->endpoints) > 0) {
215            $this->currentTest = $base;
216            return TRUE;
217        }
218        return FALSE;
219    }
220
221    /**
222    *  getResults
223    * retrieve results from the database, stuff them into the endpoint array
224    *
225    * @access private
226    */
227    function getResults($test = 'base', $type = 'php', $wsdl = 0) {
228        // be sure we have the right endpoints for this test result
229        $this->getEndpoints($test);
230
231        // retrieve the results and put them into the endpoint info
232        $sql = "select * from results where class='$test' and type='$type' and wsdl=$wsdl";
233        $results = $this->dbc->getAll($sql,NULL, DB_FETCHMODE_ASSOC );
234        foreach ($results as $result) {
235            // find the endpoint
236            foreach ($this->endpoints as $epn => $epi) {
237                if ($epi['id'] == $result['endpoint']) {
238                    // store the info
239                    $this->endpoints[$epn]['methods'][$result['function']] = $result;
240                    break;
241                }
242            }
243        }
244    }
245
246    /**
247    *  saveResults
248    * save the results of a method test into the database
249    *
250    * @access private
251    */
252    function _saveResults($endpoint_id, &$soap_test) {
253        if ($this->nosave) return;
254
255        $result = $soap_test->result;
256        $wire = $result['wire'];
257        if ($result['success']) {
258            $success = 'OK';
259            $error = '';
260        } else {
261            $success = $result['fault']->faultcode;
262            $pos = strpos($success,':');
263            if ($pos !== false) {
264              $success = substr($success,$pos+1);
265            }
266            $error = $result['fault']->faultstring;
267            if (!$wire) $wire= $result['fault']->detail;
268        }
269
270        $test_name = $soap_test->test_name;
271
272        $sql = "delete from results where endpoint=$endpoint_id ".
273                    "and class='$this->currentTest' and type='$this->paramType' ".
274                    "and wsdl=$this->useWSDL and function=".
275                    $this->dbc->quote($test_name);
276        #echo "\n".$sql;
277        $res = $this->dbc->query($sql);
278        if (DB::isError($res)) {
279            die ($res->getMessage());
280        }
281        if (is_object($res)) $res->free();
282
283        $sql = "insert into results (endpoint,stamp,class,type,wsdl,function,result,error,wire) ".
284                    "values($endpoint_id,".time().",'$this->currentTest',".
285                    "'$this->paramType',$this->useWSDL,".
286                    $this->dbc->quote($test_name).",".
287                    $this->dbc->quote($success).",".
288                    $this->dbc->quote($error).",".
289                    ($wire?$this->dbc->quote($wire):"''").")";
290        #echo "\n".$sql;
291        $res = $this->dbc->query($sql);
292
293        if (DB::isError($res)) {
294            die ($res->getMessage());
295        }
296        if (is_object($res)) $res->free();
297    }
298
299    /**
300    *  decodeSoapval
301    * decodes a soap value to php type, used for test result comparisons
302    *
303    * @param SOAP_Value soapval
304    * @return mixed result
305    * @access public
306    */
307    function decodeSoapval($soapval)
308    {
309        if (gettype($soapval) == "object" &&
310            (strcasecmp(get_class($soapval),"SoapParam") == 0 ||
311             strcasecmp(get_class($soapval),"SoapVar") == 0)) {
312                if (strcasecmp(get_class($soapval),"SoapParam") == 0)
313                    $val = $soapval->param_data->enc_value;
314                else
315                    $val = $soapval->enc_value;
316        } else {
317            $val = $soapval;
318        }
319        if (is_array($val)) {
320            foreach($val as $k => $v) {
321                if (gettype($v) == "object" &&
322                    (strcasecmp(get_class($soapval),"SoapParam") == 0 ||
323                    strcasecmp(get_class($soapval),"SoapVar") == 0)) {
324                    $val[$k] = $this->decodeSoapval($v);
325                }
326            }
327        }
328        return $val;
329    }
330
331    /**
332    *  compareResult
333    * compare two php types for a match
334    *
335    * @param string expect
336    * @param string test_result
337    * @return boolean result
338    * @access public
339    */
340    function compareResult($expect, $result, $type = NULL)
341    {
342      return compare($expect, $result);
343    }
344
345
346    /**
347    *  doEndpointMethod
348    *  run a method on an endpoint and store it's results to the database
349    *
350    * @param array endpoint_info
351    * @param SOAP_Test test
352    * @return boolean result
353    * @access public
354    */
355    function doEndpointMethod(&$endpoint_info, &$soap_test) {
356        $ok = FALSE;
357
358        // prepare a holder for the test results
359        $soap_test->result['class'] = $this->currentTest;
360        $soap_test->result['type'] = $this->paramType;
361        $soap_test->result['wsdl'] = $this->useWSDL;
362
363        if ($this->useWSDL) {
364            if (array_key_exists('wsdlURL',$endpoint_info)) {
365                if (!array_key_exists('client',$endpoint_info)) {
366                    try {
367                        $endpoint_info['client'] = new SoapClient($endpoint_info['wsdlURL'], array("trace"=>1));
368                    } catch (SoapFault $ex) {
369                        $endpoint_info['client']->wsdl->fault = $ex;
370                    }
371                }
372                $soap =& $endpoint_info['client'];
373
374                # XXX how do we determine a failure on retrieving/parsing wsdl?
375                if ($soap->wsdl->fault) {
376                    $fault = $soap->wsdl->fault;
377                    $soap_test->setResult(0,'WSDL',
378                                          $fault->faultstring."\n\n".$fault->detail,
379                                          $fault->faultstring,
380                                          $fault
381                                          );
382                    return FALSE;
383                }
384            } else {
385                $fault = new SoapFault('WSDL',"no WSDL defined for $endpoint");
386                $soap_test->setResult(0,'WSDL',
387                                      $fault->faultstring,
388                                      $fault->faultstring,
389                                      $fault
390                                      );
391                return FALSE;
392            }
393            $namespace = false;
394            $soapaction = false;
395        } else {
396            $namespace = $soapaction = 'http://soapinterop.org/';
397            // hack to make tests work with MS SoapToolkit
398            // it's the only one that uses this soapaction, and breaks if
399            // it isn't right.  Can't wait for soapaction to be fully deprecated
400            if ($this->currentTest == 'base' &&
401                strstr($endpoint_info['endpointName'],'MS SOAP ToolKit 2.0')) {
402                $soapaction = 'urn:soapinterop';
403            }
404            if (!array_key_exists('client',$endpoint_info)) {
405                $endpoint_info['client'] = new SoapClient(null,array('location'=>$endpoint_info['endpointURL'],'uri'=>$soapaction,'trace'=>1));
406            }
407            $soap = $endpoint_info['client'];
408        }
409//        // add headers to the test
410//        if ($soap_test->headers) {
411//            // $header is already a SOAP_Header class
412//            foreach ($soap_test->headers as $header) {
413//              $soap->addHeader($header);
414//            }
415//        }
416        // XXX no way to set encoding
417        // this lets us set UTF-8, US-ASCII or other
418        //$soap->setEncoding($soap_test->encoding);
419try {
420        if ($this->useWSDL && !$soap_test->headers && !$soap_test->headers_expect) {
421            $args = '';
422            foreach ($soap_test->method_params as $pname => $param) {
423                $arg = '$soap_test->method_params["'.$pname.'"]';
424                $args .= $args?','.$arg:$arg;
425            }
426            $return = eval('return $soap->'.$soap_test->method_name.'('.$args.');');
427        } else {
428          if ($soap_test->headers || $soap_test->headers_expect) {
429            $return = $soap->__soapCall($soap_test->method_name,$soap_test->method_params,array('soapaction'=>$soapaction,'uri'=>$namespace), $soap_test->headers, $result_headers);
430          } else {
431            $return = $soap->__soapCall($soap_test->method_name,$soap_test->method_params,array('soapaction'=>$soapaction,'uri'=>$namespace));
432          }
433        }
434} catch (SoapFault $ex) {
435  $return = $ex;
436}
437
438        if(!is_soap_fault($return)){
439            if ($soap_test->expect !== NULL) {
440                $sent = $soap_test->expect;
441            } else if (is_array($soap_test->method_params) && count($soap_test->method_params) == 1) {
442                reset($soap_test->method_params);
443                $sent = current($soap_test->method_params);
444            } else if (is_array($soap_test->method_params) && count($soap_test->method_params) == 0) {
445                $sent = null;
446            } else {
447                $sent = $soap_test->method_params;
448            }
449
450            // compare header results
451            $headers_ok = TRUE;
452            if ($soap_test->headers || $soap_test->headers_expect) {
453              $headers_ok = $this->compareResult($soap_test->headers_expect, $result_headers);
454            }
455
456            # we need to decode what we sent so we can compare!
457            $sent_d = $this->decodeSoapval($sent);
458
459            $soap_test->result['sent'] = $sent;
460            $soap_test->result['return'] = $return;
461
462            // compare the results with what we sent
463
464            if ($soap_test->cmp_func !== NULL) {
465              $cmp_func = $soap_test->cmp_func;
466              $ok = $cmp_func($sent_d,$return);
467            } else {
468              $ok = $this->compareResult($sent_d,$return, $sent->type);
469              if (!$ok && $soap_test->expect) {
470                $ok = $this->compareResult($soap_test->expect,$return);
471              }
472            }
473
474            // save the wire
475            $wire = "REQUEST:\n".str_replace('" ',"\" \n",str_replace('>',">\n",$soap->__getlastrequest()))."\n\n".
476                    "RESPONSE:\n".str_replace('" ',"\" \n",str_replace('>',">\n",$soap->__getlastresponse()))."\n\n".
477                    "EXPECTED:\n".var_dump_str($sent_d)."\n".
478                    "RESULTL:\n".var_dump_str($return);
479            if ($soap_test->headers_expect) {
480              $wire .= "\nEXPECTED HEADERS:\n".var_dump_str($soap_test->headers_expect)."\n".
481                       "RESULT HEADERS:\n".var_dump_str($result_headers);
482            }
483            #print "Wire:".htmlentities($wire);
484
485            if($ok){
486                if (!$headers_ok) {
487                    $fault = new SoapFault('HEADER','The returned result did not match what we expected to receive');
488                    $soap_test->setResult(0,$fault->faultcode,
489                                      $wire,
490                                      $fault->faultstring,
491                                      $fault
492                                      );
493                } else {
494                    $soap_test->setResult(1,'OK',$wire);
495                    $success = TRUE;
496                }
497            } else {
498                $fault = new SoapFault('RESULT','The returned result did not match what we expected to receive');
499                $soap_test->setResult(0,$fault->faultcode,
500                                  $wire,
501                                  $fault->faultstring,
502                                  $fault
503                                  );
504            }
505        } else {
506            $fault = $return;
507            if ($soap_test->expect_fault) {
508                $ok = 1;
509                $res = 'OK';
510            } else {
511                $ok = 0;
512                $res =$fault->faultcode;
513                $pos = strpos($res,':');
514                if ($pos !== false) {
515                  $res = substr($res,$pos+1);
516                }
517            }
518            // save the wire
519            $wire = "REQUEST:\n".str_replace('" ',"\" \n",str_replace('>',">\n",$soap->__getlastrequest()))."\n\n".
520                    "RESPONSE:\n".str_replace('" ',"\" \n",str_replace('>',">\n",$soap->__getlastresponse()))."\n".
521                    "RESULTL:\n".var_dump_str($return);
522            #print "Wire:".htmlentities($wire);
523
524            $soap_test->setResult($ok,$res, $wire,$fault->faultstring, $fault);
525
526        }
527        return $ok;
528    }
529
530
531    /**
532    *  doTest
533    *  run a single round of tests
534    *
535    * @access public
536    */
537    function doTest() {
538        global $soap_tests;
539        // get endpoints for this test
540        $this->getEndpoints($this->currentTest);
541        #clear totals
542        $this->totals = array();
543
544        $i = 0;
545        foreach($this->endpoints as $endpoint => $endpoint_info){
546
547            // if we specify an endpoint, skip until we find it
548            if ($this->specificEndpoint && $endpoint != $this->specificEndpoint) continue;
549            if ($this->useWSDL && !$endpoint_info['endpointURL']) continue;
550
551            $skipendpoint = FALSE;
552            $this->totals['servers']++;
553            #$endpoint_info['tests'] = array();
554
555            if ($this->show) {
556              print "Processing $endpoint at {$endpoint_info['endpointURL']}";
557              if ($this->html) print "<br>\n"; else print "\n";
558            }
559
560            foreach($soap_tests[$this->currentTest] as $soap_test) {
561            //foreach(array_keys($method_params[$this->currentTest][$this->paramType]) as $method)
562
563                // only run the type of test we're looking for (php or soapval)
564                if ($soap_test->type != $this->paramType) continue;
565
566                // if we haven't reached our startpoint, skip
567                if ($this->startAt && $this->startAt != $endpoint_info['endpointName']) continue;
568                $this->startAt = '';
569
570                // if this is in our skip list, skip it
571                if (in_array($endpoint, $this->skipEndpointList)) {
572                    $skipendpoint = TRUE;
573                    $skipfault = new SoapFault('SKIP','endpoint skipped');
574                    $soap_test->setResult(0,$fault->faultcode, '',
575                                  $skipfault->faultstring,
576                                  $skipfault
577                                  );
578                    #$endpoint_info['tests'][] = &$soap_test;
579                    #$soap_test->showTestResult($this->debug, $this->html);
580                    #$this->_saveResults($endpoint_info['id'], $soap_test->method_name);
581                    $soap_test->result = NULL;
582                    continue;
583                }
584
585                // if we're looking for a specific method, skip unless we have it
586                if ($this->testMethod && strcmp($this->testMethod,$soap_test->test_name) != 0) continue;
587
588                // if we are skipping the rest of the tests (due to error) note a fault
589                if ($skipendpoint) {
590                    $soap_test->setResult(0,$fault->faultcode, '',
591                                  $skipfault->faultstring,
592                                  $skipfault
593                                  );
594                    #$endpoint_info['tests'][] = &$soap_test;
595                    $this->totals['fail']++;
596                } else {
597                    // run the endpoint test
598                    if ($this->doEndpointMethod($endpoint_info, $soap_test)) {
599                        $this->totals['success']++;
600                    } else {
601                        $skipendpoint = $soap_test->result['fault']->faultcode=='HTTP'
602                            && strstr($soap_test->result['fault']->faultstring,'Connect Error');
603                        $skipfault = $soap_test->result['fault'];
604                        $this->totals['fail']++;
605                    }
606                    #$endpoint_info['tests'][] = &$soap_test;
607                }
608                $soap_test->showTestResult($this->debug, $this->html);
609                $this->_saveResults($endpoint_info['id'], $soap_test);
610                $soap_test->result = NULL;
611                $this->totals['calls']++;
612            }
613            if ($this->numservers && ++$i >= $this->numservers) break;
614        }
615    }
616
617    function doGroupTests() {
618        $dowsdl = array(0,1);
619        foreach($dowsdl as $usewsdl) {
620            $this->useWSDL = $usewsdl;
621            foreach($this->paramTypes as $ptype) {
622                // skip a pointless test
623                if ($usewsdl && $ptype == 'soapval') break;
624                $this->paramType = $ptype;
625                $this->doTest();
626            }
627        }
628    }
629
630    /**
631    *  doTests
632    *  go all out.  This takes time.
633    *
634    * @access public
635    */
636    function doTests() {
637        // the mother of all interop tests
638        $dowsdl = array(0,1);
639        foreach($this->tests as $test) {
640            $this->currentTest = $test;
641            foreach($dowsdl as $usewsdl) {
642                $this->useWSDL = $usewsdl;
643                foreach($this->paramTypes as $ptype) {
644                    // skip a pointless test
645                    if ($usewsdl && $ptype == 'soapval') break;
646                    $this->paramType = $ptype;
647                    $this->doTest();
648                }
649            }
650        }
651    }
652
653    // ***********************************************************
654    // output functions
655
656    /**
657    *  getResults
658    * retrieve results from the database, stuff them into the endpoint array
659    *
660    * @access private
661    */
662    function getMethodList($test = 'base') {
663        // retrieve the results and put them into the endpoint info
664        $sql = "select distinct(function) from results where class='$test' order by function";
665        $results = $this->dbc->getAll($sql);
666        $ar = array();
667        foreach($results as $result) {
668            $ar[] = $result[0];
669        }
670        return $ar;
671    }
672
673    function outputTable()
674    {
675        $methods = $this->getMethodList($this->currentTest);
676        if (!$methods) return;
677        $this->getResults($this->currentTest,$this->paramType,$this->useWSDL);
678
679        echo "<b>Testing $this->currentTest ";
680        if ($this->useWSDL) echo "using WSDL ";
681        else echo "using Direct calls ";
682        echo "with $this->paramType values</b><br>\n";
683
684        // calculate totals for this table
685        $this->totals['success'] = 0;
686        $this->totals['fail'] = 0;
687        $this->totals['servers'] = 0; #count($this->endpoints);
688        foreach ($this->endpoints as $endpoint => $endpoint_info) {
689            if (count($endpoint_info['methods']) > 0) {
690                $this->totals['servers']++;
691                foreach ($methods as $method) {
692                    $r = $endpoint_info['methods'][$method]['result'];
693                    if ($r == 'OK') $this->totals['success']++;
694                    else $this->totals['fail']++;
695                }
696            } else {
697                unset($this->endpoints[$endpoint]);
698            }
699        }
700        $this->totals['calls'] = count($methods) * $this->totals['servers'];
701
702        echo "\n\n<b>Servers: {$this->totals['servers']} Calls: {$this->totals['calls']} Success: {$this->totals['success']} Fail: {$this->totals['fail']}</b><br>\n";
703
704        echo "<table border=\"1\" cellspacing=\"0\" cellpadding=\"2\">\n";
705        echo "<tr><td class=\"BLANK\">Endpoint</td>\n";
706        foreach ($methods as $method) {
707            $info = split(':', $method);
708            echo "<td class='BLANK' valign='top'>";
709            foreach ($info as $m) {
710                $hi = split(',',$m);
711                echo '<b>'.$hi[0]."</b><br>\n";
712                if (count($hi) > 1) {
713                    echo "&nbsp;&nbsp;Actor=".($hi[1]?'Target':'Not Target')."<br>\n";
714                    echo "&nbsp;&nbsp;MustUnderstand=$hi[2]<br>\n";
715                }
716            }
717            echo "</td>\n";
718        }
719        echo "</tr>\n";
720        $faults = array();
721        $fi = 0;
722        foreach ($this->endpoints as $endpoint => $endpoint_info) {
723            if (array_key_exists('wsdlURL',$endpoint_info)) {
724                echo "<tr><td class=\"BLANK\"><a href=\"{$endpoint_info['wsdlURL']}\">$endpoint</a></td>\n";
725            } else {
726                echo "<tr><td class=\"BLANK\">$endpoint</td>\n";
727            }
728            foreach ($methods as $method) {
729                $id = $endpoint_info['methods'][$method]['id'];
730                $r = $endpoint_info['methods'][$method]['result'];
731                $e = $endpoint_info['methods'][$method]['error'];
732                if ($e) {
733                    $faults[$fi++] = $e;
734                }
735                if ($r) {
736                    echo "<td class='$r'><a href='$PHP_SELF?wire=$id'>$r</a></td>\n";
737                } else {
738                    echo "<td class='untested'>untested</td>\n";
739                }
740            }
741            echo "</tr>\n";
742        }
743        echo "</table><br>\n";
744        if ($this->showFaults && count($faults) > 0) {
745            echo "<b>ERROR Details:</b><br>\n<ul>\n";
746            # output more error detail
747            foreach ($faults as $fault) {
748                echo '<li>'.HTMLSpecialChars($fault)."</li>\n";
749            }
750        }
751        echo "</ul><br><br>\n";
752    }
753
754    function outputTables() {
755        // the mother of all interop tests
756        $dowsdl = array(0,1);
757        foreach($this->tests as $test) {
758            $this->currentTest = $test;
759            foreach($dowsdl as $usewsdl) {
760                $this->useWSDL = $usewsdl;
761                foreach($this->paramTypes as $ptype) {
762                    // skip a pointless test
763                    if ($usewsdl && $ptype == 'soapval') break;
764                    $this->paramType = $ptype;
765                    $this->outputTable();
766                }
767            }
768        }
769    }
770
771    function showWire($id) {
772        $results = $this->dbc->getAll("select * from results where id=$id",NULL, DB_FETCHMODE_ASSOC );
773        #$wire = preg_replace("/>/",">\n",$results[0]['wire']);
774        $wire = $results[0]['wire'];
775        if ($this->html) print "<pre>";
776        echo "\n".HTMLSpecialChars($wire);
777        if ($this->html) print "</pre>";
778        print "\n";
779    }
780
781}
782
783?>
784