1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Contains ExchangeWebServices. |
4
|
|
|
*/ |
5
|
|
|
|
6
|
|
|
namespace garethp\ews\API; |
7
|
|
|
|
8
|
|
|
use garethp\ews\API\Exception\ExchangeException; |
9
|
|
|
use garethp\ews\API\Exception\NoResponseReturnedException; |
10
|
|
|
use garethp\ews\API\Exception\ServiceUnavailableException; |
11
|
|
|
use garethp\ews\API\Exception\UnauthorizedException; |
12
|
|
|
use garethp\ews\API\Message; |
13
|
|
|
use garethp\ews\API\Type\EmailAddressType; |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* Base class of the Exchange Web Services application. |
17
|
|
|
* |
18
|
|
|
* @package php-ews\Client |
19
|
|
|
* |
20
|
|
|
* @method Type CreateItem($request) |
21
|
|
|
* @method Type FindItem($request) |
22
|
|
|
* @method Type GetFolder($request) |
23
|
|
|
* @method Type SyncFolderItems($request) |
24
|
|
|
* @method Type FindFolder($request) |
25
|
|
|
* @method Type UpdateItem($request) |
26
|
|
|
* @method Type DeleteItem($request) |
27
|
|
|
* @method Type GetItem($request) |
28
|
|
|
*/ |
29
|
|
|
class ExchangeWebServices |
30
|
|
|
{ |
31
|
|
|
/** |
32
|
|
|
* Microsoft Exchange 2007 |
33
|
|
|
* |
34
|
|
|
* @var string |
35
|
|
|
*/ |
36
|
|
|
const VERSION_2007 = 'Exchange2007'; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Microsoft Exchange 2007 SP1 |
40
|
|
|
* |
41
|
|
|
* @var string |
42
|
|
|
*/ |
43
|
|
|
const VERSION_2007_SP1 = 'Exchange2007_SP1'; |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* Microsoft Exchange 2007 SP2 |
47
|
|
|
* |
48
|
|
|
* @var string |
49
|
|
|
*/ |
50
|
|
|
const VERSION_2007_SP2 = 'Exchange2007_SP2'; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* Microsoft Exchange 2007 SP3 |
54
|
|
|
* |
55
|
|
|
* @var string |
56
|
|
|
*/ |
57
|
|
|
const VERSION_2007_SP3 = 'Exchange2007_SP3'; |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* Microsoft Exchange 2010 |
61
|
|
|
* |
62
|
|
|
* @var string |
63
|
|
|
*/ |
64
|
|
|
const VERSION_2010 = 'Exchange2010'; |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* Microsoft Exchange 2010 SP1 |
68
|
|
|
* |
69
|
|
|
* @var string |
70
|
|
|
*/ |
71
|
|
|
const VERSION_2010_SP1 = 'Exchange2010_SP1'; |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* Microsoft Exchange 2010 SP2 |
75
|
|
|
* |
76
|
|
|
* @var string |
77
|
|
|
*/ |
78
|
|
|
const VERSION_2010_SP2 = 'Exchange2010_SP2'; |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* Password to use when connecting to the Exchange server. |
82
|
|
|
* |
83
|
|
|
* @var string |
84
|
|
|
*/ |
85
|
|
|
protected $password; |
86
|
|
|
|
87
|
|
|
/** |
88
|
|
|
* Location of the Exchange server. |
89
|
|
|
* |
90
|
|
|
* @var string |
91
|
|
|
*/ |
92
|
|
|
protected $server; |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* SOAP client used to make the request |
96
|
|
|
* |
97
|
|
|
* @var NTLMSoapClient |
98
|
|
|
*/ |
99
|
|
|
protected $soap; |
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* Username to use when connecting to the Exchange server. |
103
|
|
|
* |
104
|
|
|
* @var string |
105
|
|
|
*/ |
106
|
|
|
protected $username; |
107
|
|
|
|
108
|
|
|
/** |
109
|
|
|
* @var EmailAddressType |
110
|
|
|
*/ |
111
|
|
|
protected $primarySmtpMailbox; |
112
|
|
|
|
113
|
|
|
/** |
114
|
|
|
* A setting to check whether or not responses should be drilled down before being returned. Setting this to false |
115
|
|
|
* will return the raw responses without any filtering |
116
|
|
|
* |
117
|
|
|
* @var bool |
118
|
|
|
*/ |
119
|
|
|
protected $drillDownResponses = true; |
120
|
|
|
|
121
|
|
|
/** |
122
|
|
|
* @return EmailAddressType |
123
|
|
|
*/ |
124
|
20 |
|
public function getPrimarySmtpMailbox() |
125
|
|
|
{ |
126
|
20 |
|
return $this->primarySmtpMailbox; |
127
|
|
|
} |
128
|
|
|
|
129
|
1 |
|
public function getPrimarySmtpEmailAddress() |
130
|
|
|
{ |
131
|
1 |
|
if ($this->primarySmtpMailbox == null) { |
132
|
1 |
|
return null; |
133
|
|
|
} |
134
|
|
|
|
135
|
1 |
|
return $this->primarySmtpMailbox->getEmailAddress(); |
136
|
|
|
} |
137
|
|
|
|
138
|
2 |
|
public function setPrimarySmtpEmailAddress($emailAddress) |
139
|
|
|
{ |
140
|
2 |
|
$mailbox = new EmailAddressType(); |
141
|
2 |
|
$mailbox->setEmailAddress($emailAddress); |
142
|
2 |
|
$this->primarySmtpMailbox = $mailbox; |
143
|
|
|
|
144
|
2 |
|
return $this; |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
/** |
148
|
|
|
* Miscrosoft Exchange version that we are going to connect to |
149
|
|
|
* |
150
|
|
|
* @var string |
151
|
|
|
* |
152
|
|
|
* @see ExchangeWebServices::VERSION_2007 |
153
|
|
|
* @see ExchangeWebServices::VERSION_2007_SP1 |
154
|
|
|
* @see ExchangeWebServices::VERSION_2010 |
155
|
|
|
* @see ExchangeWebServices::VERSION_2010_SP1 |
156
|
|
|
*/ |
157
|
|
|
protected $version; |
158
|
|
|
|
159
|
|
|
protected $options; |
160
|
|
|
|
161
|
|
|
/** |
162
|
|
|
* The timezone for the client |
163
|
|
|
* |
164
|
|
|
* @var bool |
165
|
|
|
*/ |
166
|
|
|
protected $timezone = false; |
167
|
|
|
|
168
|
|
|
/** |
169
|
|
|
* @param boolean $timezone |
170
|
|
|
*/ |
171
|
|
|
public function setTimezone($timezone) |
172
|
|
|
{ |
173
|
|
|
$this->timezone = $timezone; |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
/** |
177
|
|
|
* Constructor for the ExchangeWebServices class |
178
|
|
|
* |
179
|
|
|
* @deprecated Since 0.6.3 |
180
|
|
|
* @param string $server |
181
|
|
|
* @param string $username |
182
|
|
|
* @param string $password |
183
|
|
|
* @param array $options |
184
|
|
|
*/ |
185
|
28 |
|
public function __construct( |
186
|
|
|
$server = null, |
187
|
|
|
$username = null, |
188
|
|
|
$password = null, |
189
|
|
|
$options = [] |
190
|
|
|
) { |
191
|
28 |
|
if ($server !== null) { |
192
|
1 |
|
$this->createClient( |
193
|
|
|
$server, |
194
|
1 |
|
ExchangeWebServicesAuth::fromUsernameAndPassword($username, $password), |
195
|
|
|
$options |
196
|
|
|
); |
197
|
|
|
} |
198
|
|
|
} |
199
|
|
|
|
200
|
26 |
|
public static function fromUsernameAndPassword($server, $username, $password, $options) |
201
|
|
|
{ |
202
|
26 |
|
$self = new static(); |
203
|
26 |
|
$self->createClient($server, ExchangeWebServicesAuth::fromUsernameAndPassword($username, $password), $options); |
204
|
|
|
|
205
|
26 |
|
return $self; |
206
|
|
|
} |
207
|
|
|
|
208
|
1 |
|
public static function fromCallbackToken($server, $token, $options) |
209
|
|
|
{ |
210
|
1 |
|
$self = new static(); |
211
|
1 |
|
$self->createClient($server, ExchangeWebServicesAuth::fromCallbackToken($token), $options); |
212
|
|
|
|
213
|
1 |
|
return $self; |
214
|
|
|
} |
215
|
|
|
|
216
|
28 |
|
protected function createClient($server, $auth, $options) |
217
|
|
|
{ |
218
|
28 |
|
$location = 'https://' . $this->cleanServerUrl($server) . '/EWS/Exchange.asmx'; |
219
|
|
|
|
220
|
28 |
|
$options = array_replace_recursive([ |
221
|
28 |
|
'version' => self::VERSION_2007, |
222
|
28 |
|
'trace' => 1, |
223
|
|
|
'exceptions' => true, |
224
|
28 |
|
'classmap' => ClassMap::getClassMap(), |
225
|
|
|
'drillDownResponses' => true |
226
|
|
|
], $options); |
227
|
|
|
|
228
|
28 |
|
$this->soap = new NTLMSoapClient( |
229
|
|
|
$location, |
230
|
|
|
$auth, |
231
|
28 |
|
dirname(__FILE__) . '/../../Resources/wsdl/services.wsdl', |
232
|
|
|
$options |
233
|
|
|
); |
234
|
|
|
|
235
|
28 |
|
if (isset($options['primarySmtpEmailAddress'])) { |
236
|
1 |
|
$this->setPrimarySmtpEmailAddress($options['primarySmtpEmailAddress']); |
237
|
|
|
} |
238
|
|
|
|
239
|
28 |
|
if (isset($options['impersonation'])) { |
240
|
1 |
|
$this->setPrimarySmtpEmailAddress($options['impersonation']); |
241
|
|
|
} |
242
|
|
|
|
243
|
28 |
|
$this->drillDownResponses = $options['drillDownResponses']; |
244
|
|
|
} |
245
|
|
|
|
246
|
|
|
/** |
247
|
|
|
* @codeCoverageIgnore |
248
|
|
|
* |
249
|
|
|
* @param $name |
250
|
|
|
* @param $arguments |
251
|
|
|
* @return Type |
252
|
|
|
* @throws \garethp\ews\API\Exception |
253
|
|
|
*/ |
254
|
|
|
public function __call($name, $arguments) |
255
|
|
|
{ |
256
|
|
|
$response = $this->getClient()->__call($name, $arguments); |
257
|
|
|
|
258
|
|
|
return $this->processResponse($response); |
259
|
|
|
} |
260
|
|
|
|
261
|
|
|
/** |
262
|
|
|
* Returns the SOAP Client that may be used to make calls against the server |
263
|
|
|
* |
264
|
|
|
* @return NTLMSoapClient |
265
|
|
|
*/ |
266
|
26 |
|
public function getClient() |
267
|
|
|
{ |
268
|
26 |
|
return $this->soap; |
269
|
|
|
} |
270
|
|
|
|
271
|
|
|
/** |
272
|
|
|
* Sets the client |
273
|
|
|
* |
274
|
|
|
* @param NTLMSoapClient $client |
275
|
|
|
* @return $this |
276
|
|
|
*/ |
277
|
2 |
|
public function setClient($client) |
278
|
|
|
{ |
279
|
2 |
|
$this->soap = $client; |
280
|
|
|
|
281
|
2 |
|
return $this; |
282
|
|
|
} |
283
|
|
|
|
284
|
|
|
/** |
285
|
|
|
* Cleans the server URL for usage |
286
|
|
|
* |
287
|
|
|
* @param $server |
288
|
|
|
* @return string |
289
|
|
|
*/ |
290
|
35 |
|
public function cleanServerUrl($server) |
291
|
|
|
{ |
292
|
35 |
|
$url = parse_url($server); |
293
|
35 |
|
if (!isset($url['host']) && isset($url['path'])) { |
294
|
30 |
|
$url['host'] = $url['path']; |
295
|
30 |
|
unset($url['path']); |
296
|
|
|
} |
297
|
|
|
|
298
|
35 |
|
$server = $url['host']; |
299
|
35 |
|
if (isset($url['port'])) { |
300
|
2 |
|
$server .= ':' . $url['port']; |
301
|
|
|
} |
302
|
|
|
|
303
|
35 |
|
if (isset($url['path'])) { |
304
|
4 |
|
$server .= $url['path']; |
305
|
|
|
} |
306
|
|
|
|
307
|
35 |
|
$server = rtrim($server, "/"); |
308
|
|
|
|
309
|
35 |
|
return $server; |
310
|
|
|
} |
311
|
|
|
|
312
|
|
|
/** |
313
|
|
|
* Process a response to verify that it succeeded and take the appropriate |
314
|
|
|
* action |
315
|
|
|
* |
316
|
|
|
* @param \garethp\ews\API\Message\BaseResponseMessageType $response |
317
|
|
|
* @return \garethp\ews\API\Message\ArrayOfResponseMessageType|\garethp\ews\API\Message\ResponseMessageType |
318
|
|
|
* @throws \garethp\ews\API\Exception |
319
|
|
|
*/ |
320
|
24 |
|
protected function processResponse($response) |
321
|
|
|
{ |
322
|
|
|
// If the soap call failed then we need to thow an exception. |
323
|
24 |
|
$code = $this->getClient()->getResponseCode(); |
324
|
24 |
|
if ($code == 401) { |
325
|
|
|
throw new UnauthorizedException(); |
326
|
|
|
} |
327
|
|
|
|
328
|
24 |
|
if ($code == 503) { |
329
|
|
|
throw new ServiceUnavailableException(); |
330
|
|
|
} |
331
|
|
|
|
332
|
24 |
|
if ($code != 200) { |
333
|
2 |
|
throw new ExchangeException('SOAP client returned status of ' . $code, $code); |
334
|
|
|
} |
335
|
|
|
|
336
|
22 |
|
if (empty($response) || |
337
|
22 |
|
empty($response->getNonNullResponseMessages()) |
338
|
|
|
) { |
339
|
|
|
throw new NoResponseReturnedException(); |
340
|
|
|
} |
341
|
|
|
|
342
|
22 |
|
if (!$this->drillDownResponses) { |
343
|
|
|
return $response; |
344
|
|
|
} |
345
|
|
|
|
346
|
22 |
|
if (!$response->exists('responseMessages')) { |
347
|
|
|
return $response; |
348
|
|
|
} |
349
|
|
|
|
350
|
22 |
|
$response = $response->getResponseMessages(); |
351
|
22 |
|
$response = $this->drillDownResponseLevels($response); |
352
|
|
|
|
353
|
22 |
|
return $response; |
354
|
|
|
} |
355
|
|
|
|
356
|
|
|
/** |
357
|
|
|
* @param $response |
358
|
|
|
* @return array |
359
|
|
|
* @throws \garethp\ews\API\Exception |
360
|
|
|
*/ |
361
|
22 |
|
public function drillDownResponseLevels($response) |
362
|
|
|
{ |
363
|
22 |
|
$items = array(); |
364
|
22 |
|
if ($response instanceof Type) { |
365
|
22 |
|
$items = $response->getNonNullItems(); |
366
|
1 |
|
} elseif (is_array($response)) { |
367
|
1 |
|
$items = $response; |
368
|
|
|
} |
369
|
|
|
|
370
|
22 |
|
if ($response instanceof Message\ResponseMessageType) { |
|
|
|
|
371
|
22 |
|
if ($response->getResponseClass() !== "Success") { |
372
|
1 |
|
throw new ExchangeException($response->getMessageText()); |
373
|
|
|
} |
374
|
|
|
|
375
|
22 |
|
unset($items['responseClass']); |
376
|
22 |
|
unset($items['responseCode']); |
377
|
|
|
} |
378
|
|
|
|
379
|
22 |
|
if (count($items) == 1) { |
380
|
22 |
|
reset($items); |
381
|
22 |
|
$key = key($items); |
382
|
22 |
|
$methodName = "get$key"; |
383
|
22 |
|
$response = $response->$methodName(); |
384
|
|
|
|
385
|
22 |
|
$response = $this->drillDownResponseLevels($response); |
386
|
22 |
|
} elseif (is_array($items) && isset($items[1]) && $items[1] instanceof Message\ResponseMessageType) { |
|
|
|
|
387
|
1 |
|
$response = array(); |
388
|
1 |
|
foreach ($items as $responseItem) { |
389
|
1 |
|
$response[] = $this->drillDownResponseLevels($responseItem); |
390
|
|
|
} |
391
|
|
|
} |
392
|
|
|
|
393
|
22 |
|
return $response; |
394
|
|
|
} |
395
|
|
|
} |
396
|
|
|
|
This error could be the result of:
1. Missing dependencies
PHP Analyzer uses your
composer.json
file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects thecomposer.json
to be in the root folder of your repository.Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the
require
orrequire-dev
section?2. Missing use statement
PHP does not complain about undefined classes in
ìnstanceof
checks. For example, the following PHP code will work perfectly fine:If you have not tested against this specific condition, such errors might go unnoticed.