Well, I have decided to listen to you all and take the plunge, so I am going to start working with PHP 8 and using the PDO interface. I am also going to attempt switching my scripts from procedural to OO.
It’s quite scary for me and I know it is going to take a while so if anybody has any tips, advice, warnings or just comments I will be happy to recieve them.
While it is a ‘plunge’, take it simple steps at a time.
First, establish the PDO object (the database connection).
Then update your queries as necessary. Usually, this is as simple as replacing mysqli_query with $pdo->query
From there, if you havent already, you’re going to want to start looking at prepared statements, as they’re infinitely more preferable to putting variables into queries.
I am with Hostpresto which do provide PHP 8 with the added advantage that you can select PHP version by domain. I have not yet tried it but I do have XAMPP with PHP 8 for windows 10 installed so I will begin my testing there
OK so this is my first attempt at creating a connection. I want to display a success message as well as a fail message but not display the actual error for security reasons (as advised on this site) so I have commented out the line that displays the exception. I do not close the connection here as it is a file to be ‘required once’ by other scripts. I also appreciate that my connection values - username, password, database name etc are weak but this is not live yet and just for testing.
<?php
$servername = "localhost";
$username = "db_user";
$password = "db_pass";
$dbname = "the_database";
try {
$pdo = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
// set the PDO error mode to exception
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
if ($pdo) {
echo "Connected to the database successfully!";
}
} catch(PDOException $e) {
//echo "Connection failed: " . $e->getMessage();
echo 'Connection failed!<br>';
}
?>
This seems to work OK but as this is all new to me (including ‘try’ and ‘catch’) I want to be sure I am on the right path and not building in security issues for later down the line.
Others may have better insight; The only security ‘issue’ i would say is don’t store your database stuff in variables.
If later in your code, or including a file that loads your database connection, i can echo out $password …
(This is a rare attack vector that requires access to your file structure, but it’s happened.)
try {
$pdo = new PDO("mysql:host=localhost;dbname=the_database", "db_user", "db_pass");
Because I never store the password or username, the only thing that can access the password is the $pdo object, and you can’t extract it from the $pdo variable.
How does someone exploit this?
I’ve done this once. Piece of third party software, encrypted code. I can’t read it. But; I can include it.
No. Don’t let a visitor to your site know what kind of internal error occurred, ever. This will only confuse a legitimate visitor with information they cannot do anything about and will let hackers know that they were successful in creating a connection error, encouraging them to do more of the same. All the visitor to your site needs to know is that a web page isn’t working, which if you do the following will cause a generic http 500 error page, which you can create your own if you choose.
When you, the developer/programmer are learning, developing, and debugging code/query(ies), you want to display all php and all failed statement errors. When on a live/public server, you want to log this information. To do this for database statement errors, SIMPLY let php catch and handle the exception, where php will use its error related settings to control what happens with the actual error information. You would then remove any existing database statement error handling logic, simplifying the code, since it will no longer get executed upon an error (execution transfers to the nearest correct type of exception handling, which will be php in this case.) Also, a connection error is a fatal problem for a database dependent web page and the posted code, since it doesn’t stop execution upon a connection error, will cause meaningless follow-on database statement errors when the code tries to use the nonexistent connection.
The only time having try/catch logic in your code for a database statement error is useful are for visitor recoverable errors, such as when inserting/updating duplicate or out of range data.
As to the posted connection code, also -
Set the character set to match your database table(s).
Set emulated prepared queries to false (you want to run real prepared queries.)
Set the default fetch mode to assoc (so that you don’t need to keep specifying it in each fetch statement.)
OK, my idea was not to display the actual full error message, but I had not considered that simply ‘Connection failed’ could be a hint for hackers - thanks for the heads up!
Also thanks for the other advice, which to be honest I don’t fully understand but I will research it as it seems to make sense.
My default character set is utf8mb4_general_ci according to phpmyadmin should I set charset in connection as ‘charset=utf8mb4’, ‘charset=utf8mb4_general_ci’ or simply ‘charset=utf8’
Yes, but put these settings in the php.ini on your system, not in your code.
That statement was specific to the posted code’s error handling of echoing something, but not stopping execution past that point. Since you are removing all that connection error handling logic, and letting php catch any connection error, this problem goes away. Your main code will no longer be executed upon a connection error.
OK I have tried this. Please remember I am new to this, and as far as I can see declare(strict_types=1); will force PHP to only accept vars of the expected type ie not interpret a number as a string. So I will get an error with this example unles I change it to ini_set('display_errors', '0');
I guess you are telling me this is a good idea to prevent possible hacking / errors? But I also guess I need to accompany this in my code by defining vars as a particular type such as int x$ ?
I am not sure exactly what advice you are giving me. Is it OK to use these settings in my code rather than in the config file on the server if I set strict types or are you saying I should always enable strict types - I am a little confused.
Thanks