diff --git a/.env.dist b/.env.dist new file mode 100644 index 0000000..31ebdcc --- /dev/null +++ b/.env.dist @@ -0,0 +1,5 @@ +HUMHUB_DOCKER_VERSION="develop" +HUMHUB_DOCKER_DOMAIN="localhost" +HUMHUB_DOCKER_DB_DSN="mysql:host=db;dbname=humhub" +HUMHUB_DOCKER_DB_USER="root" +HUMHUB_DOCKER_DB_PASSWORD="ChangeMeToSuperSecretMySqlRootPassword:-)" diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 0000000..99185ef --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,29 @@ +name: Docker Image CI +on: + push: + tags: + - '*' + workflow_dispatch: + schedule: + - cron: "33 3 * * *" + +jobs: + build: + strategy: + matrix: + branch: [develop, next] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: docker login + env: + DOCKER_USER: ${{secrets.DOCKER_USER}} + DOCKER_PASSWORD: ${{secrets.DOCKER_PASSWORD}} + run: | + docker login -u $DOCKER_USER -p $DOCKER_PASSWORD + + - name: Build the Docker image + run: cd image; docker build . --file Dockerfile --build-arg BRANCH=${{ matrix.branch }} --tag humhub/humhub-dev:${{ matrix.branch }} + + - name: Docker Push + run: docker push humhub/humhub-dev:${{ matrix.branch }} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4b1be50 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.env +humhub.env +humhub-data +caddy-data +mysql-data diff --git a/Caddyfile b/Caddyfile new file mode 100644 index 0000000..6628e3d --- /dev/null +++ b/Caddyfile @@ -0,0 +1,3 @@ +{$caddydomain} { + reverse_proxy humhub:8404 +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..2fd2024 --- /dev/null +++ b/README.md @@ -0,0 +1,97 @@ +# HumHub - Docker Image (Development Version) + +The Docker package provides all the essential components for setting up your HumHub installation. + +## Features + +- HumHub Core Software (Apache2 + FPM) +- MariaDB (Database Server) +- Caddy (Reverse Proxy w/ automatic LetsEncrypt SSL certificates) +- Redis (Cache / Queue) + +## Quick Start + +### Installation + +``` +git clone git@github.com:humhub/docker-dev.git /opt/humhub +cd /opt/humhub + +cp humhub.env.dist humhub.env +cp .env.dist .env +``` + +Then edit the `.env` file and set at least the `HUMHUB_DOCKER_DOMAIN`. + +``` +docker compose up -d +``` + +> On older Docker versions you may need to run `docker-compose up -d` instead. + +Open your HumHub installation at: https://YOUR-HUMHUB_DOCKER_DOMAIN + +> After installation, an e-mail server must be configured at: `Administration` -> `Settings` -> `Advanced` -> `E-Mail`. + +### Upgrading + +Running following commands in the main directory. + +``` +cd /opt/humhub + +git pull + +docker compose pull +docker compose down +docker compose up -d +``` + +> Also check for new configuration options in `.env.dist` and `humhub.env.dist` files. + +## Other Setup Options + +### HumHub CLI + +You can use the wrapper script in the main directoy. + +``` +./yii.sh help +``` + +### Version Control + +You can define the HumHub version using the variable `HUMHUB_DOCKER_VERSION`. + +The following tags are currently available: +- ~~`master` - For the current stable version~~ (not available yet) +- `develop` - For the current development version +- `next` - For the next development version + +For older versions: +- ~~`v1.17`~~ (not available yet) +- ~~`v1.17.0-beta.1`~~ (not available yet) + +### Custom Themes & Modules + +You can store your own themes/modules in the folders `/opt/humhub/humhub-data/themes` and `/opt/humhub/humhub-data/custom-modules`. + +### Existing Reverse Proxy + +**NGINX Example:** + +If an NGINX web server is already running on the host on which the Docker container is started on the HTTPS port, a reverse proxy to the HumHub Docker container can be created in a virtual host via the following block. + +``` + location / { + proxy_pass http://127.0.0.1:8404; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +``` + +**Apache2 Example:** + +TBD diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..780b59f --- /dev/null +++ b/compose.yaml @@ -0,0 +1,60 @@ +services: + humhub: + image: humhub/humhub-dev:${HUMHUB_DOCKER_VERSION} + ports: + - 8404:8404 + depends_on: + db: + condition: service_healthy + volumes: + - ./humhub-data:/var/lib/humhub + env_file: + - ./humhub.env + environment: + - HUMHUB_CONFIG__COMPONENTS__DB__DSN=${HUMHUB_DOCKER_DB_DSN} + - HUMHUB_CONFIG__COMPONENTS__DB__USERNAME=${HUMHUB_DOCKER_DB_USER} + - HUMHUB_CONFIG__COMPONENTS__DB__PASSWORD=${HUMHUB_DOCKER_DB_PASSWORD} + - HUMHUB_FIXED_SETTINGS__BASE__BASE_URL=https://${HUMHUB_DOCKER_DOMAIN} + - HUMHUB_FIXED_SETTINGS__BASE__CACHE_CLASS=yii\redis\Cache + - HUMHUB_CONFIG__COMPONENTS__REDIS__CLASS=yii\redis\Connection + - HUMHUB_CONFIG__COMPONENTS__REDIS__HOSTNAME=redis + - HUMHUB_CONFIG__COMPONENTS__REDIS__PORT=6379 + - HUMHUB_CONFIG__COMPONENTS__REDIS__DATABASE=0 + - HUMHUB_CONFIG__COMPONENTS__SESSION__CLASS=yii\redis\Session + db: + image: mariadb + restart: always + user: root + volumes: + - ./mysql-data:/var/lib/mysql + environment: + - MYSQL_ROOT_PASSWORD=${HUMHUB_DOCKER_DB_PASSWORD} + expose: + - 3306 + healthcheck: + test: ["CMD", "/usr/local/bin/healthcheck.sh", "--su-mysql", "--connect", "--innodb_initialized"] + interval: 10s + timeout: 5s + retries: 5 + caddy: + image: caddy:latest + ports: + - 80:80 + - 443:443 + volumes: + - ./Caddyfile:/etc/caddy/Caddyfile + - ./caddy-data:/data + environment: + - caddydomain=${HUMHUB_DOCKER_DOMAIN} + restart: always + redis: + image: redis:6.2-alpine + ports: + - 6379:6379 + restart: always + command: redis-server --save 20 1 --loglevel warning + volumes: + - cache:/data +volumes: + cache: + driver: local \ No newline at end of file diff --git a/humhub.env.dist b/humhub.env.dist new file mode 100644 index 0000000..a2a5373 --- /dev/null +++ b/humhub.env.dist @@ -0,0 +1,3 @@ +# Use this file to pass HumHub Configuration + +HUMHUB_DEBUG=false \ No newline at end of file diff --git a/image/Dockerfile b/image/Dockerfile new file mode 100644 index 0000000..f6a208e --- /dev/null +++ b/image/Dockerfile @@ -0,0 +1,111 @@ +FROM debian:bookworm + +ARG HUMHUB_GIT_BRANCH="develop" + +RUN apt-get update && apt-get install -y \ + apache2 \ + php-fpm php php-cli \ + php-imagick php-curl php-bz2 php-gd php-intl php-mbstring php-mysql php-zip php-apcu php-xml php-ldap \ + unzip curl zip joe git npm \ + supervisor + +#------------------------------------------------------------------------------------------------ +# PHP, Apache2, FPM Config +#------------------------------------------------------------------------------------------------ + +RUN sed -i 's/variables_order = "GPCS"/variables_order = "EGPCS"/g' /etc/php/8.2/cli/php.ini && \ + sed -i 's/variables_order = "GPCS"/variables_order = "EGPCS"/g' /etc/php/8.2/fpm/php.ini && \ + sed -i 's/post_max_size = 8M/post_max_size = 512M/g' /etc/php/8.2/fpm/php.ini && \ + sed -i 's/upload_max_filesize = 2M/upload_max_filesize = 512M/g' /etc/php/8.2/fpm/php.ini && \ + sed -i 's/max_execution_time = 30/max_execution_time = 90/g' /etc/php/8.2/fpm/php.ini && \ + sed -i 's/memory_limit = 128M/memory_limit = 256M/g' /etc/php/8.2/fpm/php.ini && \ + a2enmod ssl rewrite headers proxy_fcgi setenvif proxy_fcgi && \ + a2enconf php8.2-fpm && \ + echo "Listen 8404" > /etc/apache2/ports.conf + +COPY files/apache-config.conf /etc/apache2/sites-available/000-default.conf +COPY files/php-fpm-www.conf /etc/php/8.2/fpm/pool.d/www.conf + +EXPOSE 80 + +#------------------------------------------------------------------------------------------------ +# Install Requirements: Composer, NPM, Less, Grunt +#------------------------------------------------------------------------------------------------ + +RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer && \ + npm install -g grunt-cli less less-plugin-clean-css + +#------------------------------------------------------------------------------------------------ +# HumHub Base GIT Install +#------------------------------------------------------------------------------------------------ + +RUN mkdir -p /opt/humhub +WORKDIR /opt/humhub + +RUN git clone https://github.com/humhub/humhub.git /opt/humhub && \ + git config --global --add safe.directory /opt/humhub && \ + git checkout ${HUMHUB_GIT_BRANCH} && \ + composer install --no-interaction --optimize-autoloader --prefer-dist && \ + npm install && \ + grunt build-assets && \ + rm -rf /var/www/html/* && \ + mkdir -p /var/www/html/protected/runtime && \ + cp /opt/humhub/.htaccess.dist /var/www/html/.htaccess && \ + ln -s /var/lib/humhub/uploads/ /var/www/html/ && \ + ln -s /var/lib/humhub/assets/ /var/www/html/ && \ + ln -s /var/lib/humhub/themes/ /var/www/html/ && \ + ln -s /var/lib/humhub/config/ /var/www/html/protected/ && \ + ln -s /var/lib/humhub/modules/ /var/www/html/protected/ && \ + ln -s /var/lib/humhub/logs/ /var/www/html/protected/runtime/ && \ + ln -s /opt/humhub/protected/humhub /var/www/html/protected/ && \ + ln -s /opt/humhub/protected/vendor /var/www/html/protected/ && \ + ln -s /opt/humhub/static /var/www/html/ && \ + mkdir -p /var/lib/humhub-modules-custom && \ + rm -rf /opt/humhub/.git* && \ + rm -rf /opt/humhub/.idea && \ + rm -rf /opt/humhub/.editorconfig && \ + rm -rf /opt/humhub/.php-cs* && \ + rm -rf /opt/humhub/index-test.php && \ + rm -rf /opt/humhub/node_modules && \ + rm -rf /opt/humhub/LICENSE* && \ + rm -rf /opt/humhub/*.js && \ + rm -rf /opt/humhub/*.lock && \ + rm -rf /opt/humhub/*.json && \ + rm -rf /opt/humhub/*.md && \ + rm -rf /opt/humhub/*.dist && \ + rm -rf /opt/humhub/robots.txt && \ + rm -rf /root/.cache && \ + rm -rf /root/.npm && \ + rm -rf /var/lib/apt/lists/* + +# We cannot symlink these entry scripts atm, since the DynamicConfig is otherwise loaded from /opt/humhub +RUN cp /opt/humhub/protected/yii /var/www/html/protected/ && \ + cp /opt/humhub/index.php /var/www/html/index.php + +#------------------------------------------------------------------------------------------------ + +COPY ["files/humhub-queue-listen.sh", "files/humhub-cron.sh", "files/humhub-startup.sh", "files/docker-entrypoint.sh", "/"] +RUN chmod +x /humhub-queue-listen.sh && \ + chmod +x /humhub-startup.sh && \ + chmod +x /docker-entrypoint.sh && \ + mkdir -p /var/log/supervisord && \ + mkdir -p /var/run/supervisord + +COPY files/supervisord.conf /etc + + +#------------------------------------------------------------------------------------------------ + +ENV HUMHUB_CONFIG__COMPONENTS__URL_MANAGER__SHOW_SCRIPT_NAME=false +ENV HUMHUB_CONFIG__COMPONENTS__URL_MANAGER__ENABLE_PRETTY_URL=true +ENV HUMHUB_CONFIG__MODULES__INSTALLER__ENABLE_AUTO_SETUP=true +ENV HUMHUB_CONFIG__MODULES__MARKETPLACE__MODULE_BLACKLIST='["updater"]' +ENV HUMHUB_CONFIG__PARAMS__MODULE_AUTOLOAD_PATHS='["/var/lib/humhub/modules-custom"]' +ENV HUMHUB_CONFIG__COMPONENTS__REQUEST__TRUSTED_HOSTS='["0.0.0.0/0"]' +ENV HUMHUB_CONFIG__RUNTIME_PATH=/var/www/html/protected/runtime +ENV HUMHUB_ALIASES__WEBROOT=/var/www/html +ENV HUMHUB_ALIASES__APP=/var/www/html/protected +ENV HUMHUB_ALIASES__CONFIG=/var/www/html/protected/config +ENV HUMHUB_ALIASES__HUMHUB=/var/www/html/protected/humhub + +CMD ["/docker-entrypoint.sh"] \ No newline at end of file diff --git a/image/build.sh b/image/build.sh new file mode 100755 index 0000000..f006489 --- /dev/null +++ b/image/build.sh @@ -0,0 +1 @@ +docker build --build-arg HUMHUB_GIT_BRANCH=develop --tag humhub/humhub-dev:latest . \ No newline at end of file diff --git a/image/debug-shell.sh b/image/debug-shell.sh new file mode 100755 index 0000000..e76a5db --- /dev/null +++ b/image/debug-shell.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +CONTAINER_IMAGE_NAME="humhub/humhub-dev" + +# Find containers running with the specified image base name (ignoring the tag) +CONTAINER_IDS=$(docker ps --format "{{.ID}} {{.Image}}" | grep -E "^.+ ${CONTAINER_IMAGE_NAME}(:.+)?$" | awk '{print $1}') + +# Check if any containers are running with the specified image name +if [ -z "$CONTAINER_IDS" ]; then + echo "Error: No container running with image '${CONTAINER_IMAGE_NAME}'." + exit 1 +fi + +# Count the number of containers +CONTAINER_COUNT=$(echo "$CONTAINER_IDS" | wc -l) + +if [ "$CONTAINER_COUNT" -gt 1 ]; then + echo "Error: Multiple containers are running with image '${CONTAINER_IMAGE_NAME}'." + exit 1 +fi + +# Exactly one container is running, execute the PHP script inside it +CONTAINER_ID=$(echo "$CONTAINER_IDS" | head -n 1) + +echo "Executing PHP script in container '${CONTAINER_ID}'..." +docker exec -it "$CONTAINER_ID" /bin/bash \ No newline at end of file diff --git a/image/files/apache-config.conf b/image/files/apache-config.conf new file mode 100644 index 0000000..df99f7c --- /dev/null +++ b/image/files/apache-config.conf @@ -0,0 +1,34 @@ + + DocumentRoot /var/www/html + + + Options -Indexes +FollowSymLinks + AllowOverride All + Require all granted + + + + Order Deny,Allow + Deny from all + + + + Order Deny,Allow + Deny from all + + + + Header set Cache-Control "max-age=172800, public" + + + PassEnv HUMHUB_DEBUG + PassEnv HUMHUB_CONFIG__COMPONENTS__DB__DSN HUMHUB_CONFIG__COMPONENTS__DB__USERNAME HUMHUB_CONFIG__COMPONENTS__DB__PASSWORD + PassEnv HUMHUB_CONFIG__COMPONENTS__URL_MANAGER__SHOW_SCRIPT_NAME HUMHUB_CONFIG__COMPONENTS__URL_MANAGER__ENABLE_PRETTY_URL + PassEnv HUMHUB_CONFIG__COMPONENTS__REQUEST__TRUSTED_HOSTS + PassEnv HUMHUB_CONFIG__MODULES__INSTALLER__ENABLE_AUTO_SETUP + PassEnv HUMHUB_ALIASES__WEBROOT HUMHUB_ALIASES__APP HUMHUB_ALIASES__HUMHUB + PassEnv HUMHUB_FIXED_SETTINGS__BASE__BASE_URL + + ErrorLog /dev/stderr + CustomLog /dev/stdout combined + \ No newline at end of file diff --git a/image/files/docker-entrypoint.sh b/image/files/docker-entrypoint.sh new file mode 100644 index 0000000..5531ca3 --- /dev/null +++ b/image/files/docker-entrypoint.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +#---------------------------------------------------------------------- +# MOUNTED DATA FOLDER HANDLING +#---------------------------------------------------------------------- + +#--- Ensure mounted data folder structure +mkdir -p /var/lib/humhub/{uploads,assets,logs,config,modules,modules-custom,themes} + +#--- Copy defaults (if not exist) to mounted data folder +cp -rn /opt/humhub/protected/config/ /var/lib/humhub/ +cp -rn /opt/humhub/uploads/ /var/lib/humhub/ +rm -rf /var/lib/humhub/themes/HumHub && cp -rf /opt/humhub/themes/HumHub /var/lib/humhub/themes/HumHub + +#--- Check Permissions +chown -R www-data:www-data /var/www/html/protected/runtime +chown -R www-data:www-data /var/lib/humhub/* + +cd /var/www/html/ + +#---------------------------------------------------------------------- +# HUMHUB INIT +#---------------------------------------------------------------------- +su www-data -s /bin/bash -c '/humhub-startup.sh' + +#---------------------------------------------------------------------- +# STARTUP +#---------------------------------------------------------------------- + +if [ -z "$@" ]; then + exec /usr/bin/supervisord -c /etc/supervisord.conf --nodaemon +else + exec PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin $@ +fi \ No newline at end of file diff --git a/image/files/humhub-cron.sh b/image/files/humhub-cron.sh new file mode 100644 index 0000000..5aab07e --- /dev/null +++ b/image/files/humhub-cron.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +sleep 5 + +while true; do + + output=$(/usr/bin/php /var/www/html/protected/yii queue/info 2>&1) + + if [[ "$output" != *"PDOException"* ]]; then + break + else + + echo "Cron: Database not configured and initialized. Waiting..." + sleep 10 + fi +done + +while true; do + + /usr/bin/php /var/www/html/protected/yii cron/run + sleep 60 + +done \ No newline at end of file diff --git a/image/files/humhub-queue-listen.sh b/image/files/humhub-queue-listen.sh new file mode 100644 index 0000000..235aa84 --- /dev/null +++ b/image/files/humhub-queue-listen.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +#--------------------------------------------- +# +# This script starts the Queue Listener. +# Before that, it checks whether the database connection and the HumHub setup have been completed. +# +#--------------------------------------------- + + +sleep 5 + +while true; do + + output=$(/usr/bin/php /var/www/html/protected/yii queue/info 2>&1) + + if [[ "$output" != *"PDOException"* ]]; then + break + else + + echo "Worker: Database not configured and initialized. Waiting..." + sleep 10 + fi +done + +/usr/bin/php /var/www/html/protected/yii queue/listen --verbose=1 --color=0 diff --git a/image/files/humhub-startup.sh b/image/files/humhub-startup.sh new file mode 100644 index 0000000..1865962 --- /dev/null +++ b/image/files/humhub-startup.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# Check if the current user is 'www-data' +if [ "$(whoami)" != "www-data" ]; then + echo "Error: This script must be run as the 'www-data' user." >&2 + exit 1 +fi + +# Check if HumHub is installed +adminSettings=$(protected/yii settings/list-module admin 2>&1) +if [[ $adminSettings == *"installationId"* ]]; then + + protected/yii cache/flush-all + protected/yii migrate/up --includeModuleMigrations=1 + protected/yii module/update-all + + # Recompile/Update ThemeBuilder based themes after start + tbModule=$(protected/yii module/info theme-builder 2>&1) + if [[ $tbModule == *"Enabled: Yes"* ]]; then + protected/yii theme-builder/compile-all-less '/usr/bin/lessc' + fi + +fi \ No newline at end of file diff --git a/image/files/php-fpm-www.conf b/image/files/php-fpm-www.conf new file mode 100644 index 0000000..8bfe0f2 --- /dev/null +++ b/image/files/php-fpm-www.conf @@ -0,0 +1,15 @@ +[www] + +user = www-data +group = www-data +listen = /run/php/php8.2-fpm.sock +listen.owner = www-data +listen.group = www-data + +pm = dynamic +pm.max_children = 5 +pm.start_servers = 2 +pm.min_spare_servers = 1 +pm.max_spare_servers = 3 + +clear_env = no \ No newline at end of file diff --git a/image/files/supervisord.conf b/image/files/supervisord.conf new file mode 100644 index 0000000..3910145 --- /dev/null +++ b/image/files/supervisord.conf @@ -0,0 +1,44 @@ +[supervisord] +nodaemon = true +logfile = /dev/null +logfile_maxbytes = 0 +pidfile = /run/supervisord.pid +user = root + +[program:apache2] +command=/usr/bin/pidproxy /var/run/apache2/apache2.pid /bin/bash -c "/usr/sbin/apache2ctl -D FOREGROUND" +autorestart=true +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:php-fpm] +command = /usr/sbin/php-fpm8.2 --nodaemonize -O +autorestart=true +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:cron] +command=/humhub-cron.sh +user=www-data +autostart = true +autorestart = true +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:humhub-worker] +command=/humhub-queue-listen.sh +user=www-data +process_name=%(program_name)s_%(process_num)02d +autostart=true +autorestart=true +numprocs=2 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 diff --git a/yii.sh b/yii.sh new file mode 100755 index 0000000..d3b6840 --- /dev/null +++ b/yii.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +CONTAINER_IMAGE_NAME="humhub/humhub-dev" + +PHP_SCRIPT_PATH="/var/www/html/protected/yii" +PHP_SCRIPT_PARAMS="$@" +CONTAINER_IDS=$(docker ps --format "{{.ID}} {{.Image}}" | grep -E "^.+ ${CONTAINER_IMAGE_NAME}(:.+)?$" | awk '{print $1}') + +# Check if any containers are running with the specified image name +if [ -z "$CONTAINER_IDS" ]; then + echo "Error: No container running with image '${CONTAINER_IMAGE_NAME}'." + exit 1 +fi + +# Count the number of containers +CONTAINER_COUNT=$(echo "$CONTAINER_IDS" | wc -l) + +if [ "$CONTAINER_COUNT" -gt 1 ]; then + echo "Error: Multiple containers are running with image '${CONTAINER_IMAGE_NAME}'." + exit 1 +fi + +# Exactly one container is running, execute the PHP script inside it +CONTAINER_ID=$(echo "$CONTAINER_IDS" | head -n 1) + +echo "Executing PHP script in container '${CONTAINER_ID}'..." +docker exec "$CONTAINER_ID" php "$PHP_SCRIPT_PATH" $PHP_SCRIPT_PARAMS + +if [ $? -eq 0 ]; then + echo "PHP script executed successfully." +else + echo "Error occurred while executing the PHP script." + exit 1 +fi \ No newline at end of file