Checking if sql query has any results in PHP - php

I'm trying to check if an sql query brings back any results in PHP, I've tried using mysql_num_rows($res) but I keep getting an error saying that the function expected parameter to be a resource but it is instead getting an object.
I've attached the relevant code here
$dsn = "mysql://$username:$password#$host/$dbName";
require_once('MDB2.php');
$db =& MDB2::connect($dsn);
if(PEAR::isError($db)){
    die($db->getMessage());
}
$sql=//sql query
$res =& $db->query($sql);
if(PEAR::isError($res)){
    die($res->getMessage());
}
$resultsFound = false;
if (mysql_num_rows($res)>0){
while($row=$res->fetchRow()){
//insert results here
}
} else {
echo "<br><h2>Sorry, invalid input</h2>";
}
I'm sure the solution is fiendlishly simple but I'm new to php and sql and would really appreciate your help!

Maybe this one helps?
https://pear.php.net/manual/en/package.database.mdb2.intro-fetch.php
You could use fetchAll() to fetch all results - count() on the response of fetchAll() should do the trick for you.
After you've built up your functionality, I suggest you migrate to some newer stuff, you should not use MDB2 anymore - it's deprecated stuff.
https://www.php.net/manual/en/pdo.query.php may be the more modern way to use PHP with mysql.
Otherwise use https://www.php.net/manual/en/mysqli.query.php - you can also retrieve the number of datasets in there.

Related

How To Catch Exception DB::unprepared()

I want to run SQL script file in Laravel 5.5 and I use DB::unprepared($sql) which is good so far. But I found that DB::unprepared($sql) seems didn't return any error Exception. I try with different method but still didn't work.
Here some Exception class that I tried: \Exception, PDOException, \Illuminate\Database\QueryException, but didn't work.
Try tried get bolean return from DP::unprepared($sql) by doing this $return = DB::unprepared($sql); var_dump($return); but always return TRUE
I tried using DB::statement($sql), but it looks like use only for executing statement per statement. I need to run a whole sql file without any modification.
Could anyone help me how to catch any SQL script error? Any laravel function method that could help me catch SQL exception?
#Kenjiro, I'm sure you already solved your problem, one a half year past. But, if I nailed it, please mark my answer as it will help fellows with the same problem in the future. This post was the first when googling and it has no answer...
Well, it seems that, like me, you were submiting a multistatement query to DB::unprepared.
Say:
$sql = '
drop temporary table if exists tmp_data;
create temporary table tmp_data
select1 *
from data;'
$result = DB::unprepared($sql)
Even with the typo in select1, the code will run and $result will be true.
To make it work as expected we have to submit each single statement:
$sql = 'drop temporary table if exists tmp_data;'
DB::unprepared($sql);
$sql = '
create temporary table tmp_data
select1 *
from data;'
DB::unprepared($sql)
No need to check the result. The second call to unprepared will raise an exception.
That's it.
You can check it with try catch :
try {
//your code
} catch(\Illuminate\Database\QueryException $ex){
dd($ex->getMessage());
// Note any method of class PDOException can be called on $ex.
}
Also check For Reference : Check This out

how to execute multiple statements in loop

Hallo I have several queries to execute, all returning independent resultsets:
select * from table;
call procedureA(par1);
call procedureB(par2);
I would like to execute them within a loop to perform other operations:
$queries = array("select * from table;", "call procedureA(par1);", "call procedureB(par2);");
foreach($queries as $query) {
$res=$db->query($query);
// do something here with the query result
someFunction($res);
}
The first statement runs fine; at the second iteration, it stops stating that $res is a non object:
Call to a member function ... on a non-object
Apart from using mysqli_multi_query(), in which way could I loop execute multiple queries?
UPDATE I removed $res->close(); from the code sample since it was misleading and ininfluent for the issue.
UPDATE2 - SOLUTION
For anyone's sake, here is a complete working code:
$queries = array(
"CALL procedureA(par1)"
,"CALL procedureB()"
, "Select * from tableC"
);
// Open connection
$db = new mysqli(
$config['host']
,$config['user']
,$config['pwd']
,$config['dbname']
);
foreach($queries as $query) {
if ($res instanceof mysqli_result) {
$res->free();
}
$res=$db->query($query);
// do something with the query
echo getHtmlTable($res);
// free current result
$res->free();
// free subsequent resultset (es. the one with OK/ERR sp call status)
while ($db->next_result()) {
//free each result.
$res = $db->use_result();
if ($res instanceof mysqli_result) {
$res->free();
}
}
}
There is nothing special in running queries in a loop.
There will be no difference, either if you write two queries just one after another, or run them in a loop. So, generally speaking, a couple of queries run in a loop is no different from a couple of queries run in order just like in all our scripts.
The only possible problem a query itself. Say, a stored procedure call always return at least two resultsets. And no other query can be run until all resultsets get retrieved.
So, as a quick-and-dirty solution a line like this could be added
while ($db->next_result()) {}
at the bottom of the loop to clean up all the resultsets possibly remained in a queue after the query execution.
It qould be also highly convenient to turn on error reporting for mysqli, to make you aware of all the mysql error occurred. Having that, you would have added such error message to your question (Which is "Commands out of sync"). To do so, add this line before mysqli connect:
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$r->close();
should be
$res->close();
You are referencing a non existent object ($r).
The execution of multiple queries depends of a server configuration. But aside from thas. This would be better to use transactions (that depending of the effect of those stored procedures, of course)

How to catch DB errors in CodeIgniter PHP

I am new to CodeIgniter, PHP and MySQL. I want to handle the DB generated errors. From one of the post in Stackoverflow, I knew that by following statement one can catch the error.
$this->db->_error_message();
But I cannot figure out the exact syntax of using that. Suppose I want to update the records of table named "table_name" by the following statement:
$array['rank']="8";
$array['class']="XII";
$this->db->where('roll_no',$roll_no);
$this->db->update("table_name", $array);
Here in the above code I want to catch the DB error whenever any DB level violation occurs i.e. either field name is not valid or some unique constraint violation occurs. If anyone helps me to fix that I would be really grateful. Thank you.
You can debug the database error on database configuration in (config/database.php) like this:
$db['default']['db_debug'] = TRUE;
More info read here
Also you can use Profiler to see all the queries and their speed. In controller you can put this:
$this->output->enable_profiler(TRUE);
More information read here
codeIgniter has functions for it
$this->db->_error_message();
$this->db->_error_number();
if(!$this->db->update("table_name", $array))
{
$this->db->_error_message();
$this->db->_error_number();
}
On Codeigniter version 2,
$this->db->_error_message();
$this->db->_error_number();
On Codeigniter version 3,
$db_error = $this->db->error();
echo '<pre>';print_r($db_error);echo '</pre>';

Custom mysqli prepare function

I'm doing my first own database class at the moment and currently I'm doing the prepare function.
What this function does is to take in an SQL-query and then an array containing the variables for the statement. I'm having problems with binding the parameters to the statement.
This is how the function looks like now
public function prepare($query, $var) {
$types = '';
foreach($var as $a) {
$type = gettype($a);
switch($type) {
case 'integer':
$types .= 'i';
break;
case 'string':
$types .= 's';
break;
default:
exit('Invalid type: ' . $a .' ' . $type . '(' . count($a) . ')');
break;
}
}
$stmt = self::$connection->prepare($query);
$stmt->bind_param($types, $var); // How do I do here??
$stmt->execute();
$result = $stmt->get_result();
while($row = $result->fetch_assoc()) {
print_r($row);
}
}
Everything works as I want it to (I know this function could do some polishing but it does what it needs to do). I have commented the line where I'm having trouble figuring out what to do. $var is an array and if I recall things correctly the variables needs to be passed seperately seperated with a comma. This is where I'm clueless.
The very idea of your own database class is great.
Very few people here do share it, for some reason prefers raw api calls all over their code.
So, you're taking great step further.
However, here are some objections:
Don't use mysqli for your first own database class if you're going to use native prepared statements.
Use PDO instead. It will save you a ton of headaches.
Despite of the fact this function works all right for you, it makes not much sense:
switch($type) code block is useless. Mysql can understand every scalar value as a string - so you can bind every value as s with no problem.
most integers coming from the client side have string type anyway.
there are some legitimate types like float or NULL or object that can return a string. So, automation won't work here. If you want to distinguish different types, you have to implement type hinted placeholders instead.
Never use exit in your scripts. throw new Exception('put here your error message') instead.
This is not actually a prepare function as it does execute as well. So, give it more generic name
But now to your problem
It is direct consequence of using mysqli. It is a nightmare when dealing with prepared statements. Not even only with binding but with retrieving your data as well (because get_result() works not everywhere, and after creating your application locally you will find it doesn't work on the shared hosting). You can make yourself an idea looking at this bunch of code served for this very purpose - to bind dynamical number of variables.
So, just keep away from mysqli as far as as you could.
With PDO your function will be as simple as this
public function query($query, $var=array())
{
$stmt = self::$connection->prepare($query);
$stmt->execute($var);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// and then used
$data = $db->("SELECT 1");
print_r($data);
You can take a look at my class to get some ideas.
Feel free to ask any questions regarding database classes - it's great thing, and I am glad you're going this way.
To answer questions from the comments.
To let you know, you're not the only user of the site. There are also some innocent visitors. Unlike you, they don't need no error messages, and they get scared with some strange behavior and lack of familiar controls.
exit() with error message does many evil things
throws an error message out, revealing some system internals to a potential attacker
scaring innocent user with strange message. "What's that? Who is invalid? Is it mine fault or what? Or may be it's a virus? Better leave the site at all" - thinks them.
killing the script in the middle, so it may cause torn design (or no design at all) shown
killing the script irrecoverably. while thrown exception can be caught and gracefully handled
When connecting to PDO, no need to throw anything here as the exception already thrown by PDO. So, get rid of try ... catch and just leave it one line:
self::$connection = new PDO($dsn, $user, $pass);
then create a custom exception handler to work in 2 modes:
on a development server let it throw the message on the screen.
on a live server let it log the error while showing generic error page to the user
Use try ... catch only if you don't want to whole script die - i.e. to handle recoverable issue only.
By the way, PDO don't throw exception on connect by default. You have to set it manually:
$opt = array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION );
self::$connection = new PDO($dsn, $user, $pass, $opt);

PHP: MySQL error hook?

I've been developing a web application with PHP and MySQL. The other day, I made some changes to the database and adapted one page to the new table layout but not another page. I didn't test well enough, so the site went online with the error still in the other page. It was a simple MySQL error, and once one of my co-workers spotted it, it was a simple fix.
Now that it's happened, I'd like to know how I can catch other MySQL errors. I'm thinking about some sort of notification system, that would send me an email when a mysql_query() fails.
I understand, of course, that I wouldn't be notified until after the error occurred, but at least I would have been notified immediately, rather than my co-worker come tell me after who-knows-how-many other people had run into the same fatal error.
Is there some sort of way to put in a hook, so that PHP automatically runs a function when an error happens? Or do I need to go through my code and add this functionality to every location where I use mysql_query()?
If the latter, do you have any recommendations on how to prevent something like this in the future? If this is the case I'll probably create a class to abstract SQL operations. I know I should have been doing this the whole time... But I did organize my sets of functions into different include files, so at least I'm doing most things right. Right?
You could use a wrapper function like this:
function mysql_query_wrapper($query, $link=null)
{
if (is_null($link)) {
$result = myql_query($query);
} else {
$result = myql_query($query, $link);
}
if (mysql_error($result)) {
// error occurred
}
return $result;
}
Then you just need to replace each mysql_query call with mysql_query_wrapper.
You can use custom functions for error handling using set_error_handler().
However, mysql_query won't trigger an error, but return false. The errors turn up only afterwards when trying to work with the results. In this case it might be better to define a custom wrapper function that calls mysql_query() and outputs possible errors using mysql_error(). That way, you can immediately halt your application on an error if so desired.

Categories