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.
Related
The Code is:
class anything_i
{
/*Every variable is defined and hidden fro privacy.*/
public function connect(){
return mysqli_connect(self::HOST,self::USERNAME,self::PASSWORD,self::DATBASE);
}
public function insertData($postData){
$sqli = 'INSERT INTO `payments`(`item_name`,`price`,`email`,`date`,`time`,`detail`,`volume`,`ip`,`payment_status`) VALUES ("'.$productData['name'].'","'.$productData['price'].'","'.$postData['email'].'","'.$date.'","'.$time.'","'.$postData['list'].'","'.$productData['volume'].'","'.$ip.'","On Hold")';
if(mysqli_query($this->connect(),$sqli)){
print_r(mysqli_insert_id($this->connect()));
}else{
print_r(mysqli_error($this->connect()));
}
}
}
It is inserting the data and working fine but does not return anything other than a 0 (zero) not getting any error.
Let me clear that my table contains auto_increment and my connection is fine because it is entering data just fine. Please don't disregard the question because you found similar once answered. I also found similar questions but most of them have connection problems, some of them the no AUTO_INCREMENT column and there may be some which included another query in between. So, please read it before mentioning another answer.
Here is the proof of AUTO_INCREMENT:
I suspect this code has been migrated from the legacy mysql extension where mysql_connect():
Opens or reuses a connection to a MySQL server.
This is no longer the case with mysqli_connect():
Opens a connection to the MySQL Server.
You really need to store the connection in a variable and reuse that same connection. Currently you're starting many different connections within the same script run.
When you call mysqli_connect() it will create a new connection each time. It does not reuse the previous connection. When a new connection is created all the properties of the old one are lost.
You are calling mysqli_connect() every time you call $this->connect() so you will never get the errors or the auto-generated ID.
mysqli connection should be global to your application. It does not make sense to keep recreating the same connection because it will lead to terrible performance issues and it will cause you problems like this one. If you are using dependency injection it should be easy to create the mysqli at the start of your application and then pass it as an argument to your class' constructor.
Connecting to the database using mysqli is always the same 3 lines of code. Only the details you pass as arguments are different.
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli('localhost', 'user', 'pass', 'db_name');
$mysqli->set_charset('utf8mb4'); // always set the charset
You can then pass this to your constructor whenever you create an object and store it in a private property.
Your fixed code would like this:
<?php
class anything_i {
private mysqli $db = null;
public function connect(mysqli $db) {
$this->db = $db;
}
public function insertData($postData) {
/*
...
*/
$stmt = $this->db->prepare('INSERT INTO `payments`(`item_name`,`price`,`email`,`date`,`time`,`detail`,`volume`,`ip`,`payment_status`) VALUES (?,?,?,?,?,?,?,"On Hold")');
$stmt->bind_param('ssssssss', $productData['name'], $productData['price'], $postData['email'], $date, $time, $postData['list'], $productData['volume'], $ip);
$stmt->execute();
}
}
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli('localhost', 'inet', '5432', 'test');
$mysqli->set_charset('utf8mb4'); // always set the charset
$obj = new anything_i($mysqli);
This is the code when I try connecting to database. I have intentionally given wrong database name.
<?php
try
{
$pdo = new PDO('mysql:host=localhost;dbname=ehrp', 'root', '');
}
catch (PDOException $e)
{
echo $e->getMessage();
}
?>
This is the exception that I get, which is fine :
SQLSTATE[HY000] [1049] Unknown database 'ehrp'
But when I write this :
$pdo = new PDO('mysql:host=localhost;dbname =ehrp', 'root', '');
Notice a space between dbname and = I get nothing on screen.No error is shown.
Why is that?
The argument you're passing to the PDO constructor is in URI form, and a URI cannot contain arbitrary spaces, they all mean something. So what you've actually supplied the PDO constructor as far as it can tell is mysql:host=localhost; followed by an assigned property called "database " (with a space at the end). Since PDO does not know anything about a property called "database " there are no errors (it's a legal URI property value assignment), and as an unknown property, it just gets ignored. No errors, no warnings, you've done nothing wrong and PDO does what you ask it do to.
The PDO connection to your server on localhost succeeds, and you now have a PDO instance that is connected, and simply has not been tied to a specific database yet.
To verify this, prepare a SELECT DATABASE() statement with your PDO object, and then execute it: it should work just fine, and come back with a response indicating that you're not connected to a database yet.
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 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'm trying to pass through an adodb connection to a class constructor but in doing so get this error:
mysql_error(): supplied argument is not a valid MySQL-Link resource
So to put it into context, I have instantiated a new adodb connection like this:
// establish database connection
$db = ADONewConnection($dsn);
if (!$db) die(mysql_error());
Then created my new user access object and passed in the adodb connection like this:
$user = new UserAccess($db);
This is the constructor from the user access class:
function UserAccess($oDbLink) {
// check we have a valid connection
}
Any ideas what I'm doing wrong?
Thanks,
Gaz
I can't see any obvious error in the part of code you supplied, so I'd suggest you:
leave aside the object for the time being
set your error_reporting() to E_ALL
double-check the parameters in $dsn - you may want to try to connect from the command line...
check your access privileges and run FLUSH PRIVILEGES
turn on ADODb debugging with $db->debug = TRUE;
test the thing from outside the object with a $db->Execute("SELECT * FROM tablename") or die($db->ErrorMsg());
When you get a message your connection resource is not a valid link - well, that's usually true. Don't forget to check the database is actually there and running.
The problem is most likely that you're attempting to use PHP's mysql_* functions with the $db object you get from ADONewConnection. It's not a mysql handle, so it won't work with those functions - you need to use adodb's own stuff.
Nothing wrong with your code, from what you've supplied. If you supply something more full then may be able to help.
Is there a real reason for passing a ADODB connection around? It'll just need to be passed everywhere and more work and without a real reason... I'd hesitate to do that. Even a standard global may be better (yes globals are evil) or perhaps a Singleton class?
Your code should be like this:
// establish database connection
$db = ADONewConnection($dsn);
if ( ! $db )
{
// just display error message
// you cannot use mysql_error, since you haven't connected to any database
die ("Cannot connect, check the parameter and make sure db is running!");
}
User reference, to avoid copying object
function UserAccess(&$oDbLink) {
// check we have a valid connection
}
Hope it help.
Thanks for your answers, I've managed to get this working by removing the $dsn variable and just passing in $_GLOBAL variables