Home > Net >  Official PHP:Apache Docker Image - Getting MySql Plugins to Work
Official PHP:Apache Docker Image - Getting MySql Plugins to Work

Time:09-22

I am using the official docker php:apache image but I can't use mysqli with php.
I get 'Class "mysqli" not found' whenever I try this:

$conn = new mysqli($servername, $username, $password, $dbname);

I see a ton of stuff everywhere talking about adding an install for mysqli to the dockerfile. I am really not sure if this is necessary for a few reasons:

When I open bash on my container, I see that mysqlnd is installed as a php module.

Here's the snippet from my docker-compose.yml:

lamp-www:
  depends_on:
  - db
  image: php:apache
  volumes:
  - "./www:/var/www/html"
  ports:
  - 8080:80

When I do a PhpInfo(), I see "--enable-mysqlnd" and I see a mysqlnd section.
It states version name: "mysqlnd 8.0.10".

I haven't seen anything indicating that the syntax is different between the old mysqli and mysqlnd, it suggests it's the same. I've tried using "mysqlnd" and "mysql" instead, but they all generate the same error as "mysqli".

I also am not seeing anything that indicates you can use a DockerFile when using "image: php:apache". I also don't want to go into my container to install or change things, and re-commit, I'd like use the official image.

Can I make a DockerFile when I use the "image" parameter in my docker-compose.yml?
Is there a cleaner way to do this, like just adding a parameter to my compose that installs whatever mysterious thing I'm missing?

Final question: This is the official php image, and the installed modules seem to indicate that mysql is supported from php. Am I just trying to use functions/classes that aren't recommended? If so, what should I be using instead?

CodePudding user response:

According to the docs here, it says:

What it is not

Although MySQL Native Driver is written as a PHP extension, it is important to note that it does not provide a new API to the PHP programmer. The programmer APIs for MySQL database connectivity are provided by the MySQL extension, mysqli and PDO MYSQL. These extensions can now use the services of MySQL Native Driver to communicate with the MySQL Server. Therefore, you should not think of MySQL Native Driver as an API.

Basically, mysqlnd is in a layer below mysqli or pdo_mysql, it does not add functions/classes in PHP for you to connect to a MySql db.

This can be checked running a few commands (I'm assuming a flavor of Linux or WSL):

docker pull php:apache                 #downloading the official image
docker run --rm -it php:apache bash    #and running it in a temporal container

once inside the container:

php -m     #checking the modules for php
php -a     #executing a php interactive console

(note that in the output of php -m, mysqlnd is present but mysqli or pdo_mysql are not)
then, run these lines inside the php console:

$conn = new mysqli('localhost', 'root', 'pass', 'db');              //connecting to a MySql db with mysqli
$dbh = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass'); //and the same with pdo_mysql

Both lines will throw an error:

Warning: Uncaught Error: Class "mysqli" not found in php shell code:1     //mysqli
Warning: Uncaught PDOException: could not find driver in php shell code:1 //pdo_mysql

Even in standard installations of php in the wild, neither mysqli nor pdo_mysql are bundled by default, because you may want to use other databases (PostgreSQL, SQLite, Oracle, etc...) or none at all, so you need to install the specific driver for your db.

Installing a MySQL driver with a Dockerfile

Q: Which one should you use, mysqli or pdo_mysql?

A: Nope, i'm not touching this one, go with the one you personally feel most comfortable with. This question is on par with "tabs or spaces?", "vi, vim or emacs?", "pineapple on pizza?", "Were Ross and Rachel on a break?" or "Was The Dress blue and black or white and gold?" in terms of divisiveness, both have their pros and cons, and there are no wrong answers (unless you put pineapple on a pizza, seriously, what's is wrong with you?).

To install any, or both drivers you need to create a Dockerfile that creates a new image with php and the drivers ready to use. You don't need to start from scratch or go into the container everytime you run it, since you can base your image on the official one and extend it.

There are instructions to do so in the readme of the official image, where they mention the helper commands inside the image, but i already did the legwork:

#this uses the official image as a starting point
FROM php:apache

#humblebrag
MAINTAINER gorchestopher-h

#install both modules from source, you can delete the one you aren't using
RUN docker-php-ext-install mysqli pdo_mysql

that's it! now you have a Dockerfile that you need to save in a file with the name Dockerfile (no extension) preferably in a directory right next to your docker-compose.yml file, please.

Now that you have this file, you could execute the docker build command and create it, but since you're using docker-compose, you're already a few steps ahead with automatization, so you only need to edit your compose file and the first time you run docker-compose up with the new configuration it will do the job for you.

But here's the catch, the way the image key works is:

If the image does not exist, Compose attempts to pull it, unless you have also specified build, in which case it builds it using the specified options and tags it with the specified tag.

So, that means we can set the build key inside the the compose file to build our Dockerfile. But! it needs to have an unique name so it doesn't get confused with the already existing php:apache image in your system and the official repository.

This can be done using both image and build keys:

lamp-www:
  depends_on:
      - db 
  image: gorchestopher-h/php-mysql:apache           #the resulting image gets named this
  build: ./name-of-the-directory-next-to-the-yml    #where to find the Dockerfile file
  volumes:
      - "./www:/var/www/html"
  ports:
      - 8080:80

And that's it, now the first time you docker-compose up this compose file, the image gets built since it can't be found, and if you modify the Dockerfile and spin it up again. It does nothing since the image already exists, you need to execute docker-compose build lamp-www (the name of the service is optional, if you skip it, it builds every build key) to recreate it, and also docker image prune after you spin up the new image to free the unused old one.

To check that everything went well, you can repeat the commands from before.

docker run --rm -it gorchestopher-h/php-mysql:apache bash #run the container with the awesome new name

inside the container you can run

php -m #check the installed modules, it should have mysqli and/or pdo_mysql
php -a #executes a php terminal

and on the php terminal you can test the connection again

$conn = new mysqli('localhost', 'root', 'pass', 'db');              //connecting to a MySql db with mysqli
$dbh = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass'); //and the same with pdo_mysql
  • Related