Subversion-Projekte lars-tiefland.content-management

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
// $Id: EbatNs_Client.php 4066 2011-11-03 08:13:59Z tiefland $
3
// $Log: EbatNs_Client.php,v $
4
// Revision 1.14  2008-10-08 10:31:19  carsten
5
// changed the way the meta data is stored for schema objects. Now the information is helt in a static array (in EbatNs_ComplexType) for ALL schema classes.
6
// Beside changes in the Core and the ComplexType class this will also need a different way how the schema-information is stored within the constructors of all generated schema-classes.
7
//
8
// Revision 1.13  2008/10/02 13:54:15  carsten
9
// added batched operation via curl multi
10
//
11
// Revision 1.12  2008/09/29 13:37:04  michael
12
// added $this->_incrementApiUsage($method) to callShoppingApiStyle()
13
//
14
// Revision 1.11  2008/06/13 08:51:56  michael
15
// added method getSession()
16
//
17
// Revision 1.10  2008/06/13 06:59:17  michael
18
// fixed php5 issue
19
//
20
// Revision 1.9  2008/06/09 13:55:56  michael
21
// *** empty log message ***
22
//
23
//
24
// Revision 1.5  2008/06/05 08:22:12  michael
25
// added sandbox support for shopping api
26
//
27
// Revision 1.4  2008/05/29 07:38:11  michael
28
// - adapted correct sandbox url for shopping api
29
// - use setter for token for PHP5 version
30
//
31
// Revision 1.3  2008/05/28 16:53:18  michael
32
// fixed and moved method getErrorsToString() to Client
33
//
34
// Revision 1.2  2008/05/02 15:04:05  carsten
35
// Initial, PHP5
36
//
37
//
38
require_once 'UserIdPasswordType.php';
39
 
40
require_once 'EbatNs_RequesterCredentialType.php';
41
require_once 'EbatNs_RequestHeaderType.php';
42
require_once 'EbatNs_ResponseError.php';
43
require_once 'EbatNs_ResponseParser.php';
44
 
45
require_once 'EbatNs_DataConverter.php';
46
 
47
class EbatNs_Client
48
{
49
	// endpoint for call
50
	protected $_ep;
51
	protected $_session;
52
	protected $_currentResult;
53
	protected $_parser = null;
54
	// callback-methods/functions for data-handling
55
	protected $_hasCallbacks = false;
56
	protected $_callbacks = null;
57
	// EbatNs_DataConverter object
58
	protected $_dataConverter = null;
59
 
60
	protected $_logger = null;
61
	protected $_parserOptions = null;
62
 
63
	protected $_paginationElementCounter = 0;
64
	protected $_paginationMaxElements = -1;
65
 
66
	protected $_transportOptions = array();
67
	protected $_loggingOptions   = array();
68
	protected $_callUsage = array();
69
 
70
	//
71
	// timepoint-tracing
72
	//
73
	protected $_timePoints = null;
74
	protected $_timePointsSEQ = null;
75
 
76
	protected $_selectorModels = array();
77
	protected $_activeSelectorModel = null;
78
 
79
	/**
80
	 * Curl MultiHandle
81
	 *
82
	 * @var mixed
83
	 */
84
	protected $mh;
85
	protected $useCurlBatch = false;
86
	protected $chMultiHandles = array();
87
	protected $nextMultiIndex = 0;
88
	protected $resultMethods = array();
89
	protected $responseData = array();
90
 
91
	public function startBatchOperation()
92
	{
93
	    $this->mh = curl_multi_init();
94
	    $this->useCurlBatch = true;
95
	    $this->nextMultiIndex = 0;
96
	}
97
 
98
	public function cleanBatchOperation()
99
	{
100
	    $this->responseData = array();
101
	    $this->nextMultiIndex = 0;
102
	    $this->mh = null;
103
	}
104
 
105
	/**
106
	 * Add the given curl-handle to an internal list and returns the index we added it to
107
	 *
108
	 * @param mixed $ch
109
	 * @return number
110
	 */
111
	protected function saveCurlMultiHandle($ch)
112
	{
113
	    $this->chMultiHandles[$this->nextMultiIndex] = $ch;
114
	    $ret = $this->nextMultiIndex;
115
	    $this->nextMultiIndex++;
116
 
117
	    return $ret;
118
	}
119
 
120
	public function executeBatchOperation()
121
	{
122
	    // not using a batch-operation
123
	    if (!$this->useCurlBatch)
124
	        return null;
125
 
126
	    $this->_startTp('executeBatchOperation');
127
 
128
	    // lets execute the batch-operation
129
	    $running = null;
130
	    do {
131
	        curl_multi_exec($this->mh, $running);
132
	    } while($running > 0);
133
 
134
        foreach ($this->chMultiHandles as $id => $ch)
135
        {
136
	        $responseRaw = curl_multi_getcontent( $ch );
137
 
138
    		if ( !$responseRaw )
139
    		{
140
    			$currentResult = new EbatNs_ResponseError();
141
    			$currentResult->raise( 'curl_error ' . curl_errno( $ch ) . ' ' . curl_error( $ch ), 80000 + 1, EBAT_SEVERITY_ERROR );
142
    			$this->responseData[$id] = $currentResult;
143
    		}
144
    		else
145
    		{
146
    			$responseBody = null;
147
    			if ( preg_match( "/^(.*?)\r?\n\r?\n(.*)/s", $responseRaw, $match ) )
148
    			{
149
    				$responseBody = $match[2];
150
    				$headerLines = split( "\r?\n", $match[1] );
151
    				foreach ( $headerLines as $line )
152
    				{
153
    					if ( strpos( $line, ':' ) === false )
154
    					{
155
    						$responseHeaders[0] = $line;
156
    						continue;
157
    					}
158
    					list( $key, $value ) = split( ':', $line );
159
    					$responseHeaders[strtolower( $key )] = trim( $value );
160
    				}
161
    			}
162
    			if ($responseBody)
163
    				$this->logXml( $responseBody, 'Response' );
164
    			else
165
    				$this->logXml( $responseRaw, 'ResponseRaw' );
166
 
167
    			$this->responseData[$id] = $this->decodeMessage(
168
    			    $this->resultMethods[$id],
169
    			    $responseBody,
170
    			    EBATNS_PARSEMODE_CALL );
171
    		}
172
    		curl_multi_remove_handle($this->mh, $ch);
173
        }
174
 
175
        curl_multi_close($this->mh);
176
        $this->chMultiHandles = array();
177
        $this->resultMethods = array();
178
        $this->useCurlBatch = false;
179
 
180
        $this->_stopTp('executeBatchOperation');
181
        $this->_logTp();
182
        print_r($this->_loggingOptions);
183
 
184
        // makes sense to clean this up
185
        // so use cleanBatchOperation once the result is proceeded
186
		return $this->responseData;
187
	}
188
 
189
	function getVersion()
190
	{
191
		return EBAY_WSDL_VERSION;
192
	}
193
 
194
	function __construct($session, $converter = 'EbatNs_DataConverterIso' )
195
	{
196
		$this->_session = $session;
197
		if ($converter)
198
			$this->_dataConverter = new $converter();
199
		$this->_parser = null;
200
 
201
		$timeout = $session->getRequestTimeout();
202
		if (!$timeout)
203
			$timeout = 300;
204
		$httpCompress = $session->getUseHttpCompression();
205
 
206
		$this->setTransportOptions(
207
				array(
208
					'HTTP_TIMEOUT'  => $timeout,
209
					'HTTP_COMPRESS' => $httpCompress));
210
 
211
		if ($session->getUseStandardLogger())
212
			$this->useStandardLogger();
213
	}
214
 
215
	function useStandardLogger()
216
	{
217
		require_once 'EbatNs_Logger.php';
218
		$this->attachLogger(new EbatNs_Logger(true, 'stdout', true, true));
219
	}
220
 
221
	function resetPaginationCounter($maxElements = -1)
222
	{
223
		$this->_paginationElementCounter = 0;
224
		if ($maxElements > 0)
225
			$this->_paginationMaxElements = $maxElements;
226
		else
227
			$this->_paginationMaxElements = -1;
228
	}
229
 
230
	function incrementPaginationCounter()
231
	{
232
		$this->_paginationElementCounter++;
233
 
234
		if ($this->_paginationMaxElements > 0 && ($this->_paginationElementCounter > $this->_paginationMaxElements))
235
			return false;
236
		else
237
			return true;
238
	}
239
 
240
	function getPaginationCounter()
241
	{
242
		return $this->_paginationElementCounter;
243
	}
244
 
245
	function setParserOption($name, $value = true)
246
	{
247
		$this->_parserOptions[$name] = $value;
248
	}
249
 
250
	function log( $msg, $subject = null )
251
	{
252
		if ( $this->_logger )
253
			$this->_logger->log( $msg, $subject );
254
	}
255
 
256
	function logXml( $xmlMsg, $subject = null )
257
	{
258
		if ( $this->_logger )
259
			$this->_logger->logXml( $xmlMsg, $subject );
260
	}
261
 
262
	function attachLogger($logger)
263
	{
264
		$this->_logger = $logger;
265
	}
266
 
267
	// HTTP_TIMEOUT: default 300 s
268
	// HTTP_COMPRESS: default true
269
	function setTransportOptions($options)
270
	{
271
		$this->_transportOptions = array_merge($this->_transportOptions, $options);
272
	}
273
 
274
	// LOG_TIMEPOINTS: true/false
275
	// LOG_API_USAGE: true/false
276
	function setLoggingOptions($options)
277
	{
278
		$this->_loggingOptions = array_merge($this->_loggingOptions, $options);
279
	}
280
 
281
 
282
	protected function _getMicroseconds()
283
	{
284
		list( $ms, $s ) = explode( ' ', microtime() );
285
		return floor( $ms * 1000 ) + 1000 * $s;
286
	}
287
 
288
	protected function _getElapsed( $start )
289
	{
290
		return $this->_getMicroseconds() - $start;
291
	}
292
 
293
	protected function _startTp( $key )
294
	{
295
		if (!$this->_loggingOptions['LOG_TIMEPOINTS'])
296
			return;
297
 
298
		if ( isset( $this->_timePoints[$key] ) )
299
			$tp = $this->_timePoints[$key];
300
 
301
		$tp['start_tp'] = time();
302
 
303
		$tp['start'] = $this->_getMicroseconds();
304
		$this->_timePoints[$key] = $tp;
305
	}
306
 
307
	protected function _stopTp( $key )
308
	{
309
		if (!$this->_loggingOptions['LOG_TIMEPOINTS'])
310
			return;
311
 
312
		if ( isset( $this->_timePoints[$key]['start'] ) )
313
		{
314
			$tp = $this->_timePoints[$key];
315
			$tp['duration'] = $this->_getElapsed( $tp['start'] ) . 'ms';
316
			unset( $tp['start'] );
317
			$this->_timePoints[$key] = $tp;
318
		}
319
	}
320
 
321
	protected function _logTp()
322
	{
323
		if (!$this->_loggingOptions['LOG_TIMEPOINTS'])
324
			return;
325
 
326
		// log the timepoint-information
327
		ob_start();
328
		echo "<pre><br>\n";
329
		print_r($this->_timePoints);
330
		print_r("</pre><br>\n");
331
		$msg = ob_get_clean();
332
		$this->log($msg, '_EBATNS_TIMEPOINTS');
333
	}
334
 
335
	//
336
	// end timepoint-tracing
337
	//
338
 
339
	// callusage
340
	protected function _incrementApiUsage($apiCall)
341
	{
342
		if (!$this->_loggingOptions['LOG_API_USAGE'])
343
			return;
344
 
345
		$this->_callUsage[$apiCall] = $this->_callUsage[$apiCall] + 1;
346
	}
347
 
348
	function getApiUsage()
349
	{
350
		return $this->_callUsage;
351
	}
352
 
353
	function getParser($tns = 'urn:ebay:apis:eBLBaseComponents', $parserOptions = null, $recreate = true)
354
	{
355
		if ($recreate)
356
			$this->_parser = null;
357
 
358
		if (!$this->_parser)
359
		{
360
			if ($parserOptions)
361
				$this->_parserOptions = $parserOptions;
362
			$this->_parser = new EbatNs_ResponseParser( $this, $tns, $this->_parserOptions );
363
		}
364
		return $this->_parser;
365
	}
366
 
367
	// should return true if the data should NOT be included to the
368
	// response-object !
369
	function _handleDataType( $typeName, $value, $mapName )
370
	{
371
		if ( $this->_hasCallbacks )
372
		{
373
			if (isset($this->_callbacks[strtolower( $typeName )]))
374
				$callback = $this->_callbacks[strtolower( $typeName )];
375
			else
376
				$callback = null;
377
			if ( $callback )
378
			{
379
				if ( is_object( $callback['object'] ) )
380
				{
381
					return call_user_method( $callback['method'], $callback['object'], $typeName, & $value, $mapName, & $this );
382
				}
383
				else
384
				{
385
					return call_user_func( $callback['method'], $typeName, & $value, $mapName, & $this );
386
				}
387
			}
388
		}
389
		return false;
390
	}
391
 
392
	// $typeName as defined in Schema
393
	// $method (callback, either string or array with object/method)
394
	function setHandler( $typeName, $method )
395
	{
396
		$this->_hasCallbacks = true;
397
		if ( is_array( $method ) )
398
		{
399
			$callback['object'] = $method[0];
400
			$callback['method'] = $method[1];
401
		}
402
		else
403
		{
404
			$callback['object'] = null;
405
			$callback['method'] = $method;
406
		}
407
 
408
		$this->_callbacks[strtolower( $typeName )] = $callback;
409
	}
410
 
411
	function _makeSessionHeader()
412
	{
413
		$cred = new UserIdPasswordType();
414
		$cred->setAppId($this->_session->getAppId());
415
		$cred->setDevId($this->_session->getDevId());
416
		$cred->setAuthCert($this->_session->getCertId());
417
		if ( $this->_session->getTokenMode() == 0 )
418
		{
419
			$cred->setUsername($this->_session->getRequestUser());
420
			$cred->setPassword($this->_session->getRequestPassword());
421
		}
422
		$reqCred = new EbatNs_RequesterCredentialType();
423
		$reqCred->setCredentials($cred);
424
 
425
		if ( $this->_session->getTokenMode() == 1 )
426
		{
427
			$this->_session->ReadTokenFile();
428
			$reqCred->setEBayAuthToken($this->_session->getRequestToken());
429
		}
430
 
431
		$header = new EbatNs_RequestHeaderType();
432
		$header->setRequesterCredentials($reqCred);
433
 
434
		return $header;
435
	}
436
 
437
	function call( $method, $request, $parseMode = EBATNS_PARSEMODE_CALL )
438
	{
439
		if
440
		(
441
			$this->_activeSelectorModel
442
				&& $this->_selectorModels[$this->_activeSelectorModel][$method]
443
		)
444
		{
445
			$request->setOutputSelector
446
			(
447
				$this->_selectorModels[$this->_activeSelectorModel][$method]->getSelectorArray()
448
			);
449
		}
450
 
451
		$this->_startTp('API call ' . $method);
452
		$this->_incrementApiUsage($method);
453
 
454
		$this->_startTp('Encoding SOAP Message');
455
 
456
		$body = $this->encodeMessage( $method, $request );
457
		$header = $this->_makeSessionHeader();
458
 
459
		$message = $this->buildMessage( $body, $header );
460
 
461
		$ep = $this->_session->getApiUrl();
462
		$ep .= '?callname=' . $method;
463
		$ep .= '&siteid=' . $this->_session->getSiteId();
464
		$ep .= '&appid=' . $this->_session->getAppId();
465
		$ep .= '&version=' . $this->getVersion();
466
		$ep .= '&routing=default';
467
		$this->_ep = $ep;
468
 
469
		$this->_stopTp('Encoding SOAP Message');
470
		$this->_startTp('Sending SOAP Message');
471
 
472
		$responseMsg = $this->sendMessage( $message );
473
 
474
		$this->_stopTp('Sending SOAP Message');
475
 
476
		if ( $responseMsg )
477
		{
478
			$this->_startTp('Decoding SOAP Message');
479
			$ret = & $this->decodeMessage( $method, $responseMsg, $parseMode );
480
			$this->_stopTp('Decoding SOAP Message');
481
		}
482
		else
483
		{
484
			$ret = & $this->_currentResult;
485
		}
486
 
487
		$this->_stopTp('API call ' . $method);
488
		$this->_logTp();
489
 
490
		return $ret;
491
	}
492
 
493
	// should return a serialized XML of the outgoing message
494
	function encodeMessage( $method, $request )
495
	{
496
		return $request->serialize( $method . 'Request', $request, null, true, null, $this->_dataConverter );
497
	}
498
	// should transform the response (body) to a PHP object structure
499
	function decodeMessage( $method, $msg, $parseMode )
500
	{
501
		$this->_parser = &new EbatNs_ResponseParser( $this, 'urn:ebay:apis:eBLBaseComponents', $this->_parserOptions );
502
		return $this->_parser->decode( $method . 'Response', $msg, $parseMode );
503
	}
504
	// should generate a complete SOAP-envelope for the request
505
	function buildMessage( $body, $header )
506
	{
507
		$soap = '<?xml version="1.0" encoding="utf-8"?>';
508
		$soap .= '<soap:Envelope';
509
		$soap .= ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"';
510
		$soap .= ' xmlns:xsd="http://www.w3.org/2001/XMLSchema"';
511
		$soap .= ' xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"';
512
		$soap .= ' encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"';
513
		$soap .= ' xmlns="urn:ebay:apis:eBLBaseComponents"';
514
		$soap .= ' >';
515
 
516
		if ( $header )
517
			$soap .= $header->serialize( 'soap:Header', $header, null, true, null, null );
518
 
519
		$soap .= '<soap:Body>';
520
		$soap .= $body;
521
		$soap .= '</soap:Body>';
522
		$soap .= '</soap:Envelope>';
523
		return $soap;
524
	}
525
 
526
	// this method will generate a notification-style message body
527
	// out of a response from a call
528
	function _buildNotificationMessage($response, $simulatedMessageName, $tns, $addData = null)
529
	{
530
		if ($addData)
531
		{
532
			foreach($addData as $key => $value)
533
			{
534
				$response->{$key} = $value;
535
			}
536
		}
537
		$response->setTypeAttribute('xmlns', $tns);
538
		$msgBody = $response->serialize( $simulatedMessageName, $response, isset($response->attributeValues) ? $response->attributeValues : null, true, null, $this->_dataConverter );
539
 
540
		$soap = '<?xml version="1.0" encoding="utf-8"?>';
541
		$soap .= '<soapenv:Envelope';
542
		$soap .= ' xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"';
543
		$soap .= ' xmlns:xsd="http://www.w3.org/2001/XMLSchema"';
544
		$soap .= ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"';
545
		$soap .= '>';
546
		$soap .= '<soapenv:Header>';
547
		$soap .= '<ebl:RequesterCredentials soapenv:mustUnderstand="0" xmlns:ns="urn:ebay:apis:eBLBaseComponents" xmlns:ebl="urn:ebay:apis:eBLBaseComponents">';
548
		$soap .= '<ebl:NotificationSignature xmlns:ebl="urn:ebay:apis:eBLBaseComponents">invalid_simulation</ebl:NotificationSignature>';
549
		$soap .= '</ebl:RequesterCredentials>';
550
		$soap .= '</soapenv:Header>';
551
		$soap .= '<soapenv:Body>';
552
		$soap .= $msgBody;
553
		$soap .= '</soapenv:Body>';
554
		$soap .= '</soapenv:Envelope>';
555
 
556
		return $soap;
557
	}
558
 
559
	// should send the message to the endpoint
560
	// the result should be parsed out of the envelope and return as the plain
561
	// response-body.
562
	function sendMessage( $message )
563
	{
564
		$this->_currentResult = null;
565
 
566
		$this->log( $this->_ep, 'RequestUrl' );
567
		$this->logXml( $message, 'Request' );
568
 
569
		$timeout = $this->_transportOptions['HTTP_TIMEOUT'];
570
		if (!$timeout || $timeout <= 0)
571
			$timeout = 300;
572
 
573
		$soapaction = 'dummy';
574
 
575
		$ch = curl_init();
576
		$reqHeaders[] = 'Content-Type: text/xml;charset=utf-8';
577
		if ($this->_transportOptions['HTTP_COMPRESS'])
578
		{
579
			$reqHeaders[] = 'Accept-Encoding: gzip, deflate';
580
			curl_setopt( $ch, CURLOPT_ENCODING, "gzip");
581
			curl_setopt( $ch, CURLOPT_ENCODING, "deflate");
582
		}
583
		$reqHeaders[] = 'SOAPAction: "' . $soapaction . '"';
584
 
585
		curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false);
586
		curl_setopt( $ch, CURLOPT_HTTPHEADER, $reqHeaders );
587
		curl_setopt( $ch, CURLOPT_USERAGENT, 'ebatns;1.0' );
588
		curl_setopt( $ch, CURLOPT_TIMEOUT, $timeout );
589
		curl_setopt( $ch, CURLOPT_POSTFIELDS, $message );
590
		curl_setopt( $ch, CURLOPT_URL, $this->_ep );
591
		curl_setopt( $ch, CURLOPT_POST, 1 );
592
		curl_setopt( $ch, CURLOPT_FAILONERROR, 0 );
593
		curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, 1 );
594
		curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
595
		curl_setopt( $ch, CURLOPT_HEADER, 1 );
596
		curl_setopt( $ch, CURLOPT_HTTP_VERSION, 1 );
597
 
598
		// added support for multi-threaded clients
599
		if (isset($this->_transportOptions['HTTP_CURL_MULTITHREADED']))
600
		{
601
			curl_setopt( $ch, CURLOPT_DNS_USE_GLOBAL_CACHE, 0 );
602
			// be aware of the following:
603
			// - CURLOPT_NOSIGNAL is NOT defined in the standard-PHP cURL ext	(PHP 4.x)
604
			// so the usage need a patch and rebuild of the curl.so or "inline" PHP Version
605
			// Not using CURLOPT_NOSIGNAL might break if any signal-handlers are installed. So
606
			// the usage might be recommend but it is not must.
607
			// curl_setopt( $ch, CURLOPT_NOSIGNAL, true);
608
 
609
			// - using cURL together with OpenSSL absolutely needs the multi-threading
610
			// looking functions for OpenSSL (see http://curl.haxx.se/libcurl/c/libcurl-tutorial.html#Multi-threading)
611
			// As these callbacks are NOT implemented in PHP 4.x BUT in PHP 5.x you have to do the implementation
612
			// for your own in PHP 4.x or switch to PHP 5.x
613
		}
614
 
615
		if ($this->_transportOptions['HTTP_VERBOSE'])
616
		{
617
			curl_setopt( $ch, CURLOPT_VERBOSE, 1 );
618
			ob_start();
619
		}
620
 
621
		// if running in batched mode just add the call to the multi-handle
622
		if ($this->useCurlBatch)
623
		{
624
		   curl_multi_add_handle($this->mh, $ch);
625
		   return $this->saveCurlMultiHandle($ch);
626
		}
627
 
628
		$responseRaw = curl_exec( $ch );
629
 
630
		if ( !$responseRaw )
631
		{
632
			$this->_currentResult = new EbatNs_ResponseError();
633
			$this->_currentResult->raise( 'curl_error ' . curl_errno( $ch ) . ' ' . curl_error( $ch ), 80000 + 1, EBAT_SEVERITY_ERROR );
634
			curl_close( $ch );
635
 
636
			return null;
637
		}
638
		else
639
		{
640
			curl_close( $ch );
641
 
642
			$responseBody = null;
643
			if ( preg_match( "/^(.*?)\r?\n\r?\n(.*)/s", $responseRaw, $match ) )
644
			{
645
				$responseBody = $match[2];
646
				$headerLines = split( "\r?\n", $match[1] );
647
				foreach ( $headerLines as $line )
648
				{
649
					if ( strpos( $line, ':' ) === false )
650
					{
651
						$responseHeaders[0] = $line;
652
						continue;
653
					}
654
					list( $key, $value ) = split( ':', $line );
655
					$responseHeaders[strtolower( $key )] = trim( $value );
656
				}
657
			}
658
 
659
			if ($responseBody)
660
				$this->logXml( $responseBody, 'Response' );
661
			else
662
				$this->logXml( $responseRaw, 'ResponseRaw' );
663
		}
664
 
665
		return $responseBody;
666
	}
667
 
668
	function callShoppingApiStyle($method, $request, $parseMode = EBATNS_PARSEMODE_CALL)
669
	{
670
		if ($this->_session->getAppMode() == 1)
671
			$ep = 'http://open.api.sandbox.ebay.com/shopping';
672
		else
673
			$ep = 'http://open.api.ebay.com/shopping';
674
 
675
		$this->_incrementApiUsage($method);
676
 
677
		// place all data into theirs header
678
		$reqHeaders[] = 'X-EBAY-API-VERSION: ' . $this->getVersion();
679
		$reqHeaders[] = 'X-EBAY-API-APP-ID: ' . $this->_session->getAppId();
680
		$reqHeaders[] = 'X-EBAY-API-CALL-NAME: ' . $method;
681
		$siteId = $this->_session->getSiteId();
682
		if (empty($siteId))
683
			$reqHeaders[] = 'X-EBAY-API-SITE-ID: 0';
684
		else
685
			$reqHeaders[] = 'X-EBAY-API-SITE-ID: ' . $siteId;
686
		$reqHeaders[] = 'X-EBAY-API-REQUEST-ENCODING: XML';
687
 
688
		$body = $this->encodeMessageXmlStyle( $method, $request );
689
 
690
		$message = '<?xml version="1.0" encoding="utf-8"?>' . "\n";
691
		$message .= $body;
692
 
693
		$this->_ep = $ep;
694
 
695
		$responseMsg = $this->sendMessageShoppingApiStyle( $message, $reqHeaders );
696
 
697
		if ( $responseMsg )
698
		{
699
			$this->_startTp('Decoding SOAP Message');
700
			$ret = & $this->decodeMessage( $method, $responseMsg, $parseMode );
701
			$this->_stopTp('Decoding SOAP Message');
702
		}
703
		else
704
		{
705
			$ret = & $this->_currentResult;
706
		}
707
 
708
		return $ret;
709
	}
710
 
711
	function sendMessageShoppingApiStyleNonCurl( $message, $extraXmlHeaders )
712
	{
713
		// this is the part for systems that are not have cURL installed
714
		$transport = new EbatNs_HttpTransport();
715
		if (is_array($extraXmlHeaders))
716
			$reqHeaders = array_merge((array)$reqHeaders, $extraXmlHeaders);
717
 
718
		$responseRaw = $transport->Post($this->_ep, $message, $reqHeaders);
719
		if (!$responseRaw)
720
		{
721
			$this->_currentResult = new EbatNs_ResponseError();
722
			$this->_currentResult->raise( 'transport error (none curl) ', 90000 + 1, EBAT_SEVERITY_ERROR );
723
			return null;
724
		}
725
		else
726
		{
727
			if (isset($responseRaw['errors']))
728
			{
729
				$this->_currentResult = new EbatNs_ResponseError();
730
				$this->_currentResult->raise( 'transport error (none curl) ' . $responseRaw['errors'], 90000 + 2, EBAT_SEVERITY_ERROR );
731
				return null;
732
			}
733
 
734
			$responseBody = $responseRaw['data'];
735
			if ($responseBody)
736
				$this->logXml( $responseBody, 'Response' );
737
			else
738
				$this->logXml( $responseRaw, 'ResponseRaw' );
739
 
740
			return $responseBody;
741
		}
742
	}
743
 
744
	function sendMessageShoppingApiStyle( $message, $extraXmlHeaders )
745
	{
746
		$this->_currentResult = null;
747
 
748
		$this->log( $this->_ep, 'RequestUrl' );
749
		$this->logXml( $message, 'Request' );
750
 
751
		$timeout = $this->_transportOptions['HTTP_TIMEOUT'];
752
		if (!$timeout || $timeout <= 0)
753
			$timeout = 300;
754
 
755
		// if we have a special HttpTransport-class defined use it !
756
		if (class_exists('EbatNs_HttpTransport'))
757
			return $this->sendMessageShoppingApiStyleNonCurl($message, $extraXmlHeaders);
758
 
759
		// continue with curl support !
760
		$ch = curl_init();
761
 
762
		$reqHeaders[] = 'Content-Type: text/xml;charset=utf-8';
763
 
764
		if ($this->_transportOptions['HTTP_COMPRESS'])
765
		{
766
			$reqHeaders[] = 'Accept-Encoding: gzip, deflate';
767
			curl_setopt( $ch, CURLOPT_ENCODING, "gzip");
768
			curl_setopt( $ch, CURLOPT_ENCODING, "deflate");
769
		}
770
 
771
		if (is_array($extraXmlHeaders))
772
			$reqHeaders = array_merge((array)$reqHeaders, $extraXmlHeaders);
773
 
774
		ob_start();
775
		print_r($reqHeaders);
776
		$this->log(ob_get_clean(), 'Request headers');
777
 
778
		curl_setopt( $ch, CURLOPT_URL, $this->_ep );
779
 
780
		// curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, 0);
781
		// curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 0);
782
 
783
		curl_setopt( $ch, CURLOPT_HTTPHEADER, $reqHeaders );
784
		curl_setopt( $ch, CURLOPT_USERAGENT, 'ebatns;shapi;1.0' );
785
		curl_setopt( $ch, CURLOPT_TIMEOUT, $timeout );
786
 
787
		curl_setopt( $ch, CURLOPT_POST, 1 );
788
		curl_setopt( $ch, CURLOPT_POSTFIELDS, $message );
789
 
790
		curl_setopt( $ch, CURLOPT_FAILONERROR, 0 );
791
		curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, 1 );
792
		curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
793
		curl_setopt( $ch, CURLOPT_HEADER, 1 );
794
		curl_setopt( $ch, CURLOPT_HTTP_VERSION, 1 );
795
 
796
		// added support for multi-threaded clients
797
		if (isset($this->_transportOptions['HTTP_CURL_MULTITHREADED']))
798
		{
799
			curl_setopt( $ch, CURLOPT_DNS_USE_GLOBAL_CACHE, 0 );
800
		}
801
 
802
		$responseRaw = curl_exec( $ch );
803
 
804
		if ( !$responseRaw )
805
		{
806
			$this->_currentResult = new EbatNs_ResponseError();
807
			$this->_currentResult->raise( 'curl_error ' . curl_errno( $ch ) . ' ' . curl_error( $ch ), 80000 + 1, EBAT_SEVERITY_ERROR );
808
			curl_close( $ch );
809
 
810
			return null;
811
		}
812
		else
813
		{
814
			curl_close( $ch );
815
 
816
			$responseBody = null;
817
			if ( preg_match( "/^(.*?)\r?\n\r?\n(.*)/s", $responseRaw, $match ) )
818
			{
819
				$responseBody = $match[2];
820
				$headerLines = split( "\r?\n", $match[1] );
821
				foreach ( $headerLines as $line )
822
				{
823
					if ( strpos( $line, ':' ) === false )
824
					{
825
						$responseHeaders[0] = $line;
826
						continue;
827
					}
828
					list( $key, $value ) = split( ':', $line );
829
					$responseHeaders[strtolower( $key )] = trim( $value );
830
				}
831
			}
832
 
833
			if ($responseBody)
834
				$this->logXml( $responseBody, 'Response' );
835
			else
836
				$this->logXml( $responseRaw, 'ResponseRaw' );
837
		}
838
 
839
		return $responseBody;
840
	}
841
 
842
	function callXmlStyle( $method, $request, $parseMode = EBATNS_PARSEMODE_CALL )
843
	{
844
		// Inject the Credentials into the request here !
845
		$request->_elements['RequesterCredentials'] =
846
		    array(
847
				'required' => false,
848
				'type' => 'EbatNs_RequesterCredentialType',
849
				'nsURI' => 'urn:ebay:apis:eBLBaseComponents',
850
				'array' => false,
851
				'cardinality' => '0..1');
852
 
853
		$reqCred = new EbatNs_RequesterCredentialType();
854
		if ( $this->_session->getTokenMode() == 0 )
855
		{
856
			$cred = new UserIdPasswordType();
857
			$cred->Username = $this->_session->getRequestUser();
858
			$cred->Password = $this->_session->getRequestPassword();
859
			$reqCred->Credentials = $cred;
860
		}
861
 
862
		if ( $this->_session->getTokenMode() == 1 )
863
		{
864
			$this->_session->ReadTokenFile();
865
			$reqCred->setEBayAuthToken($this->_session->getRequestToken());
866
		}
867
 
868
		$request->RequesterCredentials = $reqCred;
869
 
870
		// we support only Sandbox and Production here !
871
		if ($this->_session->getAppMode() == 1)
872
			$ep = "https://api.sandbox.ebay.com/ws/api.dll";
873
		else
874
			$ep = 'https://api.ebay.com/ws/api.dll';
875
 
876
		// place all data into theirs header
877
		$reqHeaders[] = 'X-EBAY-API-COMPATIBILITY-LEVEL: ' . $this->getVersion();
878
		$reqHeaders[] = 'X-EBAY-API-DEV-NAME: ' . $this->_session->getDevId();
879
		$reqHeaders[] = 'X-EBAY-API-APP-NAME: ' . $this->_session->getAppId();
880
		$reqHeaders[] = 'X-EBAY-API-CERT-NAME: ' . $this->_session->getCertId();
881
		$reqHeaders[] = 'X-EBAY-API-CALL-NAME: ' . $method;
882
		$reqHeaders[] = 'X-EBAY-API-SITEID: ' . $this->_session->getSiteId();
883
 
884
		$multiPartData = null;
885
		if ($method == 'UploadSiteHostedPictures')
886
		{
887
			// assuming to have the picture-binary data
888
			// in $request->PictureData
889
			$multiPartData = $request->getPictureData();
890
			$request->setPictureData(null);
891
		}
892
 
893
		$body = $this->encodeMessageXmlStyle( $method, $request );
894
 
895
		$message = '<?xml version="1.0" encoding="utf-8"?>' . "\n";
896
		$message .= $body;
897
 
898
		$this->_ep = $ep;
899
 
900
		$responseMsg = $this->sendMessageXmlStyle( $message, $reqHeaders, $multiPartData );
901
 
902
		if ( $responseMsg )
903
		{
904
			$this->_startTp('Decoding SOAP Message');
905
			$ret = & $this->decodeMessage( $method, $responseMsg, $parseMode );
906
			$this->_stopTp('Decoding SOAP Message');
907
		}
908
		else
909
		{
910
			$ret = & $this->_currentResult;
911
		}
912
 
913
		return $ret;
914
	}
915
 
916
	// sendMessage in XmlStyle,
917
	// the only difference is the extra headers we use here
918
	function sendMessageXmlStyle( $message, $extraXmlHeaders, $multiPartImageData = null )
919
	{
920
		$this->_currentResult = null;
921
 
922
		$this->log( $this->_ep, 'RequestUrl' );
923
		$this->logXml( $message, 'Request' );
924
 
925
		$timeout = $this->_transportOptions['HTTP_TIMEOUT'];
926
		if (!$timeout || $timeout <= 0)
927
			$timeout = 300;
928
 
929
		$ch = curl_init();
930
 
931
		if ($multiPartImageData !== null)
932
		{
933
			$boundary = "MIME_boundary";
934
 
935
			$CRLF = "\r\n";
936
 
937
			$mp_message .= "--" . $boundary . $CRLF;
938
			$mp_message .= 'Content-Disposition: form-data; name="XML Payload"' . $CRLF;
939
			$mp_message .= 'Content-Type: text/xml;charset=utf-8' . $CRLF . $CRLF;
940
			$mp_message .= $message;
941
			$mp_message .= $CRLF;
942
 
943
			$mp_message .= "--" . $boundary . $CRLF;
944
			$mp_message .= 'Content-Disposition: form-data; name="dumy"; filename="dummy"' . $CRLF;
945
			$mp_message .= "Content-Transfer-Encoding: binary" . $CRLF;
946
			$mp_message .= "Content-Type: application/octet-stream" . $CRLF . $CRLF;
947
			$mp_message .= $multiPartImageData;
948
 
949
			$mp_message .= $CRLF;
950
			$mp_message .= "--" . $boundary . "--" . $CRLF;
951
 
952
			$message = $mp_message;
953
 
954
			$reqHeaders[] = 'Content-Type: multipart/form-data; boundary=' . $boundary;
955
			$reqHeaders[] = 'Content-Length: ' . strlen($message);
956
		}
957
		else
958
		{
959
			$reqHeaders[] = 'Content-Type: text/xml;charset=utf-8';
960
		}
961
 
962
 
963
		if ($this->_transportOptions['HTTP_COMPRESS'])
964
		{
965
			$reqHeaders[] = 'Accept-Encoding: gzip, deflate';
966
			curl_setopt( $ch, CURLOPT_ENCODING, "gzip");
967
			curl_setopt( $ch, CURLOPT_ENCODING, "deflate");
968
		}
969
 
970
		if (is_array($extraXmlHeaders))
971
			$reqHeaders = array_merge((array)$reqHeaders, $extraXmlHeaders);
972
 
973
		curl_setopt( $ch, CURLOPT_URL, $this->_ep );
974
 
975
		curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, 0);
976
		curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 0);
977
 
978
		curl_setopt( $ch, CURLOPT_HTTPHEADER, $reqHeaders );
979
		curl_setopt( $ch, CURLOPT_USERAGENT, 'ebatns;xmlstyle;1.0' );
980
		curl_setopt( $ch, CURLOPT_TIMEOUT, $timeout );
981
 
982
		curl_setopt( $ch, CURLOPT_POST, 1 );
983
		curl_setopt( $ch, CURLOPT_POSTFIELDS, $message );
984
 
985
		curl_setopt( $ch, CURLOPT_FAILONERROR, 0 );
986
		curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, 1 );
987
		curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
988
		curl_setopt( $ch, CURLOPT_HEADER, 1 );
989
		curl_setopt( $ch, CURLOPT_HTTP_VERSION, 1 );
990
 
991
		// added support for multi-threaded clients
992
		if (isset($this->_transportOptions['HTTP_CURL_MULTITHREADED']))
993
		{
994
			curl_setopt( $ch, CURLOPT_DNS_USE_GLOBAL_CACHE, 0 );
995
		}
996
 
997
		$responseRaw = curl_exec( $ch );
998
 
999
		if ( !$responseRaw )
1000
		{
1001
			$this->_currentResult = new EbatNs_ResponseError();
1002
			$this->_currentResult->raise( 'curl_error ' . curl_errno( $ch ) . ' ' . curl_error( $ch ), 80000 + 1, EBAT_SEVERITY_ERROR );
1003
			curl_close( $ch );
1004
 
1005
			return null;
1006
		}
1007
		else
1008
		{
1009
			curl_close( $ch );
1010
 
1011
			$responseRaw = str_replace
1012
			(
1013
				array
1014
				(
1015
					"HTTP/1.1 100 Continue\r\n\r\nHTTP/1.1 200 OK\r\n",
1016
					"HTTP/1.1 100 Continue\n\nHTTP/1.1 200 OK\n"
1017
				),
1018
				array
1019
				(
1020
					"HTTP/1.1 200 OK\r\n",
1021
					"HTTP/1.1 200 OK\n"
1022
				),
1023
				$responseRaw
1024
			);
1025
 
1026
			$responseBody = null;
1027
			if ( preg_match( "/^(.*?)\r?\n\r?\n(.*)/s", $responseRaw, $match ) )
1028
			{
1029
				$responseBody = $match[2];
1030
				$headerLines = split( "\r?\n", $match[1] );
1031
				foreach ( $headerLines as $line )
1032
				{
1033
					if ( strpos( $line, ':' ) === false )
1034
					{
1035
						$responseHeaders[0] = $line;
1036
						continue;
1037
					}
1038
					list( $key, $value ) = split( ':', $line );
1039
					$responseHeaders[strtolower( $key )] = trim( $value );
1040
				}
1041
			}
1042
 
1043
			if ($responseBody)
1044
				$this->logXml( $responseBody, 'Response' );
1045
			else
1046
				$this->logXml( $responseRaw, 'ResponseRaw' );
1047
		}
1048
 
1049
		return $responseBody;
1050
	}
1051
 
1052
	function encodeMessageXmlStyle( $method, $request )
1053
	{
1054
		return $request->serialize( $method . 'Request', $request, array('xmlns' => 'urn:ebay:apis:eBLBaseComponents'), true, null, $this->_dataConverter );
1055
	}
1056
 
1057
	public function hasDataConverter()
1058
	{
1059
	    return ($this->_dataConverter !== null);
1060
	}
1061
 
1062
	public function getDataConverter()
1063
	{
1064
	    return $this->_dataConverter;
1065
	}
1066
 
1067
    public function hasCallbacks()
1068
	{
1069
	    return $this->_hasCallbacks;
1070
	}
1071
 
1072
	/**
1073
	 * Reformats the error data in the response to a printable text or html output
1074
	 *
1075
	 * @param AbstractResponseType $response	A response returned by any of the eBay API calls
1076
	 * @param Boolean $asHtml	Flag to pass the error in htmlentities for better formating
1077
	 * @param Boolean $addSlashes	Uses addslashes to make the error-string directly insertable to a DB
1078
	 * @return string
1079
	 */
1080
	public function getErrorsToString($response, $asHtml = false, $addSlashes = true)
1081
	{
1082
		$errmsg = '';
1083
 
1084
		if (count($response->getErrors()))
1085
			foreach ($response->getErrors() as $errorEle)
1086
				$errmsg .= '#' . $errorEle->getErrorCode() . ' : ' . ($asHtml ? htmlentities($errorEle->getLongMessage()) :  $errorEle->getLongMessage()) . ($asHtml ? "<br>" : "\r\n");
1087
 
1088
		if ($addSlashes)
1089
			return addslashes($errmsg);
1090
		else
1091
			return $errmsg;
1092
	}
1093
 
1094
	public function addSelectorModel($callName, $selectorModel, $active)
1095
	{
1096
		$this->_selectorModels[$selectorModel->getName()][$callName] = $selectorModel;
1097
 
1098
		if ($active)
1099
		{
1100
			$this->setActiveSelectorModel($selectorModel->getName());
1101
		}
1102
	}
1103
 
1104
	public function setActiveSelectorModel($selectorName)
1105
	{
1106
		$this->_activeSelectorModel = $selectorName;
1107
 
1108
		foreach($this->_selectorModels as $selectorModel)
1109
		{
1110
			foreach($selectorModel as $selectorModelCall)
1111
			{
1112
				if ($selectorModelCall->getName() == $selectorName)
1113
					$selectorModelCall->setActive(true);
1114
				else
1115
					$selectorModelCall->setActive(false);
1116
			}
1117
		}
1118
	}
1119
 
1120
	public function getSession()
1121
	{
1122
		return $this->_session;
1123
	}
1124
}
1125
?>