MySQLi or Die, Does It Have to Die

mysqli or die, does it have to die?

Does it have to die

Quite contrary, it shouldn't or die() ever.

PHP is a language of bad heredity. Very bad heredity. And or die() with error message is one of the worst rudiments:

  • die throws the error message out, revealing some system internals to the potential attacker
  • such error message confuses casual users, because they don't understand what does it mean
  • Besides, die kills the script in the middle, leaving users without familiar interface to work with, so they'd likely just drop out
  • it kills the script irrecoverably. While exceptions can be caught and gracefully handled
  • die() gives you no hint of where the error has been occurred. And in a relatively big application it will be quite a pain to find.

So, never use die() with MySQL errors, even for the temporary debugging: there are better ways.

Instead of manually checking for the error, just configure mysqli to throw exceptions on error, by adding the following line to your connection code

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

and after that just write every mysqli command as is, without any or die or anything else:

$result = mysqli_query($link, $sql);

This code will throw an exception in case of error and thus you will always be informed of every problem without a single line of extra code.

A more detailed explanation on how to make your error reporting production ready, uniform and overall sensible while making your code much cleaner, you can find in my article on PHP error reporting.

Is mysqli_query() or die(mysqli_error()) a good practice?

This practice is just awful. It's a bad heredity from the last century ways of writing code.

Instead, you have to add this line before connection code

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

it will relieve you from the need of writing extra code for the every mysql call, as it will make mysqli to throw an Exception in case of error automatically.

While exception itself is way better than regular error, as it can be caught and gracefully handled. Yet it will be converted into error, if not caught, which is again all right - because regular errors, depends on the site-wide settings, can be either shown on-screen or logged. Again without the need of writing a single line of extra code.

While developing, just have display_errors setting on and you will see all the errors the moment they occurred.

While on a live site, display_errors have to be turned off, but log_errors have to be on instead - and it will make your exception logged, for your future reference.

A form doesn't submit

Just simply add or die(mysqli_error($db)); at the end of your query, this will print the mysqli error.

 mysqli_query($db,"INSERT INTO stockdetails (`itemdescription`,`itemnumber`,`sellerid`,`purchasedate`,`otherinfo`,`numberofitems`,`isitdelivered`,`price`) VALUES ('$itemdescription','$itemnumber','$sellerid','$purchasedate','$otherinfo','$numberofitems','$numberofitemsused','$isitdelivered','$price')") or die(mysqli_error($db));

As a side note I'd say you are at risk of mysql injection, check here How can I prevent SQL injection in PHP?. You should really use prepared statements to avoid any risk.

mysqli_error() Can't make the conversion

From the mysqli documentation the syntax is

Object oriented style

string $mysqli->error;

Procedural style

string mysqli_error ( mysqli $link )

So depending on your programming style you have either something like

$mysqliObj = new mysqli( ... ); or $link = mysqli_connect( ... ) in your code. Depending on this you have to use either

$mysqsliobj->error

or

mysqli_error($link)

Just a few comments on this:

  • You should not use this in production. If there is an error in your Query or the Database is offline you don't want to print the whole query to the user. Maybe this query is containing something that should not be public.
  • You also don't want to stop the execution at this exact point. Just catch the error, write it into a log file and show a useful error message to the user.

Proper mysqli_query and mysqli_error configuration

There are two errors in the code above:

  • You missed to declare $link global as $mysql_hostname etc.
  • You passed the wrong argument type to mysqli_error() it expects mysqli and you passed a string

I have changed your example:

<?php

include('mysql_config.php');

// declaring an additional global var.
$link = NULL;

function mysqlConnect()
{
global $link; // using the global $link
global $mysql_hostname, $mysql_username, $mysql_password, $mysql_database;
$link = mysqli_connect($mysql_hostname, $mysql_username, $mysql_password)
or die('Could not connect: ' . mysqli_connect_error());
mysqli_select_db($link,$mysql_database) or die('Could not select database');
return $link;
}

function mysqliClose($link)
{
mysqli_close($link);
}

function sendQuery($query)
{
global $link; // using the global $link
$result = mysqli_query($link, $query) or die('Query failed: '
. mysqli_error($link)); // note $link is the param
return $result;
}

Why die with connect_error() is not working?

You need to decide whether you use procedular or object oriented version of mysqli.

However, still you can change your if condtion to:

if (!$this->con) {
die(mysqli_connect_error());
}

it should work. You can also see the example on manual

mysqli doesn't return instance with die()

The [..] or die() construct leads to funny behaviour in conjunction with the return statement: The whole thing is interpreted as a boolean expression.

And because new mysqli will never be false, the "die" is never processed, and thus, your function returns true instead of a newly created instance of mysqli.

If you still would like to use or die(), do this:

$result = new mysqli($host, $user, $pwd, $db) ;
if (!$result) die ("Can't open database.");
return $result;

Does mysqli::reap_async_query() have side effects?

Is there a reason for it [mysqli::reap_async_query()] to be here, does calling it even without reading its return value has any important side effect ?

The return value is not assigned to a local variable, however it is still returned.

So the original interest was in calling that function. And for what for, has been written about in the commit message.

According to the Git history, the call to @$GLOBALS['con']->reap_async_query(); was added to support async SQL queries.

Let's consider this example:

$con->query('SELECT SLEEP(5) as `zzzZZZ...Schnarch...Schmatz..zzz`', MYSQLI_ASYNC);

$con->reap_async_query();

How long does it take to execute this code?

This is the reason how that call supports async queries. If an async query would still run on the connection (it has not been reaped yet), every new query would fail.

So add of the call in-so-far supports async SQL queries as it allows to fire one on the same (shared) connection that might be in use for other queries, too.


Additionally you ask:

Also, why is it triggering this error ? I understand that trying to read a result before any query has been executed could trigger an error but the error indicates that the connection is not active, which does not seem to be the case.

Let's take a look at the error, actually a message on the diagnostic channel:

PHP Warning: mysqli::reap_async_query(): Connection not opened, clear or has been closed in ...

As we know the connection has been opened and has not been closed, the last point might be it:

[...] Connection [...] clear [...]

Now I have not programmed that error message, but my reading of it is that there is no async query running yet on the (open) connection - the connection is clear.

It produces a warning as this might not be intended (there is no need to reap a clear connection normally) and henceforth as with your function this is intended, the call is prefixed with the error suppression operator (@).



Related Topics



Leave a reply



Submit