Subversion Repositories Web Services

Rev

Rev 120114 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
82190 hhl 1
<?php
2
/**
3
 *
4
 * This file is part of Open Library System.
5
 * Copyright © 2009, Dansk Bibliotekscenter a/s,
6
 * Tempovej 7-11, DK-2750 Ballerup, Denmark. CVR: 15149043
7
 *
8
 * Open Library System is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License as published by
10
 * the Free Software Foundation, either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * Open Library System is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU Affero General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Affero General Public License
19
 * along with Open Library System.  If not, see <http://www.gnu.org/licenses/>.
118297 fvs 20
 */
82190 hhl 21
 
22
 
23
/** \brief Webservice server
24
 *
25
 * @author Finn Stausgaard - DBC
26
 *
27
 */
28
 
29
require_once('OLS_class_lib/curl_class.php');
120114 fvs 30
require_once('OLS_class_lib/verbose_json_class.php');
82190 hhl 31
require_once('OLS_class_lib/inifile_class.php');
32
require_once('OLS_class_lib/timer_class.php');
33
require_once('OLS_class_lib/aaa_class.php');
94544 fvs 34
require_once('OLS_class_lib/object_class.php');
82190 hhl 35
require_once('OLS_class_lib/restconvert_class.php');
36
require_once('OLS_class_lib/jsonconvert_class.php');
37
require_once('OLS_class_lib/xmlconvert_class.php');
38
require_once('OLS_class_lib/objconvert_class.php');
39
 
118297 fvs 40
/**
41
 * Class webServiceServer
42
 */
82190 hhl 43
abstract class webServiceServer {
44
 
45
  protected $config; ///< inifile object
46
  protected $watch; ///< timer object
47
  protected $aaa; ///< Authentication, Access control and Accounting object
48
  protected $xmldir = './'; ///< xml directory
49
  protected $validate = array(); ///< xml validate schemas
50
  protected $objconvert; ///< OLS object to xml convert
51
  protected $xmlconvert; ///< xml to OLS object convert
52
  protected $xmlns; ///< namespaces and prefixes
53
  protected $default_namespace; ///< -
118297 fvs 54
  protected $tag_sequence; ///< tag sequence according to XSD or noame of XSD
82190 hhl 55
  protected $soap_action; ///< -
56
  protected $dump_timer; ///< -
57
  protected $dump_timer_ip; ///< -
118297 fvs 58
  protected $output_type = ''; ///< -
82190 hhl 59
  protected $curl_recorder; ///< -
60
  protected $debug; ///< -
61
  protected $url_override; ///< array with special url-commands for the actual service
62
 
63
 
64
  /** \brief Webservice constructer
65
   *
118297 fvs 66
   * @param $inifile string
82190 hhl 67
   *
68
   */
118297 fvs 69
  public function __construct($inifile) {
82190 hhl 70
    // initialize config and verbose objects
71
    $this->config = new inifile($inifile);
72
 
73
    if ($this->config->error) {
118297 fvs 74
      die('Error: ' . $this->config->error);
82190 hhl 75
    }
76
 
77
    // service closed
78
    if ($http_error = $this->config->get_value('service_http_error', 'setup')) {
79
      header($http_error);
80
      die($http_error);
81
    }
82
 
83
    if ($this->config->get_value('only_https', 'setup') && empty($_SERVER['HTTPS'])) {
84
      header('HTTP/1.0 403.4 SSL Required');
85
      die('HTTP/1.0 403.4 SSL Required');
86
    }
87
 
88
    libxml_use_internal_errors(TRUE);
89
 
84008 fvs 90
    if (self::in_house())
82190 hhl 91
      $this->debug = $_REQUEST['debug'];
84032 fvs 92
    $this->version = $this->config->get_value('version', 'setup');
120114 fvs 93
    VerboseJson::open($this->config->get_section('setup'));
82190 hhl 94
    $this->watch = new stopwatch('', ' ', '', '%s:%01.3f');
95
 
96
    if ($this->config->get_value('xmldir'))
118297 fvs 97
      $this->xmldir = $this->config->get_value('xmldir');
82190 hhl 98
    $this->xmlns = $this->config->get_value('xmlns', 'setup');
99
    $this->default_namespace = $this->xmlns[$this->config->get_value('default_namespace_prefix', 'setup')];
100
    $this->tag_sequence = $this->config->get_value('tag_sequence', 'setup');
101
    $this->output_type = $this->config->get_value('default_output_type', 'setup');
84004 fvs 102
    $this->dump_timer = str_replace('_VERSION_', $this->version, $this->config->get_value('dump_timer', 'setup'));
82190 hhl 103
    if ($this->config->get_value('dump_timer_ip', 'setup'))
83327 fvs 104
      $this->dump_timer_ip = 'ip:' . $_SERVER['REMOTE_ADDR'] . ' ';
82190 hhl 105
    if (!$this->url_override = $this->config->get_value('url_override', 'setup'))
106
      $this->url_override = array('HowRU' => 'HowRU', 'ShowInfo' => 'ShowInfo', 'Version' => 'Version', 'wsdl' => 'Wsdl');
107
 
108
    $test_section = $this->config->get_section('test');
109
    if (is_array($test_section['curl_record_urls'])) {
110
      require_once('OLS_class_lib/curl_recorder.php');
111
      $this->curl_recorder = new CurlRecorder($test_section);
112
    }
113
 
114
    $this->aaa = new aaa($this->config->get_section('aaa'));
115
  }
116
 
118297 fvs 117
  public function __destruct() {
118
  }
82190 hhl 119
 
120
  /** \brief Handles request from webservice client
118297 fvs 121
   *
122
   * @return mixed
123
   */
82190 hhl 124
  public function handle_request() {
125
    foreach ($this->url_override as $query_par => $function_name) {
126
      if (strpos($_SERVER['QUERY_STRING'], $query_par) === 0 && method_exists($this, $function_name)) {
118297 fvs 127
        return $this->{$function_name}();
82190 hhl 128
      }
129
    }
130
    if (isset($_POST['xml'])) {
118297 fvs 131
      $xml = trim(stripslashes($_POST['xml']));
84008 fvs 132
      self::soap_request($xml);
82190 hhl 133
    }
134
    elseif (!empty($GLOBALS['HTTP_RAW_POST_DATA'])) {
84008 fvs 135
      self::soap_request($GLOBALS['HTTP_RAW_POST_DATA']);
82190 hhl 136
    }
115749 pjo 137
    // pjo 11/9/17 for php 7. @see http://php.net/manual/en/reserved.variables.httprawpostdata.php.
118297 fvs 138
    elseif ($xml = file_get_contents("php://input")) {
115749 pjo 139
      self::soap_request($xml);
140
    }
82190 hhl 141
    elseif (!empty($_SERVER['QUERY_STRING']) && ($_REQUEST['action'] || $_REQUEST['json'])) {
84008 fvs 142
      self::rest_request();
82190 hhl 143
    }
144
    elseif (!empty($_POST)) {
145
      foreach ($_POST as $k => $v) {
146
        $_SERVER['QUERY_STRING'] .= ($_SERVER['QUERY_STRING'] ? '&' : '') . $k . '=' . $v;
147
      }
84008 fvs 148
      self::rest_request();
82190 hhl 149
    }
84008 fvs 150
    elseif (self::in_house()
118297 fvs 151
      || $this->config->get_value('show_samples', 'setup')
152
      || ip_func::ip_in_interval($_SERVER['REMOTE_ADDR'], $this->config->get_value('show_samples_ip_list', 'setup'))
153
    ) {
84008 fvs 154
      self::create_sample_forms();
82190 hhl 155
    }
156
    else {
157
      header('HTTP/1.0 404 Not Found');
158
    }
159
  }
160
 
161
  /** \brief Handles and validates soap request
118297 fvs 162
   *
163
   * @param $xml string
164
   */
82190 hhl 165
  private function soap_request($xml) {
120114 fvs 166
    // Debug VerboseJson::log(TRACE, array('request' => $xml));
82190 hhl 167
 
168
    // validate request
169
    $this->validate = $this->config->get_value('validate');
170
 
171
    if ($this->validate['soap_request'] || $this->validate['request'])
118297 fvs 172
      $error = !self::validate_soap($xml, $this->validate, 'request');
82190 hhl 173
 
174
    if (empty($error)) {
175
      // parse to object
118297 fvs 176
      $this->xmlconvert = new xmlconvert();
177
      $xmlobj = $this->xmlconvert->soap2obj($xml);
82190 hhl 178
      // soap envelope?
179
      if ($xmlobj->Envelope) {
180
        $request_xmlobj = &$xmlobj->Envelope->_value->Body->_value;
181
        $soap_namespace = $xmlobj->Envelope->_namespace;
182
      }
183
      else {
184
        $request_xmlobj = &$xmlobj;
185
        $soap_namespace = 'http://www.w3.org/2003/05/soap-envelope';
186
        $this->output_type = 'xml';
187
      }
188
 
189
      // initialize objconvert and load namespaces
109120 fvs 190
      if ($_GET['marshal'] && self::in_house()) $timer = &$this->watch;
191
      $this->objconvert = new objconvert($this->xmlns, $this->tag_sequence, $timer);
82190 hhl 192
      $this->objconvert->set_default_namespace($this->default_namespace);
193
 
194
      // handle request
84008 fvs 195
      if ($response_xmlobj = self::call_xmlobj_function($request_xmlobj)) {
82190 hhl 196
        // validate response
197
        if ($this->validate['soap_response'] || $this->validate['response']) {
84008 fvs 198
          $response_xml = $this->objconvert->obj2soap($response_xmlobj, $soap_namespace);
118297 fvs 199
          $error = !self::validate_soap($response_xml, $this->validate, 'response');
82190 hhl 200
        }
201
 
202
        if (empty($error)) {
203
          // Branch to outputType
204
          list($service, $req) = each($request_xmlobj);
205
          if (empty($this->output_type) || $req->_value->outputType->_value)
117950 fvs 206
            $this->output_type = isset($req->_value->outputType) ? $req->_value->outputType->_value : '';;
82190 hhl 207
          switch ($this->output_type) {
208
            case 'json':
209
              header('Content-Type: application/json');
210
              $callback = &$req->_value->callback->_value;
211
              if ($callback && preg_match("/^\w+$/", $callback))
212
                echo $callback . ' && ' . $callback . '(' . $this->objconvert->obj2json($response_xmlobj) . ')';
213
              else
214
                echo $this->objconvert->obj2json($response_xmlobj);
215
              break;
216
            case 'php':
217
              header('Content-Type: application/php');
218
              echo $this->objconvert->obj2phps($response_xmlobj);
219
              break;
220
            case 'xml':
221
              header('Content-Type: text/xml');
222
              echo $this->objconvert->obj2xmlNS($response_xmlobj);
223
              break;
224
            default:
225
              if (empty($response_xml))
118297 fvs 226
                $response_xml = $this->objconvert->obj2soap($response_xmlobj, $soap_namespace);
82190 hhl 227
              if ($soap_namespace == 'http://www.w3.org/2003/05/soap-envelope' && empty($_POST['xml']))
228
                header('Content-Type: application/soap+xml');   // soap 1.2
229
              else
230
                header('Content-Type: text/xml; charset=utf-8');
231
              echo $response_xml;
232
          }
233
          // request done and response send, dump timer
120114 fvs 234
          if ($this->dump_timer) {
235
            VerboseJson::log(TIMER, array_merge(array('action' => $this->soap_action), $this->watch->get_timers()));
236
          }
82190 hhl 237
        }
238
        else
84008 fvs 239
          self::soap_error('Error in response validation.');
82190 hhl 240
      }
241
      else
84008 fvs 242
        self::soap_error('Incorrect SOAP envelope or wrong/unsupported request');
82190 hhl 243
    }
244
    else
84008 fvs 245
      self::soap_error('Error in request validation.');
98382 fvs 246
 
247
    if ($duplicate_request_to = $this->config->get_value('duplicate_request_to')) {
98956 fvs 248
      reset($request_xmlobj);
249
      $request = key($request_xmlobj);
250
      if (is_null($request_xmlobj->$request->_value->authentication->_value)) {
251
        unset($request_xmlobj->$request->_value->authentication);
252
      }
253
      $request = $this->objconvert->obj2soap($request_xmlobj, $soap_namespace);
98382 fvs 254
      $curl = new curl();
255
      foreach ($duplicate_request_to as $no => $uri) {
118076 fvs 256
        $curl->set_option(CURLOPT_TIMEOUT_MS, 10, $no);
98382 fvs 257
        $curl->set_url($uri, $no);
258
        if ($soap_namespace == 'http://www.w3.org/2003/05/soap-envelope') {
259
          $curl->set_post_with_header($request, 'Content-Type: application/soap+xml', $no);
260
        }
261
        else {
262
          $curl->set_post_with_header($request, 'Content-Type: text/xml; charset=utf-8', $no);
263
        }
264
      }
265
      $reply = $curl->get();
266
    }
82190 hhl 267
  }
268
 
269
  /** \brief Handles rest request, converts it to xml and calls soap_request()
118297 fvs 270
   *
271
   */
82190 hhl 272
  private function rest_request() {
273
    // convert to soap
274
    if ($_REQUEST['json']) {
275
      $json = new jsonconvert($this->default_namespace);
276
      $xml = $json->json2soap($this->config);
277
    }
278
    else {
279
      $rest = new restconvert($this->default_namespace);
280
      $xml = $rest->rest2soap($this->config);
281
    }
84008 fvs 282
    self::soap_request($xml);
82190 hhl 283
  }
284
 
285
  /** \brief Show the service version
118297 fvs 286
   *
287
   * @param $operation
288
   */
94736 fvs 289
  private function update_registry($operation) {
290
    $registry = $this->config->get_section('service_registry');
108736 fvs 291
    if ($registry && $registry['registry']) {
94736 fvs 292
      require_once('OLS_class_lib/registry_class.php');
293
      $this->watch->start('registry');
294
      Registry::set($this->default_namespace, $operation, $this->config->get_value('version', 'setup'), $registry);
295
      $this->watch->stop('registry');
296
    }
297
  }
298
 
299
  /** \brief Show the service version
118297 fvs 300
   *
301
   * @noinspection PhpUnusedPrivateMethodInspection
302
   */
82190 hhl 303
  private function version() {
304
    die($this->version);
305
  }
306
 
307
  /** \brief Show wsdl file for the service replacing __LOCATION__ with ini-file setting or current location
118297 fvs 308
   *
309
   * @noinspection PhpUnusedPrivateMethodInspection
310
   */
82190 hhl 311
  private function Wsdl() {
312
    if ($wsdl = $this->config->get_value('wsdl', 'setup')) {
313
      if (!$location = $this->config->get_value('service_location', 'setup')) {
314
        $location = $_SERVER['SERVER_NAME'] . dirname($_SERVER['SCRIPT_NAME']) . '/';
315
      }
88204 fvs 316
      if (strpos($location, '://') < 1) {
317
        if (!empty($_SERVER['HTTPS']) || ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')) {
318
          $protocol = 'https://';
118297 fvs 319
        }
320
        else {
88204 fvs 321
          $protocol = 'http://';
322
        }
323
      }
82190 hhl 324
      if (($text = file_get_contents($wsdl)) !== FALSE) {
325
        header('Content-Type: text/xml; charset="utf-8"');
326
        die(str_replace('__LOCATION__', $protocol . $location, $text));
327
      }
328
      else {
329
        die('ERROR: Cannot open the wsdl file - error in ini-file?');
330
      }
331
    }
332
    else {
333
      die('ERROR: wsdl not defined in the ini-file');
334
    }
335
  }
336
 
118297 fvs 337
  /** \brief Show selected parts of the ini-file
338
   *
339
   * @noinspection PhpUnusedPrivateMethodInspection
340
   */
82190 hhl 341
  private function ShowInfo() {
84008 fvs 342
    if (($showinfo = $this->config->get_value('showinfo', 'showinfo')) && self::in_house()) {
82190 hhl 343
      foreach ($showinfo as $line) {
84008 fvs 344
        echo self::showinfo_line($line) . "\n";
82190 hhl 345
      }
118297 fvs 346
      die();
82190 hhl 347
    }
348
  }
349
 
350
  /** \brief expands __var__ to the corresponding setting
118297 fvs 351
   *
352
   * @param $line string
353
   * @return mixed|string
354
   */
82190 hhl 355
  private function showinfo_line($line) {
356
    while (($s = strpos($line, '__')) !== FALSE) {
118297 fvs 357
      $line = substr($line, 0, $s) . substr($line, $s + 2);
82190 hhl 358
      if (($e = strpos($line, '__')) !== FALSE) {
359
        $var = substr($line, $s, $e - $s);
360
        list($key, $section) = explode('.', $var, 2);
361
        $val = $this->config->get_value($key, $section);
362
        if (is_array($val)) {
84008 fvs 363
          $val = self::implode_ini_array($val);
82190 hhl 364
        }
365
        $line = str_replace($var . '__', $val, $line);
366
      }
367
    }
368
    return $line;
369
  }
370
 
371
  /** \brief Helper function to showinfo_line()
118297 fvs 372
   *
373
   * @param $arr array
374
   * @param $prefix string
375
   * @return mixed
376
   */
82190 hhl 377
  private function implode_ini_array($arr, $prefix = '') {
378
    $ret = "\n";
379
    foreach ($arr as $key => $val) {
380
      if (is_array($val)) {
84008 fvs 381
        $val = self::implode_ini_array($val, ' - ' . $prefix);
82190 hhl 382
      }
383
      $ret .= $prefix . ' - [' . $key . '] ' . $val . "\n";
384
    }
385
    return str_replace("\n\n", "\n", $ret);
386
  }
387
 
388
  /** \brief
118297 fvs 389
   *  Return TRUE if the IP is in in_house_ip_list, or if in_house_ip_list is not set, if the name is in in_house_domain
390
   *  NB: gethostbyaddr() can take some time or even time out, is the remote name server is slow or wrongly configured
391
   */
82190 hhl 392
  protected function in_house() {
393
    static $homie;
394
    if (!isset($homie)) {
101212 fvs 395
      if (FALSE !== ($in_house_ip_list = $this->config->get_value('in_house_ip_list', 'setup'))) {
396
        $homie = ip_func::ip_in_interval($_SERVER['REMOTE_ADDR'], $in_house_ip_list);
397
      }
398
      else {
399
        if (!$domain = $this->config->get_value('in_house_domain', 'setup'))
400
          $domain = '.dbc.dk';
401
        @ $remote = gethostbyaddr($_SERVER['REMOTE_ADDR']);
402
        $domains = explode(';', $domain);
403
        foreach ($domains as $dm) {
404
          $dm = trim($dm);
405
          if ($homie = (strpos($remote, $dm) + strlen($dm) == strlen($remote)))
406
            if ($homie = (gethostbyname($remote) == $_SERVER['REMOTE_ADDR'])) // paranoia check
407
              break;
82190 hhl 408
        }
101212 fvs 409
      }
82190 hhl 410
    }
411
    return $homie;
412
  }
413
 
414
  /** \brief RegressionTest tests the webservice
118297 fvs 415
   *
416
   * @param $arg string
417
   *
418
   * @noinspection PhpUnusedPrivateMethodInspection
419
   */
420
  private function RegressionTest($arg = '') {
421
    if (!is_dir($this->xmldir . '/regression'))
82190 hhl 422
      die('No regression catalouge');
423
 
118297 fvs 424
    if ($dh = opendir($this->xmldir . '/regression')) {
425
      chdir($this->xmldir . '/regression');
82190 hhl 426
      while (($file = readdir($dh)) !== false)
118297 fvs 427
        if (!is_dir($file) && preg_match('/xml$/', $file, $matches))
82190 hhl 428
          $fnames[] = $file;
429
      if (count($fnames)) {
430
        asort($fnames);
431
        $curl = new curl();
432
        $curl->set_option(CURLOPT_POST, 1);
433
        foreach ($fnames as $fname) {
434
          $contents = str_replace("\r\n", PHP_EOL, file_get_contents($fname));
435
          $curl->set_post_xml($contents);
436
          $reply = $curl->get($_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']);
437
          echo $reply;
438
        }
439
      }
440
      else
441
        die('No files found for regression test');
442
    }
443
    else
118297 fvs 444
      die('Cannot open regression catalouge: ' . $this->xmldir . '/regression');
82190 hhl 445
  }
446
 
447
  /** \brief HowRU tests the webservice and answers "Gr8" if none of the tests fail. The test cases resides in the inifile.
118297 fvs 448
   *
449
   *  Handles zero or more set of tests.
450
   *  Each set, can contain one or more tests, where just one of them has to succeed
451
   *  If all tests in a given set fails, the corresponding error will be displayed
452
   *
453
   * @noinspection PhpUnusedPrivateMethodInspection
454
   */
82190 hhl 455
  private function HowRU() {
456
    $tests = $this->config->get_value('test', 'howru');
457
    if ($tests) {
458
      $curl = new curl();
120161 pjo 459
 
460
      $proxy = $this->config->get_section('proxy');
461
      if ($proxy['domain_and_port']) {
462
        $curl->set_proxy($proxy['domain_and_port']);
463
      }
464
 
82190 hhl 465
      $reg_matchs = $this->config->get_value('preg_match', 'howru');
466
      $reg_errors = $this->config->get_value('error', 'howru');
467
      if (!$server_name = $this->config->get_value('server_name', 'howru')) {
118297 fvs 468
        if (!$server_name = $_SERVER['SERVER_NAME']) {
469
          $server_name = $_SERVER['HTTP_HOST'];
470
        }
82190 hhl 471
      }
118297 fvs 472
      $url = $server_name . $_SERVER['PHP_SELF'];
82190 hhl 473
      if ($_SERVER['HTTPS'] == 'on') $url = 'https://' . $url;
474
      foreach ($tests as $i_test => $test) {
475
        if (is_array($test)) {
476
          $reg_match = $reg_matchs[$i_test];
477
        }
478
        else {
479
          $test = array($test);
480
          $reg_match = array($reg_matchs[$i_test]);
481
        }
482
        $error = $reg_errors[$i_test];
483
        foreach ($test as $i => $t) {
118297 fvs 484
          $reply = $curl->get($url . '?action=' . $t);
94736 fvs 485
          $preg_match = $reg_match[$i];
118297 fvs 486
          if (preg_match("/$preg_match/", $reply)) {
82190 hhl 487
            unset($error);
488
            break;
489
          }
490
        }
120063 fvs 491
        if ($error) {
492
          header('HTTP/1.0 503 Service Unavailable');
82190 hhl 493
          die($error);
120063 fvs 494
        }
82190 hhl 495
      }
496
      $curl->close();
497
    }
498
    die('Gr8');
499
  }
500
 
501
  /** \brief Validates soap and xml
118297 fvs 502
   *
503
   * @param $soap string
504
   * @param $schemas array
505
   * @param $validate_schema string
506
   * @return bool
507
   */
82190 hhl 508
  protected function validate_soap($soap, $schemas, $validate_schema) {
509
    $validate_soap = new DomDocument;
510
    $validate_soap->preserveWhiteSpace = FALSE;
511
    @ $validate_soap->loadXml($soap);
118297 fvs 512
    if (($sc = $schemas['soap_' . $validate_schema]) && !@ $validate_soap->schemaValidate($sc))
82190 hhl 513
      return FALSE;
514
 
515
    if ($sc = $schemas[$validate_schema]) {
516
      if ($validate_soap->firstChild->localName == 'Envelope'
118297 fvs 517
        && $validate_soap->firstChild->hasChildNodes()
518
      ) {
82190 hhl 519
        foreach ($validate_soap->firstChild->childNodes as $soap_node) {
520
          if ($soap_node->localName == 'Body') {
521
            $xml = &$soap_node->firstChild;
522
            $validate_xml = new DOMdocument;
523
            @ $validate_xml->appendChild($validate_xml->importNode($xml, TRUE));
524
            break;
525
          }
526
        }
527
      }
528
      if (empty($validate_xml))
529
        $validate_xml = &$validate_soap;
530
 
118297 fvs 531
      if (!@ $validate_xml->schemaValidate($sc))
82190 hhl 532
        return FALSE;
533
    }
534
 
535
    return TRUE;
536
  }
537
 
538
  /** \brief send an error header and soap fault
118297 fvs 539
   *
540
   * @param $err string
541
   *
542
   */
82190 hhl 543
  protected function soap_error($err) {
544
    $elevel = array(LIBXML_ERR_WARNING => "\n Warning",
545
                    LIBXML_ERR_ERROR => "\n Error",
546
                    LIBXML_ERR_FATAL => "\n Fatal");
547
    if ($errors = libxml_get_errors()) {
548
      foreach ($errors as $error) {
118297 fvs 549
        $xml_err .= $elevel[$error->level] . ": " . trim($error->message) .
550
          ($error->file ? " in file " . $error->file : " on line " . $error->line);
82190 hhl 551
      }
552
    }
553
    header('HTTP/1.0 400 Bad Request');
554
    header('Content-Type: text/xml; charset="utf-8"');
555
    echo '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
556
    <SOAP-ENV:Body>
557
    <SOAP-ENV:Fault>
558
    <faultcode>SOAP-ENV:Server</faultcode>
559
    <faultstring>' . htmlspecialchars($err . $xml_err) . '</faultstring>
560
    </SOAP-ENV:Fault>
561
    </SOAP-ENV:Body>
562
    </SOAP-ENV:Envelope>';
563
  }
564
 
565
  /** \brief Validates xml
118297 fvs 566
   *
567
   * @param $xml string
568
   * @param $schema_filename string
569
   * @param $resolve_externals boolean
570
   * @return bool
571
   */
572
  protected function validate_xml($xml, $schema_filename, $resolve_externals = FALSE) {
82190 hhl 573
    $validateXml = new DomDocument;
574
    $validateXml->resolveExternals = $resolve_externals;
575
    $validateXml->loadXml($xml);
576
    if (@ $validateXml->schemaValidate($schema_filename)) {
577
      return TRUE;
578
    }
579
    else {
580
      return FALSE;
581
    }
582
  }
583
 
584
  /** \brief Find operation in object created from xml and and calls this function defined by developer in extended class.
118297 fvs 585
   * Authentication is by default found in the authentication node, in userIdAut, groupIdAut and passwordAut
586
   * These names can be changed by doing so in the aaa-section, like:
587
   * userIdAut = theNameOfUserIdInThisService
588
   *
589
   * @param $xmlobj object
590
   * @return bool - from the service entry point called
591
   */
82190 hhl 592
  private function call_xmlobj_function($xmlobj) {
593
    if ($xmlobj) {
594
      $soapActions = $this->config->get_value('soapAction', 'setup');
118297 fvs 595
      $request = key($xmlobj);
82190 hhl 596
      if ($this->soap_action = array_search($request, $soapActions)) {
118297 fvs 597
        $params = $xmlobj->$request->_value;
82190 hhl 598
        if (method_exists($this, $this->soap_action)) {
120114 fvs 599
          VerboseJson::set_action($this->soap_action);
600
          VerboseJson::set_tracking_id($this->config->get_value('default_namespace_prefix', 'setup'), $params->trackingId->_value);
82190 hhl 601
          if (is_object($this->aaa)) {
602
            foreach (array('authentication', 'userIdAut', 'groupIdAut', 'passwordAut') as $par) {
603
              if (!$$par = $this->config->get_value($par, 'aaa')) {
604
                $$par = $par;
605
              }
606
            }
607
            $auth = &$params->$authentication->_value;
608
            $this->aaa->init_rights($auth->$userIdAut->_value,
609
                                    $auth->$groupIdAut->_value,
610
                                    $auth->$passwordAut->_value,
611
                                    $_SERVER['REMOTE_ADDR']);
612
          }
94736 fvs 613
          self::update_registry($this->soap_action);
118297 fvs 614
          return $this->{$this->soap_action}($params);
82190 hhl 615
        }
616
      }
617
    }
618
 
619
    return FALSE;
620
  }
621
 
622
  /** \brief Create sample form for testing webservice. This is called of no request is send via browser.
118297 fvs 623
   *
624
   *
625
   */
82190 hhl 626
 
627
  private function create_sample_forms() {
628
    if ($sample_header = $this->config->get_value('sample_header', 'setup')) {
629
      $header_warning = '<p>Ensure that the character set of the request match your browser settings</p>';
630
    }
631
    else {
632
      $sample_header = 'Content-type: text/html; charset=utf-8';
633
    }
118297 fvs 634
    header($sample_header);
82190 hhl 635
 
636
    // Open a known directory, and proceed to read its contents
118297 fvs 637
    if (is_dir($this->xmldir . '/request')) {
638
      if ($dh = opendir($this->xmldir . '/request')) {
639
        chdir($this->xmldir . '/request');
82190 hhl 640
        $fnames = $reqs = array();
641
        while (($file = readdir($dh)) !== false) {
642
          if (!is_dir($file)) {
118297 fvs 643
            if (preg_match('/html$/', $file, $matches)) $info = file_get_contents($file);
644
            if (preg_match('/xml$/', $file, $matches)) $fnames[] = $file;
82190 hhl 645
          }
646
        }
647
        closedir($dh);
648
 
84008 fvs 649
        $html = strpos($info, '__REQS__') ? $info : str_replace('__INFO__', $info, self::sample_form());
82190 hhl 650
 
651
        if ($info || count($fnames)) {
109106 fvs 652
          natsort($fnames);
82190 hhl 653
          foreach ($fnames as $fname) {
654
            $contents = str_replace("\r\n", PHP_EOL, file_get_contents($fname));
118297 fvs 655
            $contents = addcslashes(str_replace("\n", '\n', $contents), '"');
656
            $reqs[] = $contents;
657
            $names[] = $fname;
82190 hhl 658
          }
659
 
660
          foreach ($reqs as $key => $req)
118297 fvs 661
            $options .= '<option value="' . $key . '">' . $names[$key] . '</option>' . "\n";
84008 fvs 662
          if ($_GET['debug'] && self::in_house())
82190 hhl 663
            $debug = '<input type="hidden" name="debug" value="' . $_GET['debug'] . '">';
664
 
118297 fvs 665
          $html = str_replace('__REQS__', implode("\",\n\"", $reqs), $html);
666
          $html = str_replace('__XML__', htmlspecialchars($_REQUEST['xml']), $html);
667
          $html = str_replace('__OPTIONS__', $options, $html);
82190 hhl 668
        }
669
        else {
670
          $error = 'No example xml files found...';
671
        }
118297 fvs 672
        $html = str_replace('__ERROR__', $error, $html);
673
        $html = str_replace('__DEBUG__', $debug, $html);
674
        $html = str_replace('__HEADER_WARNING__', $header_warning, $html);
675
        $html = str_replace('__VERSION__', $this->version, $html);
82190 hhl 676
      }
677
    }
678
    echo $html;
679
  }
680
 
118297 fvs 681
  /**
682
   * @return string
683
   */
82190 hhl 684
  private function sample_form() {
118297 fvs 685
    return
686
      '<html><head>
82190 hhl 687
__HEADER_WARNING__
688
<script language="javascript">
118997 fvs 689
  function useTab() {
690
    document.f.target=(document.f.usetab.checked ? "tab" : "_blank");
691
  }
82190 hhl 692
  var reqs = Array("__REQS__");
693
</script>
694
</head><body>
695
  <form target="_blank" name="f" method="POST" accept-charset="utf-8">
696
    <textarea name="xml" rows=20 cols=90>__XML__</textarea>
697
    <br /> <br />
698
    <select name="no" onChange="if (this.selectedIndex) document.f.xml.value = reqs[this.options[this.selectedIndex].value];">
699
      <option>Pick a test-request</option>
700
      __OPTIONS__
701
    </select>
118997 fvs 702
    <input type="submit" name="subm" value="Try me"/>
703
    &nbsp; Reuse tab <input id="usetab" type="checkbox" name="usetab/" onClick="useTab()">
82190 hhl 704
    __DEBUG__
705
  </form>
706
  __INFO__
707
  __ERROR__
708
  <p style="font-size:0.6em">Version: __VERSION__</p>
709
</body></html>';
710
  }
711
 
712
}