无法在Openstreetmap的simplexml_load_file上加载外部实体

时间:2018-06-11 10:06:52

标签: php xml openstreetmap nominatim

我最近检查了一个网站,发现邮政编码的搜索工作不再有效。

我收到以下错误:

  

'无法加载外部实体'

如果我使用simplexml_load_string(),我会收到

  

'预期开始代码','<'没找到'。

这是我正在使用的代码:

libxml_use_internal_errors(true);
$xml = simplexml_load_file('https://nominatim.openstreetmap.org/search?postalcode=28217&country=DE&format=xml&polygon=1&addressdetails=1&boundary=postalcode');
if (false === $xml) {
    $errors = libxml_get_errors();
    var_dump($errors);
}

我在某处读到它实际上可能与HTTP标题有关,但我没有找到任何有用的信息。

2 个答案:

答案 0 :(得分:1)

在OSM Nominatim的使用政策中,声明您需要提供User-AgentHTTP-Referer请求标头来标识该应用程序。因此,使用用户代理伪装成最终用户浏览器实际上并不是很好的礼仪。

您可以找到使用政策here。它还说http库使用的默认值(如simplexml_load_file()使用的那个)是不可接受的。

您说您正在使用simplexml_load_string(),但未能说明如何将XML用于该功能。但最可能的情况是,无论您使用哪种方法来获取XML文件,您都忽略了传递强制标题。

因此,我使用php-curl创建了一个请求,提供其中一个标头来标识您的应用;并使用simplexml_parse_string()解析生成的XML字符串。

E.g:

// setup variables
$nominatim_url = 'https://nominatim.openstreetmap.org/search?postalcode=28217&country=DE&format=xml&polygon=1&addressdetails=1&boundary=postalcode';
$user_agent    = 'ID_Identifying_Your_App v100';
$http_referer  = 'http://www.urltoyourapplication.com';
$timeout       = 10;

// curl initialization
$ch         = curl_init();
curl_setopt($ch, CURLOPT_URL, $nominatim_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);

// this is are the bits you are missing
// Setting curl's user-agent
curl_setopt($ch, CURLOPT_USERAGENT, $user_agent); 
// you an also use this one (http-referer), it's up to you. Either one or both.
curl_setopt($ch, CURLOPT_REFERER, $http_referer); 

// get the XML
$data = curl_exec($ch);
curl_close($ch);

// load it in simplexml
$xml = simplexml_load_string($data);
// This was your code, left as it was
if (false === $xml) {
    $errors = libxml_get_errors();
    var_dump($errors);
}

答案 1 :(得分:0)

您可以使用curl添加自定义标头,我希望此代码对您有用:

<?php
$request_url='https://nominatim.openstreetmap.org/search?postalcode=28217&country=DE&format=xml&polygon=1&addressdetails=1&boundary=postalcode';

$ch = curl_init();
$timeout = 5;
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Accept-Language: en-US,en;q=0.9,fa;q=0.8,und;q=0.7',
'User-Agent:    Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36'));

curl_setopt($ch, CURLOPT_URL, $request_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
$data = curl_exec($ch);
curl_close($ch);

echo($data);