Broken pdo_mysql in php 8.3

I’ve looked in vain for a definitive answer to this, but there doesn’t seem to be one. I’ve installed a LAMP stack on a fresh build of xubuntu 24.04 with php8.3 which I use mostly from a shell. phpinfo() claims that pdo_mysql is loaded:

PDO

PDO support => enabled
PDO drivers => mysql

pdo_mysql

PDO Driver for MySQL => enabled
Client API version => mysqlnd 8.3.6

Directive => Local Value => Master Value
pdo_mysql.default_socket => /var/run/mysqld/mysqld.sock => /var/run/mysqld/mysqld.sock

but ->prepare() statements fail. Trying to load the extension from php.ini results in

PHP Warning: PHP Startup: Unable to load dynamic library ‘pdo_mysql’ (tried: /usr/lib/php/20230831/pdo_mysql

despite the fact that ls shows the file is there in both cases. Anybody know what gives?

Well, I looked that error up and some other people have solved it with these commands below.
But, you should make a backup of your PHP system before you run them in case it causes issues.
( Better safe than sorry!) I think the issue is something to do with the library address. Yours is /usr/lib/php/20230831/pdo_mysql and it might not be linked to correctly in the PHP system.

First, you might want to just reinstall it using this command:
sudo apt-get install php8.3-mysql
If does not work, try these after backing up your PHP system.
sudo apt-get --purge remove php-common
sudo apt-get install php-common php-mysql php-cli

Here is the location of the page I got this info from in case you want to read further before trying these.
Stack Overflow PDO load error

Thanks Ernie, I saw that page and tried everything that was suggested (purge & re-install, --forece-reinstall), but still no dice. I’m no linux expert but the files are properly linked and in the right places as far as I can tell. I think I’ve determined that the fault is with pdo, not just pdo_mysql.

This has happened before, so all my scripts are safely backed up. I’ll install lamp stacks on some other machines I have about and see what I can see. Annoying though.

I understand Annoying! Ha! Been there so many times.

They keep saying to just use: sudo apt install php-pdo so install PDO on PHP in Lamp.
Did you use a full install package or do it piece by piece?
I read awhile ago how to install of it and reread it. Here is a link you might get something out of.
I have one Ubuntu system somewhere here, a small pi system if I remember correctly.
Maybe I could try it this weekend and see how it goes. Here is that link I was reading
on the install procedures. Not sure if it will help, but, maybe… Lamp-Ubunto-Php-PDO-install
Good luck, leaving for several hours. Will check back when I get back!

Tks, that’s actually the page I typically use. I’ve tried the re-install php-pdo, but I’ll give it another whirl.

How are you invoking/requesting the script with the phpinfo() statement and how are you invoking/requesting the script that fails?

How do you know that ->prepare() statements fail? What symptom or error do you get and do you have and have confirmed via a phpinfo() statement that php’s error_reporting set to E_ALL (it should always be this value) and display_errors set to ON so that all php errors get reported and displayed?

What is your database specific code, starting with the connection through to the code that fails, less any connection credentials?

phdr:

PHP Fatal error: Uncaught Error: Call to undefined method PDOException::prepare() in /home/mar...

which results when calling

	function fn_chart_read(string $category) : array	{
		$dbh = fn_db_connect();
		try	{
			$s = $dbh->prepare("CALL accounts.p_chart_read(?)");
			$s->bindParam(1, $category);
			$s->execute();
			return $s->fetchAll(PDO::FETCH_ASSOC);
		}
		catch (PDOException $err)	{
			return false;
		}
	}

All errors are on:

ini_set('display_errors', 1);
error_reporting(E_ALL);

and as shown above, phpinfo() says pdo_mysql is loaded for both cli and apache.

The process is initiated from the cli:

chart list x
using
alias chart='php chart.php'

$command = $argv[1] ?? NULL;
	switch ($command)	{
...
		case "list" :						// list [{"category"}]
			$operand = strtoupper($argv[2] ?? "X");
			switch (true)	{
				case !in_array($operand, ["A", "L", "Q", "R", "E", "X"]) :
					die(RED . "Invalid operand.\n" . WHT);
					break;
				default :
					fn_chart_display(fn_chart_read($operand));
					die();
					break;
			}
			break;

Having had trouble with other memory-hogging software, I built another machine with 32GB, as above, with xubuntu 24.04. The scripts worked without issue on the older 16GB machine (and still do!), so I don’t believe they are the issue.
Tks.

The error means that $dbh is an instance of the PDOException class. The fn_db_connect() is somehow returning an instance of this class, not a connection.

Sorry, I’m not clear on what you mean:

	function fn_db_connect()	{		// get database handle
		try	{
			return new PDO("mysql:host=yadayadayada", "dev", "dev");
		}
		catch (PDOException $err)	{
			return $err;
		}
	}

which works flawlessly on the prior machine. There’s no failure until the prepare() statement.

The scripts were designed to be stateless so I can use them to drive a REST api (whenever I get around to that).

The more I think about this, the more I think it’s an issue with the ubuntu installer not flipping switches properly. Is there a more trustworthy ppa on, say, github or php.net?

You are returning the connection error, which is an instance of the PDOException class.

The only database exceptions you should catch and handle in your code are for user recoverable errors, such as when inserting/updating duplicate user submitted data. For all other query errors and all other type of queries and the connection, you should do nothing in your code and let php handle any database exception in these cases. Once you remove the try/catch for the connection logic, php will report and display the actual reason for the connection failure, via an uncaught exception error. By handling this in your code and NOT testing the return value from the connection call before using it, you are just getting a follow-on error having nothing to do with the actual problem.

Also, when you make the connection, you should -

  1. Set the character set to match your database tables, so that no character conversion occurs over the connection.
  2. Set the emulated prepared query setting to false, you want to run real prepared queries whenever possible.
  3. Set the default fetch mode to assoc, so that you don’t need to specify it in each fetch statement.
  4. If you are calling the connection function multiple times in any script, you need to make the connection a static variable inside the function and only make a new connection if there isn’t already one.

Thanks. I still don’t understand how that explains why it works on one machine and not the other. I’ll fire up the old machine and try returning a boolean on it and on this machine for the connection to see if it is indeed the issue.

Everything is set to utf-8, since I handle various languages. Since the ultimate aim is a stateless api, there’s no point in popping open a database handle until it’s actually needed and there are no logic errors in the cli request - hence the die() once we’re done. As for default fetch mode, the system is expected to be db agnostic, so some sql queries are returning explicit integer values to avoid problems with different dbms persuasions. Hence for example, this:

	function fn_account_create(array $data) : bool	{
		$dbh = fn_db_connect();
		try	{
			$s = $dbh->prepare("CALL accounts.p_ac_create(?, ?, ?, ?, ?, ?)");
			$s->bindParam(1, $data["account"]);
			$s->bindParam(2, $data["category"]);
			$s->bindParam(3, $data["title"]);
			$s->bindParam(4, $data["description"]);
			$s->bindParam(5, $data["sigma"]);
			$s->bindParam(6, $data["postable"]);
			$s->execute();
			return $s->fetch(PDO::FETCH_NUM)[0] == 1;
		}
		catch (PDOException $err)	{
			return false;
		}
	}

The catch clause is eventually meant to write the error to a log, not the user.

Turning off prepared query emulation is a good idea. I’ll let you know how I make out with things: I’m on salad duty, so I’m back and forth. :slight_smile:
Tks
M

You can always specify the fetch mode in a fetch statement if you want to use a mode different from the default.

If you do what I wrote, the uncaught exception will AUTOMATICALLY get displayed or logged, the same as php errors, based on php’s error_reporting, display_errors, and log_errors settings. No code is required.

I’ll give it a whirl.

Sponsor our Newsletter | Privacy Policy | Terms of Service