Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error when loading external xml file with php via https : SSL3_GET_SERVER_CERTIFICATE

Tags:

php

xml

I can't get a xml file to load.

This code works great:

$url = 'http://www.w3schools.com/xml/note.xml';
$xml = simplexml_load_file($url);
print_r($xml);

But this one

$url = 'https://www.boardgamegeek.com/xmlapi2/thing?id=105551';
$xml = simplexml_load_file($url);
print_r($xml);

doesn't work. I get this error:

Warning: simplexml_load_file(): SSL operation failed with code 1. OpenSSL Error messages: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed in /storage/content/59/113059/boardgamelevelup.com/public_html/index.php on line 19 Warning: simplexml_load_file(): Failed to enable crypto in /storage/content/59/113059/boardgamelevelup.com/public_html/index.php on line 19 Warning: simplexml_load_file(https://www.boardgamegeek.com/xmlapi2/thing?id=105551): failed to open stream: operation failed in /storage/content/59/113059/boardgamelevelup.com/public_html/index.php on line 19 Warning: simplexml_load_file(): I/O warning : failed to load external entity "https://www.boardgamegeek.com/xmlapi2/thing?id=105551" in /storage/content/59/113059/boardgamelevelup.com/public_html/index.php on line 19

The xml file from boardgamegeek works on other sites. Should I use a different php code to load that xml file?

like image 983
Roberth Avatar asked Sep 17 '15 02:09

Roberth


1 Answers

short cookbook answer:

  1. Download https://raw.githubusercontent.com/bagder/ca-bundle/master/ca-bundle.crt and place that file on your server.
  2. Add

    $context = stream_context_create(array('ssl'=>array(
        'verify_peer' => true,
        'cafile' => '/path/to/ca-bundle.crt'
    )));
    libxml_set_streams_context($context);

to your script so it gets executed before simplexml_load_file().
Or - instead of the code above - set openssl.cafile=/path/to/ca-bundle.crt in your php.ini.

Very short explaination:
Your php version uses openssl to handle the https transport. openssl tries to verify whether the server really is who it claims to be. It does that by checking whether its certificate is trusted. A X.509 certificate contains some data about the owner and is signed by an issuer (itself having a certificate that is again signed and so on and on until a certificate where owner and issuer are identical -> self-signed/root certificate). A certificate is considered "trusted" if in that chain of certificates there is (at least) one certificate on which openssl "says": "ok, I have been instructed to trust this one". This instruction takes the form of (or can take the form of) "here's a file containing certificates that you're supposed to trust" (cafile).
The above code tells the libxml-wrapper of php to tell openssl where that cafile is when simplexml_load_file uses the https/openssl-wrapper.
And openssl.cafile=/path/to/ca-bundle.crt just sets it as default; unless instructed otherwise all openssl operations will use that file - including libxml/simple_xml_loadfile.

The ca-bundle.crt I've linked to is from a project that "claims" to provide the extracted root certificates as shipped with mozilla firefox. Regarding "claims": I have no reason to doubt that this really is the untampered root cert list; but you never know: You're putting your trust a) in this project and b) mozilla doing a good job and only putting trustworthy certificates in that list....

for more explaination see http://phpsecurity.readthedocs.org/en/latest/Transport-Layer-Security-%28HTTPS-SSL-and-TLS%29.html#php-streams

like image 173
VolkerK Avatar answered Sep 26 '22 13:09

VolkerK