Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
//
3
// +----------------------------------------------------------------------+
4
// | PHP Version 4                                                        |
5
// +----------------------------------------------------------------------+
6
// | Copyright (c) 1997-2003 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 at 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>   Port to PEAR and more   |
17
// | Authors: Dietrich Ayala <dietrich@ganx4.com> Original Author         |
18
// +----------------------------------------------------------------------+
19
//
20
// $Id: Base.php 696 2011-09-08 09:08:23Z tiefland $
21
//
22
 
23
/*
24
   SOAP_OBJECT_STRUCT makes pear::soap use objects for soap structures
25
   rather than arrays.  This has been done to provide a closer match to php-soap.
26
   If the old behaviour is needed, set to false.  The old behaviour is deprecated.
27
*/
28
$GLOBALS['SOAP_OBJECT_STRUCT'] = true;
29
/*
30
   SOAP_RAW_CONVERT makes pear::soap attempt to determine what SOAP type
31
   a php string COULD be.  This may result in slightly better interoperability when
32
   you are not using WSDL, and are being lazy and not using SOAP_Value to define
33
   types for your values.
34
*/
35
$GLOBALS['SOAP_RAW_CONVERT'] = false;
36
 
37
require_once 'PEAR.php';
38
require_once 'PayPal/SOAP/Type/dateTime.php';
39
require_once 'PayPal/SOAP/Type/hexBinary.php';
40
 
41
// optional features
42
$GLOBALS['SOAP_options'] = array();
43
 
44
@include_once 'Mail/mimePart.php';
45
@include_once 'Mail/mimeDecode.php';
46
if (class_exists('Mail_mimePart')) {
47
    $GLOBALS['SOAP_options']['Mime'] = 1;
48
    define('MAIL_MIMEPART_CRLF', "\r\n");
49
}
50
 
51
@include_once 'Net/DIME.php';
52
if (class_exists('Net_DIME_Message')) {
53
    $GLOBALS['SOAP_options']['DIME'] = 1;
54
}
55
 
56
/**
57
 * Enable debugging informations?
58
 *
59
 * @name   $SOAP_DEBUG
60
 * @global $GLOBALS['SOAP_DEBUG']
61
 */
62
$GLOBALS['SOAP_DEBUG'] = false;
63
 
64
if (!function_exists('version_compare') ||
65
    version_compare(phpversion(), '4.1', '<')) {
66
    die("requires PHP 4.1 or higher\n");
67
}
68
if (version_compare(phpversion(), '4.1', '>=') &&
69
    version_compare(phpversion(), '4.2', '<')) {
70
    define('FLOAT', 'double');
71
} else {
72
    define('FLOAT', 'float');
73
}
74
 
75
if (!defined('INF')) {
76
    define('INF', 1.8e307);
77
}
78
if (!defined('NAN')) {
79
    define('NAN', 0.0);
80
}
81
 
82
define('SOAP_LIBRARY_VERSION', '0.8.0RC4');
83
define('SOAP_LIBRARY_NAME',    'PEAR-SOAP 0.8.0RC4-devel');
84
 
85
// set schema version
86
define('SOAP_XML_SCHEMA_VERSION',   'http://www.w3.org/2001/XMLSchema');
87
define('SOAP_XML_SCHEMA_INSTANCE',  'http://www.w3.org/2001/XMLSchema-instance');
88
define('SOAP_XML_SCHEMA_1999',      'http://www.w3.org/1999/XMLSchema');
89
define('SOAP_SCHEMA',               'http://schemas.xmlsoap.org/wsdl/soap/');
90
define('SOAP_SCHEMA_ENCODING',      'http://schemas.xmlsoap.org/soap/encoding/');
91
define('SOAP_ENVELOP',              'http://schemas.xmlsoap.org/soap/envelope/');
92
 
93
define('SCHEMA_DISCO',              'http://schemas.xmlsoap.org/disco/');
94
define('SCHEMA_DISCO_SCL',          'http://schemas.xmlsoap.org/disco/scl/');
95
 
96
define('SCHEMA_SOAP',               'http://schemas.xmlsoap.org/wsdl/soap/');
97
define('SCHEMA_SOAP_HTTP',          'http://schemas.xmlsoap.org/soap/http');
98
define('SCHEMA_WSDL_HTTP',          'http://schemas.xmlsoap.org/wsdl/http/');
99
define('SCHEMA_MIME',               'http://schemas.xmlsoap.org/wsdl/mime/');
100
define('SCHEMA_WSDL',               'http://schemas.xmlsoap.org/wsdl/');
101
define('SCHEMA_DIME',               'http://schemas.xmlsoap.org/ws/2002/04/dime/wsdl/');
102
define('SCHEMA_CONTENT',            'http://schemas.xmlsoap.org/ws/2002/04/content-type/');
103
define('SCHEMA_REF',                'http://schemas.xmlsoap.org/ws/2002/04/reference/');
104
 
105
define('SOAP_DEFAULT_ENCODING',  'UTF-8');
106
 
107
if (!function_exists('is_a'))
108
{
109
    function is_a(&$object, $class_name)
110
    {
111
        if (strtolower(get_class($object)) == $class_name) {
112
            return true;
113
        }
114
        return is_subclass_of($object, $class_name);
115
    }
116
}
117
 
118
if (!class_exists('stdClass')) {
119
    /* PHP5 doesn't define this? */
120
    class stdClass {
121
        function __constructor() {}
122
    };
123
}
124
 
125
class SOAP_Base_Object extends PEAR
126
{
127
    /**
128
     * Store debugging information in $debug_data?
129
     *
130
     * @var  boolean if true debugging informations will be store in $debug_data
131
     * @see  $debug_data, SOAP_Base
132
     */
133
    var $_debug_flag = false;
134
 
135
    /**
136
     * String containing debugging informations if $debug_flag is set to true
137
     *
138
     * @var      string  debugging informations - mostyl error messages
139
     * @see      $debug_flag, SOAP_Base
140
     * @access   public
141
     */
142
    var $_debug_data = '';
143
 
144
    /**
145
     * supported encodings, limited by XML extension
146
     */
147
    var $_encodings = array('ISO-8859-1', 'US-ASCII', 'UTF-8');
148
 
149
    /**
150
     * Fault code
151
     *
152
     * @var  string
153
     */
154
    var $_myfaultcode = '';
155
 
156
    /**
157
     * Recent PEAR error object
158
     *
159
     * @var  object  PEAR Error
160
     */
161
    var $fault = null;
162
 
163
    /**
164
     * Constructor
165
     *
166
     * @param    string  error code
167
     * @see  $debug_data, _debug()
168
     */
169
    function SOAP_Base_Object($faultcode = 'Client')
170
    {
171
        $this->_myfaultcode = $faultcode;
172
        $this->_debug_flag = $GLOBALS['SOAP_DEBUG'];
173
        parent::PEAR('SOAP_Fault');
174
    }
175
 
176
    /**
177
     * Raise a soap error
178
     *
179
     * Please referr to the SOAP definition for an impression of what a certain parameter
180
     * stands for.
181
     *
182
     * Use $debug_flag to store errors to the member variable $debug_data
183
     *
184
     * @param    string  error message
185
     * @param    string  detailed error message.
186
     * @param    string  actor
187
     * @param    mixed
188
     * @param    mixed
189
     * @param    mixed
190
     * @param    boolean
191
     * @see      $debug_flag, $debug_data
192
     */
193
    function &_raiseSoapFault($str, $detail = '', $actorURI = '', $code = null, $mode = null, $options = null, $skipmsg = false)
194
    {
195
        // Pass through previous faults.
196
        $is_instance = isset($this);
197
        if (is_object($str)) {
198
            $fault =& $str;
199
        } else {
200
            if (!$code) {
201
                $code = $is_instance?$this->_myfaultcode:'Client';
202
            }
203
            $fault =& new SOAP_Fault($str,
204
                                     $code,
205
                                     $actorURI,
206
                                     $detail,
207
                                     $mode,
208
                                     $options);
209
        }
210
        if ($is_instance) {
211
            $this->fault =& $fault;
212
        }
213
        return $fault;
214
    }
215
 
216
    function __isfault()
217
    {
218
        return $this->fault != null;
219
    }
220
 
221
    function &__getfault()
222
    {
223
        return $this->fault;
224
    }
225
 
226
    /**
227
     * maintains a string of debug data.
228
     *
229
     * @param    debugging message - sometimes an error message
230
     */
231
    function _debug($string)
232
    {
233
        if ($this->_debug_flag) {
234
            $this->_debug_data .= get_class($this) . ': ' . preg_replace("/>/", ">\r\n", $string) . "\n";
235
        }
236
    }
237
 
238
}
239
 
240
/**
241
 * SOAP_Base
242
 * Common base class of all Soap lclasses
243
 *
244
 * @access   public
245
 * @package  SOAP::Client
246
 * @author   Shane Caraveo <shane@php.net> Conversion to PEAR and updates
247
 */
248
class SOAP_Base extends SOAP_Base_Object
249
{
250
    var $_XMLSchema = array('http://www.w3.org/2001/XMLSchema', 'http://www.w3.org/1999/XMLSchema');
251
    var $_XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
252
 
253
    // load types into typemap array
254
    var $_typemap = array(
255
        'http://www.w3.org/2001/XMLSchema' => array(
256
            'string' => 'string',
257
            'boolean' => 'boolean',
258
            'float' => FLOAT,
259
            'double' => FLOAT,
260
            'decimal' => FLOAT,
261
            'duration' => 'integer',
262
            'dateTime' => 'string',
263
            'time' => 'string',
264
            'date' => 'string',
265
            'gYearMonth' => 'integer',
266
            'gYear' => 'integer',
267
            'gMonthDay' => 'integer',
268
            'gDay' => 'integer',
269
            'gMonth' => 'integer',
270
            'hexBinary' => 'string',
271
            'base64Binary' => 'string',
272
            // derived datatypes
273
            'normalizedString' => 'string',
274
            'token' => 'string',
275
            'language' => 'string',
276
            'NMTOKEN' => 'string',
277
            'NMTOKENS' => 'string',
278
            'Name' => 'string',
279
            'NCName' => 'string',
280
            'ID' => 'string',
281
            'IDREF' => 'string',
282
            'IDREFS' => 'string',
283
            'ENTITY' => 'string',
284
            'ENTITIES' => 'string',
285
            'integer' => 'integer',
286
            'nonPositiveInteger' => 'integer',
287
            'negativeInteger' => 'integer',
288
            'long' => 'integer',
289
            'int' => 'integer',
290
            'short' => 'integer',
291
            'byte' => 'string',
292
            'nonNegativeInteger' => 'integer',
293
            'unsignedLong' => 'integer',
294
            'unsignedInt' => 'integer',
295
            'unsignedShort' => 'integer',
296
            'unsignedByte' => 'integer',
297
            'positiveInteger'  => 'integer',
298
            'anyType' => 'string',
299
            'anyURI' => 'string',
300
            'QName' => 'string'
301
        ),
302
        'http://www.w3.org/1999/XMLSchema' => array(
303
            'i4' => 'integer',
304
            'int' => 'integer',
305
            'boolean' => 'boolean',
306
            'string' => 'string',
307
            'double' => FLOAT,
308
            'float' => FLOAT,
309
            'dateTime' => 'string',
310
            'timeInstant' => 'string',
311
            'base64Binary' => 'string',
312
            'base64' => 'string',
313
            'ur-type' => 'string'
314
        ),
315
        'http://schemas.xmlsoap.org/soap/encoding/' => array(
316
            'base64' => 'string',
317
            'array' => 'array',
318
            'Array' => 'array',
319
            'Struct' => 'array')
320
        );
321
 
322
    /**
323
     * Default class name to use for decoded response objects.
324
     */
325
    var $_defaultObjectClassname = 'stdClass';
326
 
327
    // Load namespace uris into an array of uri => prefix
328
    var $_namespaces;
329
    var $_namespace;
330
 
331
    var $_xmlEntities = array('&' => '&amp;', '<' => '&lt;', '>' => '&gt;', "'" => '&apos;', '"' => '&quot;');
332
 
333
    var $_doconversion = false;
334
 
335
    var $__attachments = array();
336
 
337
    var $_wsdl = null;
338
 
339
    /**
340
     * section5
341
     *
342
     * @var  boolean  defines if we use section 5 encoding, or false if this is literal
343
     */
344
    var $_section5 = true;
345
 
346
    // handle type to class mapping
347
    var $_auto_translation = false;
348
    var $_type_translation = array();
349
 
350
    /**
351
     * Constructor
352
     *
353
     * @param    string  error code
354
     * @see  $debug_data, _debug()
355
     */
356
    function SOAP_Base($faultcode = 'Client')
357
    {
358
        parent::SOAP_Base_Object($faultcode);
359
        $this->_resetNamespaces();
360
    }
361
 
362
    function _resetNamespaces()
363
    {
364
        $this->_namespaces = array(
365
            'http://schemas.xmlsoap.org/soap/envelope/' => 'SOAP-ENV',
366
            'http://www.w3.org/2001/XMLSchema' => 'xsd',
367
            'http://www.w3.org/2001/XMLSchema-instance' => 'xsi',
368
            'http://schemas.xmlsoap.org/soap/encoding/' => 'SOAP-ENC');
369
    }
370
 
371
    /**
372
     * _setSchemaVersion
373
     *
374
     * sets the schema version used in the soap message
375
     *
376
     * @param string (see globals.php)
377
     *
378
     * @access private
379
     */
380
    function _setSchemaVersion($schemaVersion)
381
    {
382
        if (!in_array($schemaVersion, $this->_XMLSchema)) {
383
            return $this->_raiseSoapFault("unsuported XMLSchema $schemaVersion");
384
        }
385
        $this->_XMLSchemaVersion = $schemaVersion;
386
        $tmpNS = array_flip($this->_namespaces);
387
        $tmpNS['xsd'] = $this->_XMLSchemaVersion;
388
        $tmpNS['xsi'] = $this->_XMLSchemaVersion. '-instance';
389
        $this->_namespaces = array_flip($tmpNS);
390
    }
391
 
392
    function _getNamespacePrefix($ns)
393
    {
394
        if ($this->_namespace && $ns == $this->_namespace) {
395
            return '';
396
        }
397
        if (isset($this->_namespaces[$ns])) {
398
            return $this->_namespaces[$ns];
399
        }
400
        $prefix = 'ns' . count($this->_namespaces);
401
        $this->_namespaces[$ns] = $prefix;
402
        return $prefix;
403
    }
404
 
405
    function _getNamespaceForPrefix($prefix)
406
    {
407
        $flipped = array_flip($this->_namespaces);
408
        if (isset($flipped[$prefix])) {
409
            return $flipped[$prefix];
410
        }
411
        return null;
412
    }
413
 
414
    function _isSoapValue(&$value)
415
    {
416
        return is_object($value) && is_a($value, 'soap_value');
417
    }
418
 
419
    function _serializeValue(&$value, $name = '', $type = false, $elNamespace = null,
420
                             $typeNamespace = null, $options = array(), $attributes = array(), $artype = '')
421
    {
422
        $namespaces = array();
423
        $arrayType = $array_depth = $xmlout_value = null;
424
        $typePrefix = $elPrefix = $xmlout_offset = $xmlout_arrayType = $xmlout_type = $xmlns = '';
425
        $ptype = $array_type_ns = '';
426
 
427
        if (!$name || is_numeric($name)) {
428
            $name = 'item';
429
        }
430
 
431
        if ($this->_wsdl) {
432
            list($ptype, $arrayType, $array_type_ns, $array_depth)
433
                = $this->_wsdl->getSchemaType($type, $name, $typeNamespace);
434
        }
435
 
436
        if (!$arrayType) {
437
            $arrayType = $artype;
438
        }
439
        if (!$ptype) {
440
            $ptype = $this->_getType($value);
441
        }
442
        if (!$type) {
443
            $type = $ptype;
444
        }
445
 
446
        if (strcasecmp($ptype, 'Struct') == 0 || strcasecmp($type, 'Struct') == 0) {
447
            // struct
448
            $vars = null;
449
            if (is_object($value)) {
450
                $vars = get_object_vars($value);
451
            } else {
452
                $vars = &$value;
453
            }
454
            if (is_array($vars)) {
455
                foreach (array_keys($vars) as $k) {
456
                    // Hide private vars.
457
                    if ($k[0] == '_') continue;
458
                    if (is_object($vars[$k])) {
459
                        if (is_a($vars[$k], 'soap_value')) {
460
                            $xmlout_value .= $vars[$k]->serialize($this);
461
                        } else {
462
                            // XXX get the members and serialize them instead
463
                            // converting to an array is more overhead than we
464
                            // should really do.
465
                            $dvar = get_object_vars($vars[$k]);
466
                            $xmlout_value .= $this->_serializeValue( $dvar, $k, false, $this->_section5 ? null : $elNamespace);
467
                        }
468
                    } else {
469
                        $xmlout_value .= $this->_serializeValue($vars[$k], $k, false, $this->_section5 ? null : $elNamespace);
470
                    }
471
                }
472
            }
473
        } elseif (strcasecmp($ptype, 'Array') == 0 || strcasecmp($type, 'Array') == 0) {
474
            // Array.
475
            $typeNamespace = SOAP_SCHEMA_ENCODING;
476
            $orig_type = $type;
477
            $type = 'Array';
478
            $numtypes = 0;
479
            // XXX this will be slow on larger arrays. Basically, it
480
            // flattens arrays to allow us to serialize
481
            // multi-dimensional arrays. We only do this if arrayType
482
            // is set, which will typically only happen if we are
483
            // using WSDL
484
            if (isset($options['flatten']) || ($arrayType && (strchr($arrayType, ',') || strstr($arrayType, '][')))) {
485
                $numtypes = $this->_multiArrayType($value, $arrayType, $ar_size, $xmlout_value);
486
            }
487
 
488
            $array_type = $array_type_prefix = '';
489
            if ($numtypes != 1) {
490
                $arrayTypeQName =& new QName($arrayType);
491
                $arrayType = $arrayTypeQName->name;
492
                $array_types = array();
493
                $array_val = null;
494
 
495
                // Serialize each array element.
496
                $ar_size = count($value);
497
                foreach ($value as $array_val) {
498
                    if ($this->_isSoapValue($array_val)) {
499
                        $array_type = $array_val->type;
500
                        $array_types[$array_type] = 1;
501
                        $array_type_ns = $array_val->type_namespace;
502
                        $xmlout_value .= $this->_serializeValue($array_val, $array_val->name, $array_type, $array_type_ns);
503
                    } else {
504
                        $array_type = $this->_getType($array_val);
505
                        $array_types[$array_type] = 1;
506
                        $xmlout_value .= $this->_serializeValue($array_val, 'item', $array_type, $this->_section5 ? null : $elNamespace);
507
                    }
508
                }
509
 
510
                $xmlout_offset = " SOAP-ENC:offset=\"[0]\"";
511
                if (!$arrayType) {
512
                    $numtypes = count($array_types);
513
                    if ($numtypes == 1) {
514
                        $arrayType = $array_type;
515
                    }
516
                    // Using anyType is more interoperable.
517
                    if ($array_type == 'Struct') {
518
                        $array_type = '';
519
                    } elseif ($array_type == 'Array') {
520
                        $arrayType = 'anyType';
521
                        $array_type_prefix = 'xsd';
522
                    } else {
523
                        if (!$arrayType) {
524
                            $arrayType = $array_type;
525
                        }
526
                    }
527
                }
528
            }
529
            if (!$arrayType || $numtypes > 1) {
530
                $arrayType = 'xsd:anyType'; // should reference what schema we're using
531
            } else {
532
                if ($array_type_ns) {
533
                    $array_type_prefix = $this->_getNamespacePrefix($array_type_ns);
534
                } elseif (isset($this->_typemap[$this->_XMLSchemaVersion][$arrayType])) {
535
                    $array_type_prefix = $this->_namespaces[$this->_XMLSchemaVersion];
536
                }
537
                if ($array_type_prefix)
538
                    $arrayType = $array_type_prefix. ':' .$arrayType;
539
            }
540
 
541
            $xmlout_arrayType = " SOAP-ENC:arrayType=\"" . $arrayType;
542
            if ($array_depth != null) {
543
                for ($i = 0; $i < $array_depth; $i++) {
544
                    $xmlout_arrayType .= '[]';
545
                }
546
            }
547
            $xmlout_arrayType .= "[$ar_size]\"";
548
        } elseif ($this->_isSoapValue($value)) {
549
            $xmlout_value =& $value->serialize($this);
550
        } elseif ($type == 'string') {
551
            $xmlout_value = htmlspecialchars($value);
552
        } elseif ($type == 'rawstring') {
553
            $xmlout_value =& $value;
554
        } elseif ($type == 'boolean') {
555
            $xmlout_value = $value?'true':'false';
556
        } else {
557
            $xmlout_value =& $value;
558
        }
559
 
560
        // Add namespaces.
561
        if ($elNamespace) {
562
            $elPrefix = $this->_getNamespacePrefix($elNamespace);
563
            if ($elPrefix) {
564
                $xmlout_name = "$elPrefix:$name";
565
            } else {
566
                $xmlout_name = $name;
567
            }
568
        } else {
569
            $xmlout_name = $name;
570
        }
571
 
572
        if ($typeNamespace) {
573
            $typePrefix = $this->_getNamespacePrefix($typeNamespace);
574
            if ($typePrefix) {
575
                $xmlout_type = "$typePrefix:$type";
576
            } else {
577
                $xmlout_type = $type;
578
            }
579
        } elseif ($type && isset($this->_typemap[$this->_XMLSchemaVersion][$type])) {
580
            $typePrefix = $this->_namespaces[$this->_XMLSchemaVersion];
581
            if ($typePrefix) {
582
                $xmlout_type = "$typePrefix:$type";
583
            } else {
584
                $xmlout_type = $type;
585
            }
586
        }
587
 
588
        // Handle additional attributes.
589
        $xml_attr = '';
590
        if (count($attributes)) {
591
            foreach ($attributes as $k => $v) {
592
                $kqn =& new QName($k);
593
                $vqn =& new QName($v);
594
                $xml_attr .= ' ' . $kqn->fqn() . '="' . $vqn->fqn() . '"';
595
            }
596
        }
597
 
598
        // Store the attachement for mime encoding.
599
        if (isset($options['attachment'])) {
600
            $this->__attachments[] = $options['attachment'];
601
        }
602
 
603
        if ($this->_section5) {
604
            if ($xmlout_type) {
605
                $xmlout_type = " xsi:type=\"$xmlout_type\"";
606
            }
607
            if (is_null($xmlout_value)) {
608
                $xml = "\r\n<$xmlout_name$xmlout_type$xmlns$xmlout_arrayType$xml_attr xsi:nil=\"true\"/>";
609
            } else {
610
                $xml = "\r\n<$xmlout_name$xmlout_type$xmlns$xmlout_arrayType$xmlout_offset$xml_attr>" .
611
                    $xmlout_value . "</$xmlout_name>";
612
            }
613
        } else {
614
            if (is_null($xmlout_value)) {
615
                $xml = "\r\n<$xmlout_name$xmlns$xml_attr/>";
616
            } else {
617
                $xml = "\r\n<$xmlout_name$xmlns$xml_attr>" .
618
                    $xmlout_value . "</$xmlout_name>";
619
            }
620
        }
621
 
622
        return $xml;
623
    }
624
 
625
    /**
626
     * SOAP::Value::_getType
627
     *
628
     * Convert a php type to a soap type.
629
     *
630
     * @param string &$value  The value to inspect.
631
     *
632
     * @return string  Soap type.
633
     *
634
     * @access   private
635
     */
636
    function _getType(&$value)
637
    {
638
        global $SOAP_OBJECT_STRUCT, $SOAP_RAW_CONVERT;
639
        $type = gettype($value);
640
        switch ($type) {
641
        case 'object':
642
            if (is_a($value, 'soap_value')) {
643
                $type = $value->type;
644
            } else {
645
                $type = 'Struct';
646
            }
647
            break;
648
 
649
        case 'array':
650
            // XXX hashes always get done as structs by pear::soap
651
            if ($this->_isHash($value)) {
652
                $type = 'Struct';
653
            } else {
654
                $ar_size = count($value);
655
                reset($value);
656
                $key1 = key($value);
657
                if ($ar_size > 0 && is_a($key1, 'soap_value')) {
658
                    // fixme for non-wsdl structs that are all the same type
659
                    $key2 = key($value);
660
                    if ($ar_size > 1 &&
661
                        $this->_isSoapValue($key1) &&
662
                        $this->_isSoapValue($key2) &&
663
                        $key1->name != $key2->name) {
664
                        // this is a struct, not an array
665
                        $type = 'Struct';
666
                    } else {
667
                        $type = 'Array';
668
                    }
669
                } else {
670
                    $type = 'Array';
671
                }
672
            }
673
            break;
674
 
675
        case 'integer':
676
        case 'long':
677
            $type = 'int';
678
            break;
679
 
680
        case 'boolean':
681
            break;
682
 
683
        case 'double':
684
            $type = 'float'; // double is deprecated in 4.2 and later
685
            break;
686
 
687
        case 'null':
688
            $type = '';
689
            break;
690
 
691
        case 'string':
692
            if ($SOAP_RAW_CONVERT) {
693
                if (is_numeric($value)) {
694
                    if (strstr($value, '.')) {
695
                        $type = 'float';
696
                    } else {
697
                        $type = 'int';
698
                    }
699
                } else {
700
                    if (SOAP_Type_hexBinary::is_hexbin($value)) {
701
                        $type = 'hexBinary';
702
                    } else {
703
                        if ($this->_isBase64($value)) {
704
                            $type = 'base64Binary';
705
                        } else {
706
                            $dt =& new SOAP_Type_dateTime($value);
707
                            if ($dt->toUnixtime() != -1) {
708
                                $type = 'dateTime';
709
                            }
710
                        }
711
                    }
712
                }
713
            }
714
            break;
715
 
716
        default:
717
            break;
718
        }
719
 
720
        return $type;
721
    }
722
 
723
    function _multiArrayType(&$value, &$type, &$size, &$xml)
724
    {
725
        $sz = count($value);
726
        if (is_array($value)) {
727
            // Seems we have a multi dimensional array, figure it out
728
            // if we do.
729
            $c = count($value);
730
            for ($i = 0; $i < $c; $i++) {
731
                $this->_multiArrayType($value[$i], $type, $size, $xml);
732
            }
733
 
734
            if ($size) {
735
                $size = $sz. ',' . $size;
736
            } else {
737
                $size = $sz;
738
            }
739
            return 1;
740
        } else {
741
            if (is_object($value)) {
742
                $type = $value->type;
743
                $xml .= $value->serialize($this);
744
            } else {
745
                $type = $this->_getType($value);
746
                $xml .= $this->_serializeValue($value, 'item', $type);
747
            }
748
        }
749
        $size = null;
750
        return 1;
751
    }
752
 
753
    /**
754
     *
755
     * @param    string
756
     * @return   boolean
757
     */
758
    function _isBase64(&$value)
759
    {
760
        $l = strlen($value);
761
        if ($l) {
762
            return $value[$l - 1] == '=' && preg_match("/[A-Za-z=\/\+]+/", $value);
763
        }
764
        return false;
765
    }
766
 
767
    /**
768
     *
769
     * @param    string
770
     * @return   boolean
771
     */
772
    function _isBase64Type($type)
773
    {
774
        return $type == 'base64' || $type == 'base64Binary';
775
    }
776
 
777
    /**
778
     *
779
     * @param    mixed
780
     * @return   boolean
781
     */
782
    function _isHash(&$a)
783
    {
784
        // XXX I really dislike having to loop through this in PHP
785
        // code, really large arrays will be slow.  We need a C
786
        // function to do this.
787
        $names = array();
788
        $it = 0;
789
        foreach ($a as $k => $v) {
790
            // Checking the type is faster than regexp.
791
            $t = gettype($k);
792
            if ($t != 'integer') {
793
                return true;
794
            } elseif ($this->_isSoapValue($v)) {
795
                $names[$v->name] = 1;
796
            }
797
            // If someone has a large hash they should realy be
798
            // defining the type.
799
            if ($it++ > 10) {
800
                return false;
801
            }
802
        }
803
        return count($names)>1;
804
    }
805
 
806
    function &_un_htmlentities($string)
807
    {
808
        $trans_tbl = get_html_translation_table(HTML_ENTITIES);
809
        $trans_tbl = array_flip($trans_tbl);
810
        return strtr($string, $trans_tbl);
811
    }
812
 
813
    /**
814
     *
815
     * @param    mixed
816
     */
817
    function &_decode(&$soapval)
818
    {
819
        global $SOAP_OBJECT_STRUCT;
820
        if (!$this->_isSoapValue($soapval)) {
821
            return $soapval;
822
        } elseif (is_array($soapval->value)) {
823
            if ($SOAP_OBJECT_STRUCT && $soapval->type != 'Array') {
824
                $classname = $this->_defaultObjectClassname;
825
                if (isset($this->_type_translation[$soapval->tqn->fqn()])) {
826
                    // This will force an error in php if the class
827
                    // does not exist.
828
                    $classname = $this->_type_translation[$soapval->tqn->fqn()];
829
                } elseif (isset($this->_type_translation[$soapval->type])) {
830
                    // This will force an error in php if the class
831
                    // does not exist.
832
                    $classname = $this->_type_translation[$soapval->type];
833
                } elseif ($this->_auto_translation) {
834
                    if (class_exists($soapval->type)) {
835
                        $classname = $soapval->type;
836
                    } elseif ($this->_wsdl) {
837
                        $t = $this->_wsdl->getComplexTypeNameForElement($soapval->name, $soapval->namespace);
838
                        if ($t && class_exists($t)) {
839
                            $classname = $t;
840
                        }
841
                    }
842
                }
843
                $return =& new $classname;
844
            } else {
845
                $return = array();
846
            }
847
 
848
            $counter = 1;
849
            $isstruct = !$SOAP_OBJECT_STRUCT || !is_array($return);
850
            foreach ($soapval->value as $item) {
851
                if (is_object($return)) {
852
                    if ($this->_wsdl) {
853
                        // Get this child's WSDL information.
854
                        // /$soapval->ns/$soapval->type/$item->ns/$item->name
855
                        $child_type = $this->_wsdl->getComplexTypeChildType(
856
                                          $soapval->namespace,
857
                                          $soapval->name,
858
                                          $item->namespace,
859
                                          $item->name);
860
                        if ($child_type) {
861
                            $item->type = $child_type;
862
                        }
863
                    }
864
                    if (!$isstruct || $item->type == 'Array') {
865
                        if (isset($return->{$item->name}) &&
866
                            is_object($return->{$item->name})) {
867
                            $return->{$item->name} =& $this->_decode($item);
868
                        } elseif (isset($return->{$item->name}) &&
869
                                  is_array($return->{$item->name})) {
870
                            $return->{$item->name}[] =& $this->_decode($item);
871
                        } elseif (is_array($return)) {
872
                            $return[] =& $this->_decode($item);
873
                        } else {
874
                            $return->{$item->name} =& $this->_decode($item);
875
                        }
876
                    } elseif (isset($return->{$item->name})) {
877
                        $isstruct = false;
878
                        if (count(get_object_vars($return)) == 1) {
879
                            $d =& $this->_decode($item);
880
                            $return = array($return->{$item->name}, $d);
881
                        } else {
882
                            $d =& $this->_decode($item);
883
                            $return->{$item->name} = array($return->{$item->name}, $d);
884
                        }
885
                    } else {
886
                        $return->{$item->name} =& $this->_decode($item);
887
                    }
888
                    // Set the attributes as members in the class.
889
                    if (method_exists($return, '__set_attribute')) {
890
                        foreach ($soapval->attributes as $key => $value) {
891
                            call_user_func_array(array(&$return, '__set_attribute'), array($key, $value));
892
                        }
893
                    }
894
                } else {
895
                    if ($soapval->arrayType && $this->_isSoapValue($item)) {
896
                        if ($this->_isBase64Type($item->type) && !$this->_isBase64Type($soapval->arrayType)) {
897
                            // Decode the value if we're losing the
898
                            // base64 type information.
899
                            $item->value = base64_decode($item->value);
900
                        }
901
                        $item->type = $soapval->arrayType;
902
                    }
903
                    if (!$isstruct) {
904
                        $return[] =& $this->_decode($item);
905
                    } elseif (isset($return[$item->name])) {
906
                        $isstruct = false;
907
                        $d =& $this->_decode($item);
908
                        $return = array($return[$item->name], $d);
909
                    } else {
910
                        $return[$item->name] =& $this->_decode($item);
911
                    }
912
                }
913
            }
914
            return $return;
915
        }
916
 
917
        if ($soapval->type == 'boolean') {
918
            if ($soapval->value != '0' && strcasecmp($soapval->value, 'false') != 0) {
919
                $soapval->value = true;
920
            } else {
921
                $soapval->value = false;
922
            }
923
        } elseif ($soapval->type && isset($this->_typemap[SOAP_XML_SCHEMA_VERSION][$soapval->type])) {
924
            // If we can, set variable type.
925
            settype($soapval->value, $this->_typemap[SOAP_XML_SCHEMA_VERSION][$soapval->type]);
926
        }
927
 
928
        if ($this->_isBase64Type($soapval->type)) {
929
            return base64_decode($soapval->value);
930
        } else {
931
            return $soapval->value;
932
        }
933
    }
934
 
935
    /**
936
     * Creates the soap envelope with the soap envelop data.
937
     *
938
     * @param string $payload       soap data (in xml)
939
     * @return associative array (headers,body)
940
     * @access private
941
     */
942
    function &_makeEnvelope(&$method, &$headers, $encoding = SOAP_DEFAULT_ENCODING, $options = array())
943
    {
944
        $smsg = $header_xml = $ns_string = '';
945
 
946
        if ($headers) {
947
            $c = count($headers);
948
            for ($i = 0; $i < $c; $i++) {
949
                $header_xml .= $headers[$i]->serialize($this);
950
            }
951
            $header_xml = "<SOAP-ENV:Header>\r\n$header_xml\r\n</SOAP-ENV:Header>\r\n";
952
        }
953
 
954
        if (!isset($options['input']) || $options['input'] == 'parse') {
955
            if (is_array($method)) {
956
                $c = count($method);
957
                for ($i = 0; $i < $c; $i++) {
958
                    $smsg .= $method[$i]->serialize($this);
959
                }
960
            } else {
961
                $smsg =& $method->serialize($this);
962
            }
963
        } else {
964
            $smsg =& $method;
965
        }
966
        $body = "<SOAP-ENV:Body>\r\n" . $smsg . "\r\n</SOAP-ENV:Body>\r\n";
967
 
968
        foreach ($this->_namespaces as $k => $v) {
969
            $ns_string .= " xmlns:$v=\"$k\"\r\n";
970
        }
971
        if ($this->_namespace) {
972
            $ns_string .= " xmlns=\"{$this->_namespace}\"\r\n";
973
        }
974
 
975
        /* if use='literal', we do not put in the encodingStyle.  This is denoted by
976
           $this->_section5 being false.
977
           XXX use can be defined at a more granular level than we are dealing with
978
           here, so this does not work for all services.
979
        */
980
        $xml = "<?xml version=\"1.0\" encoding=\"$encoding\"?>\r\n\r\n".
981
            "<SOAP-ENV:Envelope $ns_string".
982
            ($this->_section5 ? ' SOAP-ENV:encodingStyle="' . SOAP_SCHEMA_ENCODING . '"' : '').
983
            ">\r\n".
984
            "$header_xml$body</SOAP-ENV:Envelope>\r\n";
985
 
986
        return $xml;
987
    }
988
 
989
    function &_makeMimeMessage(&$xml, $encoding = SOAP_DEFAULT_ENCODING)
990
    {
991
        global $SOAP_options;
992
 
993
        if (!isset($SOAP_options['Mime'])) {
994
            return $this->_raiseSoapFault('Mime is not installed');
995
        }
996
 
997
        // encode any attachments
998
        // see http://www.w3.org/TR/SOAP-attachments
999
        // now we have to mime encode the message
1000
        $params = array('content_type' => 'multipart/related; type=text/xml');
1001
        $msg =& new Mail_mimePart('', $params);
1002
        // add the xml part
1003
        $params['content_type'] = 'text/xml';
1004
        $params['charset'] = $encoding;
1005
        $params['encoding'] = 'base64';
1006
        $msg->addSubPart($xml, $params);
1007
 
1008
        // add the attachements
1009
        $c = count($this->__attachments);
1010
        for ($i = 0; $i < $c; $i++) {
1011
            $attachment =& $this->__attachments[$i];
1012
            $msg->addSubPart($attachment['body'], $attachment);
1013
        }
1014
        return $msg->encode();
1015
    }
1016
 
1017
    // XXX this needs to be used from the Transport system
1018
    function &_makeDIMEMessage(&$xml)
1019
    {
1020
        global $SOAP_options;
1021
 
1022
        if (!isset($SOAP_options['DIME'])) {
1023
            return $this->_raiseSoapFault('DIME is not installed');
1024
        }
1025
 
1026
        // encode any attachments
1027
        // see http://search.ietf.org/internet-drafts/draft-nielsen-dime-soap-00.txt
1028
        // now we have to DIME encode the message
1029
        $dime =& new Net_DIME_Message();
1030
        $msg =& $dime->encodeData($xml,SOAP_ENVELOP,null,NET_DIME_TYPE_URI);
1031
 
1032
        // add the attachements
1033
        $c = count($this->__attachments);
1034
        for ($i = 0; $i < $c; $i++) {
1035
            $attachment =& $this->__attachments[$i];
1036
            $msg .= $dime->encodeData($attachment['body'], $attachment['content_type'], $attachment['cid'],NET_DIME_TYPE_MEDIA);
1037
        }
1038
        $msg .= $dime->endMessage();
1039
        return $msg;
1040
    }
1041
 
1042
    function _decodeMimeMessage(&$data, &$headers, &$attachments)
1043
    {
1044
        global $SOAP_options;
1045
        if (!isset($SOAP_options['Mime'])) {
1046
            $this->_raiseSoapFault('Mime Unsupported, install PEAR::Mail::Mime', '', '', 'Server');
1047
            return;
1048
        }
1049
 
1050
        $params['include_bodies'] = true;
1051
        $params['decode_bodies']  = true;
1052
        $params['decode_headers'] = true;
1053
 
1054
        // XXX lame thing to have to do for decoding
1055
        $decoder =& new Mail_mimeDecode($data);
1056
        $structure = $decoder->decode($params);
1057
 
1058
        if (isset($structure->body)) {
1059
            $data = $structure->body;
1060
            $headers = $structure->headers;
1061
            return;
1062
        } elseif (isset($structure->parts)) {
1063
            $data = $structure->parts[0]->body;
1064
            $headers = array_merge($structure->headers, $structure->parts[0]->headers);
1065
            if (count($structure->parts) > 1) {
1066
                $mime_parts = array_splice($structure->parts,1);
1067
                // prepare the parts for the soap parser
1068
 
1069
                $c = count($mime_parts);
1070
                for ($i = 0; $i < $c; $i++) {
1071
                    $p =& $mime_parts[$i];
1072
                    if (isset($p->headers['content-location'])) {
1073
                        // XXX TODO: modify location per SwA note section 3
1074
                        // http://www.w3.org/TR/SOAP-attachments
1075
                        $attachments[$p->headers['content-location']] = $p->body;
1076
                    } else {
1077
                        $cid = 'cid:' . substr($p->headers['content-id'], 1, strlen($p->headers['content-id']) - 2);
1078
                        $attachments[$cid] = $p->body;
1079
                    }
1080
                }
1081
            }
1082
            return;
1083
        }
1084
        $this->_raiseSoapFault('Mime parsing error', '', '', 'Server');
1085
    }
1086
 
1087
    function _decodeDIMEMessage(&$data, &$headers, &$attachments)
1088
    {
1089
        global $SOAP_options;
1090
        if (!isset($SOAP_options['DIME'])) {
1091
            $this->_raiseSoapFault('DIME Unsupported, install PEAR::Net::DIME', '', '', 'Server');
1092
            return;
1093
        }
1094
 
1095
        // XXX this SHOULD be moved to the transport layer, e.g. PHP itself
1096
        // should handle parsing DIME ;)
1097
        $dime =& new Net_DIME_Message();
1098
        $err = $dime->decodeData($data);
1099
        if (PEAR::isError($err)) {
1100
            $this->_raiseSoapFault('Failed to decode the DIME message!', '', '', 'Server');
1101
            return;
1102
        }
1103
        if (strcasecmp($dime->parts[0]['type'], SOAP_ENVELOP) != 0) {
1104
            $this->_raiseSoapFault('DIME record 1 is not a SOAP envelop!', '', '', 'Server');
1105
            return;
1106
        }
1107
 
1108
        $data = $dime->parts[0]['data'];
1109
        // fake it for now
1110
        $headers['content-type'] = 'text/xml';
1111
        $c = count($dime->parts);
1112
        for ($i = 0; $i < $c; $i++) {
1113
            $part =& $dime->parts[$i];
1114
            // XXX we need to handle URI's better.
1115
            $id = strncmp($part['id'], 'cid:', 4) ? 'cid:' . $part['id'] : $part['id'];
1116
            $attachments[$id] = $part['data'];
1117
        }
1118
    }
1119
 
1120
    function __set_type_translation($type, $class = null)
1121
    {
1122
        $tq =& new QName($type);
1123
        if (!$class) {
1124
            $class = $tq->name;
1125
        }
1126
        $this->_type_translation[$type]=$class;
1127
    }
1128
 
1129
}
1130
 
1131
/**
1132
 * Class used to handle QNAME values in XML.
1133
 *
1134
 * @access   public
1135
 * @package  SOAP::Client
1136
 * @author   Shane Caraveo <shane@php.net> Conversion to PEAR and updates
1137
 */
1138
class QName
1139
{
1140
    var $name = '';
1141
    var $ns = '';
1142
    var $namespace='';
1143
 
1144
    function QName($name, $namespace = '')
1145
    {
1146
        if ($name && $name[0] == '{') {
1147
            preg_match('/\{(.*?)\}(.*)/', $name, $m);
1148
            $this->name = $m[2];
1149
            $this->namespace = $m[1];
1150
        } elseif (substr_count($name, ':') == 1) {
1151
            $s = explode(':', $name);
1152
            $s = array_reverse($s);
1153
            $this->name = $s[0];
1154
            $this->ns = $s[1];
1155
            $this->namespace = $namespace;
1156
        } else {
1157
            $this->name = $name;
1158
            $this->namespace = $namespace;
1159
        }
1160
 
1161
        // a little more magic than should be in a qname.
1162
        $p = strpos($this->name, '[');
1163
        if ($p) {
1164
            // XXX need to re-examine this logic later
1165
            // chop off []
1166
            $this->arraySize = explode(',', substr($this->name, $p + 1, strlen($this->name) - $p - 2));
1167
            $this->arrayInfo = substr($this->name, $p);
1168
            $this->name = substr($this->name, 0, $p);
1169
        }
1170
    }
1171
 
1172
    function fqn()
1173
    {
1174
        if ($this->namespace) {
1175
            return '{' . $this->namespace . '}' . $this->name;
1176
        } elseif ($this->ns) {
1177
            return $this->ns . ':' . $this->name;
1178
        }
1179
        return $this->name;
1180
    }
1181
 
1182
}