How do I know if there's an error if I did $db = new SQLite3("somedb.db"); in PHP? Right now the $db doesn't really give me any sort of error?
I can check for file existance, but I'm unsure if there could be any other errors when I open a connection.
You should enable exceptions and instantiate in a try-catch block.
It is not obvious from the documentation but if you use the constructor to open the database it will throw an exception on error.
Further if you set the flag SQLITE3_OPEN_READWRITE in the second argument then it will also throw an exception when the database does not exist (rather than creating it).
class Database extends SQLite3
{
function __construct($dbName)
{
$this->enableExceptions(true);
try
{
parent::__construct($dbName, SQLITE3_OPEN_READWRITE );
}
catch(Exception $ex) { die( $ex->getMessage() ); }
}
Try:
echo $db->lastErrorMsg();
Related
I am currently writing a web app in PHP and have decided to use exceptions (duh!).
I could not find an answer to whether putting try and catch blocks in all functions would be considered bad code.
I am currently using Exceptions to handle Database errors (Application errors are handled via a simple function which just adds them to an array and then they are displayed to the user). The try blocks are placed on all functions which require a database connection.
The code in question is:
public function db_conn_verify()
{
if(!isset($this->_mysqli)){
throw new Exception("Network Error: Database connection could not be established.");
} else {
return Null;
}
}
And an example function using this code:
public function get_users() {
try {
$this->db_conn_verify();
//Rest of function code
return True;
} Catch(Exception $e) {
Core::system_error('function get_users()', $e->getMessage());
return False;
}
}
Also would it be better to extend the Exception class and then use that new Exception class to handle application errors?
Thanks
I suggest to you to use something like this:
public function get_users() {
try {
if( !isset($this->_mysqli) ) {
throw new Exception("Network Error: Database connection could not be established.");
}
//Rest of function code
} Catch(Exception $e) {
Core::system_error('function get_users()', $e->getMessage());
}
}
I prefer to use my exends of Exception, but is the same. For exdending exception you can see the PHP documentation to Example #5
EDIT: For an immediate use of try-catch on database connection error you can try this:
try{
$mysqli = new mysqli("localhost", "user", "password", "database");
if ($mysqli->connect_errno) {
throw new Exception("Network Error: Database connection could not be established.");
}
} Catch(Exception $e) {
Core::system_error('function get_users()', $e->getMessage());
}
This question already has answers here:
What to do with mysqli problems? Errors like mysqli_fetch_array(): Argument #1 must be of type mysqli_result and such
(2 answers)
Closed 2 years ago.
I started using OO-MySQLi after procedural MySQL and I have a problem.
In production environment my system displays all errors as a custom page.
MySQLi errors is an "error" too and I want catch them, but in documentation described only one way to do this:
if (!$mysqli->query("SET a=1")) {
exit('An error occurred: ' . $mysqli->error);
}
(just for example).
This is a very bad way, because in my system I'm doing many things when error occurred, like logging, calling events, etc.
Of course, I can extend mysqli class, for example:
class myMysqli {
public function __construct(/* ... */)
{
parent::__construct(/* ... */);
}
public function query(/* .. */)
{
parent::query(/* ... */);
if($this->errno !== 0)
{
// An error occurred
}
}
}
$mysqli = new myMysqli(/* ... */);
$mysqli->query(/* ... */);
But this way I need to extend almost ALL methods where error can occur.
Moreover, MySQLi provides prepared statements (mysqli_stmt class) that has its own errors!
Can you know a better way to handle MySQLi errors?
Thank you in advance.
Added
About exceptions:
Do I understand correctly that with exceptions I need do something like this:
try {
$mysqli->query(/* ... */);
} catch (Exception $e) {
// An error occurred
}
But this is similar to
if(!$mysqli->query(/* ... */))
{
// An error occured
}
What a difference?
First of all, your old approach was wrong.
exit('An error occurred: ' . $mysqli->error);
is a bad practice in general and shouldn't be used with mysqli as well.
What you really want is error/exception handler. Where you can do whatever things like logging, calling events, showing pages.
Exception is better than regular error - so, set your mysqli in exception mode as shown in other answer, and then catch all the errors in error handler. While try..catch have to be used only when you have a distinct particular action to handle the error.
I use the try...catch method like this...
try {
// get result of record from 'id'
$query = "SELECT * FROM models WHERE id =$id";
$result = $mysqli->query($query);
if (!$result) {
throw new Exception($mysqli->error());
}
$row = $result->fetch_array();
}
catch (Exception $e)
{
echo "We are currently experiencing issues. Please try again later.";
echo $e->getMessage();
}
finally
{
$result->free();
}
Does that help at all?
You use 'try' to test a condition and throw an exception if it returns true (!$result). And use 'catch' to catch everything else that might just happen!
I am writing a script to install the database of an application in php. It working fine but when im trying to install a database that doesnt exist i want only my own error message but i keep getting the default Warning : Warning: mysqli::mysqli() [mysqli.mysqli]: (HY000/2005): Unknown MySQL server host 'kasdasd'.
So I know that the host is wrong and I want it to be so, with only my own errormessage. How do I get rid of this message?
My connectclass with parameter DBConfig $config:
$this->mysqli = new mysqli($config->m_host,
$config->m_user,
$config->m_passw,
$config->m_db);
if ($this->mysqli->connect_error) {
return false;
}
$this->mysqli->set_charset("utf8");
return true;
an easy solution would be to see if you can open the hostname using fsockopen and suppressing the errors:
$port = 80;
if($fp = #fsockopen($config->m_host,$port)){
$db = new mysqli($config->m_host,$config->m_user,$config->m_passw,$config->m_db);
}else{
echo 'hostname not recognized';
}
#fclose($fp);
Edited:
You can use
if ($mysqli->connect_error) {
/** handle your error here **/
// Throw a custom exception if you like! (see below)
// or just echo "There was an error";
}
You can further use mysqli_connect_errno() to find out wht happened and handle it accordingly.
Edit: mysqli doesn't throw erros so below is incorrect.
Wrap your code in a try-catch, then you can throw whatever kind of error you like:
try {
/** your code here **/
} catch (Exception $e) {
/** your handling here **/
// i.e.
throw new BadHostNameException($config->m_host);
// or
echo "Could not connect!":
}
Note: you should replace Exception $e with the specific kind of exception a bad host throws so catch(MysqlBadHostnameException $e) (the type of error will be in your error log from your previous attempts or you can do get_class($e) in my example above.
// Isusing a custom exception: Add this outside of your class..
class BadHostNameException extends Exception {}
I'm using the following script to use a database using PHP:
try{
$db = new PDO('mysql:host='.$host.';port='.$port.';dbname='.$db, $user, $pass, $options);
}
catch(Exception $e){
$GLOBALS['errors'][] = $e;
}
Now, I want to use this database handle to do a request using this code:
try{
$query = $db->prepare("INSERT INTO users (...) VALUES (...);");
$query->execute(array(
'...' => $...,
'...' => $...
));
}
catch(Exception $e){
$GLOBALS['errors'][] = $e;
}
Here is the problem:
When the connection to the DB is OK, everything works,
When the connection fails but I don't use the DB, I have the $GLOBALS['errors'][] array and the script is still running afterwards,
When the connection to the DB has failed, I get the following fatal error:
Notice: Undefined variable: db in C:\xampp\htdocs[...]\test.php on line 32
Fatal error: Call to a member function prepare() on a non-object in C:\xampp\htdocs[...]\test.php on line 32
Note: Line 32 is the $query = $db->prepare(...) instruction.
That is to say, the script crashes, and the try/catch seems to be useless. Do you know why this second try/catch don't works and how to solve it?
Thanks for the help!
EDIT: There are some really good replies. I've validated one which is not exactly what I wanted to do, but which is probably the best approach.
try/catch blocks only work for thrown exceptions (throw Exception or a subclass of Exception must be called). You cannot catch fatal errors using try/catch.
If your DB connection cannot be established, I would consider it fatal since you probably need your DB to do anything meaningful on the page.
PDO will throw an exception if the connection cannot be established. Your specific problem is that $db is not defined when you try to call a method with it so you get a null pointer (sort of) which is fatal. Rather than jump through if ($db == null) hoops as others are suggesting, you should just fix your code to make sure that $db is either always defined when you need it or have a less fragile way of making sure a DB connection is available in the code that uses it.
If you really want to "catch" fatal errors, use set_error_handler, but this still stops script execution on fatal errors.
In PHP7, we now can using try catch fatal error with simple work
try {
do some thing evil
} catch (Error $e) {
echo 'Now you can catch me!';
}
But usualy, we should avoid using catch Error, because it involve to miss code which is belong to programmer's reponsibility :-)
I will not report what has already been written about testing if $db is empty. Just add that a "clean" solution is to artificially create an exception if the connection to the database failed:
if ($db == NULL) throw new Exception('Connection failed.');
Insert the previous line in the try - catch as follow:
try{
// This line create an exception if $db is empty
if ($db == NULL) throw new Exception('Connection failed.');
$query = $db->prepare("INSERT INTO users (...) VALUES (...);");
$query->execute(array(
'...' => $...,
'...' => $...
));
}
catch(Exception $e){
$GLOBALS['errors'][] = $e;
}
Hope this will help others!
If database connection fails, $db from your first try .. catch block will be null. That's why later you cannot use a member of non-object, in your case $db->prepare(...). Before using this add
if ($db) {
// other try catch statement
}
This will ensure that you have db instance to work with it.
Try adding the following if statement :
if ($db) {
$query = $db->prepare("INSERT INTO users (...) VALUES (...);");
$query->execute(....);
}
else die('Connection lost');
try{
if(!is_null($db))
{
$query = $db->prepare("INSERT INTO users (...) VALUES (...);");
$query->execute(array(
'...' => $...,
'...' => $...
));
}
}
catch(Exception $e){
$GLOBALS['errors'][] = $e;
}
I am creating a model for a small PHP application. This will utilize PDO to communicate with a MySQL-server. I have understood that the recommended error mode is the one which throws exceptions, as this allows for graceful error handling. But I don't understand how I should handle these exceptions?
Technically, it is easy, but let me give you an example:
class Model()
{
private $host = "localhost",
$user = "",
$pass = "",
$DBH;
function __construct()
{
try
{
$DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
$DBH->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
}
catch(PDOException $e)
{
error_log($e->getMessage());
}
}
}
If I create an object Model in my controller, and it fails, I have no way of handling this in my controller, right? Or what happens when I create that object, "new Model" returns false?
Excuse me for being a newbie, but I want to be able to handle any exceptions also from other functions in the model. How should I go about this? I need to be able to know if something went wrong in my controller and be able to do the appropriate thing there.
If you want your controller to catch the exception as well, you can always rethrow it after logging.
class Model()
{
...
function __construct()
{
try
{
...
}
catch(PDOException $e)
{
error_log($e->getMessage());
throw $e;
}
}
}
Depends entirely on what the error_log function does.
You can return the exception.
You can simply die after logging the error (presumably if your application can't hit the DB then theres no graceful recovery).
You can return a custom exception via throw();
It's really just your preference.