# Docker:PHP/PDO + MySQL.. How to?

Photo by [fabio](https://unsplash.com/@fabioha?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)

## Context
A _PHP_ server and a _MySQL_ database. This is a very common setup. **You’ve to create a PHP script that interact with that database**, but you’ve no access to the server because only script from localhost works due to firewall security restriction for example.

**Problem:** To test your script you’ve to open a FTP client, upload the `.php` script to the server and test it. Every time the php file changes you’ve to repeat this procedure, not considering that make attempts in production is a very bad practice.

## Solution: Docker

> _Docker_ can come to rescue as he let the developer to create in a few steps an environment similar to the production one. **This even allow developer testing their code in a local environment without fear to make mistakes!**

There are ready to use containers for [PHP](https://hub.docker.com/_/php) and [MySQL](https://hub.docker.com/_/mysql), many tutorial and online resources that tell how to put them together with and without *docker-compose.* I found [this one](https://alysivji.github.io/php-mysql-docker-containers.html) very useful using docker-compose, and [this one](https://severalnines.com/database-blog/mysql-docker-containers-understanding-basics) not using it, but **I struggled trying to use PHP+PDO to simply open a connection with my MySQL database only reading these articles**. The reason why I’d use PDO is that MySQLi extension has been deprecated, as [W3C says](https://www.w3schools.com/php/php_mysql_connect.asp).

## Environment configuration problems (the reason why I’m writing this article):
Communication from Host to MySQL container worked, but communication from PHP container to MySQL container not.

> _docker-compose_ and an adequate variable assignment in the `.php` file are the keys to solve the problem

Here’s my `docker-compose`:
```yml
version: '3'

services:
  database:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: 123
      MYSQL_DATABASE: stt_db
      MYSQL_USER: devuser
      MYSQL_PASSWORD: 123
    ports:
      - "9906:3306"
  web:
    build: .
    container_name: php_web
    depends_on:
      - database
    volumes:
      - ./local/:/var/www/html/
    ports:
      - "8100:80"
    stdin_open: true
    tty: true
```

We can see that `db` image has left as is (`mysql:5.7`), but not the web one, since we’ve to install PDO extension to the base PHP image. Note that both containers are exposed to host by ports 8100 for _PHP_ container and by 9906 port for _MySQL_ database: in this way we can connect to it through [mysql-cli](https://dev.mysql.com/doc/refman/8.0/en/mysql.html) from host terminal with a command like the one below:

```sh
mysql -uroot -p123 -h127.0.0.1 -P9906
```

where `-P` stands for “Port” and must match with the hots-exposed one defined in `docker-compose`. `-p` stands for “password” and `-u` stands for “user”.

### Below the `Dockerfile`
```dockerfile
FROM php:7.4-cli
COPY ./local /usr/src/dst_folder
WORKDIR /usr/src/dst_folder
RUN docker-php-ext-install pdo pdo_mysql
```

last line install the required extensions.

## Let's put things together

At the end, this is my **MySQL PHP connection script**:
```php
<html>
 <head>
  <title>PHP Test</title>
 </head>
 <body>
 <?php  
 $servername = "database";
 $username = "root";
 $password = "123";
 $dbname = "stt_db";
 $port = "3306";
 
 try{
    $conn = new PDO("mysql:host=$servername;port=$port;dbname=$dbname",$username,$password);
    $conn -> setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
    echo "Connected succesfully";
 } catch(PDOException $e){
    echo "Connection failed: " . $e -> getMessage();
 }
 ?> 
 </body>
</html>
```

note two important things:

*   `$servername` is set to the **mysql service name** in `docker-compose.yml` since docker-compose allow containers declared inside `docker-compose.yml` to communicate each other by service name. No worries about IP address
*   `$port` is set to the in-network port where “in-network” is the one created automatically by docker-compose when run by `docker-compose up`
*   browse [http://localhost:8100](http://localhost:8100) and you’ll se the message: “Connected succesfully”

![An happy runner](https://cdn.hashnode.com/res/hashnode/image/upload/v1637873012996/Wy3ackYcV.jpeg)

Photo by [Wesley Eland](https://unsplash.com/@wesleyeland?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)

### Thanks for reading :)
