Migrating from PHP 7 to PHP 8 and PDO

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.

And if it all goes wrong - it is your fault ! :laughing:

3 Likes

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.

2 Likes

The live paid for server I use doesn’t yet support PHP8 (as far as I can see). Does yours? I wonder how many do at the moment?

Which server is that? Mine has since PHP8 was released.

1 Like

UK Web Solutions Direct Ltd

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

1 Like

That’s exactly the kind of helpful step by step advice I need - thanks.

1 Like

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.

Thanks in advance

1 Like

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.)

Compare:

<?php
$servername = "localhost";
$username = "db_user";
$password = "db_pass";
$dbname = "the_database";

try {
  $pdo = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);

vs

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.

<?php
include_once("hiddencode.php");
print_r(get_defined_vars());
?>

Suddenly I know what variables they left laying around in the variable table…

1 Like

Good advice I think, I will adopt that approach

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 -

  1. Set the character set to match your database table(s).
  2. Set emulated prepared queries to false (you want to run real prepared queries.)
  3. Set the default fetch mode to assoc (so that you don’t need to keep specifying it in each fetch statement.)
1 Like

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.

Thank you

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’

^ That one.

1 Like

Thank you again, with regard to your suggestions for error handling do you mean keep it simple for development then when live hide using

ini_set('display_errors', 0);

and log using

ini_set('log_errors', 1);

How do I prevent this happening

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.

1 Like

Thank you again so much

I have an amazon lightsail server and manage it with serverpilot.io. Pretty easy to switch to different PHP versions, including PHP 8.

Try this validation declaration at the start of the file and notice the warnings:

<?php declare(strict_types=1);
// error_reporting(-1); // recommended maximum error reporting
ini_set(‘display_errors’, 1); // expects string value 

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