[Initial Commit]

This commit is contained in:
Evann Regnault 2024-06-07 20:27:58 +00:00
commit 6b55ae7c70
11 changed files with 360 additions and 0 deletions

6
.gitignore vendored Executable file
View file

@ -0,0 +1,6 @@
.idea
.DS_Store
.env
vendor
public
composer.lock

78
README.md Executable file
View file

@ -0,0 +1,78 @@
# Docker PHP Development Environment
This repository allows you to quickly get a development environment up and running using Docker, including a MySQL database and some debugging tools.
This environment includes the latest versions of the following software:
- `nginx:alpine`
- `php:8.3-fpm`
- `mysql:latest`
- `xdebug`
## Prerequisites
- Docker - https://www.docker.com/products/docker-desktop
- Tested and confirmed working on:
- macOS 12.3 (Monterey)
- Windows 10 Version 21H1 build 19043.1165
## Project Setup
Run `composer create-project jlucki/docker-php-dev-env "project_name"`
Alternatively, download the files from this repo and copy them to your project directory.
## Running the Container
1. Run `docker compose up` from the project directory
- Note: the above command will only work on versions newer than 3.6. If you are using Docker 3.6 or older, use `docker-compose up`
2. Visit `localhost` in your browser
## Setting up Xdebug in Your IDE
_The following instructions are for PHPStorm._
1. Click on Run > Edit Configurations
2. Click the `+` and add a new PHP Remote Debug configuration
3. Give the configuration a name
4. Tick _Filter debug connection by IDE key_
5. Add `PHPSTORM` in the session id
6. Click the `...` next to Server
7. Click the `+` to add a new server
8. Give the server a name, and set the host to `localhost`
9. Tick _Use path mappings_
10. Under the `Project files` file/directory, next to your project folder, for the `Absolute path on the server` column add `/var/www/html`
11. Hit Apply and OK until you've returned to the IDE
12. Click the _Start Listening for PHP Debug Connections_ icon
13. Set a breakpoint in your code
14. Refresh the page in your browser
15. Accept _Incoming Connection From Xdebug_
16. Happy debugging!
See https://xdebug.org/docs/remote for how to enable xdebug sessions.
## Additional Notes
For database connections, use `mysql` as the hostname. If you would like a different hostname, change the service name in the `docker-compose.yml` file.
## Windows 10 Troubleshooting
If you are having problems and can't seem to fix the issue, try one or both of these fixes:
### Solution 1
Try switching to **Windows containers**:
Right-click the Docker icon in the system tray and click **Switch to Windows containers** as seen below:
![Context Menu](https://i.imgur.com/enYmIPH.png)
### Solution 2
If the **Use the WSL 2 based engine** setting is checked:
Uncheck the setting, then enable file sharing located under the **Resources** section, then the **File Sharing** section as seen below:
![Docker Settings](https://i.imgur.com/maub2Wh.png)
If the **Use the WSL 2 based engine** setting is unchecked:
Enable/check the setting (file sharing is automatically configured)

31
composer.json Executable file
View file

@ -0,0 +1,31 @@
{
"name": "jlucki/docker-php-dev-env",
"description": "A simple web development environment using Docker with NGINX, PHP, MySQL and Xdebug.",
"type": "project",
"keywords": [
"docker",
"development",
"environment",
"php",
"xdebug",
"nginx"
],
"license": "MIT",
"authors": [
{
"name": "Jan Lucki",
"email": "jan@lucki.dev"
}
],
"require": {
"sabre/dav": "^4.6",
"ext-curl": "*"
},
"autoload": {
"psr-0": {
"Keycloak": "src",
"Collections": "src",
"Principal": "src"
}
}
}

24
docker-compose.yml Executable file
View file

@ -0,0 +1,24 @@
version: '3.7'
services:
web:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./:/var/www/html
- ./docker/conf/default.conf:/etc/nginx/conf.d/default.conf
php:
build:
context: ./docker
volumes:
- ./:/var/www/html
- ./docker/php/xdebug.ini:/usr/local/etc/php/conf.d/xdebug.ini
mysql:
image: mysql:latest
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: webapp
MYSQL_USER: webapp
MYSQL_PASSWORD: root

15
docker/Dockerfile Executable file
View file

@ -0,0 +1,15 @@
FROM php:8.3-fpm
ARG WITH_XDEBUG=true
RUN apt-get update && apt-get install -y \
libfreetype6-dev \
libjpeg62-turbo-dev \
libpng-dev \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install -j$(nproc) gd \
&& docker-php-ext-install mysqli \
&& docker-php-ext-install pdo pdo_mysql; \
if [ $WITH_XDEBUG = "true" ] ; then \
pecl install xdebug; \
fi ;

22
docker/conf/default.conf Executable file
View file

@ -0,0 +1,22 @@
server {
listen 80;
index index.php index.html;
server_name localhost;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /var/www/html/src;
location / {
try_files $uri $uri.js /index.php$is_args$args;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}

6
docker/php/xdebug.ini Executable file
View file

@ -0,0 +1,6 @@
[Xdebug]
zend_extension=xdebug.so
xdebug.mode=debug
xdebug.client_port = 9000
xdebug.client_host = host.docker.internal
xdebug.idekey=PHPSTORM

40
index.php Executable file
View file

@ -0,0 +1,40 @@
<?php
use Collections\HomeCollection;
use Sabre\DAV;
// The autoloader
require 'vendor/autoload.php';
$aclPlugin = new \Sabre\DAVACL\Plugin();
// Set Auth
$authBackend = new Keycloak\KeycloakAuth($aclPlugin,$_ENV['client_id'], $_ENV['client_secret'], $_ENV['keycloak_token_url'] );
$authBackend->setRealm($_ENV['realm']);
$authPlugin = new DAV\Auth\Plugin($authBackend);
// The server object is responsible for making sense out of the WebDAV protocol
$server = new DAV\Server([new HomeCollection($authPlugin, $_ENV['users_path'])]);
// If your server is not on your webroot, make sure the following line has the
// correct information
$server->setBaseUri($_ENV['base_uri']);
// The lock manager is responsible for making sure users don't overwrite
// each others changes.
$lockBackend = new DAV\Locks\Backend\File('data/locks');
$lockPlugin = new DAV\Locks\Plugin($lockBackend);
$server->addPlugin($lockPlugin);
// This ensures that we get a pretty index in the browser, but it is
// optional.
$server->addPlugin(new DAV\Browser\Plugin());
$server->addPlugin($authPlugin);
$server->addPlugin($aclPlugin);
// All we need to do now, is to fire up the server
$server->start();

View file

@ -0,0 +1,38 @@
<?php
namespace Collections;
use Sabre\DAV\Collection;
use Sabre\DAV\Auth\Plugin as AuthPlugin;
use Sabre\DAV\FS\Directory;
class HomeCollection extends Collection
{
private $plugin;
private $userPath;
public function __construct(AuthPlugin $authPlugin, $userPath)
{
$this->plugin = $authPlugin;
$this->userPath = $userPath;
}
public function getChildren()
{
$principal = $this->plugin->getCurrentPrincipal();
$username = explode("/", $principal)[1];
$path = $this->userPath;
if (!is_dir($path.$username)) {
mkdir($path.$username, 0777 , true);
}
return [new Directory($path.$username, $username)];
}
public function getName()
{
return "Home";
}
}

View file

@ -0,0 +1,56 @@
<?php
namespace Keycloak;
use Sabre\DAV\Auth\Backend\AbstractBasic;
use Sabre\DAVACL\Plugin as AclPlugin;
class KeycloakAuth extends AbstractBasic
{
private $aclPlugin;
private $client_id;
private $client_secret;
private $keycloakTokenUrl;
public function __construct(AclPlugin $plugin, $client_id, $client_secret, $keycloakTokenUrl)
{
$this->aclPlugin = $plugin;
$this->client_id = $client_id;
$this->client_secret = $client_secret;
$this->keycloakTokenUrl = $keycloakTokenUrl;
}
protected function validateUserPass($username, $password)
{
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => $this->keycloakTokenUrl,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "grant_type=password&client_id=" . $this->client_id . "&client_secret=" . $this->client_secret . "&username=".$username."&password=".$password,
CURLOPT_HTTPHEADER => [
"Content-Type: application/x-www-form-urlencoded"
],
]);
curl_exec($curl);
$err = curl_error($curl);
$data = curl_getinfo($curl);
curl_close($curl);
if ($err || $data['http_code'] != 200) {
return false;
} else {
return true;
}
}
}

View file

@ -0,0 +1,44 @@
<?php
namespace Principal;
use Sabre\DAVACL\PrincipalBackend\AbstractBackend;
class CustomBackend extends AbstractBackend
{
public function getPrincipalsByPrefix($prefixPath)
{
// TODO: Implement getPrincipalsByPrefix() method.
}
public function getPrincipalByPath($path)
{
// TODO: Implement getPrincipalByPath() method.
}
public function updatePrincipal($path, \Sabre\DAV\PropPatch $propPatch)
{
// TODO: Implement updatePrincipal() method.
}
public function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof')
{
// TODO: Implement searchPrincipals() method.
}
public function getGroupMemberSet($principal)
{
// TODO: Implement getGroupMemberSet() method.
}
public function getGroupMembership($principal)
{
// TODO: Implement getGroupMembership() method.
}
public function setGroupMemberSet($principal, array $members)
{
// TODO: Implement setGroupMemberSet() method.
}
}