Unable to catch XML exception/error in PHP - php

I am not able to catch exception with below code. Can anyone help me with this thing?
try
{
$xml_emp_name = $xpath->evaluate("//EMPLOYEES[ID='" . $emp_id . "']/EMP-NAME/text()")->item(0)->nodeValue;
}
catch(Exception $e)
{
echo "Error: " . $e->getMessage();
}

DOMXPath::evaulate does not throw exceptions. domxpath evaluate
If the expression is malformed or the contextnode is invalid, DOMXPath::evaluate() returns FALSE.
Try
$xml_emp_name = $xpath->evaluate("//EMPLOYEES[ID='" . $emp_id . "']/EMP-NAME/text()");
if(!$xml_emp_name){
echo 'Error';
}else{
$name = $xml_emp_name->item(0)->nodeValue;
}
You try to access a property on a non-object if evaulate fails and returns false.

Your code is prone to xpath injection. Fix that first. The error then goes away automatically (because the xpath can not become syntactically invalid). Also you need to check/validate return values.
So you're missing the basic principles of input validation and return value validation. All you need to do is to take more care.
Input validation:
You directly inject the variable $emp_id into the xpath string for substitution:
"//EMPLOYEES[ID='" . $emp_id . "']/EMP-NAME/text()"
However at that place you can not have a single quote inside that string. Instead check the input value (Validation) or filter/streamline it (Sanitization). For exampe, validate that it does not contain a single quote or sanitize for a numeric value. Here the second:
$expression = sprintf('//EMPLOYEES[ID="%d"]/EMP-NAME/text()', $emp_id);
$result = $xpath->evaluate($expression);
This little call to sprintf() takes care that only numeric integer values are being used. They never contain quotes, so the expression is always valid. Invalid values that are no number will become 0. As it's the general principle to never assign the ID 0 this should normally not cause any issue in a well designed system. If you want to do the filtering more granular please see Data Filtering in the PHP manual.
return value validation
In your code you just take over the return value of the result with very little checks (actually no checks). That is wrong. For each method or function you use you need to look it up in the PHP manual and check the documentation for all possible return values. Here the method is DOMXpath::evaluate(), click the link and locate the Return Values section. You find this for each method and function in the PHP manual.
When you read the documentation also figure out which kind of error-handling a method makes use of. Does it throws exceptions (and if yes, which ones?) or does it show an error-condition with it's return value (like in your case)? This information is needed to decide whether to do try/catch as you did (and which is wrong because it does not throw exceptions) or if you need to check the return value:
$expression = sprintf('//EMPLOYEES[ID="%d"]/EMP-NAME/text()', $emp_id);
$result = $xpath->evaluate($expression);
if (!$result) {
throw new Exception(
sprintf('No such employee (id: %s)', var_export($emp_id, true))
);
}
This example turns a falsy return value into an exception with an individual exception message. You also might want to consider a different exception, the SPL offers some pre-defined exceptions.
I hope this answer helps you to deal with this issue and forthcoming ones.

->evaluate will for some reason not throw any exceptions, so what I would advise is to check if the result is false, then throw an exception:
if (($xml_emp_name = $xpath->evaluate("//EMPLOYEES[ID='" . $emp_id . "']/EMP-NAME/text()") ) !== false) {
$xml_emp_name = $xml_emp_name->item(0)->nodeValue;
}
else {
// Throw Exception
}

Related

PHP DomCrawler fails

I'm grabing some information using PHP, 'DomDrawler' and 'Xpath Helper'
When I query some node information, there is no matched value returned.
I don't know why it doesn't work.
Page
<?php
require '../vendor/autoload.php';
use GuzzleHttp\Client;
use Symfony\Component\DomCrawler\Crawler;
function showcourse($response){
$data = []; //Store
$crawler = new Crawler();
$crawler->addHtmlContent($response);
try {
$data['name'] = $crawler->filterXPath('/html/body/div[#id=\'brief\']
/table/tbody/tr[1]/td[1]/table[#class=\'items\'][1]/tbody/tr/td[#class=
\'cover\'][1]/a[#id=\'NEU01000219238\']/img/#src')->text();
} catch (\Exception $e) {
echo "No nodes ";
}
print_r($data);
//echo $response;
}
?>
Result
Nothing is returned.
First, your shown xpath examples are different from each other ... without having a xml document its just wild guessing, but this kind of error is most likely an xpath expression issue. Try to reduce the complexity of the xpath expression until an expected result returns. Or try to begin with the simplest expression /html. If this also does not return anything try // as expression ... if there is also no result, the error is most probably not your expression.
Double check if a valid document returns from your response.

php time validation without zero in hours

I want to validate for a 24 hour format.
The below code accepts 1:05:24 which is wrong, as it should instead only accept 01:05:24
try
{
foreach ($arr as $key=>$item)
{
if (date('H:i:s', strtotime($item[1])))
{
} else {
throw new Exception('Invalid Time Format');
}
}
}
catch (Exception $e)
{
echo $exp = $e->getMessage();
}
The following use of preg_match will differentiate between the two cases you have mentioned.
However, note that neither this nor the method that you mentioned in the question will correctly detect an invalid time such as 00:99:99.
If you require that, you need a different method, the easiest of which is probably to parse out the numbers and run this function on it.
<?php
$mydate_bad = "1:05:70";
$mydate_good = "01:05:24";
print (preg_match("/^\d\d:\d\d:\d\d$/", $mydate_bad)); # Returns 0
print (preg_match("/^\d\d:\d\d:\d\d$/", $mydate_good)); # Returns 1
?>
Based on the code you've provided, one way would be the following:
$php_date = date('H:i:s', strtotime($item[1]));
if ($php_date && $php_date == $item[1]) {
// valid date
}
This will check that a date could be created as in your code, and it will also ensure that the resulting date in the format H:i:s corresponds to what the user entered.
However, in terms of user-friendliness, if you can create a date from the user input, it might be better just to accept it and add the leading 0 yourself if it is missing. Simply use $php_date in favor of $item[1] afterwards.

Unit Testing in PHPUnit - Handling Multiple Conditions

I want to write a test using PHPUnit which includes a check to make sure that a value is either a string or NULL.
AFAIK, I can write such a test like so:
if (is_string($value) || is_null($value)) {
$result = TRUE;
} else {
$result = FALSE;
}
$this->assertTrue($result);
However, I've seen that PHPUnit has a logicalOr() method, which I don't know if I should be using to make a more 'native' test? And if I should be using it, I can't figure out how to do so...
Using phpunit v5.5 it (also) works this way:
if (is_string($value) || is_null($value)) {
$result = TRUE;
} else {
$result = FALSE;
}
$this->assertThat($value, $this->logicalOr(
$this->isType('string'),
$this->isNull()
));
logicalOr returns an object that is used to build a condition that can be passed to assertThat. I can't check the syntax on my phone, but it should look something like this:
self::assertThat(self::logicalOr(self::stringValue(), self::nullValue()));
The method names are no doubt incorrect as I am used to Hamcrest, but I he structure is similar.
The best approach is the one which will give you the most usable output in the event of a problem. In this case, I don't think it matters too much which way you so it, as long as you know what went wrong. The following code will provide a meaningful error message:
$message = '$value should have been either a string or null, but was actually a '
.gettype($value);
$this->asertTrue($valueIsEitherStringOrNull, $message);

How would you go about validating that a regex actually compiles and works, ie doesn't throw an error?

I'm creating an administration panel that has regex's submitted to it. Any ideas on how I would go about validating the submitted regex's to see if they work. When I say "see if they work" I mean if the regex's are valid and compile properly, not that they actually match data or not?
FYI, This would be in PHP.
Solved it myself after checking the docs.
preg_match('/'.$pattern.'/', 'foobar foobar foobar');
if(preg_last_error() === PREG_NO_ERROR)
{
// ok
}
preg_match returns boolean false on error so it's a simple matter of checking the return value (make sure you use the === not ==) and suppress the warning output:
if (#preg_match('/some expression/', '') === false) {
// bad regex
}
Another solution that wont throw a warning but uses ugly error supressing...
$good_re = '~\d+~';
$bad_re = '##$';
$good_check = #preg_match( $good_re, 'asdd' );
var_dump($good_check);
$bad_check = #preg_match( $bad_re, 'asdd' );
var_dump($bad_check);

Why PHP is not showing exception?

I am using following code. When the query crashes, it is not displaying the ALERT that I defined in the "catch" block.
<?php
error_reporting(E_ALL ^ E_NOTICE);
require_once("../Lib/dbaccess.php");
//Retrieve values from Input Form
$CategoryName = $_POST["inCategory"];
$TotalMembers = $_POST["inTotalMembers"];
$Details = $_POST["inDetails"];
$CategoryName = $_POST["inCategory"];
$Chairman = $_POST["inChairman"];
$InsertQuery = "REPLACE INTO electioncategorymaster (ecname, ecdescription, ectotalmembers, ecchairman, lastupdated) VALUES ('".$CategoryName."','".$Details."',".$TotalMembers.",'".$Chairman."',now())";
try
{
$Result = dbaccess::InsertRecord($InsertQuery);
}
catch(exception $ex)
{
echo "<script type='text/javascript'>alert('".$ex."');</script>";
}
?>
If you want to get the message of the exception, you should use :
$ex->getMessage();
And not only $ex.
Also, you should escape the quotes in that string, to be sure to have some valid Javascript string -- addslashes might help, here.
If that doesn't change a thing :
are you sure there is an exception thrown ?
can you take a look at the output of your script ? ("view source" in your browser)
Also, if you want to get the full stack-trace of the exception, you might want to use something like this, instead of doing a JS alert :
echo '<pre>';
var_dump($ex);
echo '</pre>';
And, as always : installing the great Xdebug extension can help a lot, on a development server ;-)
For future reference, when outputting values to JavaScript from PHP it's usually best just to use json_encode. This removes the need to encapsulate it in quotes and escape it.

Categories