I am working on on a small personal project to understand PHP and MySql. I set up a simple class to get started to make a connection to a database and wanted to verify the connection was good and was attempting to use the connect_errno property but I am not getting the results I expected. This is just test code so it may be missing some of the error/security checking that would normally be included in such code.
Please note that the code is running on a LAMP Stack with Ubuntu 16.04 and PHP Version of: PHP Version 7.0.22-0ubuntu0.16.04.1
In the code below I intentionally set the DB_PASS constant to an invalid value to test two different methods of verifying the connection.
Using the connect_errno method does not seem to work.
class Database
{
public $conn;
public $connStatus;
public function __construct()
{
echo "Hi There, I am a database! <br><br>";
$this->conn = mysqli_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME);
if($this->conn->connect_errno)
{
echo "Bad Connection using connect_errno method <br/>";
}
else
{
echo "Good Connection using connect_errno method <br/>";
}
if ($this->conn == false)
{
echo "Bad Connection using db==false method <br/>";
}
else
{
echo "Good Connection using db==false method <br/>";
}
}
}
This code block indicates that the connection is good despite the incorrect DB_PASS. Return: Good Connection using connect_errno method.
if($this->conn->connect_errno)
{
echo "Bad Connection using connect_errno method <br/>";
}
else
{
echo "Good Connection using connect_errno method <br/>";
}
This code block indicates that the connection is bad, which is correct due to the incorrect DB_PASS. Return: Bad Connection using db==false method
if ($this->conn == false)
{
echo "Bad Connection using db==false method <br/>";
}
else
{
echo "Good Connection using db==false method <br/>";
}
I am fine with using the 'db==false' method of checking but I was curious about this. I have read several posts within Stack Exchange and tried some of those examples but they did not seem to work.
Example1: echoing-mysqli-connect-errno-not-working.
Example2: error on mysqli::connect_errno
Ok, after going back and reviewing the other posts I now understand the issue. The procedural method sets it up like this:
$this->conn = mysqli_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME);
while the OOP method sets it up like this:
$this->conn = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
So I guess being relatively new to PHP and MySQL I did not really see the difference until taking a step back. Thanks for everyones help!
The difference is that mysqli_connect() will return either a mysqli object or a boolean false. But you can't use the -> operator on a variable that isn't an object.
$x = false;
echo $x->attrib; // fatal error, booleans can't have OO members or methods
This is one of the WTF moments in PHP. Because of its history, PHP language design is a Frankenstein's monster of object-oriented and non-object-oriented (made worse by many years of developing the language with no sensible design process).
So there are lots of functions in PHP which return either an object or a non-object. This makes it hard to write safe code, because you never know if you can use -> on the thing returned by a function, until you check what type it is.
The confusion is reduced if you use new mysqli(), because the OO operator new is guaranteed to return an object of that type, even if the connection fails because you gave an incorrect password or something.
$conn = new mysqli(...);
if ($conn->connect_errno) { // this is not a fatal error even if the connect failed
...
}
Related
I have a PHP file which sometimes has a long execution and the MySQL connection (a mysqli object) goes stale. If I check the connection with mysqli_ping (and reconnect if mysqli_ping returns false), then I never have a problem. However, pinging before every query seems highly inefficient, so I'd like to only perform the ping check (and reconnect) upon the query failing. My problem is that I cannot seem to get my code to throw an exception upon the failure of the mysqli_query in order to trigger a reconnect.
Here is my "basic" code:
<?php
function query($query) {
$connection = $GLOBALS['global_connection'];
if(empty($connection) || mysqli_connect_errno()) $connection = connect();
try {
$result = mysqli_query($connection, $query);
} catch(Exception $e) {
if(!mysqli_ping($connection)) {
$connection = connect(); // reestablish the connection
$GLOBALS['global_connection'] = $connection; // update global connection value
$result = mysqli_query($connection, $query); // requery using the new connection
}
}
return $result;
}
The problem is that a bad connection in the mysqli_query does not cause an exception to be thrown, but it does cause an error to show up in my error log.
I have tried mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); (as suggested in other questions) before the mysqli_query but it does not change the outcome. I also have mysqli.reconnect enabled in my PHP config, but that doesn't seem to stop this.
So my question is either:
How do I throw an exception when a mysqli_query fails (due to a timed out connection)?
or
How do I automatically reconnect database in an efficient manner?
Per Barmar's help in the comments I realized all I had to do was this:
<?php
$result = mysqli_query($connection, $query);
if(empty($result)) {
if(!mysqli_ping($connection)) {
$connection = connect(); // re-establish the connection
$GLOBALS['global_connection'] = $connection; // update global connection value
$result = mysqli_query($connection, $query); // re-query using the new connection
}
}
No try{}catch needed at all! Clean and simple.
You will need to manage (throw) your own custom exceptions for this to work the way you need it too. I would consider making a database abstraction class to help handle this. The database class would have a member variable that is the connection reference and could use the mysqli built in error handling to throw custom exceptions relating to that instance of the mysqli connection object.
If you only need one database connection I might try a singleton pattern.
I'm learning php and i have a file that connects to a mysql database, i'd like to know what is the condition inside the brackets of the following "if structure" in the file, $con is an instance of the class mysqli:
if ($con->connect_errno)
{
echo "fail to connect to mysql";
}
I know that $con is invoking to connect_errno but what is conditioning if(what?){...}?
That's a status flag for mysqli handles.
See http://php.net/manual/en/mysqli.connect-errno.php
It's not a function, but a property (or a "variable" if you will). It's 0 when the connection was correctly established. It contains other values (e.g. 1043) for connection problems (such as wrong password, inavailable database server).
So the if ($con->connect_errno) check asserts that your $con instance is usable.
When ->connect_errno == 0 then the if block will be skipped.
If ->connect_errno > 0 (any other value) the error message will be printed out. (You'd more commonly see die(), trigger_error() or new Exception() than just an echo there.)
Alternatively mysqli can be configured to throw an error/exception by itself. Which would make this whole condition/block redundant.
I am having some issues trying to grasp the idea behind certain lines of code that may be above me at this moment since I am fairly sure they have to do with OOP(something that I don't know much about as I am just starting on the concept behind OOP)This came to me as I was readig a PHP book.The code is as follows.
$mysqli = new mysqli('example','example','example');
if(!$mysqli){
die("Could not connect".mysql_error());
}
else {
echo("Connection established");
}
if($mysqli->query("CREATE DATABASE querycreation1")===TRUE){
echo"<p>Database Querycreation1 created</p>";
}
else {
echo "Error creating database".mysql_error();
}
I understand the first couple of lines(and appreciate input on best practices),but the part that I am having issues is after the next set of if-else statements.
The second if statement checks if the creation of a database is true,but can someone explain at what time exactly was the database created? do I need to create one and then check for it in the future? Any input would be greatly appreciated.
In a comparison in PHP first all expressions get evaluated. This means that in
if($mysqli->query("CREATE DATABASE querycreation1")===TRUE)
PHP will first run the query() function on the $mysql-object. That function returns a result. In the case of successfull creating a database it will return TRUE (http://nl1.php.net/mysqli_query). The result of calling this function (TRUE) is then compared to TRUE.
Perhaps more verbose for you to see this:
$databaseCreated = $mysqli->query("CREATE DATABASE querycreation1");
if($databaseCreated ===TRUE){
echo"<p>Database Querycreation1 created</p>";
}
else {
echo "Error creating database".mysql_error();
}
$mysqli->query() performs the query, in this case, a CREATE query. The function then returns TRUE if the query was executed successfully and FALSE if an error occurred. So the database is created exactly at the time the first argument to the === comparison is evaluated.
Generally, creating databases in php scripts won't happen often, usually only in "installation" scripts use to setup some php driven piece of software (such as a discussion board/forum). Other than that, you'll want to create the databases once either through a database management system such as phpMyAdmin or a script you delete afterwards. Then in your actual site scripts, you just assume the databases exist because you also usually don't just delete them.
You could write it differently by assigning the return value of the query to a variable and checking against that:
$success = $mysqli->query("CREATE DATABASE querycreation1");
if ($success===TRUE){
// ...
But that's purely a matter of preference.
Also, the first else is not strictly necessary because of the die statement. There is a number of ways you could simplify (or let's say modify) that part:
// The "just no else" version
if (!$mysqli)
die("Could not connect".mysql_error());
echo("Connection established");
// The one-liner version
if (!$mysqli) die("Could not connect".mysql_error());
echo("Connection established");
// The short-circuit version
$mysqli OR die("Could not connect".mysql_error());
echo("Connection established");
// same using the symbolic version of OR
$mysqli || die("Could not connect".mysql_error());
echo("Connection established");
// you can also include that in the first call
$mysqli = new mysqli('example','example','example') OR die("Could not connect".mysql_error());
echo("Connection established");
The last three examples work based on the fact that php handles logical operators in a short-circuit way, that is, if the first part is TRUE, then the entire OR expression will be TRUE no matter what the second argument is, so php doesn't even bother evaluating it. If the first part is FALSE, however, the expression's value depends on the second argument, so it is evaluated.
Point one:
You are creating an instance of a class mysqli which contains methods to connect, query, manage database. You need to pass some parameters which are used by the class'es constructor to connect to the database.
This instance is called an object and now this object has the connection and can use the methods from the class to query, manage that database.
For better understanding: http://www.php.net/manual/en/language.oop5.php
I am trying to connect to a database using the default values for the mysqli constructor, which is documented to be:
host = ini_get("mysqli.default_host")
username = ini_get("mysqli.default_user")
passwd = ini_get("mysqli.default_pw")
The reason I want to use the defaults is so I can have the credentials in the config file instead of scattered through my code. However, when I pass no values, the connection succeeds but then subsequent queries fail with no error.
$db = new mysqli();
if ($db->connect_errno) die("Connect failed: " . $db->connect_error);
if ($rs = $db->query("select user();") or die("Query failed: " . $db->error)) {
$row = $rs->fetch_row();
echo $row[0];
$rs->close();
}
This outputs:
Query failed:
That means the connection succeeded, but any query fails with an error. (Other actions, such as select_db, fail the same way.)
Interestingly, I can fix it by changing the first line to:
$db = new mysqli(ini_get("mysqli.default_host"),
ini_get("mysqli.default_user"),
ini_get("mysqli.default_pw"));
... but I'd prefer to not have to type out the default values everywhere I need a database connection. What am I doing wrong? Is there a way to use the mysqli constructor with no arguments?
While writing this question, I happened to scroll down the documentation page and noted the following:
Note: Calling the constructor with no parameters is the same as calling mysqli_init().
Looking up the mysqli_init documentation, it says:
Note: Any subsequent calls to any mysqli function (except mysqli_options()) will fail until mysqli_real_connect() was called.
Therefore, the fix is to change the first line from:
$db = new mysqli();
To:
$db = new mysqli();
$db->real_connect();
I would have expected in that scenario that mysqli_error would have returned something like "not connected" instead of an empty string. That's a bit counter-intuitive, but at least it's somewhat documented.
i am trying escape some data before it goes into my database, but i keep getting this error:
Warning: mysql_real_escape_string(): Access denied for user
Now this would usually suggest that i have not connected to the database (it also states (using password: NO)).
I was a little confused by this because when connecting to a database i have a 'die' clause so if it fails to connect i get told about it. So i tested this theory by running a simple query in the same function that im trying to escape the data and it works just fine.
So why on earth won't the escape method work or get a connection to the database. I did notice that the user the error states is not the user i use to access the database its something like 'www-data#localhost'. Could it be trying to log in with a different user, if so why and how? Because i another area of my website the escape function works just fine and i didn't do anything special to make it work, just added the code into my web page.
thanks for the help.
Are there any other ways of sanitizing my code?
Okay, so here we go, when the user submits the form, i use AJAX to collect the data and put it into an obj to post(JSON encoding) it to the first PHP script which is here:
http://codepad.org/kGPljN4I
This script checks all the data is there and then calls a function to add it to the database
this Mysql class is called to escape the data and then add a new record to the database, when and instance of the class is made it makes a connection to the database:
http://codepad.org/wwGNrTJm
The third file is for constants, it holds the information for the database like pass, user and so on:
http://codepad.org/dl0QQbi9
any better?
thanks again for the help.
The problem is that you have established your connection using MySQLi, but are then calling mysql_real_escape_string(). You intend to be calling mysqli_real_escape_string() either in procedural context, or object oriented contex.
class Mysql
{
private $conn;
function __construct()
{
$this->conn = new mysqli(DB_SERVER, DB_USER, DB_PASSWORD, DB_NAME) or
die('No Connection to database!');
}
function add_non_member($data)
{
$email = $data->email;
// Procedural call
$san_email = mysqli_real_escape_string($this->conn, $email);
// Or OO call (recommended)
$san_email = $this->conn->real_escape_string($email);
// etc...
}
// etc...;
}
You're mixing ext/mysqli
$this->conn = new mysqli(DB_SERVER, DB_USER, DB_PASSWORD, DB_NAME
with ext/mysql functions:
$san_email = mysql_real_escape_string($email);
that last line should be
$san_email = $this->conn->real_escape_string($email);
I also got this access denied warning and I was able to find the solution. The problem is that I have not setup mysql db connection before calling mysql_real_escape_string function.
Solution:
Call mysql_connect($host, $user, $password) first (Or you can call your database connect function)
Then use mysql_real_escape_string($var)