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.

Guys, this isn’t about the code at all but failing to load the extension.
So the error from the very first post was already the correct one to look at.

There are multiple reasons why this can fail.

  • it is a wrong version of the file potentially compiled for a different architecture (32 bit vs. 64 bit , amd64 vs arm)
    => This can be fixed by installing the correct version

  • the file actually is named pdo_mysql.so and the config is not auto-appending the .so extension
    => This can be fixed by adjusting the configfile

  • there is a dependecy (another library used by the pfo_mysql extension) missing like i.e. the general mysql client libraries
    => This can be fixed by installing the missing library

  • the loading order of the extensions is wrong
    => This can be fixed by changing the config

  • you have more than one concurrent version of php installed and the “wrong” (older?) one is called
    => this can be fixed by adjusting the search path or uninstalling the concurrent version

  • you are running the php with a non privileged user which isn’t allowed to read the extensions
    => this can be fixed by changing the file permissions


you should therefore test with less complicated code called from the CLI

As a first step just running
php -v
from the cli

This should print the version information best case without errors, but I would expect the “extension” error to show

This has been my suspicion all along. It has just happened again, a result, I expect, of keeping my little lab machines updated regularly. Code that has worked without issue for months all of sudden shows up with the same old error. I’ve tried all of your suggestions - uninstall/reinstall, purge/reinstall, change file permissions, re-install libraries (that are already there), check for more than one version (only 8.3.19 is there), rebuild machines and start with a fresh install, mess with config files. Maybe the php gods are angry with me. I’m at the point where I’m either going to stop updating machines (not) or just give up on php in favour of something else. One machine is a nuisance, 5 or 6 is a pain in the ass. :slight_smile:

This started with a complaint about ->prepare() statements failing. The database dependent code SHOULD have never reached the point of a prepare() statement if the connection failed.

Once the actual error and connection code was posted, the symptom of ->prepare() statements failing turned out to be connection code catching and returning the PDOException object, where it was (unconditionally) treated as through it was a PDO object, producing a follow-on error, instead of halting code execution and displaying/logging the actual reason for the connection failure.

@mcg, once you followed the recommendations and changed the connection code to NOT catch and (miss) handle a connection exception, what actual connection error did (are) you getting?

As it happens, precisely the same error as above. As I’ve said repeatedly, the code works and has worked for months on end with no alterations. In fact, it still does work as-is on a different machine. What the code should have done is, IMHO amateur opinion, irrelevant. In any event, I appreciate your advice on good coding habits.

If the error is this -

It means that the connection is failing for some reason. The error handling for a connection error (which apparently reverted back to returning the PDOException object) is hiding whatever error information there is and because it is not halting execution, is producing a bogus follow-on error at the ->prepare() statement.

If you simply remove all the try/catch logic in the connection function, as was already stated -

Which operating system are you using and how have you installed php on those boxes?

Actually this is the first time I hear about such a “stubborn” extension, specially when it’s kind of a standard one like PDO.

Please be as well aware that there are zts and none-zts versions existing which may be incompatible with each others extension.

Please post your full install commands for review.

Also please check
php -v
output on the working machine

This is a bit of looking into a black hole somehow.
It should work “out of the box” on a fresh install.
Still there can be things impacting the installation like pulling from a broken repository or so.

It’s hard to debug remotely

Edit:
Just seen that you are running xubuntu 24.04
I haven’t have huge experience with that one as I usually use debian machines, but still it should just work.
Regardless, package names might be slightly different per each distro.

I’ve just rebuilt one of the offenders (same xubuntu 24.04 server on a rpi 4b), this time skipping the apache install: my earlier project to build an API has gone up in smoke (too much work, other more interesting projects I have my eye on).
So the install was this, following a fresh OS install & full update/upgrade:
sudo apt install mariadb-server mariadb-client
followed, after securing the db, with
sudo apt install php8.3-cli php8.3-common
and everything magically works again.
On another machine,
$dbh = new PDO("mysql:server=127.0.0.1;dbname=gutenberg", "yada", "yada");
results in

PHP Fatal error:  Uncaught PDOException: SQLSTATE[HY000] [2002] No such file or directory in /home/mcg/indexes.php:3
Stack trace:
#0 /home/marcel/indexes.php(3): PDO->__construct()

the cause of which is obvious. (Don’t yell at me about the code: it was a quick and dirty script to populate a database, and it ran successfully unaltered on another machine.)
At the risk of being monotonous, I think I need to point out again:
phdr: I followed your advice, same problem: PDO issue.
phdr/reddig: The code has not changed. This seems to just happen out of the blue: I’m religious about making sure all machines are updated and singing from the same songbook. No new software is ever installed, they’re just plain-jane LAMP servers. One day it works, next day the PDO issue. Version checking always shows php 8.3. Go look for the socket file, sometimes it’s there, sometimes it isn’t. Where would it go? It’s inexplicable and makes me question my sanity. More than usual.

P.S. The long-and-short of it is this: all of my messing around tells me this is an os/apt/file issue, not a problem with the php install itself. How to resolve it? No idea. I’ll keep an eye on the newest installs and watch for it to happen again.

Sponsor our Newsletter | Privacy Policy | Terms of Service