mysql query occasionally returns nothing - php

We have a function used within our PHP/MySQL application which returns basic configuration information, it contains a simple select query and looks like this:
public function getConfigurationValue($field)
{
$res = mysql_query("SELECT `cfg_value` FROM `ls_config` WHERE `cfg_name` = '".mysql_real_escape_string($field)."'");
$cfg = htmlspecialchars(mysql_result($res,0));
return $cfg;
}
This problem we are having is that occasionally, seemingly at random, this query throws a mysql error on mysql_result saying that "supplied argument is not a valid mysql result resource". In our debugging we have determined though that this is not because $field is not being passed. Essentially, for a reason we cannot determine a perfectly valid query fails and returns no results causing an empty result set and the subsequent error. If the error was due to the mysql connection failing the script would have died well before this. Also, this function may be called 50-100 times on some page loads but it only tends to fail once on each load.
Please let me know if you need any other information to work this out.
Thanks.

searching for php "supplied argument is not a valid mysql result resource" reveals that to get the actual error, you'd need to call mysql_error, and the error that you get is because the result of the query is FALSE - this value not being a valid mysql result resource.
i.e. in short you have something like:
$res = FALSE; # should contain the mysql result but does not, due to error.
$cfg = htmlspecialchars(mysql_result($res,0)); # the attempt to call mysql_result on invalid argument errors out.
So you'd want to use something like this:
$query = "SELECT * FROM cats WHERE id=$id";
$qr1 = mysql_query ($query)
or die ("Query failed: " . mysql_error() . " Actual query: " . $query);
You might want to give this a shot and see what the underlying error message says.
Given that the error is "MySQL server has gone away", There can be multitude of reasons for it - this article would be a good start to investigate. Searching suggests also some php-related and stack-specific bugs, so it looks like you might need to debug it with a closer attention.
Maybe try to duplicate the setup on another box and then start experimenting with the versions/settings, and see if any of the already reported scenarios match your case. Unfortunately, seems there's no single simple answer to this.

Related

Error accessing MySQL database with PHP object (nested queries)

I want to get some data from a Sphinx server and pass it to MySQL to execute some queries. I'm new to PHP so probably I'm missing something here. I've looked for similar questions but can't find anything so maybe you can help me.
The error is in the first while. I'm pretty sure it's due to the $rown variable but don't know the reason. (I've verified that I can retrieve data from the connections so it is passing the data where the error lies - could be the sql syntax of the query but that seems fine).
Edited the code thanks to the comments below, now I get the error: Warning: mysqli_fetch_object() expects parameter 1 to be mysqli_result, boolean given in C:\Apache24\htdocs\test3.php on line 20. This is because the query failed, I still suspect it is because $rown.
$sphinxcon = mysqli_connect...
$mysqlcon = mysqli_connect...
$query = "SELECT names FROM iproducts LIMIT 0,1000";
$raw_results= mysqli_query($sphinxcon, $query);
//Until here works ok, now I want to pass $raw_results to MySQL
while ($row = mysqli_fetch_object($raw_results)) {
$rown = $row->names;
$mquery = "SELECT text FROM claims WHERE EXISTS ($rown) LIMIT 0,1000";
$mysqlresults = mysqli_query($mysqlcon, $mquery);
while ($final = mysqli_fetch_object($mysqlresults)) //this is line 20
{
printf ("%s<br />", $final->text);
}
}
Thanks :)
Well $row contains an object, so would have to use it as such, maybe
$rown = (string)$row->names;
... assuming you want the variable to contain the 'names' attribute you just SELECTed from Sphinx index.
As for the mysql EXISTS(), no idea what you really doing here, seems confused. How you structured it currently suggests that 'names' attribute in sphinx contains a complete SELECT query, that mysql could execute for the exists condition. That seems unlikely.
Guessing you meaning to more normal query something like
$mquery = "SELECT text FROM claims WHERE text LIKE '%$rown%' LIMIT 0,1000";
But that is subject to SQL injection, particully if names might contain single quotes. SO should escape it. Perhaps
$rown = mysqli_real_escape_string($mysqlcon, $row->names);
But might be worth reading up on prepared queries.
btw, the 'Error' you getting, is because you creating an invalid query and not dealing with it. So $mysqlresults is FALSE.
$mysqlresults = mysqli_query($mysqlcon, $mquery) or die("Mysql Error: ".mysqli_error($link)."\n");

MySQL query results are not a resource

I am having trouble with the query in this code. The problem is one I have had before, the $num = mysql_num_rows($result); part gives me a MySQL error saying it expected a resource. Usually when I have this error it is because I misplaced a single quote some where, but after looking I cannot find any problem, though this query is a bit more complex than what I usually have to deal with.
//connect to the database and stuff
$last_year = idate("Y")-1;
$month = date("m");
$day = date("d");
$query = "SELECT bills.b_id, bills.c_id, bills.grand_total, bills.void, bills.date_added,
customers.b_name, customers.l_name, customers.f_name, customers.phone
FROM bills, customers
WHERE bills.c_id = customers.c_id
AND bills.void = '0'
AND date_added BETWEEN '".$last_year."-".$month."-".$day."' AND CURDATE()";
$result = mysql_query($query);
mysql_close($link);
$num = mysql_num_rows($result);
EDIT:
Although I already know the mysql_close() function is not the problem I went ahead and removed it and my code still does not work. This EXACT same code (other than the query) works in nearly a dozen other pages. The problem is in the query, the MySQL error (as stated before) is mysql_num_rows() expects parameter 1 to be resource. I am working on getting the specific error now.
Add some error handling to your code.
$result = mysql_query($query);
if ( !$result ) {
echo 'the query failed: ', mysql_error();
die;
}
(in "real" production code you might not want to display the actual query and error message to just any arbitrary user though).
see also: http://docs.php.net/mysql_error
Check to see if there were mysql errors. If you don't already have error reporting turned on, turn it on for development (error_reporting(E_ALL);).
Try waiting to close your mysql connection until after you're done with the result sets.
Try with the mysql_close() function at the end. If you close the mysql connection, mysql_num_rows() is not going to work
$num = mysql_num_rows($result);
.
.
//Any others mysql operations
.
.
mysql_close($link);
You close link to mysql before retrieving query results. That's the problem. Just don't use mysql_close() as PHP can automatically handle it.
"not a resource" error means your query failed.
change your mysql_query call in that manner
$result = mysql_query($query) or trigger_error(mysql_error().$query);
and see what's wrong with your query.
always do it this way to keep in touch with every error may occur

weird error in php and mysql

$result=mysql_query("SELECT * FROM playerlocations WHERE player<>'0'");
$returntext="";
while($row=mysql_fetch_array($result))
{
if($returntext!=""){$returntext.="&";}
$returntext.=$row['player']."#".$row['locations'];
}
the error message claims that $result isn't a valid result set. I tested it in phpmyadmin, and it worked. I don't know why it won't work here, please help.
It says it isn't a valid result set. That doesn't necessarily mean it isn't a valid query. (Although != instead of <> would be nice.)
To figure out why it's not valid, output the result of calling mysql_error() after running the query:
echo mysql_error(); //most direct way to do this
It will tell you what MySQL reports as the error message.
One obvious thing to check: have you opened the connection (with mysql_connecst()) before running the query?

Why does this PHP code hang on calls to mysql_query()?

I'm having trouble with this PHP script where I get the error
Fatal error: Maximum execution time of 30 seconds exceeded in /var/www/vhosts/richmondcondo411.com/httpdocs/places.php on line 77
The code hangs here:
function getLocationsFromTable($table){
$query = "SELECT * FROM `$table`";
if( ! $queryResult = mysql_query($query)) return null;
return mysql_fetch_array($queryResult, MYSQL_ASSOC);
}
and here (so far):
function hasCoordinates($houseNumber, $streetName){
$query = "SELECT lat,lng FROM geocache WHERE House = '$houseNumber' AND StreetName = '$streetName'";
$row = mysql_fetch_array(mysql_query($query), MYSQL_ASSOC);
return ($row) ? true : false;
}
both on the line with the mysql_query() call.
I know I use different styles for each code snippet, it's because I've been playing with the first one trying to isolate the issue.
The $table in the first example is 'school' which is a table which definitely exists.
I just don't know why it sits there and waits to time out instead of throwing an error back at me.
The mysql queries from the rest of the site are working properly. I tried making sure I was connected like this
//connection was opened like this:
//$GLOBALS['dbh']=mysql_connect ($db_host, $db_user, $db_pswd) or die ('I cannot connect to the database because: ' . mysql_error());
if( ! $GLOBALS['dbh']) return null;
and it made it past that fine. Any ideas?
Update
It's not the size of the tables. I tried getting only five records and it still timed out. Also, with this line:
$query = "SELECT lat,lng FROM geocache WHERE House = '$houseNumber' AND StreetName = '$streetName'";
it is only looking for one specific record and this is where it's hanging now.
It sounds like MySQL is busy transmitting valid data back to PHP, but there's so much of it that there isn't time to finish the process before Apache shuts down the PHP process for exceeding its maximum execution time.
Is it really necessary to select everything from that table? How much data is it? Are there BLOB or TEXT columns that would account for particular lag?
Analyzing what's being selected and what you really need would be a good place to start.
Time spent waiting for mysql queries to return data does not count towards the execution time. See here.
The problem is most likely somewhere else in the code - the functions that you are blaming are possibly called in an infinite loop. Try commenting out the mysql code to see if I'm right.
Does your code timeout trying to connect or does it connect and hang on the query?
If your code actually gets past the mysql_query call (even if it has to wait a long time to timeout) then you can use the mysql_error function to determine what happened:
mysql_query("SELECT * FROM table");
echo mysql_errno($GLOBALS['dbh']) . ": " . mysql_error($GLOBALS['dbh']) . "\n";
Then, you can use the error number to determine the detailed reason for the error: MySQL error codes
If your code is hanging on the query, you might try describing and running the query in a mysql command line client to see if it's a data size issue. You can also increase the maximum execution time to allow the query to complete and see what's happening:
ini_set('max_execution_time', 300); // Allow 5 minutes for execution
I don't know about the size of your table, but try using LIMIT 10 and see if still hangs.
It might be that your table is just to big to fetch it in one query.
Unless the parameters $houseNumber and $streetName for hasCoordinates() are already sanitized for the MySQL query (very unlikely) you need to treat them with mysql_real_escape_string() to prevent (intentional or unintentional) sql injections. For mysql_real_escape_string() to work properly (e.g. if you have changed the charset via mysql_set_charset) you should also pass the MySQL connection resource to the function.
Is the error reporting set to E_ALL and do you look at the error.log of the webserver (or have set display_erorrs=On)?
Try this
function hasCoordinates($houseNumber, $streetName) {
$houseNumber = mysql_real_escape_string($houseNumber);
$streetName = mysql_real_escape_string($streetName);
$query = "
EXPLAIN SELECT
lat,lng
FROM
geocache
WHERE
House='$houseNumber'
AND StreetName='$streetName'
";
$result = mysql_query($query) or die(mysql_error());
while ( false!==($row=mysql_fetch_array($result, MYSQL_ASSOC)) ) {
echo htmlspecialchars(join(' | ', $row)), "<br />\n";
}
die;
}
and refer to http://dev.mysql.com/doc/refman/5.0/en/using-explain.html to interpret the output.
-If you upped the execution time to 300 and it still went through that 300 seconds, I think that by definition you've got something like an infinite loop going.
-My first suspect would be your php code since mysql is used to dealing with large sets of data, so definitely make sure that you're actually reaching the mysql query in question (die right before it with an error message or something).
-If that works, then try actually running that query with known data on your database via some database gui or via the command line access to the database if you have that, or replacing the code with known good numbers if you don't.
-If the query works on it's own, then I would check for accidental sql injection coming from with the $houseNumber or $streetName variables, as VolkerK mentioned.

Can I detect and handle MySQL Warnings with PHP?

I'm dealing with a MySQL table that defines the JobName column as UNIQUE. If somebody tries to save a new Job to the database using a JobName that is already in the database, MySQL throws a warning.
I would like to be able to detect this warning, just like an error, in my PHP script and deal with it appropriately. Ideally I would like to know what kind of warning MySQL has thrown so that I can branch the code to handle it.
Is this possible? If not, is it because MySQL doesn't have this ability, PHP doesn't have this ability, or both?
For warnings to be "flagged" to PHP natively would require changes to the mysql/mysqli driver, which is obviously beyond the scope of this question. Instead you're going to have to basically check every query you make on the database for warnings:
$warningCountResult = mysql_query("SELECT ##warning_count");
if ($warningCountResult) {
$warningCount = mysql_fetch_row($warningCountResult );
if ($warningCount[0] > 0) {
//Have warnings
$warningDetailResult = mysql_query("SHOW WARNINGS");
if ($warningDetailResult ) {
while ($warning = mysql_fetch_assoc($warningDetailResult) {
//Process it
}
}
}//Else no warnings
}
Obviously this is going to be hideously expensive to apply en-mass, so you might need to carefully think about when and how warnings may arise (which may lead you to refactor to eliminate them).
For reference, MySQL SHOW WARNINGS
Of course, you could dispense with the initial query for the SELECT ##warning_count, which would save you a query per execution, but I included it for pedantic completeness.
First, you should turn warnings off so that your visitors don't see your MySQL errors. Second, when you call mysql_query(), you should check to see if it returned false. If it did, call mysql_errno() to find out what went wrong. Match the number returned to the error codes on this page.
It looks like this is the error number you're looking for:
Error: 1169 SQLSTATE: 23000 (ER_DUP_UNIQUE)
Message: Can't write, because of unique constraint, to table '%s'
ini_set('mysql.trace_mode', 1)
may be what you are looking for.
The PHP errors can then be handled with a custom PHP error handler, but you can also just turn off displaying php errors as they are usually logged into a log file (depends on your php configuration).
depending on what (if any) framework you're using, I suggest you do a query to check for the jobname yourself and create the proper information to user in with the rest of the validations for the form.
Depending on the number of jobnames, you could send the names to the view that contains the form and use javascript to tell use which is taken.
If this doesnt make sense to you, then to sum my view it's this: dont design your program and / or user to try to do illegal things and catch the errors when they do and handle it then. It is much better, imho, to design your system to not create errors. Keep the errors to actual bugs :)
Updated to remove the stuff about errno functions which I now realize don't apply in your situation...
One thing in MySQL to be wary of for UPDATE statements: mysqli_affected_rows() will return zero even if the WHERE clause matched rows, but the SET clause didn't actually change the data values. I only mention this because that behaviour caused a bug in a system I once looked at--the programmer used that return value to check for errors after an update, assuming a zero meant that some error had occurred. It just meant that the user didn't change any existing values before clicking the update button.
So I guess using mysqli_affected_rows() can't be relied upon to find such warnings either, unless you have something like an update_time column in your table that will always be assigned a new timestamp value when updated. That sort of workaround seems kinda kludgey though.
You can detect Unique key violations using mysqli statement error no. The mysqli statement returns error 1062 , that is ER_DUP_ENTRY. You can look for error 1062 and print a suitable error message. If you want to print your column (jobName) also as part of your error message then you should parse the statement error string.
if($stmt = $mysqli->prepare($sql)){
$stmt->bind_param("sss",
$name,
$identKey,
$domain);
$stmt->execute();
if($mysqli->affected_rows != 1) {
//This will return errorno 1062
trigger_error('mysql error >> '.$stmt->errno .'::' .$stmt->error, E_USER_ERROR);
exit(1);
}
$stmt->close();
} else {
trigger_error('mysql error >> '. $mysqli->errno.'::'.$mysqli->error,E_USER_ERROR);
}
It is possible to get the warnings, and in a more efficient way with mysqli than with mysql.
Here is the code suggested on the manual page on php.net for the property mysqli->warning_count:
$mysqli->query($query);
if ($mysqli->warning_count) {
if ($result = $mysqli->query("SHOW WARNINGS")) {
$row = $result->fetch_row();
printf("%s (%d): %s\n", $row[0], $row[1], $row[2]);
$result->close();
}
}
Note on suppressing warnings: Generally, it is not a good idea to prevent warnings from being displayed since you might be missing something important. If you absolutely must hide warnings for some reason, you can do it on an individual basis by placing an # sign in front of the statement. That way you don't have to turn off all warning reporting and can limit it to a specific instance.
Example:
// this suppresses warnings that might result if there is no field titled "field" in the result
$field_value = #mysql_result($result, 0, "field");

Categories