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
Related
I am attempting to port an 8-year-old PHP/MySQL web app to a more recent server stack using MariaDB instead of MySQL. I have found it impossible to run more than one stored procedure on the same connection due to a "packets out of order" error. Below is code that should work, but doesn't. Can someone point out where I may have gone astray here or what would be a successful alternative approach?
<?php
$host = "localhost";
$user = "mysqli_test";
$password = "";
$database = "mysqli_test";
function get_connection()
{
GLOBAL $host, $user, $password, $database;
$connection = new mysqli($host, $user, $password, $database);
if (! $connection || mysqli_connect_errno() )
printf("Connection failure: %s.\n", mysqli_connect_error());
return $connection;
}
// Minimum viable function: isolate necessary steps.
function get_person($connection, $first_name)
{
$query = "CALL Get_By_First_Name(?)";
if (($stmt = $connection->prepare($query))) // error here after first pass
{
$stmt->bind_param('s', $first_name);
if ($stmt->execute())
{
$stmt->store_result();
$stmt->bind_result($id, $fname, $lname, $pets);
while($stmt->fetch())
printf("%3d %20s %20s %2d.\n", $id, $fname, $lname, $pets);
$stmt->free_result();
while ($stmt->next_result()) // my suspected culprit
{
$stmt->store_result();
while ($stmt->fetch())
;
$stmt->free_result();
}
}
$stmt->close();
}
}
if ($conn = get_connection())
{
get_person($conn, "Samuel"); // it works the first time
get_person($conn, "Zelda"); // this time it fails
}
?>
Running aPHP/mysqli code,
lmost identical C++ code using the C API works fine, so I can isolate where I think the problem starts: with the next_result() function. In the C++ code, next_result() returns TRUE to indicate a new result was available after using the prepared statement to run the stored procedure. In the PHP/mysqli code, next_result() returns false, and, in fact, fails to produce a new result even if I ignore the false return value.
I created a github repository that includes more explanation and scripts that can run on your computer to replicate the error, if anyone is interested.
The best practice is to avoid using stored procedures from PHP... That is not always possible; sometimes stored procedures are necessary and they might even be useful on rare occasions. But if you can, try to move the logic to the PHP application rather than storing it on a MySQL server. It's much less cumbersome this way.
If you want to know how to call stored procedures correctly, the best resource to reach for is the PHP manual. I have recently improved most of the examples in the manual so I know that the examples there reflect best practices and actually work. Read stored procedures using mysqli and mysqli::multi_query() documentation.
I would advise avoiding mysqli::multi_query(), despite stored procedures being probably the primary reason that function even exists. You have made the right choice to use prepared statements so you can bind the parameters and avoid SQL injection.
The main thing you have to remember is that CALL() statement produces an empty result. If the stored procedure also produces result set/sets then you need to iterate over them and fetch each one. The problem with stored procedures is that you can never be certain how many result sets will be produced. How can you handle the unknown?
Take a look at this example (it's your code but I made some changes and enabled error reporting):
function get_connection($host, $user, $password, $database): mysqli
{
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
return new mysqli($host, $user, $password, $database);
// you might want to set the correct charset (e.g. utf8mb4) here before returning
}
function get_person(mysqli $connection, $first_name): mysqli_result
{
$query = "CALL Get_By_First_Name(?)";
$stmt = $connection->prepare($query);
$stmt->bind_param('s', $first_name);
$stmt->execute();
/* We expect this SP to return the main result set,
which we want to return and then an empty result for CALL.
Get the result here and return immediately.
The prepared statement will be closed automatically once
we leave the scope and this will clean up the remaining result set.
*/
return $stmt->get_result();
}
$conn = get_connection($host, $user, $password, $database);
$res1 = get_person($conn, "Samuel");
$res2 = get_person($conn, "Zelda");
var_dump($res1->fetch_all(), $res2->fetch_all());
In the above code, I make an assumption that the SP I am calling will return only two result sets. I want only the first one and I don't care about the result of CALL(). The second result set is discarded when the statement is cleaned up. If that was not the case, I would need to call mysqli_stmt::next_result() until all result sets are fetched (not the mysqli::next_result()!). This is the easiest way to handle the cumbersome stored procedures.
Even if you converted the code to PDO, this would still be the simplest way to do it. With mysqli things can get very complicated if you go over the board though, so be careful not to overengineer the solution. If your stored procedures use cursors, note that there was a bug in PHP up to PHP 7.4.
A lot of tutorials and books I have been over and read have used the die() method to catch an exception when interacting with a local MySQL database
For example:
mysql_connect($dbhost, $dbuser, $dbpass)or die(mysql_error());
Would a try/catch block be more beneficial over the die() method or is that just the standard way that exception handling works with db connections?
or die() is an extremely primitive way to "handle" errors and only for examples or debugging at best. In practice, it depends on how you handle your errors. You may want to return false from a function call or you may want to throw your own exception instead; e.g.:
if (!$con = mysql_connect(..)) {
throw new DatabaseConnectionError(mysql_error());
}
try..catch will do exactly nothing with mysql, since mysql never throws any exceptions. It only ever returns false on failure.
You will have to have your own error handling strategy. You'll probably want to log errors and display a user friendly error page instead of cryptic error messages. mysql is not concerned with that part. It only gives you a way to check whether an operation was successful or not (check if it returns false); what you do with this information is up to you. die kills the entire application and at least doesn't allow the problem to propagate further; but it certainly does not display any user friendly error pages.
Having said all this, mysql is old and deprecated. If you'd use something newer like PDO instead, it can properly throw exceptions itself.
The mysql_connect method does not throw exceptions and thus die() is used by many applications to terminate when there is no connection available.
You can use the solution mentioned here: how to use throw exception in mysql database connect
Included for completeness:
try
{
if ($db = mysqli_connect($hostname_db, $username_db, $password_db))
{
//do something
}
else
{
throw new Exception('Unable to connect');
}
}
catch(Exception $e)
{
echo $e->getMessage();
}
Alternatively use the new and more OOP styled database access: http://php.net/manual/en/book.pdo.php
The reason a lot of applications uses die is from the fact that they are so reliant on the database that continuing without a connection is utterly fruitless.
Edit As mentioned in the comments, the code example above is for illustrational purposes. Catching right after throwing is pointless.
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.
This might be a silly question. I have two separate databases that are being used with Laravel 4. One of them can only be accessed with a certain IP (security reasons) while the other can be accessed. I have two different mysql connections. I have seen the Database connection test using this:
if(DB::connection('mysql')->getDatabaseName()){ }
To test what can be seen and what can't be seen, I tried to give the mysql a false password. I get this nice ugly error how it can't connect. Is there a way to make it where if the Database cannot be reached, just to ignore it? There's only one PHP class that's calling the secure only database on page load, but the above check doesn't seem to be working.
Going through the core code of laravel, there is no specific exceptions being thrown when a database connection fails.
The solution hence, is:
try {
//Strings always evaluate to boolean true
$dbConnected = (bool)DB::connection('mysql')->getDatabaseName();
}
catch (Exception $e)
{
$dbConnected = false;
}
Then work your code based on the variable $dbConnected.
I have host, database name, username and the password given as form inputs like:
$form['dbname']->getData()
I need to check if these data is correct for the mysql connection. So I chose to use mysql_connect() to check this:
$conn = mysql_connect($form['host']->getData(), $form['username']->getData(), $form['password']->getData(), $form['dbname']->getData());
if($conn) // ...
else // ...
But it displays some mysql_connect() warning with no other specific message...
What's wrong? Does the symfony 2 has any mechanism to check the connection?
Symfony uses repositories and entities to manage the database. The programmer doesn't manipulate the connection itself (Doctrine).
You could try to check a connection using PDO. Try to instance a PDO Object, and catch exceptions (PDOException for connection errors). However, you're "breaking" the framework's philosophy, trying to initiate an "extern" DB connection. If you need to work with several connections in Symfony, I suggest this reference :
http://symfony.com/doc/current/cookbook/doctrine/multiple_entity_managers.html
use the following format to receive the connection error if there is any.
$con = mysql_query() or die(mysql_error());