hakopako

Full-stack Engineer's blog

"simplexml_load_string" throws an error - how to catch it -

日本語 | English

Loading xml data with just one line like below would bring a few troubles in php, even though it returns "false" when failed.

$xml = simplexml_load_string($data);  

because ...

  • Loading xml that contains control characters will lead to error.
  • When the method returns "false", we can't catch the reason.

Control characters will lead to error.

If you're not familiar with control character, check here.

First of all, you need to find out the way to see the exists of control characters in xml file.
I'll show you 2 ways.

1. Open the file with Chrome browser and check the alert.
f:id:hakopako03:20140510171613p:plain

2. Open the file with Sublime text and you can see control character as symbols.
(SOH is a control character)
f:id:hakopako03:20140510171622p:plain

By the way, for generating control character, I used binary editor which called 0xED. Input hexadecimal notation data, and output it as a control character.

f:id:hakopako03:20140510171632p:plain

Let's back to main topic. These control characters are caused an error when you use simplexml_load_string() function. So safest way is to replace them to safe-character (or delete) before the function runs.

$search = array("\0", "\x01", "\x02", "\x03", "\x04", "\x05","\x06", "\x07", "\x08", "\x0b", "\x0c", "\x0e", "\x0f");  
$data = str_replace($search, '', $data);  
$xml = simplexml_load_string($data);  

 

Catch the parse error

simplexml_load_string() function throws an exception as a warning, so we can't get the cause of false by try-catch statement.
Reference: How do I handle Warning: SimpleXMLElement::__construct()?

So, use set_error_handler. It can temporary upgrade the warning level to error.

set_error_handler(function($errno, $errstr, $errfile, $errline) {  
    throw new Exception($errstr, $errno);  
});  

try {  
    $search = array("\0", "\x01", "\x02", "\x03", "\x04", "\x05","\x06", "\x07", "\x08", "\x0b", "\x0c", "\x0e", "\x0f");  
    $data = str_replace($search, '', $data);  
    $xml = simplexml_load_string($data);  
    restore_error_handler();
}catch(Exception $e) {  
    restore_error_handler();  
    echo $e;  
}  

Then, we can catch the reason of false. By set_error_handler(), the warning is temporary upgraded to error, So don't forget to back that to warning level after parsing xml data with restore_error_handler(). If php version is 5.5 or later, writing restore_error_handler() in "finally" is better.