如何使用PHP-EWS连接到Office365服务器(获取404)

时间:2017-07-18 19:58:01

标签: php web-services soap exchangewebservices php-ews

我目前正在尝试更新内部工具,以便将我们的Exchange服务器升级到Office 365。

我正在使用最新版本的James Armas的PHP-EWS工具。 jamesiarmes/php-ews

以下是我们用于获取特定日期范围内事件的函数内部的代码段。

$email = '*email@domain*';
$password = '*password*';
$server = 'outlook.office365.com';

// Define EWS
//$ews = EWSAutodiscover::getEWS($email, $password);

$ews = new Client($server, $email, $password);

// Set init class
$request = new FindItemType();
// Use this to search only the items in the parent directory in question or use ::SOFT_DELETED
// to identify "soft deleted" items, i.e. not visible and not in the trash can.
$request->Traversal = ItemQueryTraversalType::SHALLOW;
// This identifies the set of properties to return in an item or folder response
$request->ItemShape = new ItemResponseShapeType();
$request->ItemShape->BaseShape = DefaultShapeNamesType::ALL_PROPERTIES;

// Define the timeframe to load calendar items
$request->CalendarView = new CalendarViewType();
$request->CalendarView->StartDate = $start_date;// an ISO8601 date e.g. 2012-06-12T15:18:34+03:00
$request->CalendarView->EndDate = $end_date;// an ISO8601 date later than the above


// Only look in the "calendars folder"
$request->ParentFolderIds = new NonEmptyArrayOfBaseFolderIdsType();
$request->ParentFolderIds->DistinguishedFolderId = new DistinguishedFolderIdType();
$request->ParentFolderIds->DistinguishedFolderId->Id = DistinguishedFolderIdNameType::CALENDAR;
$request->ParentFolderIds->DistinguishedFolderId->Mailbox = new StdClass;
$request->ParentFolderIds->DistinguishedFolderId->Mailbox->EmailAddress = $email_address;

// Send request
$response = $ews->FindItem($request);

运行此代码时,我们从SOAP客户端获取404:

Fatal error: Uncaught exception 'Exception' with message 'SOAP client returned status of 404.' in /*dirs*/Client.php:1650 Stack trace: #0 /*dirs*/Client.php(1633): jamesiarmes\PhpEws\Client->processResponse(NULL) #1 /*dirs*/Client.php(670): jamesiarmes\PhpEws\Client->makeRequest('FindItem', Object(jamesiarmes\PhpEws\Request\FindItemType)) #2 /*dirs*/index_dev.php(64): jamesiarmes\PhpEws\Client->FindItem(Object(jamesiarmes\PhpEws\Request\FindItemType)) #3 /*dirs*/index_dev.php(269): getEventHTML('email@domain...', '2017-07-18T02:0...', '2017-07-18T21:5...') #4 {main} thrown in /*dirs*/Client.php on line 1650

我相信我确实已正确设置连接,因为当我更改凭据时,我确实得到了401。

我查看了这个页面:PHP-EWS “Soap client returned status of 404” 我也尝试了outlook.office365.com/EWS/Exchange.asmx端点,但我仍然得到SOAP 404.

因此,我认为这是一个单独的问题。 (虽然我研究得越多,REST客户端下一步就越多)

我可能也处于完全错误的轨道上,所以任何帮助都将不胜感激!

3 个答案:

答案 0 :(得分:3)

当我们从内部部署Exchange服务器迁移到Office 365并设法将问题追溯到php-ntlm下的SoapClient.php时,我遇到了类似的问题。

从您的请求中抛出的错误开始:

Fatal error: Uncaught exception 'Exception' with message 'SOAP client returned status of 404.' .... thrown in /*dirs*/Client.php on line 1650

如果我们在Client.php中查看该行,则异常似乎来自调用上述SoapClient.php脚本的函数。

protected function processResponse($response)
{
    // If the soap call failed then we need to throw an exception.
    $code = $this->soap->getResponseCode();
    if ($code != 200) {
        throw new \Exception(
            "SOAP client returned status of $code.",
            $code
        );
    }

    return $response;
}

我能够通过修改SoapClient.php(位于第180行附近)中的CURL请求选项来解决此问题。

原始代码:

protected function curlOptions($action, $request)
{
    $options = $this->options['curlopts'] + array(
        CURLOPT_SSL_VERIFYPEER => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => $this->buildHeaders($action),
        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
        CURLOPT_HTTPAUTH => CURLAUTH_BASIC | CURLAUTH_NTLM,
        CURLOPT_USERPWD => $this->options['user'] . ':'
                           . $this->options['password'],
    );
    // We shouldn't allow these options to be overridden.
    $options[CURLOPT_HEADER] = true;
    $options[CURLOPT_POST] = true;
    $options[CURLOPT_POSTFIELDS] = $request;
    return $options;
}

修改后的代码:

protected function curlOptions($action, $request)
{
    $cOpts = array(
        CURLOPT_PROXY => "my.proxy.com:8080",
        CURLOPT_PROXYUSERPWD => $this->options['user'] . ':'
                           . $this->options['password'],
        CURLOPT_SSL_VERIFYPEER => false,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => $this->buildHeaders($action),
        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
        CURLOPT_HTTPAUTH => CURLAUTH_BASIC | CURLAUTH_NTLM,
        CURLOPT_USERPWD => $this->options['user'] . ':'
                           . $this->options['password'],
    );
    $options = $this->options['curlopts'] + $cOpts;
    // We shouldn't allow these options to be overridden.
    $options[CURLOPT_HEADER] = true;
    $options[CURLOPT_POST] = true;
    $options[CURLOPT_POSTFIELDS] = $request;

    return $options;
}

我将CURLOPT_SSL_VERIFYPEER设置为false,并且还为请求添加了代理选项,因为连接是从公司网络内部进行的,需要代理身份验证才能访问任何外部站点。

在我的邮件PHP脚本中,我使用以下代码创建客户端:

$server = 'outlook.office365.com';
$username = 'user@domain.com';
$password = 'myPassword';
$version = Client::VERSION_2016;
$client = new Client($server, $username, $password, $version);

答案 1 :(得分:2)

您是否尝试过使用https://github.com/jamesiarmes/php-ews/issues/196中的解决方案,例如更改

$version = Client::VERSION_2016; 
$ews = new Client($server, $email, $password,$version);

答案 2 :(得分:1)

我无法确定您的代码出了什么问题,但以下内容可能会有所帮助。我正在成功使用此脚本从o365定期导出我的日历。

主机和用户如下:

host = "outlook.office365.com"
username = "user@domain.com"

脚本:

$start_date = new Datetime('today -1 months');
$end_date = new Datetime('today +1 months');

$timezone = 'W. Europe Standard Time';

$ini_array = parse_ini_file($credentials_ini);
$host = $ini_array['host'];
$username = $ini_array['username'];
$password = $ini_array['password'];
$version = Client::VERSION_2016;

$client = new Client($host, $username, $password, $version);

$client->setTimezone($timezone);

$request = new FindItemType();
$request->ParentFolderIds = new NonEmptyArrayOfBaseFolderIdsType();

$request->ItemShape = new ItemResponseShapeType();
$request->ItemShape->BaseShape = DefaultShapeNamesType::ALL_PROPERTIES;
$folder_id = new DistinguishedFolderIdType();
$folder_id->Id = DistinguishedFolderIdNameType::CALENDAR;
$request->ParentFolderIds->DistinguishedFolderId[] = $folder_id;
$request->Traversal = ItemQueryTraversalType::SHALLOW;
$request->CalendarView = new CalendarViewType();
$request->CalendarView->StartDate = $start_date->format('c');
$request->CalendarView->EndDate = $end_date->format('c');
$request->ConnectionTimeout = 60;

$response = $client->FindItem($request);

$response_messages = $response->ResponseMessages->FindItemResponseMessage;
foreach ($response_messages as $response_message) {
  $items = $response_message->RootFolder->Items->CalendarItem;

  foreach ($items as $event){
    $id = $event->ItemId->Id;
    $subject = $event->Subject;
    $location = $event->Location;
    // ...

    // do something with it
  }
}