【问题标题】:Access Exchange Web Services with PHP and cURL使用 PHP 和 cURL 访问 Exchange Web 服务
【发布时间】:2011-12-01 15:07:58
【问题描述】:

你好,

我目前正在编写一个客户端来访问 Microsoft Exchange 服务器并从中读取联系人、约会等。

通过几天的搜索,我已经能够通过 PHP 的 Soap 客户端和自定义 HTTPS 流包装器连接到 EWS。 This 网站在这一点上对我帮助很大。

使用 XAMPP 在我的 Windows 7 机器上一切正常

现在我将我的项目上传到 Debian 6.0 Squeeze 开发机器上,该机器在 web 服务器、php 设置、mysql 设置等方面与我的 Windows 机器具有完全相同的配置,但它不再工作了

debian机器可以解析和ping交换服务器没有问题

我将实际问题归结为 cURL 无法检索 EWS 的 WSDL 文件

它总是收到一个空响应和一个 401(未授权)状态码

我使用的凭据是正确的,相同的凭据在我的 Windows 机器上工作

我提取了错误的代码并尝试单独运行它,它看起来像这样:

    echo "Trying to get https://".$cfg[ 'Exchange.Server' ]."/EWS/Services.wsdl<br>";
    $curl = curl_init( 'https://'.$cfg[ 'Exchange.Server' ].'/EWS/Services.wsdl' );
    curl_setopt( $curl, CURLOPT_RETURNTRANSFER,     true );
    curl_setopt( $curl, CURLOPT_HTTP_VERSION,       CURL_HTTP_VERSION_1_1 );
    curl_setopt( $curl, CURLOPT_HTTPAUTH,           CURLAUTH_NTLM );
    curl_setopt( $curl, CURLOPT_USERPWD,            $cfg[ 'Exchange.User' ].':'.$cfg[ 'Exchange.Password' ] );
    curl_setopt( $curl, CURLOPT_SSL_VERIFYPEER,     false );
    curl_setopt( $curl, CURLOPT_SSL_VERIFYHOST,     false );

    echo '<pre>';
    $response = curl_exec( $curl );
    $info = curl_getinfo( $curl );

    var_dump( $info );
    var_dump( $response );

    curl_close( $curl );

我在这里收到的结果是提到的 401 状态代码和一个空响应 当我在浏览器中调用相同的 url 或在我的 windows 机器上使用相同的代码时,我得到了我想要的 WSDL 文件

实际上,我什至无法判断这是基于 linux 的问题,还是我在某些时候做错了什么,我已经为此苦苦挣扎了 2 天。

有没有人能找出我的错误或告诉我为什么它不起作用?

我可以根据需要提供任何进一步需要的信息

【问题讨论】:

  • 您是否也尝试在命令行上获取文件,例如使用curl 命令行工具?它可以揭示相当多的信息。
  • 是的,我使用命令行工具“curl”尝试了同样的事情,使用参数 -k(忽略无效证书)、--ntlm(NTLM 身份验证)和 -u 作为我的用户凭据收到一个空响应
  • 启用详细输出,我认为是-v,检查--help。对于证书等 IIRC,还有一些其他“调试”选项。
  • 似乎与您客户端上的 NTLM 库有关....
  • 在这种情况下我不使用任何 NTLM 库,cURL 内置了 NTLM 身份验证 -v 指出我犯的一个错误,即使用 \\ 而不是 \ 作为我的用户名的域分隔符,不过,我仍然收到 401 响应

标签: php curl ntlm exchangewebservices http-status-code-401


【解决方案1】:

如果你正确初始化了你的soap客户端,你应该能够以这种方式执行任何请求:

$curl = curl_init($location); //'https://'.$server_address.'/EWS/Exchange.asmx'
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); //valid soap headers with keep-alive
curl_setopt($ch, CURLOPT_POST, true );
curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_USERPWD, $user.':'.$password);
$response = curl_exec($curl);

至于您的代码,请尝试注释掉以下行:

curl_setopt( $curl, CURLOPT_HTTPAUTH, CURLAUTH_NTLM );

还请查看此包装器在您的设置中的任何位置: http://ewswrapper.lafiel.net/ 如果是这样,请查看那里使用的 SOAP 类 - 它使用内置的 php 作为基础。

为什么你不能在本地存储 wsdl 文件?


更新:

好的,我在我的 Debian 盒子里玩过这个,这对我来说完美无缺:

$domain = 'xxxxxx';
$user = 'xxxxxx';
$password = 'xxxxxx';
$ch = curl_init('https://'.$domain.'/EWS/Services.wsdl'); 
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_USERPWD, $user.':'.$password);
$response = curl_exec($ch);
$info = curl_getinfo( $ch );
$error =  curl_error ($ch);
print_r(array($response,$info,$error));

返回

Array
(
    [0] => <?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions 
(...)
</wsdl:definitions>
    [1] => Array
        (
            [url] => xxxxx/EWS/Services.wsdl
            [content_type] => text/xml
            [http_code] => 200
            [header_size] => 250
            [request_size] => 147
            [filetime] => -1
            [ssl_verify_result] => 0
            [redirect_count] => 0
            [total_time] => 0.60574
            [namelookup_time] => 0.165249
            [connect_time] => 0.268173
            [pretransfer_time] => 0.474009
            [size_upload] => 0
            [size_download] => 55607
            [speed_download] => 91800
            [speed_upload] => 0
            [download_content_length] => 55607
            [upload_content_length] => 0
            [starttransfer_time] => 0.580931
            [redirect_time] => 0
            [certinfo] => Array
                (
                )

            [redirect_url] => 
        )

    [2] => 
)

【讨论】:

  • 感谢您的回答。抱歉,我认为我没有充分指出这一点,但这并不完全是因为 SOAP 无法检索 WSDL,cURL 不是。我无法将其存储在本地,因为我们不确定它是否可能会更改,该项目将在多个环境中运行。对我来说,另一种选择是使用 cURL 下载它,然后将本地版本提供给 SOAP,但这已经是问题所在。我不能简单地在 Linux 上使用 cURL 下载 WSDL。顺便说一下,Microsoft Exchange 需要 NTLM 身份验证
  • 你试过用 HTTPAUTH 注释掉这行吗?尽管从技术上讲,MS Ex 需要 NTLM 身份验证,但有时在 curl 执行中跳过该身份验证可以解决问题。要从 Ex 服务器下载 wsdl,我实际上会遍历所有身份验证类型并查看哪个返回 wsdl 文件并使用该文件连接到服务器。您会惊讶地发现各种 MS Ex 服务器使用不同的身份验证类型。
  • 我已经试过注释掉了,也没有用。我还尝试了 cURL 提供的所有身份验证方法,也没有运气。它仍然可以在我的 windows 机器上使用相同的代码,所以它可能不是服务器端的问题,而是客户端的问题
  • 我尝试了您的代码,并且我尝试了您的代码并在这里和那里进行了一些调整,我一直得到 401。当我输入 NTLM 身份验证时,我在我的 Windows 机器上得到了正确的结果,我的Debian上仍然没有。顺便谢谢你的帮助
  • 这很奇怪,我发布的代码适用于我在 Debian 机器上的交换。也许从不同的 linux 机器上尝试一下,因为在你的 win 机器上它可以工作。至于 NTLM auth - 我正在使用的交换在 windows 下需要它,但在我的 Debian 上不喜欢它。或者,如果您喜欢 python,您可能还想尝试使用 urllib2 + ntml 下载 wsdl 并循环通过所有 auth 方法检查哪些返回 401 - 可能问题出在您的 php/curl 版本
【解决方案2】:

您的第一次检查不应使用任何复杂的脚本。 而是尝试从 Debian 机器上的简单浏览器窗口打开 WDSL,如下所示: https://your.exchange-server.com/EWS/Services.wsdl

如果这不起作用,则可能存在取决于客户端 IP 或客户端网络的访问限制(例如,您的开发机器位于受信任的网络中,而您的 Debian 则不是)。您收到 401(“未经授权” - 请求需要用户身份验证)这一事实表明联系服务器没有问题,但身份验证。

我建议的另一项检查是查看 phpinfo() 以确保在 Debian 上安装的 PHP 能够处理 HTTP*S* 请求。确保已安装 OpenSSL!

【讨论】:

  • HTTPS 包装器存在,安装了 OpenSSL,Debian 上没有浏览器,但是从命令行尝试了 wget 和 curl,wget 得到 403(显然),curl 得到 401,我尝试了各种用户名和密码组合,带和不带域,1 到 4 个反斜杠作为域分隔符,没有激活 IP 或客户端限制
  • 从我在网上找到的信息来看,这可能是 NTML v2(显然被 Exchange 服务器完全接受)和 NTML v1(由 Linux 客户端提供)的问题。两个世界之间似乎存在共同的谈判问题,即使它们都支持 v2.2 版本。这并不能回答您的问题,但可能会提示您进一步测试的正确方向。
【解决方案3】:

这篇文章帮助我指明了正确的方向。要记住的一件事是 您的 PHP 安装可能没有共享您系统的 cURL / libcurl 设置。

http://blog.ianty.com/ubuntu/exchange-web-services-ews-ntlmv2-and-linux/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多