使用 PHP 和 cURL 访问 Exchange Web 服务
Posted
技术标签:
【中文标题】使用 PHP 和 cURL 访问 Exchange Web 服务【英文标题】:Access Exchange Web Services with PHP and cURL 【发布时间】: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 响应
【参考方案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/
【讨论】:
以上是关于使用 PHP 和 cURL 访问 Exchange Web 服务的主要内容,如果未能解决你的问题,请参考以下文章
php curl - 需要使用 curl 提供对受保护目录的访问权限
通过 PHP 和 cURL 访问 NodeJS / Socket.io