通过PHP获取远程XML文件的一部分的最有效方法是什么?

时间:2014-07-12 00:58:23

标签: php xml performance

我正在尝试获取远程XML文件的一部分,在这种情况下,通过Google地图获取邮政编码的经度和纬度。这是我目前使用的功能:

function slug_get_coordinates( $zip ) {
    $url = "http://maps.googleapis.com/maps/api/geocode/xml?address={$zip}&sensor=false";
    $result = simplexml_load_file( $url );
    $coordinates = $result->result->geometry->location;
    return $coordinates;
}

这有时在长页面加载后起作用,但通常会超时。有没有办法直接获取我需要的XML文件部分而无需加载整个内容或其他方式来优化它?

2 个答案:

答案 0 :(得分:2)

除非服务提供此功能,否则您无法基于选择器(例如XPath / CSS)请求部分响应。

关于效率,我建议尽可能详细地分解请求时间,以找出某个请求需要一段时间的原因。 cURL对此有很好的支持,例如:

$zip = urlencode('1 infinite loop');
$ch = curl_init("http://maps.googleapis.com/maps/api/geocode/xml?address={$zip}&sensor=false");
curl_exec($ch);
print_r(curl_getinfo($ch));

这会生成一个包含您请求的所有元数据的数组:

Array
(
    ...
    [total_time] => 0.11955
    [namelookup_time] => 0.02996
    [connect_time] => 0.035803
    [pretransfer_time] => 0.035874
    ...
    [size_upload] => 0
    [size_download] => 1737
    [speed_download] => 14529
    [speed_upload] => 0
    [download_content_length] => -1
    [upload_content_length] => 0
    [starttransfer_time] => 0.119444
    [redirect_time] => 0
    ...
)

使用此数据,您可以制定适当的方法来处理问题。缓存响应可能会减少重复搜索的请求时间,但它可能不适用于您的特定情况。

答案 1 :(得分:2)

  

通过PHP获取远程XML文件的一部分的最有效方法是什么?

这个问题无法具体回答,因为这有很多含义。

实际上,您在这里处理远程服务。我通常建议总是包装/代理这些(比较:The Daily Mistake: Not to Proxy Remote Services)。这是因为它们总是带来许多含义。您可以通过将数据检索包装到函数中来部分执行此操作:

function slug_get_coordinates( $zip ) {
    $url = "http://maps.googleapis.com/maps/api/geocode/xml?address={$zip}&sensor=false";
    $result = simplexml_load_file( $url );
    $coordinates = $result->result->geometry->location;
    return $coordinates;
}

然而,这个单一的功能还不足以解决服务可能带来的所有问题。例如。远程位置可能只是关闭 - 这样的响应超时可能符合条件 - 或者当你体验它时,它只需要太长时间。

因此,您基本上不满意服务质量

由于远程服务很常见,您无法完全控制它们,而且您对服务质量影响不大,因此将其包装起来可以解决此类问题在包装器中,以便保护应用程序逻辑的其余部分免受所有这些影响。

这要求您不仅要封装数据的解析(就像您开始使用的功能一样),还需要检索(远程请求)。您还需要在函数中缺少错误处理。这里的另一个暗示是设计失败。例如。让您的应用程序仍然有效,即使您尝试检索(添加)的信息也丢失了。

这种代理的另一个好处是,您可以在其中实现调试功能。例如,使用您提供的代码,我完全没有问题快速检索数据:

$zip = '55416';

$start = microtime(true);

slug_get_coordinates($zip)->asXML('php://output');

printf("\n----\nTook %.5f seconds\n", microtime(true) - $start);

输出:

<location>
    <lat>44.9465193</lat>
    <lng>-93.3439291</lng>
   </location>
----
Took 0.11873 seconds

如果您需要深入了解远程请求,可以访问PHP的流通知。我编写了一个StreamNotifyPrinter来完成这项工作并且可以轻松注册:

$zip = '55416';

$notifier = new StreamNotifyPrinter();
libxml_set_streams_context($notifier->registerOnContext());

$start = microtime(true);

slug_get_coordinates($zip)->asXML('php://output');

printf("\n----\nTook %.5f seconds\n", microtime(true) - $start);

输出:

2014-07-12T09:07:40.146422+0000 [0.00000] Connected...
2014-07-12T09:07:40.228122+0000 [0.08170] Found the mime-type: application/xml; charset=UTF-8
2014-07-12T09:07:40.228251+0000 [0.08183] Made some progress, downloaded 0 so far
2014-07-12T09:07:40.228341+0000 [0.08192] Made some progress, downloaded 757 so far
<location>
    <lat>44.9465193</lat>
    <lng>-93.3439291</lng>
   </location>
----
Took 0.11873 seconds

如果此信息不够,您可能希望切换传输层(例如,使用Curl作为 Jack suggested,它具有更专用的API来调试请求;请参阅{ {3}})。

万不得已:如果您无法通过故障排除解决问题,正确包装可能会使用更好的工作数据库更换远程服务变得容易。但也许结帐,如果地理坐标实际上与邮政编码很好地合作:Php - Debugging Curl