diff --git a/.github/workflows/publish-dockerhub.yml b/.github/workflows/publish-dockerhub.yml new file mode 100644 index 0000000..e30452b --- /dev/null +++ b/.github/workflows/publish-dockerhub.yml @@ -0,0 +1,33 @@ +name: Publish to Docker Hub +on: + workflow_dispatch: + push: + branches: [ main ] + paths: + - 'docker/**' + - '.github/workflows/**' +jobs: + build-and-push: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: docker/setup-qemu-action@v3 + - uses: docker/setup-buildx-action@v3 + - uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Build & Push WEB + uses: docker/build-push-action@v6 + with: + context: . + file: docker/Dockerfile.web + push: true + tags: jcabo65/php-sample-web:latest + - name: Build & Push DB + uses: docker/build-push-action@v6 + with: + context: . + file: docker/Dockerfile.db + push: true + tags: jcabo65/php-sample-db:latest diff --git a/composer.json b/composer.json index a164f98..5de3161 100644 --- a/composer.json +++ b/composer.json @@ -2,5 +2,10 @@ "require": { "willdurand/negotiation": "^2.2", "twbs/bootstrap": "^3.3" + }, + "autoload": { + "psr-4": { + "": "src/" + } } } diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..bfbaab1 --- /dev/null +++ b/composer.lock @@ -0,0 +1,130 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "6226c4e050e2b55576c081b6dd9120d0", + "packages": [ + { + "name": "twbs/bootstrap", + "version": "v3.4.1", + "source": { + "type": "git", + "url": "https://github.com/twbs/bootstrap.git", + "reference": "68b0d231a13201eb14acd3dc84e51543d16e5f7e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twbs/bootstrap/zipball/68b0d231a13201eb14acd3dc84e51543d16e5f7e", + "reference": "68b0d231a13201eb14acd3dc84e51543d16e5f7e", + "shasum": "" + }, + "replace": { + "twitter/bootstrap": "self.version" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.4.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jacob Thornton", + "email": "jacobthornton@gmail.com" + }, + { + "name": "Mark Otto", + "email": "markdotto@gmail.com" + } + ], + "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.", + "homepage": "https://getbootstrap.com/", + "keywords": [ + "JS", + "css", + "framework", + "front-end", + "less", + "mobile-first", + "responsive", + "web" + ], + "support": { + "issues": "https://github.com/twbs/bootstrap/issues", + "source": "https://github.com/twbs/bootstrap/tree/v3.4.1" + }, + "time": "2019-02-13T15:55:38+00:00" + }, + { + "name": "willdurand/negotiation", + "version": "v2.3.1", + "source": { + "type": "git", + "url": "https://github.com/willdurand/Negotiation.git", + "reference": "03436ededa67c6e83b9b12defac15384cb399dc9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/willdurand/Negotiation/zipball/03436ededa67c6e83b9b12defac15384cb399dc9", + "reference": "03436ededa67c6e83b9b12defac15384cb399dc9", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + }, + "autoload": { + "psr-4": { + "Negotiation\\": "src/Negotiation" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "William Durand", + "email": "will+git@drnd.me" + } + ], + "description": "Content Negotiation tools for PHP provided as a standalone library.", + "homepage": "http://williamdurand.fr/Negotiation/", + "keywords": [ + "accept", + "content", + "format", + "header", + "negotiation" + ], + "support": { + "issues": "https://github.com/willdurand/Negotiation/issues", + "source": "https://github.com/willdurand/Negotiation/tree/2.x" + }, + "time": "2017-05-14T17:21:12+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.6.0" +} diff --git a/docker/Dockerfile.db b/docker/Dockerfile.db new file mode 100644 index 0000000..2d82bac --- /dev/null +++ b/docker/Dockerfile.db @@ -0,0 +1,8 @@ +FROM mariadb:10.3 + +COPY sql/db.sql /docker-entrypoint-initdb.d/ + +ENV MYSQL_ROOT_PASSWORD=rootpass \ + MYSQL_DATABASE=sample \ + MYSQL_USER=sampleuser \ + MYSQL_PASSWORD=samplepass diff --git a/docker/Dockerfile.web b/docker/Dockerfile.web new file mode 100644 index 0000000..a27e374 --- /dev/null +++ b/docker/Dockerfile.web @@ -0,0 +1,35 @@ +FROM php:7.4-apache + +# Forzar actualización de fuentes APT +RUN apt-get update -o Acquire::Check-Valid-Until=false -o Acquire::Check-Date=false || { sleep 10; apt-get update -o Acquire::Check-Valid-Until=false -o Acquire::Check-Date=false; } + +# Instalar dependencias y Composer +RUN apt-get install -y wget unzip libzip-dev vim-tiny +RUN docker-php-ext-install pdo pdo_mysql zip +RUN apt-get clean && rm -rf /var/lib/apt/lists/* +COPY --from=composer:latest /usr/bin/composer /usr/bin/composer + +WORKDIR /var/www/html +COPY . . + +# Instalar dependencias de Composer +RUN composer install --no-scripts --no-interaction + +# Ajustar permisos y enlaces +RUN chown -R www-data:www-data /var/www/html/web /var/www/html/vendor || { echo "Error ajustando permisos"; exit 1; } \ + && chmod -R 755 /var/www/html/web /var/www/html/vendor \ + && ln -sf /var/www/html/vendor/twbs/bootstrap/dist/fonts/ /var/www/html/web/fonts + +RUN a2enmod rewrite \ + && echo '\n ServerName localhost\n DocumentRoot /var/www/html/web\n \n Options Indexes FollowSymLinks\n AllowOverride All\n Require all granted\n \n ErrorLog ${APACHE_LOG_DIR}/error.log\n CustomLog ${APACHE_LOG_DIR}/access.log combined\n' > /etc/apache2/sites-available/000-default.conf \ + && a2ensite 000-default.conf \ + && sed -i 's/LogLevel warn/LogLevel debug/g' /etc/apache2/apache2.conf \ + && apache2ctl configtest \ + && apache2ctl restart + +EXPOSE 80 + +ENV DB_HOST=mariadb \ + DB_NAME=sample \ + DB_USER=sampleuser \ + DB_PASS=samplepass \ No newline at end of file diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 0000000..cc8018b --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,33 @@ +version: '3.8' + +services: + web: + build: + context: .. + dockerfile: docker/Dockerfile.web + image: tuusuario/php-sample-web:latest + ports: + - "8080:80" + depends_on: + - db + environment: + - DB_HOST=db + - DB_NAME=sample + - DB_USER=sampleuser + - DB_PASS=samplepass + + db: + build: + context: .. + dockerfile: docker/Dockerfile.db + image: tuusuario/php-sample-db:latest + environment: + MYSQL_ROOT_PASSWORD: rootpass + MYSQL_DATABASE: sample + MYSQL_USER: sampleuser + MYSQL_PASSWORD: samplepass + volumes: + - db_data:/var/lib/mysql + +volumes: + db_data: diff --git a/web/README-ITEM2-DOCKER.md b/web/README-ITEM2-DOCKER.md new file mode 100644 index 0000000..0e4e315 --- /dev/null +++ b/web/README-ITEM2-DOCKER.md @@ -0,0 +1,22 @@ +# Item 2 – Application Containerization (Docker) + +Este documento complementa el README original **sin modificar el código fuente**. +Se publican dos imágenes en Docker Hub y se provee `docker-compose` para ejecutar la app. + +## Imágenes públicas +- Web: https://hub.docker.com/r/jcabo65/php-sample-web +- DB: https://hub.docker.com/r/jcabo65/php-sample-db + +## Archivos relevantes en este repo +- `docker/Dockerfile.web` – imagen PHP/Apache de la aplicación. +- `docker/Dockerfile.db` – imagen de base (MariaDB). +- `docker/docker-compose.yml` – orquesta `web` y `db` usando **las imágenes públicas**. +- `docker/docker-compose.override.yml` – comparte `/var/run/mysqld` para que la app (que usa `host=localhost`) conecte por **socket** sin cambiar código. + +## Requisitos +- Docker + Docker Compose. + +## Cómo ejecutar (2 líneas) +```bash +docker compose -f docker/docker-compose.yml -f docker/docker-compose.override.yml up -d +# abrir http://localhost:8080 diff --git a/web/autoloader.php b/web/autoloader.php new file mode 100644 index 0000000..9f8b565 --- /dev/null +++ b/web/autoloader.php @@ -0,0 +1 @@ +spl_autoload_register(function ($className) { if (stream_resolve_include_path($file = ("../src/" . str_replace("\\", "/", $className) . ".php"))) { include $file; } }); diff --git a/web/bootstrap.php b/web/bootstrap.php new file mode 100644 index 0000000..ba554f7 --- /dev/null +++ b/web/bootstrap.php @@ -0,0 +1,4 @@ +format("c")}] [$errno] $errstr in $errfile on line $errline\n", FILE_APPEND | LOCK_EX); + } +); + +set_exception_handler( + function ($exception) + { + header($_SERVER["SERVER_PROTOCOL"] . " 500 Internal Server Error", true, 500); + $dateTime = new DateTime(); + file_put_contents(__DIR__ . "/logs/error.log", "[{$dateTime->format("c")}] " . $exception->getMessage() . "\n", FILE_APPEND | LOCK_EX); + } +);