Can somebody help me in converting the following code written using if-else to try/catch. Also let me know is trycatch needed in this case or if-else is apt
$results = mysql_query($query);
if(mysql_num_rows($results)!=0)
{
while(($result = mysql_fetch_row($results))!=FALSE)
{
$res ="DELETE FROM table1 WHERE id ='".$result['id']."'";
if(mysql_query($res)==false)
{
echo mysql_error();
exit;
}
}
echo $res ="DELETE FROM table2 WHERE id ='".$id."'";
if(mysql_query($res)!==false)
{
header("Location:list.php?m=4");
}
else
{
echo mysql_error();
exit;
}
}
else
{
echo "Error";
}
try...catch only makes any sense if your functions are throwing exceptions. If they don't, there's nothing to catch. I'd start with this as a refactoring:
$results = mysql_query($query);
if (!mysql_num_rows($results)) {
echo 'No results!';
exit;
}
$ids = array();
while (($result = mysql_fetch_row($results)) !== false) {
$ids[] = $result['id'];
}
$ids = array_map('mysql_real_escape_string', $ids);
$query = "DELETE FROM table1 WHERE id IN ('" . join("','", $ids) . "')";
if (!mysql_query($query)) {
echo mysql_error();
exit;
}
$query = "DELETE FROM table2 WHERE id = '$id'";
if (!mysql_query($query)) {
echo mysql_error();
exit;
}
header("Location: list.php?m=4");
exit;
This can still be improved a lot, but it's already an improvement over your spaghetti logic. If you're seriously interested in properly using exceptions, you should first move on to properly using functions for repetitive tasks (like the error, exit parts), then possibly restructure the whole thing into classes and objects, and lastly use exceptions to communicate between the now nested layers. Maybe start using a PHP framework to get a feeling for the whole thing.
Putting exceptions into the above code would be hardly more than a goto, but just for illustrative purposes:
try {
$results = mysql_query($query);
if (!mysql_num_rows($results)) {
throw new Exception('No results!');
}
$ids = array();
while (($result = mysql_fetch_row($results)) !== false) {
$ids[] = $result['id'];
}
$ids = array_map('mysql_real_escape_string', $ids);
$query = "DELETE FROM table1 WHERE id IN ('" . join("','", $ids) . "')";
if (!mysql_query($query)) {
throw new Exception(mysql_error());
}
$query = "DELETE FROM table2 WHERE id = '$id'";
if (!mysql_query($query)) {
throw new Exception(mysql_error());
}
header("Location: list.php?m=4");
exit;
} catch (Exception $e) {
echo 'ERROR: ' . $e->getMessage();
exit;
}
from the sound of it, it seems you think try/catch and if-else as the same behaviour. That is not the case. Try catch is used to prevent an exception from making the application crash or to handle exceptions gracefully, and to perform logging and giving user feedback. If-else (else if) is used to check the internal state of your application, and perform different actions accordingly.
Generally, a try-catch is less efficient than if there is a switch-case or else-if approach to the problem.
Related
I am new to PDO, and am in the process of upgrading an application from mysql_query to PDO. This is surely a stupid question - but I hope someone can help me wrap my head around it.
I need to see if a PDO query has any data:
- if it doesn't, throw an error
- if it does, retrieve that data
I could do this easily with mysql_num_rows, but that's deprecated as we all know.
The issue is that once I've checked if there is any data, I can no longer retrieve it.
The check runs fine, but then when trying to retrieve the actual result, it's empty. I can of course execute the query again after the check - but I'd rather avoid having to run a query twice.
try
{
$result = $pdo2->prepare("SELECT first_name FROM users WHERE email = :email;");
$result->bindValue(':email', $email);
$result->execute();
$data = $result->fetchAll();
}
catch (PDOException $e)
{
$error = 'Error fetching user: ' . $e->getMessage();
echo $error;
exit();
}
if (!$data) {
echo "No data!";
} else {
echo "Data found!";
}
$row = $result->fetch();
echo "First name: " . $row['first_name'];
How can I solve this?
I tried to assign $result to another variable ($test = $result), and then run the data check on the $test variable instead - but even so, the $result variable STILL doesn't return any data after running the check (see the commented lines):
try
{
$result = $pdo2->prepare("SELECT first_name FROM users WHERE email = :email;");
$result->bindValue(':email', $email);
$result->execute();
$test = $result; // Duplicating the variable
$data = $test->fetchAll(); // Running the check on the duplicated variable
}
catch (PDOException $e)
{
$error = 'Error fetching user: ' . $e->getMessage();
echo $error;
exit();
}
if (!$data) {
echo "No data!";
} else {
echo "Data found!";
}
$row = $result->fetch(); // Still doesn't return the result!
echo "First name: " . $row['first_name'];
This is really doing my head in... I think there's a simple solution somewhere, I just can't see it. Please help!
$result->fetch() only fetches rows that haven't already been fetched. Since you fetched everything with $result->fetchAll(), there's nothing left.
If you want the first row, you can use:
$row = data[0];
If you want to process all the rows, use:
foreach ($data as $row)
Instead of fetching everything, you can use the rowCount() method.
if (!$result->rowCount()) {
echo "No data";
} else {
echo "Data found!";
}
There are caveats regarding the use of rowCount() with SELECT queries in PDO, but I think it generally works with MySQL.
As you are using a try/catch block you can raise your own exceptions as well as catch those thrown by PDO - so you could do something like this:
try{
$sql='SELECT first_name FROM users WHERE email = :email;';
$stmt = $pdo2->prepare( $sql );
if( !$stmt )throw new Exception('Failed to prepare sql statement');
$result=$stmt->execute( array( ':email' => $email ) );
if( !$result )throw new Exception('Failed to get any results');
$rows = $stmt->rowCount();
if( $rows == 0 )throw new Exception('Empty recordset');
while( $rs=$stmt->fetch( PDO::FETCH_OBJ ) ){
echo $rs->firstname;
}
}catch ( PDOException $e ){
exit( 'Error fetching user: ' . $e->getMessage() );
}
You can always fetch individual rows and for the first row, check if the data is returned and process if not. Then enter a do...while() loop which processes the data and then reads the next row at the end of the loop...
try
{
$result = $pdo2->prepare("SELECT first_name FROM users WHERE email = :email;");
$result->bindValue(':email', $email);
$result->execute();
$row = $result->fetch(); // Fetch first row of data
if (!$row) {
echo "No data!";
} else {
echo "Data found!";
do {
echo "First name: " . $row['first_name'];
}
while ($row = $result->fetch());
}
}
catch (PDOException $e)
{
$error = 'Error fetching user: ' . $e->getMessage();
echo $error;
exit();
}
try {$db=mysqli_connect( etc )
catch {
retry on time out
handle errors
}
try { if (!($errors = $db->prepare("insert into errors (`insert`,`error`) values(?,?);
print "\n*********prepare Error:" . $db->error;
}
}
catch { repeat above}
try {$errors->bind_param("ss",$sqlLoad,$errormsg); }
catch {repeat above)
....
try {$error->execute()} catch {repeat above error handling}
Now repeat all of that 10-40 times for different SQL queries on different fields.
That is a lot of duplicated code. Make my code hard to read, and if someone wants to add more sql queries they are forced to reduplicate large blocks of code.
I was thinking something like this but ran into a stumbling block with bind.
$sql[0]=array("name","select ? from <tablename>","s");
$sql[1]=array("name","select ?,? from <tablename>","ss");
$sql[2]=array("name","select ?,?,? from <tablename>","sss");
$sql[3]=array("name","select ?,?,?,? from <tablename>","ssss");
for(i=0;i<=3,i++){
try (
$preQuery[$sql[i][0]=$db->prepare($sql[i][1]);}
catch {}
try {$preQuery[$sql[i][0]]->bind_param($sql[i][2],????);} //Here is the trouble how do I define unique variables
catch { }
}
Here is some real code
It is a work in progress
foreach ($fieldspath as $field)
{
$filepath=$_SERVER[$field];
$result=$queryfile->execute();
$getres = $queryfile->get_result();
$numRows = -1;
$numRows = $getres->num_rows;
if ($numRows <>0)
{
$qryField = $getres->fetch_assoc();
$_SERVER[$field]=$qryField["id"];
$fileCount=$qryField["count"];
$fileRating=$qryField["rating"];
mysqli_query($db, "update Files set count=count+1 where `id` ='" . $qryField["id"] . "';");
continue;
}
else
{
$output = $insertFile->execute();
$result = $queryip->execute();
$getres = $queryip->get_result();
$qryField = $getres->fetch_assoc();
$_SERVER[$field]=$qryField["id"];
}
}
Notice: How I can re-execute a query just by:
$result=$queryfile->execute();
The query doesn't have to be re-stated, nor do the parameters. Everything is automatic. The actual queries are all listed at the top of the program, and I never have to see them, or restate them ever again. Also I don't need to cram my parameters into array before I can use them.
<?php
$pipeName = '/var/run/mysql/mysql.sock';
$username = 'user';
$password = 'password';
$db = new PDO('mysql:unix_socket='.$pipeName.";dbname=dbase", $username, $password);
$sql["errors"]="insert into errors (`insert`,`error`) values(:insert,:error);";
$sql["events"]="insert into event (`message`) values(?);";
$sql["queryip"]="select id,count,rating FROM ip where address=? limit 1;";
$sql["queryUsrAgent"]="select id,count,rating FROM http_user_agent where agent=? limit 1;";
$sql["insUsrAgent"]="insert into http_user_agent (`agent`) values (?);";
$sql["insertIP"]="insert into ip (`address`) values (?);";
$sql["insertReqURI"]="insert into request (`REQUEST_URI`) values (?);";
$sql["queryReqURI"]="select * FROM request where REQUEST_URI=? LIMIT 1;";
$sql["queryfile"]="select id,count,rating FROM Files where path=? limit 1;";
$sql["insertFile"]="insert into Files (`path`) values (?);";
$sql["cntIp"]="update ip set count=count+1 where `address` = :ip";
$sql["cntFiles"]="update Files set count=count+1 where `id` = :id;";
$sql["cntAgent"]="update http_user_agent set count=count+1 where `agent` = :agent;";
$sql["reqRequest"]="select * FROM request where REQUEST_URI= :requesturi LIMIT 1;";
$sql["cntRequest"]="update request set count=count+1 where `REQUEST_URI` = :requesturi;";
$ready=doPrepare($db,$sql);
$ready["errors"]->execute(array("insert"=>"stuff","error" =>"stuff"));
pdoRun($ready,"errors",array("iniisert"=>"iiiii","error" =>"yyyyyggg"));
function doPrepare($db, $enmass) {
foreach ($enmass as $key => $sql) {
try {
$stmt[$key] = $db->prepare($sql);
} catch (PDOException $e) {
print "\nStuff";
trigger_error($e);
return false;
}
}
return $stmt;
}
function pdoRun($ready,$query,$vals) {
try {
$ready[$query]->execute($vals);
} catch (PDOException $e) {
print "\nExecution fail";
}
}
// $stmt->execute(array_values($column_values));
?>
Making prepared queries like you are doing doesn't work like you seem to think it does. The parameter placeholders can only substitute for literal values. You can't use them for column names or table names or anything else.
You also can't prepare a query like "select ? from" because it names no table. It's not a syntactically complete query.
The better practice is to code a "helper function" that does the prepare and execute for you. You can reduce repetitive code that way.
By the way, I find PDO is much easier than Mysqli when coding a helper function like this, because you don't have to use the bind_param() with variable arguments. In PDO, you just pass an array of arguments to execute().
function doInsert($db, $sql, $params) {
try {
$stmt = $db->prepare($sql);
$stmt->execute($params);
} catch (PDOException $e) {
trigger_error($e);
return false;
}
return true;
}
Now call it this way:
$sql = "insert into errors (`insert`, `error`) values(?, ?)";
$success = doInsert($db, $sql, [$sqlLoad, $errormsg]);
You might even like the function to format your INSERT statement for you:
function doInsert($db, $table, $column_values) {
$placeholders = array_fill(1, count($column_values), '?');
$columns = implode(',', array_keys($column_values));
$sql = "INSERT INTO `$table` ($columns) VALUES ($placeholders)";
try {
$stmt = $db->prepare($sql);
$stmt->execute(array_values($column_values));
} catch (PDOException $e) {
trigger_error($e);
return false;
}
return true;
}
Then call it like this:
$success = doInsert($db, "errors", ["insert"=>$sqlLoad, "error"=>$errormsg]);
You'll have to do something to apply back-ticks to the column names too.
i have several database checks with PDO before i insert some values on the DB and i don't know if one try/catch will catch all errors in the nested PDO or if i need one try/catch for every PDO. This is the code i got now:
try {
$db = connect_db();
$q = "query foobar";
$stm = $db->prepare($q);
$stm->bindParam(1, $foobar);
$status = $stm->execute();
if ($stm->rowCount() == 0) {
if ($def == 0) {
$q = "query foobar";
$stm = $db->prepare($q);
$stm->bindParam(1, $foobar);
$stm->bindParam(2, $foobar);
$stm->bindParam(3, $foobar);
$stm->bindParam(4, $foobar);
$status = $stm->execute();
if ($status) {
echo "<script>alert('foobar');window.location.assign('admin.php');</script>";
} else {
echo "<script>alert('foobar');window.location.assign('admin.php');</script>";
die();
}
} else {
$q = "query foobar";
$stm = $db->prepare($q);
$stm->bindParam(1, $nombre);
$status = $stm->execute();
if ($stm->rowCount() == 0) {
$q = "query foobar";
$stm = $db->prepare($q);
$stm->bindParam(1, $foobar);
$stm->bindParam(2, $foobar);
$stm->bindParam(3, $foobar);
$stm->bindParam(4, $user);
$status = $stm->execute();
if ($status) {
echo "<script>alert('foobar.');window.location.assign('admin.php');</script>";
} else {
echo "<script>alert('foobar.');window.location.assign('admin.php');</script>";
die();
}
}
}
} else {
echo "<script>alert('foobar.'); history.back();</script>";
die();
}
} catch (Exception $e) {
// Proccess error
$msg = $e->getMessage();
$timestamp = date("Y-m-d H:i:s");
$line = $e->getLine();
$code = $e->getCode();
handle_error($msg, $timestamp, $line, $code);
die("foobar");
}
PDO::ERRMODE_EXCEPTION
In addition to setting the error code, PDO will throw a PDOException and set its properties to reflect the error code and error information. This setting is also useful during debugging, as it will effectively "blow up" the script at the point of the error, very quickly pointing a finger at potential problem areas in your code (remember: transactions are automatically rolled back if the exception causes the script to terminate).
Exception mode is also useful because you can structure your error handling more clearly than with traditional PHP-style warnings, and with less code/nesting than by running in silent mode and explicitly checking the return value of each database call.
So, one is enough
I hvae the following PHP source:
$type_ID =$_GET["typeID"];
try{
$article_ID =$_GET["articleID"];
$select_query = mysql_query("SELECT articleContent, articleTitle From articles WHERE articleID=$article_ID && typeID=$type_ID");
}
catch(Exception $e)
{ $select_query = mysql_query("SELECT articleContent, articleTitle From articles WHERE typeID=$type_ID");
}
$row = mysql_fetch_assoc($select_query);
echo '<h1>'.$row['articleTitle'].'</h1>';
echo $row['articleContent'];
I know that this code is no safe, and yo can easlily do sql injection.
There problem here is that it's didn't go into the catch part (after the try)even when it should.
The solution may be easy but I can't solve it.
Why it's didn't go into the catch section?
You'd have to change your queries to use the or to catch the fail in this case something like this may work though I'm not 100% (can anyone correct me?) You'd be far better off moving away from mysql_ functions though and moving to mysqli or pdo in an OO style then you can better trap and handle the errors.
$type_ID =$_GET["typeID"];
try{
$article_ID =$_GET["articleID"];
$select_query = mysql_query("SELECT articleContent, articleTitle From articles WHERE articleID=$article_ID && typeID=$type_ID") or throw new Exception("ERROR HERE");
}
catch(Exception $e)
{
$select_query = mysql_query("SELECT articleContent, articleTitle From articles WHERE typeID=$type_ID"); // note we can't throw exception here because its already in the try catch. perhaps we should look at something like the finally statement.
//echo $e->getMessage(); //uncomment this line if you want to output the exception error text set above
}
$row = mysql_fetch_assoc($select_query);
echo '<h1>'.$row['articleTitle'].'</h1>';
echo $row['articleContent'];
Actually just had a thought you'd be much better doing something like this and validating your inputs before hand. (note i'm doing no string escaping here don't forget to do it)
$type_ID =$_GET["typeID"];
$article_ID =$_GET["articleID"];
if (strlen($type_ID)>0 && strlen($article_ID)>0 && is_numeric($type_ID) && is_numeric($article_ID)) {
$sqlquery = "SELECT articleContent, articleTitle From articles WHERE articleID=$article_ID && typeID=$type_ID";
} else {
$sqlquery = "SELECT articleContent, articleTitle From articles WHERE typeID=$type_ID";
}
try {
$queryresult = mysql_query($sqlquery) or throw new Exception("Query Failed");
} catch(Exception $e) {
echo $e->getMessage();
}
So basically you're validating and checking your inputs and switching your sql statements before then your try catch logic is purely for did the query succeed or fail which is far more sensible than what you were attempting.
Mysql query will return FALSE on error
So you can throw an exception for that
$result = mysql_query("SELECT articleContent, articleTitle From articles WHERE articleID=$article_ID && typeID=$type_ID");
if(!$result) throw new Exception("Invalid query: ". mysql_error());
And catch them in your catch block
catch(Exception $e)
{ echo $e->getMessage()}
Its up to you what you will do with it echo or log.
function get_total_adults()
{
$sql = "SELECT SUM(number_adults_attending) as number_of_adults FROM is_nfo_rsvp";
$result = mysql_query($sql) or die(mysql_error());
$array = mysql_fetch_assoc($result);
return $array['number_of_adults'];
}
I know there is a way to write this with less code. I'm just looking for the best way (without using something like ezSQL).
function get_total_adults() {
$sql = 'SELECT SUM(number_adults_attending) FROM is_nfo_rsvp';
$result = mysql_query($sql) or die(mysql_error());
// I'd throw a catchable exception (see below) rather than die with a MySQl error
return mysql_result($result, 0);
}
As to how I'd rather handle errors:
function get_total_adults() {
$sql = 'SELECT SUM(number_adults_attending) FROM is_nfo_rsvp';
$result = mysql_query($sql);
if (!$result) {
throw new Exception('Failed to get total number of adults attending');
}
return mysql_result($result, 0);
}
try {
$total_adults = get_total_adults();
} catch(Exception $ex) {
die('Whoops! An error occurred: ' . $ex->getMessage());
// or even better, add to your template and dump the template at this point
}
// continue code
You can drop the "as number_of_adults" part of the query and use mysql_result.
You could also try refactormycode.com