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

如何使用PHP-EWS连接到Office365服务器(获取404),php,web-services,soap,exchangewebservices,php-ews,Php,Web Services,Soap,Exchangewebservices,Php Ews,我当前正在尝试更新一个内部工具,以处理将exchange服务器升级到office 365的操作 我使用的是James Armas的PHP-EWS工具的最新版本 下面是我们用来获取特定日期范围事件的函数内部的代码片段 $email = '*email@domain*'; $password = '*password*'; $server = 'outlook.office365.com'; // Define EWS //$ews = EWSAutodiscover::getEWS($email

我当前正在尝试更新一个内部工具,以处理将exchange服务器升级到office 365的操作

我使用的是James Armas的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

我查看了这一页: 我也尝试了outlook.office365.com/EWS/Exchange.asmx端点,但仍然得到了soap404

因此,我认为这已经足够成为一个单独的问题了。尽管我研究得越多,REST客户端可能是下一步的目标


我可能是在完全错误的轨道,以及,所以任何帮助将不胜感激

您是否尝试过使用eg change的解决方案

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

你试过使用eg change的解决方案吗

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

当我们从内部部署的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);

当我们从内部部署的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);

我看不出你的代码出了什么问题,但下面的内容可能会有所帮助。我正在使用此脚本成功地定期从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
  }
}

我看不出你的代码出了什么问题,但下面的内容可能会有所帮助。我正在使用此脚本成功地定期从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
  }
}

不幸的是我有。无论$version变量是否存在,我仍然会得到相同的错误。谢谢你的帮助!在Office365上,您应该使用的身份验证是基本的,如果您有不同的UPN到电子邮件地址,那么您应该使用UPN作为用户名,而不是电子邮件。您可以尝试使用EWS编辑器进行一些测试,以验证要使用的正确详细信息。无论$version变量是否存在,我仍然会得到相同的错误。谢谢你的帮助!在Office365上,您应该使用的身份验证是基本的,如果您有不同的UPN到电子邮件地址,那么您应该使用UPN作为用户名,而不是电子邮件。您可以尝试使用EWS编辑器进行一些测试,以验证要使用的正确详细信息