1: <?php
2:
3: namespace tschiemer\Aspsms\Soap;
4: use \tschiemer\Aspsms as Aspsms;
5:
6: if ( ! class_exists('\SoapClient'))
7: {
8: throw new \Exception('SOAP extension required for Aspsms\SoapClient');
9: }
10:
11: /**
12: * SOAP driver / interface.
13: *
14: * @version 1.1.0
15: * @package aspsms
16: * @license LGPL v3 http://www.gnu.org/licenses/lgpl-3.0.txt
17: * @copyright 2013 Philip Tschiemer, <tschiemer@filou.se>
18: * @link https://github.com/tschiemer/aspsms-php
19: */
20: class SoapClient extends Aspsms\AbstractClient
21: {
22: /**
23: * Default WSDL source
24: *
25: * @var string
26: */
27: var $wsdl = 'https://webservice.aspsms.com/aspsmsx2.asmx?WSDL';
28:
29: /**
30: * @var \SoapClient
31: */
32: var $soap;
33:
34: /**
35: * List or default SOAP options
36: *
37: * @var array
38: */
39: var $soapOpt = array(
40: // 'cache_wsdl' => WSDL_CACHE_NONE,
41: 'user_agent' => 'aspsms-php v1 soap:1'
42: );
43:
44: /**
45: * Request configuration
46: *
47: * Foreach request:
48: * 'service' := actual service name to use
49: * 'param' := list of fields and default settings to use
50: *
51: * @var array[]
52: */
53: var $requests = array(
54: 'getVersion' => array(
55: 'service' => 'VersionInfo'
56: ),
57: 'getCredits' => array(
58: 'service' => 'CheckCredits',
59: 'param' => array(
60: 'UserKey' => '',
61: 'Password' => ''
62: )),
63: 'getStatusCodeDescription' => array(
64: 'service' => 'GetStatusCodeDescription',
65: 'param' => array(
66: 'StatusCode' => ''
67: )),
68:
69: 'sendText' => array(
70: 'service' => 'SendUnicodeSMS',
71: 'param' => array(
72: 'UserKey' => '',
73: 'Password' => '',
74: 'Recipients'=> '',
75: 'Originator'=> '',
76: 'MessageText' => '',
77: 'DeferredDeliveryTime' => '',
78: 'FlashingSMS'=> '',
79: 'TimeZone' => '',
80: 'URLBufferedMessageNotification' => '',
81: 'URLDeliveryNotification' => '',
82: 'URLNonDeliveryNotification' => '',
83: 'AffiliateId' => ''
84: )),
85: 'sendWapPush' => array(
86: 'service' => 'SimpleWAPPush',
87: 'param' => array(
88: 'UserKey' => '',
89: 'Password' => '',
90: 'Recipients'=> '',
91: 'Originator'=> '',
92: 'WapDescription' => '',
93: 'WapURL' => '',
94: 'DeferredDeliveryTime' => '',
95: 'FlashingSMS'=> '',
96: 'TimeZone' => '',
97: 'URLBufferedMessageNotification' => '',
98: 'URLDeliveryNotification' => '',
99: 'URLNonDeliveryNotification' => '',
100: 'AffiliateId' => ''
101: )),
102: 'sendToken' => array(
103: 'service' => 'SendTokenSMS',
104: 'param' => array(
105: 'UserKey' => '',
106: 'Password' => '',
107: 'Recipients'=> '',
108: 'Originator'=> '',
109: 'MessageData'=>'',
110: 'TokenReference'=>'',
111: 'TokenValidity'=>'5',
112: 'TokenMask' => '',
113: 'VerificationCode' => '',
114: 'TokenCaseSensitive' => '0',
115: 'URLBufferedMessageNotification' => '',
116: 'URLDeliveryNotification' => '',
117: 'URLNonDeliveryNotification' => '',
118: 'AffiliateId' => ''
119: )),
120: 'verifyToken' => array(
121: 'service' => 'VerifyToken',
122: 'param' => array(
123: 'UserKey' => '',
124: 'Password' => '',
125: 'PhoneNumber'=> '',
126: 'TokenReference'=>'',
127: 'VerificationCode' => '',
128: )),
129:
130: 'getDeliveryStatus' => array(
131: 'service' => 'InquireDeliveryNotifications',
132: 'param' => array(
133: 'UserKey' => '',
134: 'Password' => '',
135: 'TransactionReferenceNumbers'=> ''
136: )),
137:
138: 'checkOriginator' => array(
139: 'service' => 'CheckOriginatorAuthorization',
140: 'param' => array(
141: 'UserKey' => '',
142: 'Password' => '',
143: 'Originator'=> ''
144: )),
145: 'sendOriginatorCode' => array(
146: 'service' => 'SendOriginatorUnlockCode',
147: 'param' => array(
148: 'UserKey' => '',
149: 'Password' => '',
150: 'Originator'=> ''
151: )),
152: 'unlockOriginator' => array(
153: 'service' => 'UnlockOriginator',
154: 'param' => array(
155: 'UserKey' => '',
156: 'Password' => '',
157: 'Originator'=> '',
158: 'OriginatorUnlockCode'=>'',
159: 'AffiliateId'=> ''
160: ))
161: );
162:
163: /**
164: * Constructor, initialize and configure SoapClient
165: * Possible options (to be passed in assoc array):
166: *
167: * "wsdl" optional WSDL resource to rely upon
168: * "soap" optional SOAP options
169: *
170: * @see SoapClient::$wsdl
171: * @see SoapClient::$soapOpt
172: *
173: * @param string $wsdl
174: * @param array $options
175: * @throws \SoapFault Most likely
176: */
177: public function __construct($options = array())
178: {
179: if (isset($options['wsdl']))
180: {
181: $wsdl = $options['wsdl'];
182: }
183: else
184: {
185: $wsdl = $this->wsdl;
186: }
187:
188: $soapOpt = $this->soapOpt;
189:
190: if (isset($options['soap']))
191: {
192: array_merge($soapOpt,$options['soap']);
193: }
194:
195: try {
196: $this->soap = @new \SoapClient($wsdl, $soapOpt);
197: }
198: catch (\SoapFault $e) {
199: $this->soap = NULL;
200: throw new Aspsms\ServiceException('Could not retrieve WSDL or is invalid:'.$e->getMessage());
201: }
202: }
203:
204: /**
205: * Send given request.
206: *
207: * @param \Aspsms\Request $request
208: * @throws AspsmsException
209: * @see AbstractClient::getResponse()
210: */
211: public function send($request)
212: {
213: // Set internal request
214: $this->request = $request;
215:
216: // friendly shortcut
217: $requestName = $request->getRequestName();
218:
219:
220: $cfg =& $this->requests[$requestName];
221:
222: // friendly shortcut
223: $serviceName = $cfg['service'];
224:
225: // Initialize new response object
226: $this->response = new Aspsms\Response($request);
227:
228: // Prepare parameters
229: if (isset($cfg['param']))
230: {
231: $param = $request->extractObject($cfg['param']);
232: }
233: else
234: {
235: $param = NULL;
236: }
237:
238:
239: // attempt to perform request
240: try {
241:
242: // returns stdClass
243: $soapResponse = $this->soap->$serviceName($param);
244:
245: // get result field (name depends on service name (for some wierd reason)
246: $this->response->result = $soapResponse->{$serviceName.'Result'};
247:
248: }
249: catch (\SoapFault $e)
250: {
251: throw new Aspsms\ServiceException('SoapFault: '.$e->getMessage());
252: }
253:
254: // Result post-processing
255: if (method_exists($this, 'post_'.$serviceName))
256: {
257: $this->{'post_'.$serviceName}();
258: }
259: else
260: {
261: $this->post_default();
262: }
263: }
264:
265:
266: /**
267: * Default Post-Processor (applied if no specific PP to be used)
268: */
269: public function post_default()
270: {
271: if (preg_match('/^StatusCode\:(\d+)$/',$this->response->result,$m))
272: {
273: $this->response->result = intval($m[1]) == Aspsms\Response::STAT_OK;
274: $this->response->statusCode($m[1]);
275: }
276: else
277: {
278: $this->response->result = FALSE;
279: }
280: }
281:
282: /**
283: * Post-Processing for CheckCredits
284: */
285: public function post_CheckCredits()
286: {
287: if (preg_match('/^Credits:((?:\d|\.)+)$/',$this->response->result,$m))
288: {
289: $this->response->result = floatval($m[1]);
290: $this->response->statusCode(Aspsms\Response::STAT_OK);
291: }
292: else
293: {
294: $this->post_default();
295: }
296: }
297:
298:
299: /**
300: * If invalid status code given, returns status code as description
301: */
302: public function post_GetStatusCodeDescription()
303: {
304: if ($this->request->get('StatusCode') != $this->response->result)
305: {
306: $this->response->statusCode(Aspsms\Response::STAT_OK);
307: }
308: }
309:
310: public function post_CheckOriginatorAuthorization()
311: {
312: $result_str = $this->response->result;
313:
314: switch($result_str)
315: {
316: case 'StatusCode:31':
317: $this->response->result = TRUE;
318: $this->response->statusCode(31);
319: break;
320: case 'StatusCode:30':
321: $this->response->result = FALSE;
322: $this->response->statusCode(30);
323: break;
324: default:
325: $this->response->result = NULL;
326: if (preg_match('/^StatusCode\:(\d+)$/',$result_str,$m))
327: {
328: $this->response->statusCode($m[1]);
329: }
330: else
331: {
332: $this->response->statusCode(0);
333: }
334: }
335: }
336:
337: /**
338: * Post-Processing for InquireDeliveryNotifications
339: */
340: public function post_InquireDeliveryNotifications()
341: {
342: $result_str = $this->response->result;
343:
344: if (preg_match('/^StatusCode\:(\d+)$/',$result_str,$m))
345: {
346: $this->response->result = FALSE;
347: $this->response->statusCode($m[1]);
348: return;
349: }
350:
351: if (strlen($result_str) == 0)
352: {
353: $this->response->result = array();
354: return;
355: }
356:
357: // Get keys to be used for status fields
358: $keys = $this->request->get('DeliveryStatusFields');
359: if (empty($keys))
360: {
361: $keys = range(0,6);
362: }
363: $nr = $keys[0];
364:
365: // Select only last result for each tracking number
366: $index_by_nr = (boolean)$this->request->get('DeliveryStatusIndexing');
367:
368: // Create list of results
369: $all_list = explode("\n",$result_str);
370:
371: $list = array();
372: foreach($all_list as $one)
373: {
374: $tmp = array_combine($keys, explode(';',$one));
375:
376: if ($index_by_nr)
377: {
378: $list[$tmp[$nr]] = $tmp;
379: }
380: else
381: {
382: $list[] = $tmp;
383: }
384: }
385:
386: $this->response->result = $list;
387: }
388:
389: /**
390: * Post-Processing for VersionInfo
391: *
392: * Creates an associative array with complete response, service version and build number.
393: */
394: public function post_VersionInfo()
395: {
396: $result_str = $this->response->result;
397:
398: if (preg_match('/^StatusCode\:(\d+)$/',$result_str,$m))
399: {
400: $this->response->result = FALSE;
401: $this->response->statusCode($m[1]);
402: return;
403: }
404:
405: // api and version is found at beginning of response
406: if (preg_match('/^([^ ]+)/',$result_str,$m))
407: {
408: $v = $m[1];
409: }
410: else
411: {
412: $v = '';
413: }
414:
415: // build number follows 'build:'
416: if (preg_match('/build:((?:\d|\.)+)/',$result_str,$m))
417: {
418: $b = $m[1];
419: }
420: else
421: {
422: $b = '';
423: }
424:
425: $this->response->result = array(
426: 'all' => $result_str,
427: 'version' => $v,
428: 'build' => $b
429: );
430: }
431: }
432:
433: