-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add EspoCRM official image #7603
base: master
Are you sure you want to change the base?
Conversation
@tianon please have a look. |
@tianon, @yosifkit, please take a look. I would like to say that while creating the docker image we followed all the recommendations. For example:
|
Is there any chance to review the image? |
apk update; \
apk add --no-cache --virtual .build-deps \ The php7-gd \
php7-exif \ This is definitely not right -- when you're # Install php-zmq
cd /usr; \
curl -fSL https://github.com/zeromq/libzmq/releases/download/v4.3.2/zeromq-4.3.2.tar.gz -o zeromq-4.3.2.tar.gz; \
tar -xvzf zeromq-4.3.2.tar.gz; \
rm zeromq-4.3.2.tar.gz; \
cd /usr/zeromq-4.3.2; \
./configure; \
make; \
make install; \
cd /usr; \
git clone https://github.com/zeromq/php-zmq.git; \
cd /usr/php-zmq; \
phpize && ./configure; \
make; \
make install; \ This seems odd to me -- why are we building Additionally, why are we grabbing the latest ENV DOCUMENT_ROOT /var/www/html
ENV DEFAULT_OWNER www-data
ENV DEFAULT_GROUP www-data What is the intent of these variables? As a user reading these, it feels like I can adjust these and expect the webserver configuration to adjust as well, but I don't think that's going to be the case. It seems like perhaps a local variable is what was intended instead? In the entrypoint, you probably don't want to use ENV ESPOCRM_UPGRADE_VERSION 5.8.5
ENV ESPOCRM_UPGRADE_URL https://www.espocrm.com/downloads/upgrades/EspoCRM-upgrade-5.8.5-to-5.9.3.zip
ENV ESPOCRM_UPGRADE_SHA256 a04d4fdadd877d684abd885dc7356ea2f0593e8a805851d79d4a6f68b6168700 This is interesting -- can you elaborate on what this is for, especially since it's only downloaded/used in the entrypoint and doesn't appear to be part of the image itself? VOLUME ${DOCUMENT_ROOT} This and the (fairly complex) entrypoint script have me a little bit concerned/confused. This appears to be copied from the general pattern of the WordPress official image (or from another PHP-based image which copied the WordPress pattern), wherein WordPress considers the code of itself to be mutable state that it manages (by doing automatic upgrades especially for security fixes, for example). From what I can find, EspoCRM is not similar in the sense that upgrades to EspoCRM are always performed manually (https://www.espocrm.com/documentation/administration/upgrading/), and updating from the UI even appears to be highly discouraged. Given this, I have to wonder why EspoCRM is not instead copied/installed directly to CMD ["sh", "-c", "cron && php-fpm"] I understand the intent of this (to run both Cron and PHP simultaneously), but this is not acceptable in the official images. What I would recommend is documenting for users how to run # Set timezone
RUN echo "UTC" > /etc/timezone && dpkg-reconfigure --frontend noninteractive tzdata This is odd to me -- the default timezone of all images in the official images is already UTC, and we even have an integration test to validate that. |
Related to |
@tianon, @yosifkit thanks again for your reviews. We made changes to your recommendations. Please check it again. Thanks
Fixed
Fixed
The installation of php-zmq is optimized. We cannot completely abandon its use, because it's required in EspoCRM.
Fixed. Now, detection of user/group is moved to the entrypoint as you recommended, https://github.com/espocrm/docker/blob/master/docker-entrypoint.sh#L188.
This is required for automatic upgrade EspoCRM depending on the version of EspoCRM docker image and the version of EspoCRM files / database. For example, if the version of EspoCRM docker container is 5.9.3, but the EspoCRM files / database is 5.8.3, then the entrypoint will upgrade EspoCRM files / database to the version of the docker container 5.9.3. EspoCRM has own upgrade system, but this
Based on that fact that EspoCRM files / database can be automatically upgraded to the version of EspoCRM docker image, we need to mount the entire EspoCRM directory. What would you recommend this this case?
Fixed, thanks for the example.
Fixed |
Thank you for your patience. 🙇 The (You could also possibly optimize a tiny bit by downloading a source archive from GitHub at that commit such as https://github.com/zeromq/php-zmq/archive/e0db82c3286da81fa8945894dd10125a528299e4.tar.gz instead of using
Let me explain this slightly differently to see if I can do a better job. Right now, the upgrade behavior is not something EspoCRM itself does automatically, but rather is a function of this image based on how EspoCRM is deployed and upgraded outside containers. What I'm proposing is that if EspoCRM itself was not stored in the data volume, then perhaps that upgrade bundle wouldn't even be necessary (nor a large part of the entrypoint code/logic), because the way to upgrade EspoCRM itself would instead just be recreating the container. In other words, the current flow (oversimplified) is something like:
Proposed flow:
In this simpler flow, instead of having all of Does that make more sense? Do you think that workflow makes sense for EspoCRM? If it's possible to accomplish, I think it could pretty dramatically simplify the logic in your container entrypoint script, and the way that users use/reason about your container image. |
Thanks for your reply. |
@tianon thanks again for your thoughts. The php-zmq installation is optimized due to your recommendations. The current upgrade process is optimized and moved to EspoCRM side. The "entrypoint" script just checking the version and run the upgrade on EspoCRM side if needed. EspoCRM has the directories for user's customizations:
At this point I see 2 issues with the new process. For successful upgrade EspoCRM we have to do:
Upgrade process deletes files that have been removed from EspoCRM. This will work fine only if a user will not have any additional extensions of EspoCRM. Add-ons can be installed on EspoCRM. All they are stored in
In some cases, we need to run some actions with the database, configuration parameters, etc. For such purposed we can run the upgrade script which is included in the upgrade package of EspoCRM. So, when only mount the volumes of For example, the new process can be:
The current process implemented in "entrypoint" script with the mounted volume
It would be great if you have any suggestions for resolving these issues. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
@tmachyshyn I opened a PR to optimize the layers and the size a bit: espocrm/espocrm-docker#42 |
@tmachyshyn I added some comments to the docs. Would be possible to address those and then squash the commits in both PRs? |
@LaurentGoderre thanks for your recommendations. That's all fixed. |
This comment has been minimized.
This comment has been minimized.
Would you be able to squash down to 1 commit for each repo? |
This comment has been minimized.
This comment has been minimized.
@LaurentGoderre Done for this and for the documentation repositories. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Diff for 5d926a3:diff --git a/_bashbrew-arches b/_bashbrew-arches
index 8b13789..79acf81 100644
--- a/_bashbrew-arches
+++ b/_bashbrew-arches
@@ -1 +1,7 @@
-
+amd64
+arm32v6
+arm32v7
+arm64v8
+i386
+ppc64le
+s390x
diff --git a/_bashbrew-cat b/_bashbrew-cat
index bdfae4a..ceb1aea 100644
--- a/_bashbrew-cat
+++ b/_bashbrew-cat
@@ -1 +1,17 @@
-Maintainers: New Image! :D (@docker-library-bot)
+Maintainers: Taras Machyshyn <[email protected]> (@tmachyshyn)
+GitRepo: https://github.com/espocrm/espocrm-docker.git
+
+Tags: apache, 8.4.1-apache, 8.4-apache, 8-apache, latest, 8.4.1, 8.4, 8
+Architectures: amd64, arm32v7, arm64v8, i386, s390x
+GitCommit: 7b933d4fc7036f1a037e5c20b5e88fd2537c669f
+Directory: apache
+
+Tags: fpm, 8.4.1-fpm, 8.4-fpm, 8-fpm
+Architectures: amd64, arm32v7, arm64v8, i386, s390x
+GitCommit: 7b933d4fc7036f1a037e5c20b5e88fd2537c669f
+Directory: fpm
+
+Tags: fpm-alpine, 8.4.1-fpm-alpine, 8.4-fpm-alpine, 8-fpm-alpine
+Architectures: amd64, arm32v6, arm32v7, arm64v8, i386, ppc64le, s390x
+GitCommit: 7b933d4fc7036f1a037e5c20b5e88fd2537c669f
+Directory: fpm-alpine
diff --git a/_bashbrew-list b/_bashbrew-list
index e69de29..eb61898 100644
--- a/_bashbrew-list
+++ b/_bashbrew-list
@@ -0,0 +1,16 @@
+espocrm:8
+espocrm:8-apache
+espocrm:8-fpm
+espocrm:8-fpm-alpine
+espocrm:8.4
+espocrm:8.4-apache
+espocrm:8.4-fpm
+espocrm:8.4-fpm-alpine
+espocrm:8.4.1
+espocrm:8.4.1-apache
+espocrm:8.4.1-fpm
+espocrm:8.4.1-fpm-alpine
+espocrm:apache
+espocrm:fpm
+espocrm:fpm-alpine
+espocrm:latest
diff --git a/_bashbrew-list-build-order b/_bashbrew-list-build-order
index e69de29..ef7107e 100644
--- a/_bashbrew-list-build-order
+++ b/_bashbrew-list-build-order
@@ -0,0 +1,3 @@
+espocrm:8
+espocrm:8-fpm
+espocrm:8-fpm-alpine
diff --git a/espocrm_8-fpm-alpine/Dockerfile b/espocrm_8-fpm-alpine/Dockerfile
new file mode 100644
index 0000000..f021806
--- /dev/null
+++ b/espocrm_8-fpm-alpine/Dockerfile
@@ -0,0 +1,81 @@
+FROM php:8.2-fpm-alpine
+
+LABEL org.opencontainers.image.source=https://github.com/espocrm/espocrm
+LABEL org.opencontainers.image.description="EspoCRM is an Open Source CRM. Try for Free."
+
+# Install php libs
+RUN set -ex; \
+ apk add --no-cache --virtual .build-deps \
+ postgresql-dev \
+ libzip-dev \
+ libpng-dev \
+ libjpeg-turbo-dev \
+ libwebp-dev \
+ freetype-dev \
+ openldap-dev \
+ imap-dev \
+ libzmq \
+ zeromq-dev \
+ bash \
+ $PHPIZE_DEPS \
+ ; \
+ \
+# Install php-zmq
+ cd /usr; \
+ curl -fSL https://github.com/zeromq/php-zmq/archive/ee5fbc693f07b2d6f0d9fd748f131be82310f386.tar.gz -o php-zmq.tar.gz; \
+ tar -zxf php-zmq.tar.gz; \
+ cd php-zmq*; \
+ phpize && ./configure; \
+ make; \
+ make install; \
+ cd .. && rm -rf php-zmq*; \
+# END: Install php-zmq
+ \
+ docker-php-ext-configure gd --with-jpeg --with-webp --with-freetype; \
+ \
+ docker-php-ext-install \
+ pdo_pgsql \
+ pdo_mysql \
+ zip \
+ gd \
+ imap \
+ ldap \
+ exif \
+ pcntl \
+ posix \
+ bcmath \
+ ; \
+ docker-php-ext-enable zmq
+
+# php.ini
+RUN { \
+ echo 'expose_php = Off'; \
+ echo 'display_errors = Off'; \
+ echo 'display_startup_errors = Off'; \
+ echo 'log_errors = On'; \
+ echo 'memory_limit=256M'; \
+ echo 'max_execution_time=180'; \
+ echo 'max_input_time=180'; \
+ echo 'post_max_size=30M'; \
+ echo 'upload_max_filesize=30M'; \
+ echo 'date.timezone=UTC'; \
+} > ${PHP_INI_DIR}/conf.d/espocrm.ini
+
+ENV ESPOCRM_VERSION 8.4.1
+ENV ESPOCRM_SHA256 1681a2f68c0fc37bd46bbb9725765ed0cf16fab48a283820efb90265a7e8301d
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.4.1.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.4.1" /usr/src/espocrm; \
+ rm EspoCRM.zip; \
+ chown -R www-data:www-data /usr/src/espocrm
+
+COPY ./docker-*.sh /usr/local/bin/
+
+ENTRYPOINT [ "docker-entrypoint.sh" ]
+
+CMD ["php-fpm"]
diff --git a/espocrm_8-fpm-alpine/docker-daemon.sh b/espocrm_8-fpm-alpine/docker-daemon.sh
new file mode 100755
index 0000000..83a2b4f
--- /dev/null
+++ b/espocrm_8-fpm-alpine/docker-daemon.sh
@@ -0,0 +1,324 @@
+#!/bin/bash
+
+set -eu
+
+DOCUMENT_ROOT="/var/www/html"
+
+# entrypoint-utils.sh
+configPrefix="ESPOCRM_CONFIG_"
+
+declare -A configPrefixArrayList=(
+ [logger]="ESPOCRM_CONFIG_LOGGER_"
+ [database]="ESPOCRM_CONFIG_DATABASE_"
+)
+
+compareVersion() {
+ local version1="$1"
+ local version2="$2"
+ local operator="$3"
+
+ echo $(php -r "echo version_compare('$version1', '$version2', '$operator');")
+}
+
+join() {
+ local sep="$1"; shift
+ local out; printf -v out "${sep//%/%%}%s" "$@"
+ echo "${out#$sep}"
+}
+
+getConfigParamFromFile() {
+ local name="$1"
+
+ php -r "
+ if (file_exists('$DOCUMENT_ROOT/data/config-internal.php')) {
+ \$config=include('$DOCUMENT_ROOT/data/config-internal.php');
+
+ if (array_key_exists('$name', \$config)) {
+ die(\$config['$name']);
+ }
+ }
+
+ if (file_exists('$DOCUMENT_ROOT/data/config.php')) {
+ \$config=include('$DOCUMENT_ROOT/data/config.php');
+
+ if (array_key_exists('$name', \$config)) {
+ die(\$config['$name']);
+ }
+ }
+ "
+}
+
+getConfigParam() {
+ local name="$1"
+
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ echo \$config->get('$name');
+ "
+}
+
+# Bool: saveConfigParam "jobRunInParallel" "true"
+# String: saveConfigParam "language" "'en_US'"
+saveConfigParam() {
+ local name="$1"
+ local value="$2"
+
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ if (\$config->get('$name') === $value) {
+ return;
+ }
+
+ \$injectableFactory = \$app->getContainer()->get('injectableFactory');
+ \$configWriter = \$injectableFactory->create('\\Espo\\Core\\Utils\\Config\\ConfigWriter');
+
+ \$configWriter->set('$name', $value);
+ \$configWriter->save();
+ "
+}
+
+saveConfigArrayParam() {
+ local key1="$1"
+ local key2="$2"
+ local value="$3"
+
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ \$arrayValue = \$config->get('$key1') ?? [];
+
+ if (!is_array(\$arrayValue)) {
+ return;
+ }
+
+ if (array_key_exists('$key2', \$arrayValue) && \$arrayValue['$key2'] === $value) {
+ return;
+ }
+
+ \$injectableFactory = \$app->getContainer()->get('injectableFactory');
+ \$configWriter = \$injectableFactory->create('\\Espo\\Core\\Utils\\Config\\ConfigWriter');
+
+ \$arrayValue['$key2'] = $value;
+
+ \$configWriter->set('$key1', \$arrayValue);
+ \$configWriter->save();
+ "
+}
+
+checkInstanceReady() {
+ local isInstalled=$(getConfigParamFromFile "isInstalled")
+
+ if [ -z "$isInstalled" ] || [ "$isInstalled" != 1 ]; then
+ echo >&2 "Instance is not ready: waiting for the installation"
+ exit 0
+ fi
+
+ local maintenanceMode=$(getConfigParamFromFile "maintenanceMode")
+
+ if [ -n "$maintenanceMode" ] && [ "$maintenanceMode" = 1 ]; then
+ echo >&2 "Instance is not ready: waiting for the upgrade"
+ exit 0
+ fi
+
+ if ! verifyDatabaseReady ; then
+ exit 0
+ fi
+}
+
+isDatabaseReady() {
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ \$helper = new \Espo\Core\Utils\Database\Helper(\$config);
+
+ try {
+ \$helper->createPdoConnection();
+ }
+ catch (Exception \$e) {
+ die(false);
+ }
+
+ die(true);
+ "
+}
+
+verifyDatabaseReady() {
+ for i in {1..40}
+ do
+ isReady=$(isDatabaseReady 2>&1)
+
+ if [ -n "$isReady" ]; then
+ return 0 #true
+ fi
+
+ echo >&2 "Waiting Database for receiving connections..."
+ sleep 3
+ done
+
+ echo >&2 "error: Database is not available"
+ return 1 #false
+}
+
+applyConfigEnvironments() {
+ local envName
+ local envValue
+ local configParamName
+ local configParamValue
+
+ compgen -v | while read -r envName; do
+
+ if [[ $envName != "$configPrefix"* ]]; then
+ continue
+ fi
+
+ envValue="${!envName}"
+
+ if isConfigArrayParam "$envName" ; then
+ saveConfigArrayValue "$envName" "$envValue"
+ continue
+ fi
+
+ saveConfigValue "$envName" "$envValue"
+
+ done
+}
+
+isValueQuoted() {
+ local value="$1"
+
+ php -r "
+ echo isQuote('$value');
+
+ function isQuote (\$value) {
+ \$value = trim(\$value);
+
+ if (\$value === '0') {
+ return false;
+ }
+
+ if (empty(\$value)) {
+ return true;
+ }
+
+ if (filter_var(\$value, FILTER_VALIDATE_IP)) {
+ return true;
+ }
+
+ if (!preg_match('/[^0-9.]+/', \$value)) {
+ return false;
+ }
+
+ if (in_array(\$value, ['null', '1'], true)) {
+ return false;
+ }
+
+ if (in_array(\$value, ['true', 'false'])) {
+ return false;
+ }
+
+ return true;
+ }
+ "
+}
+
+normalizeConfigParamName() {
+ local value="$1"
+ local prefix=${2:-"$configPrefix"}
+
+ php -r "
+ \$value = str_ireplace('$prefix', '', '$value');
+ \$value = strtolower(\$value);
+
+ \$value = preg_replace_callback(
+ '/_([a-zA-Z])/',
+ function (\$matches) {
+ return strtoupper(\$matches[1]);
+ },
+ \$value
+ );
+
+ echo \$value;
+ "
+}
+
+normalizeConfigParamValue() {
+ local value=${1//\'/\\\'}
+
+ local isValueQuoted=$(isValueQuoted "$value")
+
+ if [ -n "$isValueQuoted" ] && [ "$isValueQuoted" = 1 ]; then
+ echo "'$value'"
+ return
+ fi
+
+ echo "$value"
+}
+
+isConfigArrayParam() {
+ local envName="$1"
+
+ for i in "${!configPrefixArrayList[@]}"
+ do
+ if [[ "$envName" != ${configPrefixArrayList[$i]}* ]]; then
+ continue
+ fi
+
+ return 0 #true
+ done
+
+ return 1 #false
+}
+
+saveConfigValue() {
+ local envName="$1"
+ local envValue="$2"
+
+ local key=$(normalizeConfigParamName "$envName")
+ local value=$(normalizeConfigParamValue "$envValue")
+
+ saveConfigParam "$key" "$value"
+}
+
+saveConfigArrayValue() {
+ local envName="$1"
+ local envValue="$2"
+
+ for i in "${!configPrefixArrayList[@]}"
+ do
+ if [[ "$envName" != ${configPrefixArrayList[$i]}* ]]; then
+ continue
+ fi
+
+ local key1="$i"
+ local key2=$(normalizeConfigParamName "$envName" "${configPrefixArrayList[$i]}")
+
+ break
+ done
+
+ local value=$(normalizeConfigParamValue "$envValue")
+
+ saveConfigArrayParam "$key1" "$key2" "$value"
+}
+# END: entrypoint-utils.sh
+
+checkInstanceReady
+
+applyConfigEnvironments
+
+/usr/local/bin/php /var/www/html/daemon.php
+
+exec "$@"
\ No newline at end of file
diff --git a/espocrm_8-fpm-alpine/docker-entrypoint.sh b/espocrm_8-fpm-alpine/docker-entrypoint.sh
new file mode 100755
index 0000000..acc13a4
--- /dev/null
+++ b/espocrm_8-fpm-alpine/docker-entrypoint.sh
@@ -0,0 +1,565 @@
+#!/bin/bash
+
+set -euo pipefail
+
+# entrypoint-utils.sh
+configPrefix="ESPOCRM_CONFIG_"
+
+declare -A configPrefixArrayList=(
+ [logger]="ESPOCRM_CONFIG_LOGGER_"
+ [database]="ESPOCRM_CONFIG_DATABASE_"
+)
+
+compareVersion() {
+ local version1="$1"
+ local version2="$2"
+ local operator="$3"
+
+ echo $(php -r "echo version_compare('$version1', '$version2', '$operator');")
+}
+
+join() {
+ local sep="$1"; shift
+ local out; printf -v out "${sep//%/%%}%s" "$@"
+ echo "${out#$sep}"
+}
+
+getConfigParamFromFile() {
+ local name="$1"
+
+ php -r "
+ if (file_exists('$DOCUMENT_ROOT/data/config-internal.php')) {
+ \$config=include('$DOCUMENT_ROOT/data/config-internal.php');
+
+ if (array_key_exists('$name', \$config)) {
+ die(\$config['$name']);
+ }
+ }
+
+ if (file_exists('$DOCUMENT_ROOT/data/config.php')) {
+ \$config=include('$DOCUMENT_ROOT/data/config.php');
+
+ if (array_key_exists('$name', \$config)) {
+ die(\$config['$name']);
+ }
+ }
+ "
+}
+
+getConfigParam() {
+ local name="$1"
+
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ echo \$config->get('$name');
+ "
+}
+
+# Bool: saveConfigParam "jobRunInParallel" "true"
+# String: saveConfigParam "language" "'en_US'"
+saveConfigParam() {
+ local name="$1"
+ local value="$2"
+
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ if (\$config->get('$name') === $value) {
+ return;
+ }
+
+ \$injectableFactory = \$app->getContainer()->get('injectableFactory');
+ \$configWriter = \$injectableFactory->create('\\Espo\\Core\\Utils\\Config\\ConfigWriter');
+
+ \$configWriter->set('$name', $value);
+ \$configWriter->save();
+ "
+}
+
+saveConfigArrayParam() {
+ local key1="$1"
+ local key2="$2"
+ local value="$3"
+
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ \$arrayValue = \$config->get('$key1') ?? [];
+
+ if (!is_array(\$arrayValue)) {
+ return;
+ }
+
+ if (array_key_exists('$key2', \$arrayValue) && \$arrayValue['$key2'] === $value) {
+ return;
+ }
+
+ \$injectableFactory = \$app->getContainer()->get('injectableFactory');
+ \$configWriter = \$injectableFactory->create('\\Espo\\Core\\Utils\\Config\\ConfigWriter');
+
+ \$arrayValue['$key2'] = $value;
+
+ \$configWriter->set('$key1', \$arrayValue);
+ \$configWriter->save();
+ "
+}
+
+checkInstanceReady() {
+ local isInstalled=$(getConfigParamFromFile "isInstalled")
+
+ if [ -z "$isInstalled" ] || [ "$isInstalled" != 1 ]; then
+ echo >&2 "Instance is not ready: waiting for the installation"
+ exit 0
+ fi
+
+ local maintenanceMode=$(getConfigParamFromFile "maintenanceMode")
+
+ if [ -n "$maintenanceMode" ] && [ "$maintenanceMode" = 1 ]; then
+ echo >&2 "Instance is not ready: waiting for the upgrade"
+ exit 0
+ fi
+
+ if ! verifyDatabaseReady ; then
+ exit 0
+ fi
+}
+
+isDatabaseReady() {
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ \$helper = new \Espo\Core\Utils\Database\Helper(\$config);
+
+ try {
+ \$helper->createPdoConnection();
+ }
+ catch (Exception \$e) {
+ die(false);
+ }
+
+ die(true);
+ "
+}
+
+verifyDatabaseReady() {
+ for i in {1..40}
+ do
+ isReady=$(isDatabaseReady 2>&1)
+
+ if [ -n "$isReady" ]; then
+ return 0 #true
+ fi
+
+ echo >&2 "Waiting Database for receiving connections..."
+ sleep 3
+ done
+
+ echo >&2 "error: Database is not available"
+ return 1 #false
+}
+
+applyConfigEnvironments() {
+ local envName
+ local envValue
+ local configParamName
+ local configParamValue
+
+ compgen -v | while read -r envName; do
+
+ if [[ $envName != "$configPrefix"* ]]; then
+ continue
+ fi
+
+ envValue="${!envName}"
+
+ if isConfigArrayParam "$envName" ; then
+ saveConfigArrayValue "$envName" "$envValue"
+ continue
+ fi
+
+ saveConfigValue "$envName" "$envValue"
+
+ done
+}
+
+isValueQuoted() {
+ local value="$1"
+
+ php -r "
+ echo isQuote('$value');
+
+ function isQuote (\$value) {
+ \$value = trim(\$value);
+
+ if (\$value === '0') {
+ return false;
+ }
+
+ if (empty(\$value)) {
+ return true;
+ }
+
+ if (filter_var(\$value, FILTER_VALIDATE_IP)) {
+ return true;
+ }
+
+ if (!preg_match('/[^0-9.]+/', \$value)) {
+ return false;
+ }
+
+ if (in_array(\$value, ['null', '1'], true)) {
+ return false;
+ }
+
+ if (in_array(\$value, ['true', 'false'])) {
+ return false;
+ }
+
+ return true;
+ }
+ "
+}
+
+normalizeConfigParamName() {
+ local value="$1"
+ local prefix=${2:-"$configPrefix"}
+
+ php -r "
+ \$value = str_ireplace('$prefix', '', '$value');
+ \$value = strtolower(\$value);
+
+ \$value = preg_replace_callback(
+ '/_([a-zA-Z])/',
+ function (\$matches) {
+ return strtoupper(\$matches[1]);
+ },
+ \$value
+ );
+
+ echo \$value;
+ "
+}
+
+normalizeConfigParamValue() {
+ local value=${1//\'/\\\'}
+
+ local isValueQuoted=$(isValueQuoted "$value")
+
+ if [ -n "$isValueQuoted" ] && [ "$isValueQuoted" = 1 ]; then
+ echo "'$value'"
+ return
+ fi
+
+ echo "$value"
+}
+
+isConfigArrayParam() {
+ local envName="$1"
+
+ for i in "${!configPrefixArrayList[@]}"
+ do
+ if [[ "$envName" != ${configPrefixArrayList[$i]}* ]]; then
+ continue
+ fi
+
+ return 0 #true
+ done
+
+ return 1 #false
+}
+
+saveConfigValue() {
+ local envName="$1"
+ local envValue="$2"
+
+ local key=$(normalizeConfigParamName "$envName")
+ local value=$(normalizeConfigParamValue "$envValue")
+
+ saveConfigParam "$key" "$value"
+}
+
+saveConfigArrayValue() {
+ local envName="$1"
+ local envValue="$2"
+
+ for i in "${!configPrefixArrayList[@]}"
+ do
+ if [[ "$envName" != ${configPrefixArrayList[$i]}* ]]; then
+ continue
+ fi
+
+ local key1="$i"
+ local key2=$(normalizeConfigParamName "$envName" "${configPrefixArrayList[$i]}")
+
+ break
+ done
+
+ local value=$(normalizeConfigParamValue "$envValue")
+
+ saveConfigArrayParam "$key1" "$key2" "$value"
+}
+# END: entrypoint-utils.sh
+
+installationType() {
+ if [ -f "$DOCUMENT_ROOT/data/config.php" ]; then
+ local isInstalled=$(getConfigParamFromFile "isInstalled")
+
+ if [ -n "$isInstalled" ] && [ "$isInstalled" = 1 ]; then
+ local installedVersion=$(getConfigParamFromFile "version")
+ local isVersionGreater=$(compareVersion "$ESPOCRM_VERSION" "$installedVersion" ">")
+
+ if [ -n "$isVersionGreater" ]; then
+ echo "upgrade"
+ return
+ fi
+
+ echo "skip"
+ return
+ fi
+
+ echo "reinstall"
+ return
+ fi
+
+ echo "install"
+}
+
+actionInstall() {
+ if [ ! -d "$SOURCE_FILES" ]; then
+ echo >&2 "error: Source files [$SOURCE_FILES] are not found."
+ exit 1
+ fi
+
+ cp -a "$SOURCE_FILES/." "$DOCUMENT_ROOT/"
+
+ installEspocrm
+}
+
+actionReinstall() {
+ if [ -f "$DOCUMENT_ROOT/install/config.php" ]; then
+ sed -i "s/'isInstalled' => true/'isInstalled' => false/g" "$DOCUMENT_ROOT/install/config.php"
+ fi
+
+ installEspocrm
+}
+
+actionUpgrade() {
+ UPGRADE_NUMBER=$((UPGRADE_NUMBER+1))
+
+ if [ $UPGRADE_NUMBER -gt $MAX_UPGRADE_COUNT ];then
+ echo >&2 "The MAX_UPGRADE_COUNT exceded. The upgrading process has been stopped."
+ return
+ fi
+
+ local installedVersion=$(getConfigParamFromFile "version")
+ local isVersionEqual=$(compareVersion "$installedVersion" "$ESPOCRM_VERSION" ">=")
+
+ if [ -n "$isVersionEqual" ]; then
+ echo >&2 "Upgrade process is finished. EspoCRM version is $installedVersion."
+ return
+ fi
+
+ echo >&2 "Start upgrading process from version $installedVersion."
+
+ if ! runUpgradeStep ; then
+ return
+ fi
+
+ actionUpgrade
+}
+
+runUpgradeStep() {
+ local result=$(php command.php upgrade -y --toVersion="$ESPOCRM_VERSION")
+
+ if [[ "$result" == *"Error:"* ]]; then
+ echo >&2 "error: Upgrade error, more details:"
+ echo >&2 "$result"
+
+ return 1 #false
+ fi
+
+ return 0 #true
+}
+
+installEspocrm() {
+ echo >&2 "Start EspoCRM installation"
+
+ find . -type d -exec chmod 755 {} + && find . -type f -exec chmod 644 {} +
+ find data custom/Espo/Custom client/custom -type d -exec chmod 775 {} + && find data custom/Espo/Custom client/custom -type f -exec chmod 664 {} +
+ chmod 775 application/Espo/Modules client/modules
+
+ declare -a preferences=()
+ for optionName in "${!OPTIONAL_PARAMS[@]}"
+ do
+ local varName="${OPTIONAL_PARAMS[$optionName]}"
+ if [ -n "${!varName-}" ]; then
+ preferences+=("${optionName}=${!varName}")
+ fi
+ done
+
+ runInstallationStep "step1" "user-lang=${ESPOCRM_LANGUAGE}"
+
+ local databaseHost="${ESPOCRM_DATABASE_HOST}"
+
+ if [ -n "$ESPOCRM_DATABASE_PORT" ]; then
+ databaseHost="${ESPOCRM_DATABASE_HOST}:${ESPOCRM_DATABASE_PORT}"
+ fi
+
+ for i in {1..20}
+ do
+ settingsTestResult=$(runInstallationStep "settingsTest" "dbPlatform=${ESPOCRM_DATABASE_PLATFORM}&hostName=${databaseHost}&dbName=${ESPOCRM_DATABASE_NAME}&dbUserName=${ESPOCRM_DATABASE_USER}&dbUserPass=${ESPOCRM_DATABASE_PASSWORD}" true 2>&1)
+
+ if [[ ! "$settingsTestResult" == *"Error:"* ]]; then
+ break
+ fi
+
+ sleep 5
+ done
+
+ if [[ "$settingsTestResult" == *"Error:"* ]] && [[ "$settingsTestResult" == *"[errorCode] => 2002"* ]]; then
+ echo >&2 "warning: Unable connect to Database server. Continuing anyway"
+ return
+ fi
+
+ runInstallationStep "setupConfirmation" "db-platform=${ESPOCRM_DATABASE_PLATFORM}&host-name=${databaseHost}&db-name=${ESPOCRM_DATABASE_NAME}&db-user-name=${ESPOCRM_DATABASE_USER}&db-user-password=${ESPOCRM_DATABASE_PASSWORD}"
+ runInstallationStep "checkPermission"
+ runInstallationStep "saveSettings" "site-url=${ESPOCRM_SITE_URL}&default-permissions-user=${DEFAULT_OWNER}&default-permissions-group=${DEFAULT_GROUP}"
+ runInstallationStep "buildDatabase"
+ runInstallationStep "createUser" "user-name=${ESPOCRM_ADMIN_USERNAME}&user-pass=${ESPOCRM_ADMIN_PASSWORD}"
+ runInstallationStep "savePreferences" "$(join '&' "${preferences[@]}")"
+ runInstallationStep "finish"
+
+ saveConfigParam "jobRunInParallel" "true"
+
+ echo >&2 "End EspoCRM installation"
+}
+
+runInstallationStep() {
+ local actionName="$1"
+ local returnResult=${3-false}
+
+ if [ -n "${2-}" ]; then
+ local data="$2"
+ local result=$(php install/cli.php -a "$actionName" -d "$data")
+ else
+ local result=$(php install/cli.php -a "$actionName")
+ fi
+
+ if [ "$returnResult" = true ]; then
+ echo >&2 "$result"
+ return
+ fi
+
+ if [[ "$result" == *"Error:"* ]]; then
+ echo >&2 "error: Installation error, more details:"
+ echo >&2 "$result"
+ exit 1
+ fi
+}
+
+# ------------------------- START -------------------------------------
+# Global variables
+DOCUMENT_ROOT="/var/www/html"
+SOURCE_FILES="/usr/src/espocrm"
+MAX_UPGRADE_COUNT=20
+DEFAULT_OWNER="www-data"
+DEFAULT_GROUP="www-data"
+
+if [ "$(id -u)" = '0' ]; then
+ if [[ "$1" == "apache2"* ]]; then
+ wrongSymbol='#'
+ DEFAULT_OWNER="${APACHE_RUN_USER:-www-data}"
+ DEFAULT_OWNER="${DEFAULT_OWNER#$wrongSymbol}"
+
+ DEFAULT_GROUP="${APACHE_RUN_GROUP:-www-data}"
+ DEFAULT_GROUP="${DEFAULT_GROUP#$wrongSymbol}"
+ fi
+else
+ DEFAULT_OWNER="$(id -u)"
+ DEFAULT_GROUP="$(id -g)"
+fi
+
+declare -A DEFAULTS=(
+ ['ESPOCRM_DATABASE_PLATFORM']='Mysql'
+ ['ESPOCRM_DATABASE_HOST']='mysql'
+ ['ESPOCRM_DATABASE_PORT']=''
+ ['ESPOCRM_DATABASE_NAME']='espocrm'
+ ['ESPOCRM_DATABASE_USER']='root'
+ ['ESPOCRM_DATABASE_PASSWORD']='password'
+ ['ESPOCRM_ADMIN_USERNAME']='admin'
+ ['ESPOCRM_ADMIN_PASSWORD']='password'
+ ['ESPOCRM_LANGUAGE']='en_US'
+ ['ESPOCRM_SITE_URL']='http://localhost'
+)
+
+declare -A OPTIONAL_PARAMS=(
+ ['language']='ESPOCRM_LANGUAGE'
+ ['dateFormat']='ESPOCRM_DATE_FORMAT'
+ ['timeFormat']='ESPOCRM_TIME_FORMAT'
+ ['timeZone']='ESPOCRM_TIME_ZONE'
+ ['weekStart']='ESPOCRM_WEEK_START'
+ ['defaultCurrency']='ESPOCRM_DEFAULT_CURRENCY'
+ ['thousandSeparator']='ESPOCRM_THOUSAND_SEPARATOR'
+ ['decimalMark']='ESPOCRM_DECIMAL_MARK'
+)
+
+for defaultParam in "${!DEFAULTS[@]}"
+do
+ if [ -z "${!defaultParam-}" ]; then
+ declare "${defaultParam}"="${DEFAULTS[$defaultParam]}"
+ fi
+done
+
+installationType=$(installationType)
+
+case $installationType in
+ install)
+ echo >&2 "Run \"install\" action."
+ actionInstall
+ chown -R $DEFAULT_OWNER:$DEFAULT_GROUP "$DOCUMENT_ROOT"
+ ;;
+
+ reinstall)
+ echo >&2 "Run \"reinstall\" action."
+ actionReinstall
+ chown -R $DEFAULT_OWNER:$DEFAULT_GROUP "$DOCUMENT_ROOT"
+ ;;
+
+ upgrade)
+ echo >&2 "Run \"upgrade\" action."
+
+ if verifyDatabaseReady ; then
+ UPGRADE_NUMBER=0
+ actionUpgrade
+ chown -R $DEFAULT_OWNER:$DEFAULT_GROUP "$DOCUMENT_ROOT"
+ else
+ echo "error: Unable to upgrade the instance. Starting the current version."
+ fi
+ ;;
+
+ skip)
+ ;;
+
+ *)
+ echo >&2 "error: Unknown installation type [$installationType]"
+ exit 1
+ ;;
+esac
+
+applyConfigEnvironments
+# ------------------------- END -------------------------------------
+
+exec "$@"
diff --git a/espocrm_8-fpm-alpine/docker-websocket.sh b/espocrm_8-fpm-alpine/docker-websocket.sh
new file mode 100755
index 0000000..acad517
--- /dev/null
+++ b/espocrm_8-fpm-alpine/docker-websocket.sh
@@ -0,0 +1,324 @@
+#!/bin/bash
+
+set -eu
+
+DOCUMENT_ROOT="/var/www/html"
+
+# entrypoint-utils.sh
+configPrefix="ESPOCRM_CONFIG_"
+
+declare -A configPrefixArrayList=(
+ [logger]="ESPOCRM_CONFIG_LOGGER_"
+ [database]="ESPOCRM_CONFIG_DATABASE_"
+)
+
+compareVersion() {
+ local version1="$1"
+ local version2="$2"
+ local operator="$3"
+
+ echo $(php -r "echo version_compare('$version1', '$version2', '$operator');")
+}
+
+join() {
+ local sep="$1"; shift
+ local out; printf -v out "${sep//%/%%}%s" "$@"
+ echo "${out#$sep}"
+}
+
+getConfigParamFromFile() {
+ local name="$1"
+
+ php -r "
+ if (file_exists('$DOCUMENT_ROOT/data/config-internal.php')) {
+ \$config=include('$DOCUMENT_ROOT/data/config-internal.php');
+
+ if (array_key_exists('$name', \$config)) {
+ die(\$config['$name']);
+ }
+ }
+
+ if (file_exists('$DOCUMENT_ROOT/data/config.php')) {
+ \$config=include('$DOCUMENT_ROOT/data/config.php');
+
+ if (array_key_exists('$name', \$config)) {
+ die(\$config['$name']);
+ }
+ }
+ "
+}
+
+getConfigParam() {
+ local name="$1"
+
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ echo \$config->get('$name');
+ "
+}
+
+# Bool: saveConfigParam "jobRunInParallel" "true"
+# String: saveConfigParam "language" "'en_US'"
+saveConfigParam() {
+ local name="$1"
+ local value="$2"
+
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ if (\$config->get('$name') === $value) {
+ return;
+ }
+
+ \$injectableFactory = \$app->getContainer()->get('injectableFactory');
+ \$configWriter = \$injectableFactory->create('\\Espo\\Core\\Utils\\Config\\ConfigWriter');
+
+ \$configWriter->set('$name', $value);
+ \$configWriter->save();
+ "
+}
+
+saveConfigArrayParam() {
+ local key1="$1"
+ local key2="$2"
+ local value="$3"
+
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ \$arrayValue = \$config->get('$key1') ?? [];
+
+ if (!is_array(\$arrayValue)) {
+ return;
+ }
+
+ if (array_key_exists('$key2', \$arrayValue) && \$arrayValue['$key2'] === $value) {
+ return;
+ }
+
+ \$injectableFactory = \$app->getContainer()->get('injectableFactory');
+ \$configWriter = \$injectableFactory->create('\\Espo\\Core\\Utils\\Config\\ConfigWriter');
+
+ \$arrayValue['$key2'] = $value;
+
+ \$configWriter->set('$key1', \$arrayValue);
+ \$configWriter->save();
+ "
+}
+
+checkInstanceReady() {
+ local isInstalled=$(getConfigParamFromFile "isInstalled")
+
+ if [ -z "$isInstalled" ] || [ "$isInstalled" != 1 ]; then
+ echo >&2 "Instance is not ready: waiting for the installation"
+ exit 0
+ fi
+
+ local maintenanceMode=$(getConfigParamFromFile "maintenanceMode")
+
+ if [ -n "$maintenanceMode" ] && [ "$maintenanceMode" = 1 ]; then
+ echo >&2 "Instance is not ready: waiting for the upgrade"
+ exit 0
+ fi
+
+ if ! verifyDatabaseReady ; then
+ exit 0
+ fi
+}
+
+isDatabaseReady() {
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ \$helper = new \Espo\Core\Utils\Database\Helper(\$config);
+
+ try {
+ \$helper->createPdoConnection();
+ }
+ catch (Exception \$e) {
+ die(false);
+ }
+
+ die(true);
+ "
+}
+
+verifyDatabaseReady() {
+ for i in {1..40}
+ do
+ isReady=$(isDatabaseReady 2>&1)
+
+ if [ -n "$isReady" ]; then
+ return 0 #true
+ fi
+
+ echo >&2 "Waiting Database for receiving connections..."
+ sleep 3
+ done
+
+ echo >&2 "error: Database is not available"
+ return 1 #false
+}
+
+applyConfigEnvironments() {
+ local envName
+ local envValue
+ local configParamName
+ local configParamValue
+
+ compgen -v | while read -r envName; do
+
+ if [[ $envName != "$configPrefix"* ]]; then
+ continue
+ fi
+
+ envValue="${!envName}"
+
+ if isConfigArrayParam "$envName" ; then
+ saveConfigArrayValue "$envName" "$envValue"
+ continue
+ fi
+
+ saveConfigValue "$envName" "$envValue"
+
+ done
+}
+
+isValueQuoted() {
+ local value="$1"
+
+ php -r "
+ echo isQuote('$value');
+
+ function isQuote (\$value) {
+ \$value = trim(\$value);
+
+ if (\$value === '0') {
+ return false;
+ }
+
+ if (empty(\$value)) {
+ return true;
+ }
+
+ if (filter_var(\$value, FILTER_VALIDATE_IP)) {
+ return true;
+ }
+
+ if (!preg_match('/[^0-9.]+/', \$value)) {
+ return false;
+ }
+
+ if (in_array(\$value, ['null', '1'], true)) {
+ return false;
+ }
+
+ if (in_array(\$value, ['true', 'false'])) {
+ return false;
+ }
+
+ return true;
+ }
+ "
+}
+
+normalizeConfigParamName() {
+ local value="$1"
+ local prefix=${2:-"$configPrefix"}
+
+ php -r "
+ \$value = str_ireplace('$prefix', '', '$value');
+ \$value = strtolower(\$value);
+
+ \$value = preg_replace_callback(
+ '/_([a-zA-Z])/',
+ function (\$matches) {
+ return strtoupper(\$matches[1]);
+ },
+ \$value
+ );
+
+ echo \$value;
+ "
+}
+
+normalizeConfigParamValue() {
+ local value=${1//\'/\\\'}
+
+ local isValueQuoted=$(isValueQuoted "$value")
+
+ if [ -n "$isValueQuoted" ] && [ "$isValueQuoted" = 1 ]; then
+ echo "'$value'"
+ return
+ fi
+
+ echo "$value"
+}
+
+isConfigArrayParam() {
+ local envName="$1"
+
+ for i in "${!configPrefixArrayList[@]}"
+ do
+ if [[ "$envName" != ${configPrefixArrayList[$i]}* ]]; then
+ continue
+ fi
+
+ return 0 #true
+ done
+
+ return 1 #false
+}
+
+saveConfigValue() {
+ local envName="$1"
+ local envValue="$2"
+
+ local key=$(normalizeConfigParamName "$envName")
+ local value=$(normalizeConfigParamValue "$envValue")
+
+ saveConfigParam "$key" "$value"
+}
+
+saveConfigArrayValue() {
+ local envName="$1"
+ local envValue="$2"
+
+ for i in "${!configPrefixArrayList[@]}"
+ do
+ if [[ "$envName" != ${configPrefixArrayList[$i]}* ]]; then
+ continue
+ fi
+
+ local key1="$i"
+ local key2=$(normalizeConfigParamName "$envName" "${configPrefixArrayList[$i]}")
+
+ break
+ done
+
+ local value=$(normalizeConfigParamValue "$envValue")
+
+ saveConfigArrayParam "$key1" "$key2" "$value"
+}
+# END: entrypoint-utils.sh
+
+checkInstanceReady
+
+applyConfigEnvironments
+
+/usr/local/bin/php /var/www/html/websocket.php
+
+exec "$@"
\ No newline at end of file
diff --git a/espocrm_8-fpm/Dockerfile b/espocrm_8-fpm/Dockerfile
new file mode 100644
index 0000000..bed9d47
--- /dev/null
+++ b/espocrm_8-fpm/Dockerfile
@@ -0,0 +1,110 @@
+FROM php:8.2-fpm
+
+LABEL org.opencontainers.image.source=https://github.com/espocrm/espocrm
+LABEL org.opencontainers.image.description="EspoCRM is an Open Source CRM. Try for Free."
+
+RUN set -ex; \
+ \
+ aptMarkList="$(apt-mark showmanual)"; \
+ \
+ apt-get update; \
+ # Install php libs
+ apt-get install -y --no-install-recommends \
+ libpq-dev \
+ libjpeg-dev \
+ libpng-dev \
+ libmagickwand-dev \
+ libwebp-dev \
+ libfreetype6-dev \
+ libzip-dev \
+ libxml2-dev \
+ libc-client-dev \
+ libkrb5-dev \
+ libldap2-dev \
+ libzmq5-dev \
+ zlib1g-dev \
+ ; \
+ \
+# Install php-zmq
+ cd /usr; \
+ curl -fSL https://github.com/zeromq/php-zmq/archive/ee5fbc693f07b2d6f0d9fd748f131be82310f386.tar.gz -o php-zmq.tar.gz; \
+ tar -zxf php-zmq.tar.gz; \
+ cd php-zmq*; \
+ phpize && ./configure; \
+ make; \
+ make install; \
+ cd .. && rm -rf php-zmq*; \
+# END: Install php-zmq
+ \
+ debMultiarch="$(dpkg-architecture --query DEB_BUILD_MULTIARCH)"; \
+ docker-php-ext-configure ldap --with-libdir="lib/$debMultiarch"; \
+ docker-php-ext-configure gd --with-jpeg --with-freetype --with-webp; \
+ PHP_OPENSSL=yes docker-php-ext-configure imap --with-kerberos --with-imap-ssl; \
+ \
+ docker-php-ext-install \
+ pdo_pgsql \
+ pdo_mysql \
+ zip \
+ gd \
+ imap \
+ ldap \
+ exif \
+ pcntl \
+ posix \
+ bcmath \
+ ; \
+ docker-php-ext-enable \
+ zmq \
+ ; \
+ \
+# reset a list of apt-mark
+ apt-mark auto '.*' > /dev/null; \
+ apt-mark manual $aptMarkList; \
+ ldd "$(php -r 'echo ini_get("extension_dir");')"/*.so \
+ | awk '/=>/ { print $3 }' \
+ | sort -u \
+ | xargs -r realpath | xargs -r dpkg-query --search \
+ | cut -d: -f1 \
+ | sort -u \
+ | xargs -rt apt-mark manual; \
+ \
+ apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \
+ # Install required libs
+ apt-get install -y --no-install-recommends \
+ unzip \
+ libldap-common \
+ ; \
+ rm -rf /var/lib/apt/lists/*
+
+# php.ini
+RUN { \
+ echo 'expose_php = Off'; \
+ echo 'display_errors = Off'; \
+ echo 'display_startup_errors = Off'; \
+ echo 'log_errors = On'; \
+ echo 'memory_limit=256M'; \
+ echo 'max_execution_time=180'; \
+ echo 'max_input_time=180'; \
+ echo 'post_max_size=30M'; \
+ echo 'upload_max_filesize=30M'; \
+ echo 'date.timezone=UTC'; \
+} > ${PHP_INI_DIR}/conf.d/espocrm.ini
+
+ENV ESPOCRM_VERSION 8.4.1
+ENV ESPOCRM_SHA256 1681a2f68c0fc37bd46bbb9725765ed0cf16fab48a283820efb90265a7e8301d
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.4.1.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.4.1" /usr/src/espocrm; \
+ rm EspoCRM.zip; \
+ chown -R www-data:www-data /usr/src/espocrm
+
+COPY ./docker-*.sh /usr/local/bin/
+
+ENTRYPOINT [ "docker-entrypoint.sh" ]
+
+CMD ["php-fpm"]
diff --git a/espocrm_8-fpm/docker-daemon.sh b/espocrm_8-fpm/docker-daemon.sh
new file mode 100755
index 0000000..83a2b4f
--- /dev/null
+++ b/espocrm_8-fpm/docker-daemon.sh
@@ -0,0 +1,324 @@
+#!/bin/bash
+
+set -eu
+
+DOCUMENT_ROOT="/var/www/html"
+
+# entrypoint-utils.sh
+configPrefix="ESPOCRM_CONFIG_"
+
+declare -A configPrefixArrayList=(
+ [logger]="ESPOCRM_CONFIG_LOGGER_"
+ [database]="ESPOCRM_CONFIG_DATABASE_"
+)
+
+compareVersion() {
+ local version1="$1"
+ local version2="$2"
+ local operator="$3"
+
+ echo $(php -r "echo version_compare('$version1', '$version2', '$operator');")
+}
+
+join() {
+ local sep="$1"; shift
+ local out; printf -v out "${sep//%/%%}%s" "$@"
+ echo "${out#$sep}"
+}
+
+getConfigParamFromFile() {
+ local name="$1"
+
+ php -r "
+ if (file_exists('$DOCUMENT_ROOT/data/config-internal.php')) {
+ \$config=include('$DOCUMENT_ROOT/data/config-internal.php');
+
+ if (array_key_exists('$name', \$config)) {
+ die(\$config['$name']);
+ }
+ }
+
+ if (file_exists('$DOCUMENT_ROOT/data/config.php')) {
+ \$config=include('$DOCUMENT_ROOT/data/config.php');
+
+ if (array_key_exists('$name', \$config)) {
+ die(\$config['$name']);
+ }
+ }
+ "
+}
+
+getConfigParam() {
+ local name="$1"
+
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ echo \$config->get('$name');
+ "
+}
+
+# Bool: saveConfigParam "jobRunInParallel" "true"
+# String: saveConfigParam "language" "'en_US'"
+saveConfigParam() {
+ local name="$1"
+ local value="$2"
+
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ if (\$config->get('$name') === $value) {
+ return;
+ }
+
+ \$injectableFactory = \$app->getContainer()->get('injectableFactory');
+ \$configWriter = \$injectableFactory->create('\\Espo\\Core\\Utils\\Config\\ConfigWriter');
+
+ \$configWriter->set('$name', $value);
+ \$configWriter->save();
+ "
+}
+
+saveConfigArrayParam() {
+ local key1="$1"
+ local key2="$2"
+ local value="$3"
+
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ \$arrayValue = \$config->get('$key1') ?? [];
+
+ if (!is_array(\$arrayValue)) {
+ return;
+ }
+
+ if (array_key_exists('$key2', \$arrayValue) && \$arrayValue['$key2'] === $value) {
+ return;
+ }
+
+ \$injectableFactory = \$app->getContainer()->get('injectableFactory');
+ \$configWriter = \$injectableFactory->create('\\Espo\\Core\\Utils\\Config\\ConfigWriter');
+
+ \$arrayValue['$key2'] = $value;
+
+ \$configWriter->set('$key1', \$arrayValue);
+ \$configWriter->save();
+ "
+}
+
+checkInstanceReady() {
+ local isInstalled=$(getConfigParamFromFile "isInstalled")
+
+ if [ -z "$isInstalled" ] || [ "$isInstalled" != 1 ]; then
+ echo >&2 "Instance is not ready: waiting for the installation"
+ exit 0
+ fi
+
+ local maintenanceMode=$(getConfigParamFromFile "maintenanceMode")
+
+ if [ -n "$maintenanceMode" ] && [ "$maintenanceMode" = 1 ]; then
+ echo >&2 "Instance is not ready: waiting for the upgrade"
+ exit 0
+ fi
+
+ if ! verifyDatabaseReady ; then
+ exit 0
+ fi
+}
+
+isDatabaseReady() {
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ \$helper = new \Espo\Core\Utils\Database\Helper(\$config);
+
+ try {
+ \$helper->createPdoConnection();
+ }
+ catch (Exception \$e) {
+ die(false);
+ }
+
+ die(true);
+ "
+}
+
+verifyDatabaseReady() {
+ for i in {1..40}
+ do
+ isReady=$(isDatabaseReady 2>&1)
+
+ if [ -n "$isReady" ]; then
+ return 0 #true
+ fi
+
+ echo >&2 "Waiting Database for receiving connections..."
+ sleep 3
+ done
+
+ echo >&2 "error: Database is not available"
+ return 1 #false
+}
+
+applyConfigEnvironments() {
+ local envName
+ local envValue
+ local configParamName
+ local configParamValue
+
+ compgen -v | while read -r envName; do
+
+ if [[ $envName != "$configPrefix"* ]]; then
+ continue
+ fi
+
+ envValue="${!envName}"
+
+ if isConfigArrayParam "$envName" ; then
+ saveConfigArrayValue "$envName" "$envValue"
+ continue
+ fi
+
+ saveConfigValue "$envName" "$envValue"
+
+ done
+}
+
+isValueQuoted() {
+ local value="$1"
+
+ php -r "
+ echo isQuote('$value');
+
+ function isQuote (\$value) {
+ \$value = trim(\$value);
+
+ if (\$value === '0') {
+ return false;
+ }
+
+ if (empty(\$value)) {
+ return true;
+ }
+
+ if (filter_var(\$value, FILTER_VALIDATE_IP)) {
+ return true;
+ }
+
+ if (!preg_match('/[^0-9.]+/', \$value)) {
+ return false;
+ }
+
+ if (in_array(\$value, ['null', '1'], true)) {
+ return false;
+ }
+
+ if (in_array(\$value, ['true', 'false'])) {
+ return false;
+ }
+
+ return true;
+ }
+ "
+}
+
+normalizeConfigParamName() {
+ local value="$1"
+ local prefix=${2:-"$configPrefix"}
+
+ php -r "
+ \$value = str_ireplace('$prefix', '', '$value');
+ \$value = strtolower(\$value);
+
+ \$value = preg_replace_callback(
+ '/_([a-zA-Z])/',
+ function (\$matches) {
+ return strtoupper(\$matches[1]);
+ },
+ \$value
+ );
+
+ echo \$value;
+ "
+}
+
+normalizeConfigParamValue() {
+ local value=${1//\'/\\\'}
+
+ local isValueQuoted=$(isValueQuoted "$value")
+
+ if [ -n "$isValueQuoted" ] && [ "$isValueQuoted" = 1 ]; then
+ echo "'$value'"
+ return
+ fi
+
+ echo "$value"
+}
+
+isConfigArrayParam() {
+ local envName="$1"
+
+ for i in "${!configPrefixArrayList[@]}"
+ do
+ if [[ "$envName" != ${configPrefixArrayList[$i]}* ]]; then
+ continue
+ fi
+
+ return 0 #true
+ done
+
+ return 1 #false
+}
+
+saveConfigValue() {
+ local envName="$1"
+ local envValue="$2"
+
+ local key=$(normalizeConfigParamName "$envName")
+ local value=$(normalizeConfigParamValue "$envValue")
+
+ saveConfigParam "$key" "$value"
+}
+
+saveConfigArrayValue() {
+ local envName="$1"
+ local envValue="$2"
+
+ for i in "${!configPrefixArrayList[@]}"
+ do
+ if [[ "$envName" != ${configPrefixArrayList[$i]}* ]]; then
+ continue
+ fi
+
+ local key1="$i"
+ local key2=$(normalizeConfigParamName "$envName" "${configPrefixArrayList[$i]}")
+
+ break
+ done
+
+ local value=$(normalizeConfigParamValue "$envValue")
+
+ saveConfigArrayParam "$key1" "$key2" "$value"
+}
+# END: entrypoint-utils.sh
+
+checkInstanceReady
+
+applyConfigEnvironments
+
+/usr/local/bin/php /var/www/html/daemon.php
+
+exec "$@"
\ No newline at end of file
diff --git a/espocrm_8-fpm/docker-entrypoint.sh b/espocrm_8-fpm/docker-entrypoint.sh
new file mode 100755
index 0000000..acc13a4
--- /dev/null
+++ b/espocrm_8-fpm/docker-entrypoint.sh
@@ -0,0 +1,565 @@
+#!/bin/bash
+
+set -euo pipefail
+
+# entrypoint-utils.sh
+configPrefix="ESPOCRM_CONFIG_"
+
+declare -A configPrefixArrayList=(
+ [logger]="ESPOCRM_CONFIG_LOGGER_"
+ [database]="ESPOCRM_CONFIG_DATABASE_"
+)
+
+compareVersion() {
+ local version1="$1"
+ local version2="$2"
+ local operator="$3"
+
+ echo $(php -r "echo version_compare('$version1', '$version2', '$operator');")
+}
+
+join() {
+ local sep="$1"; shift
+ local out; printf -v out "${sep//%/%%}%s" "$@"
+ echo "${out#$sep}"
+}
+
+getConfigParamFromFile() {
+ local name="$1"
+
+ php -r "
+ if (file_exists('$DOCUMENT_ROOT/data/config-internal.php')) {
+ \$config=include('$DOCUMENT_ROOT/data/config-internal.php');
+
+ if (array_key_exists('$name', \$config)) {
+ die(\$config['$name']);
+ }
+ }
+
+ if (file_exists('$DOCUMENT_ROOT/data/config.php')) {
+ \$config=include('$DOCUMENT_ROOT/data/config.php');
+
+ if (array_key_exists('$name', \$config)) {
+ die(\$config['$name']);
+ }
+ }
+ "
+}
+
+getConfigParam() {
+ local name="$1"
+
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ echo \$config->get('$name');
+ "
+}
+
+# Bool: saveConfigParam "jobRunInParallel" "true"
+# String: saveConfigParam "language" "'en_US'"
+saveConfigParam() {
+ local name="$1"
+ local value="$2"
+
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ if (\$config->get('$name') === $value) {
+ return;
+ }
+
+ \$injectableFactory = \$app->getContainer()->get('injectableFactory');
+ \$configWriter = \$injectableFactory->create('\\Espo\\Core\\Utils\\Config\\ConfigWriter');
+
+ \$configWriter->set('$name', $value);
+ \$configWriter->save();
+ "
+}
+
+saveConfigArrayParam() {
+ local key1="$1"
+ local key2="$2"
+ local value="$3"
+
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ \$arrayValue = \$config->get('$key1') ?? [];
+
+ if (!is_array(\$arrayValue)) {
+ return;
+ }
+
+ if (array_key_exists('$key2', \$arrayValue) && \$arrayValue['$key2'] === $value) {
+ return;
+ }
+
+ \$injectableFactory = \$app->getContainer()->get('injectableFactory');
+ \$configWriter = \$injectableFactory->create('\\Espo\\Core\\Utils\\Config\\ConfigWriter');
+
+ \$arrayValue['$key2'] = $value;
+
+ \$configWriter->set('$key1', \$arrayValue);
+ \$configWriter->save();
+ "
+}
+
+checkInstanceReady() {
+ local isInstalled=$(getConfigParamFromFile "isInstalled")
+
+ if [ -z "$isInstalled" ] || [ "$isInstalled" != 1 ]; then
+ echo >&2 "Instance is not ready: waiting for the installation"
+ exit 0
+ fi
+
+ local maintenanceMode=$(getConfigParamFromFile "maintenanceMode")
+
+ if [ -n "$maintenanceMode" ] && [ "$maintenanceMode" = 1 ]; then
+ echo >&2 "Instance is not ready: waiting for the upgrade"
+ exit 0
+ fi
+
+ if ! verifyDatabaseReady ; then
+ exit 0
+ fi
+}
+
+isDatabaseReady() {
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ \$helper = new \Espo\Core\Utils\Database\Helper(\$config);
+
+ try {
+ \$helper->createPdoConnection();
+ }
+ catch (Exception \$e) {
+ die(false);
+ }
+
+ die(true);
+ "
+}
+
+verifyDatabaseReady() {
+ for i in {1..40}
+ do
+ isReady=$(isDatabaseReady 2>&1)
+
+ if [ -n "$isReady" ]; then
+ return 0 #true
+ fi
+
+ echo >&2 "Waiting Database for receiving connections..."
+ sleep 3
+ done
+
+ echo >&2 "error: Database is not available"
+ return 1 #false
+}
+
+applyConfigEnvironments() {
+ local envName
+ local envValue
+ local configParamName
+ local configParamValue
+
+ compgen -v | while read -r envName; do
+
+ if [[ $envName != "$configPrefix"* ]]; then
+ continue
+ fi
+
+ envValue="${!envName}"
+
+ if isConfigArrayParam "$envName" ; then
+ saveConfigArrayValue "$envName" "$envValue"
+ continue
+ fi
+
+ saveConfigValue "$envName" "$envValue"
+
+ done
+}
+
+isValueQuoted() {
+ local value="$1"
+
+ php -r "
+ echo isQuote('$value');
+
+ function isQuote (\$value) {
+ \$value = trim(\$value);
+
+ if (\$value === '0') {
+ return false;
+ }
+
+ if (empty(\$value)) {
+ return true;
+ }
+
+ if (filter_var(\$value, FILTER_VALIDATE_IP)) {
+ return true;
+ }
+
+ if (!preg_match('/[^0-9.]+/', \$value)) {
+ return false;
+ }
+
+ if (in_array(\$value, ['null', '1'], true)) {
+ return false;
+ }
+
+ if (in_array(\$value, ['true', 'false'])) {
+ return false;
+ }
+
+ return true;
+ }
+ "
+}
+
+normalizeConfigParamName() {
+ local value="$1"
+ local prefix=${2:-"$configPrefix"}
+
+ php -r "
+ \$value = str_ireplace('$prefix', '', '$value');
+ \$value = strtolower(\$value);
+
+ \$value = preg_replace_callback(
+ '/_([a-zA-Z])/',
+ function (\$matches) {
+ return strtoupper(\$matches[1]);
+ },
+ \$value
+ );
+
+ echo \$value;
+ "
+}
+
+normalizeConfigParamValue() {
+ local value=${1//\'/\\\'}
+
+ local isValueQuoted=$(isValueQuoted "$value")
+
+ if [ -n "$isValueQuoted" ] && [ "$isValueQuoted" = 1 ]; then
+ echo "'$value'"
+ return
+ fi
+
+ echo "$value"
+}
+
+isConfigArrayParam() {
+ local envName="$1"
+
+ for i in "${!configPrefixArrayList[@]}"
+ do
+ if [[ "$envName" != ${configPrefixArrayList[$i]}* ]]; then
+ continue
+ fi
+
+ return 0 #true
+ done
+
+ return 1 #false
+}
+
+saveConfigValue() {
+ local envName="$1"
+ local envValue="$2"
+
+ local key=$(normalizeConfigParamName "$envName")
+ local value=$(normalizeConfigParamValue "$envValue")
+
+ saveConfigParam "$key" "$value"
+}
+
+saveConfigArrayValue() {
+ local envName="$1"
+ local envValue="$2"
+
+ for i in "${!configPrefixArrayList[@]}"
+ do
+ if [[ "$envName" != ${configPrefixArrayList[$i]}* ]]; then
+ continue
+ fi
+
+ local key1="$i"
+ local key2=$(normalizeConfigParamName "$envName" "${configPrefixArrayList[$i]}")
+
+ break
+ done
+
+ local value=$(normalizeConfigParamValue "$envValue")
+
+ saveConfigArrayParam "$key1" "$key2" "$value"
+}
+# END: entrypoint-utils.sh
+
+installationType() {
+ if [ -f "$DOCUMENT_ROOT/data/config.php" ]; then
+ local isInstalled=$(getConfigParamFromFile "isInstalled")
+
+ if [ -n "$isInstalled" ] && [ "$isInstalled" = 1 ]; then
+ local installedVersion=$(getConfigParamFromFile "version")
+ local isVersionGreater=$(compareVersion "$ESPOCRM_VERSION" "$installedVersion" ">")
+
+ if [ -n "$isVersionGreater" ]; then
+ echo "upgrade"
+ return
+ fi
+
+ echo "skip"
+ return
+ fi
+
+ echo "reinstall"
+ return
+ fi
+
+ echo "install"
+}
+
+actionInstall() {
+ if [ ! -d "$SOURCE_FILES" ]; then
+ echo >&2 "error: Source files [$SOURCE_FILES] are not found."
+ exit 1
+ fi
+
+ cp -a "$SOURCE_FILES/." "$DOCUMENT_ROOT/"
+
+ installEspocrm
+}
+
+actionReinstall() {
+ if [ -f "$DOCUMENT_ROOT/install/config.php" ]; then
+ sed -i "s/'isInstalled' => true/'isInstalled' => false/g" "$DOCUMENT_ROOT/install/config.php"
+ fi
+
+ installEspocrm
+}
+
+actionUpgrade() {
+ UPGRADE_NUMBER=$((UPGRADE_NUMBER+1))
+
+ if [ $UPGRADE_NUMBER -gt $MAX_UPGRADE_COUNT ];then
+ echo >&2 "The MAX_UPGRADE_COUNT exceded. The upgrading process has been stopped."
+ return
+ fi
+
+ local installedVersion=$(getConfigParamFromFile "version")
+ local isVersionEqual=$(compareVersion "$installedVersion" "$ESPOCRM_VERSION" ">=")
+
+ if [ -n "$isVersionEqual" ]; then
+ echo >&2 "Upgrade process is finished. EspoCRM version is $installedVersion."
+ return
+ fi
+
+ echo >&2 "Start upgrading process from version $installedVersion."
+
+ if ! runUpgradeStep ; then
+ return
+ fi
+
+ actionUpgrade
+}
+
+runUpgradeStep() {
+ local result=$(php command.php upgrade -y --toVersion="$ESPOCRM_VERSION")
+
+ if [[ "$result" == *"Error:"* ]]; then
+ echo >&2 "error: Upgrade error, more details:"
+ echo >&2 "$result"
+
+ return 1 #false
+ fi
+
+ return 0 #true
+}
+
+installEspocrm() {
+ echo >&2 "Start EspoCRM installation"
+
+ find . -type d -exec chmod 755 {} + && find . -type f -exec chmod 644 {} +
+ find data custom/Espo/Custom client/custom -type d -exec chmod 775 {} + && find data custom/Espo/Custom client/custom -type f -exec chmod 664 {} +
+ chmod 775 application/Espo/Modules client/modules
+
+ declare -a preferences=()
+ for optionName in "${!OPTIONAL_PARAMS[@]}"
+ do
+ local varName="${OPTIONAL_PARAMS[$optionName]}"
+ if [ -n "${!varName-}" ]; then
+ preferences+=("${optionName}=${!varName}")
+ fi
+ done
+
+ runInstallationStep "step1" "user-lang=${ESPOCRM_LANGUAGE}"
+
+ local databaseHost="${ESPOCRM_DATABASE_HOST}"
+
+ if [ -n "$ESPOCRM_DATABASE_PORT" ]; then
+ databaseHost="${ESPOCRM_DATABASE_HOST}:${ESPOCRM_DATABASE_PORT}"
+ fi
+
+ for i in {1..20}
+ do
+ settingsTestResult=$(runInstallationStep "settingsTest" "dbPlatform=${ESPOCRM_DATABASE_PLATFORM}&hostName=${databaseHost}&dbName=${ESPOCRM_DATABASE_NAME}&dbUserName=${ESPOCRM_DATABASE_USER}&dbUserPass=${ESPOCRM_DATABASE_PASSWORD}" true 2>&1)
+
+ if [[ ! "$settingsTestResult" == *"Error:"* ]]; then
+ break
+ fi
+
+ sleep 5
+ done
+
+ if [[ "$settingsTestResult" == *"Error:"* ]] && [[ "$settingsTestResult" == *"[errorCode] => 2002"* ]]; then
+ echo >&2 "warning: Unable connect to Database server. Continuing anyway"
+ return
+ fi
+
+ runInstallationStep "setupConfirmation" "db-platform=${ESPOCRM_DATABASE_PLATFORM}&host-name=${databaseHost}&db-name=${ESPOCRM_DATABASE_NAME}&db-user-name=${ESPOCRM_DATABASE_USER}&db-user-password=${ESPOCRM_DATABASE_PASSWORD}"
+ runInstallationStep "checkPermission"
+ runInstallationStep "saveSettings" "site-url=${ESPOCRM_SITE_URL}&default-permissions-user=${DEFAULT_OWNER}&default-permissions-group=${DEFAULT_GROUP}"
+ runInstallationStep "buildDatabase"
+ runInstallationStep "createUser" "user-name=${ESPOCRM_ADMIN_USERNAME}&user-pass=${ESPOCRM_ADMIN_PASSWORD}"
+ runInstallationStep "savePreferences" "$(join '&' "${preferences[@]}")"
+ runInstallationStep "finish"
+
+ saveConfigParam "jobRunInParallel" "true"
+
+ echo >&2 "End EspoCRM installation"
+}
+
+runInstallationStep() {
+ local actionName="$1"
+ local returnResult=${3-false}
+
+ if [ -n "${2-}" ]; then
+ local data="$2"
+ local result=$(php install/cli.php -a "$actionName" -d "$data")
+ else
+ local result=$(php install/cli.php -a "$actionName")
+ fi
+
+ if [ "$returnResult" = true ]; then
+ echo >&2 "$result"
+ return
+ fi
+
+ if [[ "$result" == *"Error:"* ]]; then
+ echo >&2 "error: Installation error, more details:"
+ echo >&2 "$result"
+ exit 1
+ fi
+}
+
+# ------------------------- START -------------------------------------
+# Global variables
+DOCUMENT_ROOT="/var/www/html"
+SOURCE_FILES="/usr/src/espocrm"
+MAX_UPGRADE_COUNT=20
+DEFAULT_OWNER="www-data"
+DEFAULT_GROUP="www-data"
+
+if [ "$(id -u)" = '0' ]; then
+ if [[ "$1" == "apache2"* ]]; then
+ wrongSymbol='#'
+ DEFAULT_OWNER="${APACHE_RUN_USER:-www-data}"
+ DEFAULT_OWNER="${DEFAULT_OWNER#$wrongSymbol}"
+
+ DEFAULT_GROUP="${APACHE_RUN_GROUP:-www-data}"
+ DEFAULT_GROUP="${DEFAULT_GROUP#$wrongSymbol}"
+ fi
+else
+ DEFAULT_OWNER="$(id -u)"
+ DEFAULT_GROUP="$(id -g)"
+fi
+
+declare -A DEFAULTS=(
+ ['ESPOCRM_DATABASE_PLATFORM']='Mysql'
+ ['ESPOCRM_DATABASE_HOST']='mysql'
+ ['ESPOCRM_DATABASE_PORT']=''
+ ['ESPOCRM_DATABASE_NAME']='espocrm'
+ ['ESPOCRM_DATABASE_USER']='root'
+ ['ESPOCRM_DATABASE_PASSWORD']='password'
+ ['ESPOCRM_ADMIN_USERNAME']='admin'
+ ['ESPOCRM_ADMIN_PASSWORD']='password'
+ ['ESPOCRM_LANGUAGE']='en_US'
+ ['ESPOCRM_SITE_URL']='http://localhost'
+)
+
+declare -A OPTIONAL_PARAMS=(
+ ['language']='ESPOCRM_LANGUAGE'
+ ['dateFormat']='ESPOCRM_DATE_FORMAT'
+ ['timeFormat']='ESPOCRM_TIME_FORMAT'
+ ['timeZone']='ESPOCRM_TIME_ZONE'
+ ['weekStart']='ESPOCRM_WEEK_START'
+ ['defaultCurrency']='ESPOCRM_DEFAULT_CURRENCY'
+ ['thousandSeparator']='ESPOCRM_THOUSAND_SEPARATOR'
+ ['decimalMark']='ESPOCRM_DECIMAL_MARK'
+)
+
+for defaultParam in "${!DEFAULTS[@]}"
+do
+ if [ -z "${!defaultParam-}" ]; then
+ declare "${defaultParam}"="${DEFAULTS[$defaultParam]}"
+ fi
+done
+
+installationType=$(installationType)
+
+case $installationType in
+ install)
+ echo >&2 "Run \"install\" action."
+ actionInstall
+ chown -R $DEFAULT_OWNER:$DEFAULT_GROUP "$DOCUMENT_ROOT"
+ ;;
+
+ reinstall)
+ echo >&2 "Run \"reinstall\" action."
+ actionReinstall
+ chown -R $DEFAULT_OWNER:$DEFAULT_GROUP "$DOCUMENT_ROOT"
+ ;;
+
+ upgrade)
+ echo >&2 "Run \"upgrade\" action."
+
+ if verifyDatabaseReady ; then
+ UPGRADE_NUMBER=0
+ actionUpgrade
+ chown -R $DEFAULT_OWNER:$DEFAULT_GROUP "$DOCUMENT_ROOT"
+ else
+ echo "error: Unable to upgrade the instance. Starting the current version."
+ fi
+ ;;
+
+ skip)
+ ;;
+
+ *)
+ echo >&2 "error: Unknown installation type [$installationType]"
+ exit 1
+ ;;
+esac
+
+applyConfigEnvironments
+# ------------------------- END -------------------------------------
+
+exec "$@"
diff --git a/espocrm_8-fpm/docker-websocket.sh b/espocrm_8-fpm/docker-websocket.sh
new file mode 100755
index 0000000..acad517
--- /dev/null
+++ b/espocrm_8-fpm/docker-websocket.sh
@@ -0,0 +1,324 @@
+#!/bin/bash
+
+set -eu
+
+DOCUMENT_ROOT="/var/www/html"
+
+# entrypoint-utils.sh
+configPrefix="ESPOCRM_CONFIG_"
+
+declare -A configPrefixArrayList=(
+ [logger]="ESPOCRM_CONFIG_LOGGER_"
+ [database]="ESPOCRM_CONFIG_DATABASE_"
+)
+
+compareVersion() {
+ local version1="$1"
+ local version2="$2"
+ local operator="$3"
+
+ echo $(php -r "echo version_compare('$version1', '$version2', '$operator');")
+}
+
+join() {
+ local sep="$1"; shift
+ local out; printf -v out "${sep//%/%%}%s" "$@"
+ echo "${out#$sep}"
+}
+
+getConfigParamFromFile() {
+ local name="$1"
+
+ php -r "
+ if (file_exists('$DOCUMENT_ROOT/data/config-internal.php')) {
+ \$config=include('$DOCUMENT_ROOT/data/config-internal.php');
+
+ if (array_key_exists('$name', \$config)) {
+ die(\$config['$name']);
+ }
+ }
+
+ if (file_exists('$DOCUMENT_ROOT/data/config.php')) {
+ \$config=include('$DOCUMENT_ROOT/data/config.php');
+
+ if (array_key_exists('$name', \$config)) {
+ die(\$config['$name']);
+ }
+ }
+ "
+}
+
+getConfigParam() {
+ local name="$1"
+
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ echo \$config->get('$name');
+ "
+}
+
+# Bool: saveConfigParam "jobRunInParallel" "true"
+# String: saveConfigParam "language" "'en_US'"
+saveConfigParam() {
+ local name="$1"
+ local value="$2"
+
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ if (\$config->get('$name') === $value) {
+ return;
+ }
+
+ \$injectableFactory = \$app->getContainer()->get('injectableFactory');
+ \$configWriter = \$injectableFactory->create('\\Espo\\Core\\Utils\\Config\\ConfigWriter');
+
+ \$configWriter->set('$name', $value);
+ \$configWriter->save();
+ "
+}
+
+saveConfigArrayParam() {
+ local key1="$1"
+ local key2="$2"
+ local value="$3"
+
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ \$arrayValue = \$config->get('$key1') ?? [];
+
+ if (!is_array(\$arrayValue)) {
+ return;
+ }
+
+ if (array_key_exists('$key2', \$arrayValue) && \$arrayValue['$key2'] === $value) {
+ return;
+ }
+
+ \$injectableFactory = \$app->getContainer()->get('injectableFactory');
+ \$configWriter = \$injectableFactory->create('\\Espo\\Core\\Utils\\Config\\ConfigWriter');
+
+ \$arrayValue['$key2'] = $value;
+
+ \$configWriter->set('$key1', \$arrayValue);
+ \$configWriter->save();
+ "
+}
+
+checkInstanceReady() {
+ local isInstalled=$(getConfigParamFromFile "isInstalled")
+
+ if [ -z "$isInstalled" ] || [ "$isInstalled" != 1 ]; then
+ echo >&2 "Instance is not ready: waiting for the installation"
+ exit 0
+ fi
+
+ local maintenanceMode=$(getConfigParamFromFile "maintenanceMode")
+
+ if [ -n "$maintenanceMode" ] && [ "$maintenanceMode" = 1 ]; then
+ echo >&2 "Instance is not ready: waiting for the upgrade"
+ exit 0
+ fi
+
+ if ! verifyDatabaseReady ; then
+ exit 0
+ fi
+}
+
+isDatabaseReady() {
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ \$helper = new \Espo\Core\Utils\Database\Helper(\$config);
+
+ try {
+ \$helper->createPdoConnection();
+ }
+ catch (Exception \$e) {
+ die(false);
+ }
+
+ die(true);
+ "
+}
+
+verifyDatabaseReady() {
+ for i in {1..40}
+ do
+ isReady=$(isDatabaseReady 2>&1)
+
+ if [ -n "$isReady" ]; then
+ return 0 #true
+ fi
+
+ echo >&2 "Waiting Database for receiving connections..."
+ sleep 3
+ done
+
+ echo >&2 "error: Database is not available"
+ return 1 #false
+}
+
+applyConfigEnvironments() {
+ local envName
+ local envValue
+ local configParamName
+ local configParamValue
+
+ compgen -v | while read -r envName; do
+
+ if [[ $envName != "$configPrefix"* ]]; then
+ continue
+ fi
+
+ envValue="${!envName}"
+
+ if isConfigArrayParam "$envName" ; then
+ saveConfigArrayValue "$envName" "$envValue"
+ continue
+ fi
+
+ saveConfigValue "$envName" "$envValue"
+
+ done
+}
+
+isValueQuoted() {
+ local value="$1"
+
+ php -r "
+ echo isQuote('$value');
+
+ function isQuote (\$value) {
+ \$value = trim(\$value);
+
+ if (\$value === '0') {
+ return false;
+ }
+
+ if (empty(\$value)) {
+ return true;
+ }
+
+ if (filter_var(\$value, FILTER_VALIDATE_IP)) {
+ return true;
+ }
+
+ if (!preg_match('/[^0-9.]+/', \$value)) {
+ return false;
+ }
+
+ if (in_array(\$value, ['null', '1'], true)) {
+ return false;
+ }
+
+ if (in_array(\$value, ['true', 'false'])) {
+ return false;
+ }
+
+ return true;
+ }
+ "
+}
+
+normalizeConfigParamName() {
+ local value="$1"
+ local prefix=${2:-"$configPrefix"}
+
+ php -r "
+ \$value = str_ireplace('$prefix', '', '$value');
+ \$value = strtolower(\$value);
+
+ \$value = preg_replace_callback(
+ '/_([a-zA-Z])/',
+ function (\$matches) {
+ return strtoupper(\$matches[1]);
+ },
+ \$value
+ );
+
+ echo \$value;
+ "
+}
+
+normalizeConfigParamValue() {
+ local value=${1//\'/\\\'}
+
+ local isValueQuoted=$(isValueQuoted "$value")
+
+ if [ -n "$isValueQuoted" ] && [ "$isValueQuoted" = 1 ]; then
+ echo "'$value'"
+ return
+ fi
+
+ echo "$value"
+}
+
+isConfigArrayParam() {
+ local envName="$1"
+
+ for i in "${!configPrefixArrayList[@]}"
+ do
+ if [[ "$envName" != ${configPrefixArrayList[$i]}* ]]; then
+ continue
+ fi
+
+ return 0 #true
+ done
+
+ return 1 #false
+}
+
+saveConfigValue() {
+ local envName="$1"
+ local envValue="$2"
+
+ local key=$(normalizeConfigParamName "$envName")
+ local value=$(normalizeConfigParamValue "$envValue")
+
+ saveConfigParam "$key" "$value"
+}
+
+saveConfigArrayValue() {
+ local envName="$1"
+ local envValue="$2"
+
+ for i in "${!configPrefixArrayList[@]}"
+ do
+ if [[ "$envName" != ${configPrefixArrayList[$i]}* ]]; then
+ continue
+ fi
+
+ local key1="$i"
+ local key2=$(normalizeConfigParamName "$envName" "${configPrefixArrayList[$i]}")
+
+ break
+ done
+
+ local value=$(normalizeConfigParamValue "$envValue")
+
+ saveConfigArrayParam "$key1" "$key2" "$value"
+}
+# END: entrypoint-utils.sh
+
+checkInstanceReady
+
+applyConfigEnvironments
+
+/usr/local/bin/php /var/www/html/websocket.php
+
+exec "$@"
\ No newline at end of file
diff --git a/espocrm_8/Dockerfile b/espocrm_8/Dockerfile
new file mode 100644
index 0000000..1d5ba38
--- /dev/null
+++ b/espocrm_8/Dockerfile
@@ -0,0 +1,112 @@
+FROM php:8.2-apache
+
+LABEL org.opencontainers.image.source=https://github.com/espocrm/espocrm
+LABEL org.opencontainers.image.description="EspoCRM is an Open Source CRM. Try for Free."
+
+RUN set -ex; \
+ \
+ aptMarkList="$(apt-mark showmanual)"; \
+ \
+ apt-get update; \
+ # Install php libs
+ apt-get install -y --no-install-recommends \
+ libpq-dev \
+ libjpeg-dev \
+ libpng-dev \
+ libmagickwand-dev \
+ libwebp-dev \
+ libfreetype6-dev \
+ libzip-dev \
+ libxml2-dev \
+ libc-client-dev \
+ libkrb5-dev \
+ libldap2-dev \
+ libzmq5-dev \
+ zlib1g-dev \
+ ; \
+ \
+# Install php-zmq
+ cd /usr; \
+ curl -fSL https://github.com/zeromq/php-zmq/archive/ee5fbc693f07b2d6f0d9fd748f131be82310f386.tar.gz -o php-zmq.tar.gz; \
+ tar -zxf php-zmq.tar.gz; \
+ cd php-zmq*; \
+ phpize && ./configure; \
+ make; \
+ make install; \
+ cd .. && rm -rf php-zmq*; \
+# END: Install php-zmq
+ \
+ debMultiarch="$(dpkg-architecture --query DEB_BUILD_MULTIARCH)"; \
+ docker-php-ext-configure ldap --with-libdir="lib/$debMultiarch"; \
+ docker-php-ext-configure gd --with-jpeg --with-freetype --with-webp; \
+ PHP_OPENSSL=yes docker-php-ext-configure imap --with-kerberos --with-imap-ssl; \
+ \
+ docker-php-ext-install \
+ pdo_pgsql \
+ pdo_mysql \
+ zip \
+ gd \
+ imap \
+ ldap \
+ exif \
+ pcntl \
+ posix \
+ bcmath \
+ ; \
+ docker-php-ext-enable \
+ zmq \
+ ; \
+ \
+# reset a list of apt-mark
+ apt-mark auto '.*' > /dev/null; \
+ apt-mark manual $aptMarkList; \
+ ldd "$(php -r 'echo ini_get("extension_dir");')"/*.so \
+ | awk '/=>/ { print $3 }' \
+ | sort -u \
+ | xargs -r realpath | xargs -r dpkg-query --search \
+ | cut -d: -f1 \
+ | sort -u \
+ | xargs -rt apt-mark manual; \
+ \
+ apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \
+ # Install required libs
+ apt-get install -y --no-install-recommends \
+ unzip \
+ libldap-common \
+ ; \
+ rm -rf /var/lib/apt/lists/*
+
+# php.ini
+RUN { \
+ echo 'expose_php = Off'; \
+ echo 'display_errors = Off'; \
+ echo 'display_startup_errors = Off'; \
+ echo 'log_errors = On'; \
+ echo 'memory_limit=256M'; \
+ echo 'max_execution_time=180'; \
+ echo 'max_input_time=180'; \
+ echo 'post_max_size=30M'; \
+ echo 'upload_max_filesize=30M'; \
+ echo 'date.timezone=UTC'; \
+} > ${PHP_INI_DIR}/conf.d/espocrm.ini
+
+RUN a2enmod rewrite;
+
+ENV ESPOCRM_VERSION 8.4.1
+ENV ESPOCRM_SHA256 1681a2f68c0fc37bd46bbb9725765ed0cf16fab48a283820efb90265a7e8301d
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.4.1.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.4.1" /usr/src/espocrm; \
+ rm EspoCRM.zip; \
+ chown -R www-data:www-data /usr/src/espocrm
+
+COPY ./docker-*.sh /usr/local/bin/
+
+ENTRYPOINT [ "docker-entrypoint.sh" ]
+
+CMD ["apache2-foreground"]
diff --git a/espocrm_8/docker-daemon.sh b/espocrm_8/docker-daemon.sh
new file mode 100755
index 0000000..83a2b4f
--- /dev/null
+++ b/espocrm_8/docker-daemon.sh
@@ -0,0 +1,324 @@
+#!/bin/bash
+
+set -eu
+
+DOCUMENT_ROOT="/var/www/html"
+
+# entrypoint-utils.sh
+configPrefix="ESPOCRM_CONFIG_"
+
+declare -A configPrefixArrayList=(
+ [logger]="ESPOCRM_CONFIG_LOGGER_"
+ [database]="ESPOCRM_CONFIG_DATABASE_"
+)
+
+compareVersion() {
+ local version1="$1"
+ local version2="$2"
+ local operator="$3"
+
+ echo $(php -r "echo version_compare('$version1', '$version2', '$operator');")
+}
+
+join() {
+ local sep="$1"; shift
+ local out; printf -v out "${sep//%/%%}%s" "$@"
+ echo "${out#$sep}"
+}
+
+getConfigParamFromFile() {
+ local name="$1"
+
+ php -r "
+ if (file_exists('$DOCUMENT_ROOT/data/config-internal.php')) {
+ \$config=include('$DOCUMENT_ROOT/data/config-internal.php');
+
+ if (array_key_exists('$name', \$config)) {
+ die(\$config['$name']);
+ }
+ }
+
+ if (file_exists('$DOCUMENT_ROOT/data/config.php')) {
+ \$config=include('$DOCUMENT_ROOT/data/config.php');
+
+ if (array_key_exists('$name', \$config)) {
+ die(\$config['$name']);
+ }
+ }
+ "
+}
+
+getConfigParam() {
+ local name="$1"
+
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ echo \$config->get('$name');
+ "
+}
+
+# Bool: saveConfigParam "jobRunInParallel" "true"
+# String: saveConfigParam "language" "'en_US'"
+saveConfigParam() {
+ local name="$1"
+ local value="$2"
+
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ if (\$config->get('$name') === $value) {
+ return;
+ }
+
+ \$injectableFactory = \$app->getContainer()->get('injectableFactory');
+ \$configWriter = \$injectableFactory->create('\\Espo\\Core\\Utils\\Config\\ConfigWriter');
+
+ \$configWriter->set('$name', $value);
+ \$configWriter->save();
+ "
+}
+
+saveConfigArrayParam() {
+ local key1="$1"
+ local key2="$2"
+ local value="$3"
+
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ \$arrayValue = \$config->get('$key1') ?? [];
+
+ if (!is_array(\$arrayValue)) {
+ return;
+ }
+
+ if (array_key_exists('$key2', \$arrayValue) && \$arrayValue['$key2'] === $value) {
+ return;
+ }
+
+ \$injectableFactory = \$app->getContainer()->get('injectableFactory');
+ \$configWriter = \$injectableFactory->create('\\Espo\\Core\\Utils\\Config\\ConfigWriter');
+
+ \$arrayValue['$key2'] = $value;
+
+ \$configWriter->set('$key1', \$arrayValue);
+ \$configWriter->save();
+ "
+}
+
+checkInstanceReady() {
+ local isInstalled=$(getConfigParamFromFile "isInstalled")
+
+ if [ -z "$isInstalled" ] || [ "$isInstalled" != 1 ]; then
+ echo >&2 "Instance is not ready: waiting for the installation"
+ exit 0
+ fi
+
+ local maintenanceMode=$(getConfigParamFromFile "maintenanceMode")
+
+ if [ -n "$maintenanceMode" ] && [ "$maintenanceMode" = 1 ]; then
+ echo >&2 "Instance is not ready: waiting for the upgrade"
+ exit 0
+ fi
+
+ if ! verifyDatabaseReady ; then
+ exit 0
+ fi
+}
+
+isDatabaseReady() {
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ \$helper = new \Espo\Core\Utils\Database\Helper(\$config);
+
+ try {
+ \$helper->createPdoConnection();
+ }
+ catch (Exception \$e) {
+ die(false);
+ }
+
+ die(true);
+ "
+}
+
+verifyDatabaseReady() {
+ for i in {1..40}
+ do
+ isReady=$(isDatabaseReady 2>&1)
+
+ if [ -n "$isReady" ]; then
+ return 0 #true
+ fi
+
+ echo >&2 "Waiting Database for receiving connections..."
+ sleep 3
+ done
+
+ echo >&2 "error: Database is not available"
+ return 1 #false
+}
+
+applyConfigEnvironments() {
+ local envName
+ local envValue
+ local configParamName
+ local configParamValue
+
+ compgen -v | while read -r envName; do
+
+ if [[ $envName != "$configPrefix"* ]]; then
+ continue
+ fi
+
+ envValue="${!envName}"
+
+ if isConfigArrayParam "$envName" ; then
+ saveConfigArrayValue "$envName" "$envValue"
+ continue
+ fi
+
+ saveConfigValue "$envName" "$envValue"
+
+ done
+}
+
+isValueQuoted() {
+ local value="$1"
+
+ php -r "
+ echo isQuote('$value');
+
+ function isQuote (\$value) {
+ \$value = trim(\$value);
+
+ if (\$value === '0') {
+ return false;
+ }
+
+ if (empty(\$value)) {
+ return true;
+ }
+
+ if (filter_var(\$value, FILTER_VALIDATE_IP)) {
+ return true;
+ }
+
+ if (!preg_match('/[^0-9.]+/', \$value)) {
+ return false;
+ }
+
+ if (in_array(\$value, ['null', '1'], true)) {
+ return false;
+ }
+
+ if (in_array(\$value, ['true', 'false'])) {
+ return false;
+ }
+
+ return true;
+ }
+ "
+}
+
+normalizeConfigParamName() {
+ local value="$1"
+ local prefix=${2:-"$configPrefix"}
+
+ php -r "
+ \$value = str_ireplace('$prefix', '', '$value');
+ \$value = strtolower(\$value);
+
+ \$value = preg_replace_callback(
+ '/_([a-zA-Z])/',
+ function (\$matches) {
+ return strtoupper(\$matches[1]);
+ },
+ \$value
+ );
+
+ echo \$value;
+ "
+}
+
+normalizeConfigParamValue() {
+ local value=${1//\'/\\\'}
+
+ local isValueQuoted=$(isValueQuoted "$value")
+
+ if [ -n "$isValueQuoted" ] && [ "$isValueQuoted" = 1 ]; then
+ echo "'$value'"
+ return
+ fi
+
+ echo "$value"
+}
+
+isConfigArrayParam() {
+ local envName="$1"
+
+ for i in "${!configPrefixArrayList[@]}"
+ do
+ if [[ "$envName" != ${configPrefixArrayList[$i]}* ]]; then
+ continue
+ fi
+
+ return 0 #true
+ done
+
+ return 1 #false
+}
+
+saveConfigValue() {
+ local envName="$1"
+ local envValue="$2"
+
+ local key=$(normalizeConfigParamName "$envName")
+ local value=$(normalizeConfigParamValue "$envValue")
+
+ saveConfigParam "$key" "$value"
+}
+
+saveConfigArrayValue() {
+ local envName="$1"
+ local envValue="$2"
+
+ for i in "${!configPrefixArrayList[@]}"
+ do
+ if [[ "$envName" != ${configPrefixArrayList[$i]}* ]]; then
+ continue
+ fi
+
+ local key1="$i"
+ local key2=$(normalizeConfigParamName "$envName" "${configPrefixArrayList[$i]}")
+
+ break
+ done
+
+ local value=$(normalizeConfigParamValue "$envValue")
+
+ saveConfigArrayParam "$key1" "$key2" "$value"
+}
+# END: entrypoint-utils.sh
+
+checkInstanceReady
+
+applyConfigEnvironments
+
+/usr/local/bin/php /var/www/html/daemon.php
+
+exec "$@"
\ No newline at end of file
diff --git a/espocrm_8/docker-entrypoint.sh b/espocrm_8/docker-entrypoint.sh
new file mode 100755
index 0000000..acc13a4
--- /dev/null
+++ b/espocrm_8/docker-entrypoint.sh
@@ -0,0 +1,565 @@
+#!/bin/bash
+
+set -euo pipefail
+
+# entrypoint-utils.sh
+configPrefix="ESPOCRM_CONFIG_"
+
+declare -A configPrefixArrayList=(
+ [logger]="ESPOCRM_CONFIG_LOGGER_"
+ [database]="ESPOCRM_CONFIG_DATABASE_"
+)
+
+compareVersion() {
+ local version1="$1"
+ local version2="$2"
+ local operator="$3"
+
+ echo $(php -r "echo version_compare('$version1', '$version2', '$operator');")
+}
+
+join() {
+ local sep="$1"; shift
+ local out; printf -v out "${sep//%/%%}%s" "$@"
+ echo "${out#$sep}"
+}
+
+getConfigParamFromFile() {
+ local name="$1"
+
+ php -r "
+ if (file_exists('$DOCUMENT_ROOT/data/config-internal.php')) {
+ \$config=include('$DOCUMENT_ROOT/data/config-internal.php');
+
+ if (array_key_exists('$name', \$config)) {
+ die(\$config['$name']);
+ }
+ }
+
+ if (file_exists('$DOCUMENT_ROOT/data/config.php')) {
+ \$config=include('$DOCUMENT_ROOT/data/config.php');
+
+ if (array_key_exists('$name', \$config)) {
+ die(\$config['$name']);
+ }
+ }
+ "
+}
+
+getConfigParam() {
+ local name="$1"
+
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ echo \$config->get('$name');
+ "
+}
+
+# Bool: saveConfigParam "jobRunInParallel" "true"
+# String: saveConfigParam "language" "'en_US'"
+saveConfigParam() {
+ local name="$1"
+ local value="$2"
+
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ if (\$config->get('$name') === $value) {
+ return;
+ }
+
+ \$injectableFactory = \$app->getContainer()->get('injectableFactory');
+ \$configWriter = \$injectableFactory->create('\\Espo\\Core\\Utils\\Config\\ConfigWriter');
+
+ \$configWriter->set('$name', $value);
+ \$configWriter->save();
+ "
+}
+
+saveConfigArrayParam() {
+ local key1="$1"
+ local key2="$2"
+ local value="$3"
+
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ \$arrayValue = \$config->get('$key1') ?? [];
+
+ if (!is_array(\$arrayValue)) {
+ return;
+ }
+
+ if (array_key_exists('$key2', \$arrayValue) && \$arrayValue['$key2'] === $value) {
+ return;
+ }
+
+ \$injectableFactory = \$app->getContainer()->get('injectableFactory');
+ \$configWriter = \$injectableFactory->create('\\Espo\\Core\\Utils\\Config\\ConfigWriter');
+
+ \$arrayValue['$key2'] = $value;
+
+ \$configWriter->set('$key1', \$arrayValue);
+ \$configWriter->save();
+ "
+}
+
+checkInstanceReady() {
+ local isInstalled=$(getConfigParamFromFile "isInstalled")
+
+ if [ -z "$isInstalled" ] || [ "$isInstalled" != 1 ]; then
+ echo >&2 "Instance is not ready: waiting for the installation"
+ exit 0
+ fi
+
+ local maintenanceMode=$(getConfigParamFromFile "maintenanceMode")
+
+ if [ -n "$maintenanceMode" ] && [ "$maintenanceMode" = 1 ]; then
+ echo >&2 "Instance is not ready: waiting for the upgrade"
+ exit 0
+ fi
+
+ if ! verifyDatabaseReady ; then
+ exit 0
+ fi
+}
+
+isDatabaseReady() {
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ \$helper = new \Espo\Core\Utils\Database\Helper(\$config);
+
+ try {
+ \$helper->createPdoConnection();
+ }
+ catch (Exception \$e) {
+ die(false);
+ }
+
+ die(true);
+ "
+}
+
+verifyDatabaseReady() {
+ for i in {1..40}
+ do
+ isReady=$(isDatabaseReady 2>&1)
+
+ if [ -n "$isReady" ]; then
+ return 0 #true
+ fi
+
+ echo >&2 "Waiting Database for receiving connections..."
+ sleep 3
+ done
+
+ echo >&2 "error: Database is not available"
+ return 1 #false
+}
+
+applyConfigEnvironments() {
+ local envName
+ local envValue
+ local configParamName
+ local configParamValue
+
+ compgen -v | while read -r envName; do
+
+ if [[ $envName != "$configPrefix"* ]]; then
+ continue
+ fi
+
+ envValue="${!envName}"
+
+ if isConfigArrayParam "$envName" ; then
+ saveConfigArrayValue "$envName" "$envValue"
+ continue
+ fi
+
+ saveConfigValue "$envName" "$envValue"
+
+ done
+}
+
+isValueQuoted() {
+ local value="$1"
+
+ php -r "
+ echo isQuote('$value');
+
+ function isQuote (\$value) {
+ \$value = trim(\$value);
+
+ if (\$value === '0') {
+ return false;
+ }
+
+ if (empty(\$value)) {
+ return true;
+ }
+
+ if (filter_var(\$value, FILTER_VALIDATE_IP)) {
+ return true;
+ }
+
+ if (!preg_match('/[^0-9.]+/', \$value)) {
+ return false;
+ }
+
+ if (in_array(\$value, ['null', '1'], true)) {
+ return false;
+ }
+
+ if (in_array(\$value, ['true', 'false'])) {
+ return false;
+ }
+
+ return true;
+ }
+ "
+}
+
+normalizeConfigParamName() {
+ local value="$1"
+ local prefix=${2:-"$configPrefix"}
+
+ php -r "
+ \$value = str_ireplace('$prefix', '', '$value');
+ \$value = strtolower(\$value);
+
+ \$value = preg_replace_callback(
+ '/_([a-zA-Z])/',
+ function (\$matches) {
+ return strtoupper(\$matches[1]);
+ },
+ \$value
+ );
+
+ echo \$value;
+ "
+}
+
+normalizeConfigParamValue() {
+ local value=${1//\'/\\\'}
+
+ local isValueQuoted=$(isValueQuoted "$value")
+
+ if [ -n "$isValueQuoted" ] && [ "$isValueQuoted" = 1 ]; then
+ echo "'$value'"
+ return
+ fi
+
+ echo "$value"
+}
+
+isConfigArrayParam() {
+ local envName="$1"
+
+ for i in "${!configPrefixArrayList[@]}"
+ do
+ if [[ "$envName" != ${configPrefixArrayList[$i]}* ]]; then
+ continue
+ fi
+
+ return 0 #true
+ done
+
+ return 1 #false
+}
+
+saveConfigValue() {
+ local envName="$1"
+ local envValue="$2"
+
+ local key=$(normalizeConfigParamName "$envName")
+ local value=$(normalizeConfigParamValue "$envValue")
+
+ saveConfigParam "$key" "$value"
+}
+
+saveConfigArrayValue() {
+ local envName="$1"
+ local envValue="$2"
+
+ for i in "${!configPrefixArrayList[@]}"
+ do
+ if [[ "$envName" != ${configPrefixArrayList[$i]}* ]]; then
+ continue
+ fi
+
+ local key1="$i"
+ local key2=$(normalizeConfigParamName "$envName" "${configPrefixArrayList[$i]}")
+
+ break
+ done
+
+ local value=$(normalizeConfigParamValue "$envValue")
+
+ saveConfigArrayParam "$key1" "$key2" "$value"
+}
+# END: entrypoint-utils.sh
+
+installationType() {
+ if [ -f "$DOCUMENT_ROOT/data/config.php" ]; then
+ local isInstalled=$(getConfigParamFromFile "isInstalled")
+
+ if [ -n "$isInstalled" ] && [ "$isInstalled" = 1 ]; then
+ local installedVersion=$(getConfigParamFromFile "version")
+ local isVersionGreater=$(compareVersion "$ESPOCRM_VERSION" "$installedVersion" ">")
+
+ if [ -n "$isVersionGreater" ]; then
+ echo "upgrade"
+ return
+ fi
+
+ echo "skip"
+ return
+ fi
+
+ echo "reinstall"
+ return
+ fi
+
+ echo "install"
+}
+
+actionInstall() {
+ if [ ! -d "$SOURCE_FILES" ]; then
+ echo >&2 "error: Source files [$SOURCE_FILES] are not found."
+ exit 1
+ fi
+
+ cp -a "$SOURCE_FILES/." "$DOCUMENT_ROOT/"
+
+ installEspocrm
+}
+
+actionReinstall() {
+ if [ -f "$DOCUMENT_ROOT/install/config.php" ]; then
+ sed -i "s/'isInstalled' => true/'isInstalled' => false/g" "$DOCUMENT_ROOT/install/config.php"
+ fi
+
+ installEspocrm
+}
+
+actionUpgrade() {
+ UPGRADE_NUMBER=$((UPGRADE_NUMBER+1))
+
+ if [ $UPGRADE_NUMBER -gt $MAX_UPGRADE_COUNT ];then
+ echo >&2 "The MAX_UPGRADE_COUNT exceded. The upgrading process has been stopped."
+ return
+ fi
+
+ local installedVersion=$(getConfigParamFromFile "version")
+ local isVersionEqual=$(compareVersion "$installedVersion" "$ESPOCRM_VERSION" ">=")
+
+ if [ -n "$isVersionEqual" ]; then
+ echo >&2 "Upgrade process is finished. EspoCRM version is $installedVersion."
+ return
+ fi
+
+ echo >&2 "Start upgrading process from version $installedVersion."
+
+ if ! runUpgradeStep ; then
+ return
+ fi
+
+ actionUpgrade
+}
+
+runUpgradeStep() {
+ local result=$(php command.php upgrade -y --toVersion="$ESPOCRM_VERSION")
+
+ if [[ "$result" == *"Error:"* ]]; then
+ echo >&2 "error: Upgrade error, more details:"
+ echo >&2 "$result"
+
+ return 1 #false
+ fi
+
+ return 0 #true
+}
+
+installEspocrm() {
+ echo >&2 "Start EspoCRM installation"
+
+ find . -type d -exec chmod 755 {} + && find . -type f -exec chmod 644 {} +
+ find data custom/Espo/Custom client/custom -type d -exec chmod 775 {} + && find data custom/Espo/Custom client/custom -type f -exec chmod 664 {} +
+ chmod 775 application/Espo/Modules client/modules
+
+ declare -a preferences=()
+ for optionName in "${!OPTIONAL_PARAMS[@]}"
+ do
+ local varName="${OPTIONAL_PARAMS[$optionName]}"
+ if [ -n "${!varName-}" ]; then
+ preferences+=("${optionName}=${!varName}")
+ fi
+ done
+
+ runInstallationStep "step1" "user-lang=${ESPOCRM_LANGUAGE}"
+
+ local databaseHost="${ESPOCRM_DATABASE_HOST}"
+
+ if [ -n "$ESPOCRM_DATABASE_PORT" ]; then
+ databaseHost="${ESPOCRM_DATABASE_HOST}:${ESPOCRM_DATABASE_PORT}"
+ fi
+
+ for i in {1..20}
+ do
+ settingsTestResult=$(runInstallationStep "settingsTest" "dbPlatform=${ESPOCRM_DATABASE_PLATFORM}&hostName=${databaseHost}&dbName=${ESPOCRM_DATABASE_NAME}&dbUserName=${ESPOCRM_DATABASE_USER}&dbUserPass=${ESPOCRM_DATABASE_PASSWORD}" true 2>&1)
+
+ if [[ ! "$settingsTestResult" == *"Error:"* ]]; then
+ break
+ fi
+
+ sleep 5
+ done
+
+ if [[ "$settingsTestResult" == *"Error:"* ]] && [[ "$settingsTestResult" == *"[errorCode] => 2002"* ]]; then
+ echo >&2 "warning: Unable connect to Database server. Continuing anyway"
+ return
+ fi
+
+ runInstallationStep "setupConfirmation" "db-platform=${ESPOCRM_DATABASE_PLATFORM}&host-name=${databaseHost}&db-name=${ESPOCRM_DATABASE_NAME}&db-user-name=${ESPOCRM_DATABASE_USER}&db-user-password=${ESPOCRM_DATABASE_PASSWORD}"
+ runInstallationStep "checkPermission"
+ runInstallationStep "saveSettings" "site-url=${ESPOCRM_SITE_URL}&default-permissions-user=${DEFAULT_OWNER}&default-permissions-group=${DEFAULT_GROUP}"
+ runInstallationStep "buildDatabase"
+ runInstallationStep "createUser" "user-name=${ESPOCRM_ADMIN_USERNAME}&user-pass=${ESPOCRM_ADMIN_PASSWORD}"
+ runInstallationStep "savePreferences" "$(join '&' "${preferences[@]}")"
+ runInstallationStep "finish"
+
+ saveConfigParam "jobRunInParallel" "true"
+
+ echo >&2 "End EspoCRM installation"
+}
+
+runInstallationStep() {
+ local actionName="$1"
+ local returnResult=${3-false}
+
+ if [ -n "${2-}" ]; then
+ local data="$2"
+ local result=$(php install/cli.php -a "$actionName" -d "$data")
+ else
+ local result=$(php install/cli.php -a "$actionName")
+ fi
+
+ if [ "$returnResult" = true ]; then
+ echo >&2 "$result"
+ return
+ fi
+
+ if [[ "$result" == *"Error:"* ]]; then
+ echo >&2 "error: Installation error, more details:"
+ echo >&2 "$result"
+ exit 1
+ fi
+}
+
+# ------------------------- START -------------------------------------
+# Global variables
+DOCUMENT_ROOT="/var/www/html"
+SOURCE_FILES="/usr/src/espocrm"
+MAX_UPGRADE_COUNT=20
+DEFAULT_OWNER="www-data"
+DEFAULT_GROUP="www-data"
+
+if [ "$(id -u)" = '0' ]; then
+ if [[ "$1" == "apache2"* ]]; then
+ wrongSymbol='#'
+ DEFAULT_OWNER="${APACHE_RUN_USER:-www-data}"
+ DEFAULT_OWNER="${DEFAULT_OWNER#$wrongSymbol}"
+
+ DEFAULT_GROUP="${APACHE_RUN_GROUP:-www-data}"
+ DEFAULT_GROUP="${DEFAULT_GROUP#$wrongSymbol}"
+ fi
+else
+ DEFAULT_OWNER="$(id -u)"
+ DEFAULT_GROUP="$(id -g)"
+fi
+
+declare -A DEFAULTS=(
+ ['ESPOCRM_DATABASE_PLATFORM']='Mysql'
+ ['ESPOCRM_DATABASE_HOST']='mysql'
+ ['ESPOCRM_DATABASE_PORT']=''
+ ['ESPOCRM_DATABASE_NAME']='espocrm'
+ ['ESPOCRM_DATABASE_USER']='root'
+ ['ESPOCRM_DATABASE_PASSWORD']='password'
+ ['ESPOCRM_ADMIN_USERNAME']='admin'
+ ['ESPOCRM_ADMIN_PASSWORD']='password'
+ ['ESPOCRM_LANGUAGE']='en_US'
+ ['ESPOCRM_SITE_URL']='http://localhost'
+)
+
+declare -A OPTIONAL_PARAMS=(
+ ['language']='ESPOCRM_LANGUAGE'
+ ['dateFormat']='ESPOCRM_DATE_FORMAT'
+ ['timeFormat']='ESPOCRM_TIME_FORMAT'
+ ['timeZone']='ESPOCRM_TIME_ZONE'
+ ['weekStart']='ESPOCRM_WEEK_START'
+ ['defaultCurrency']='ESPOCRM_DEFAULT_CURRENCY'
+ ['thousandSeparator']='ESPOCRM_THOUSAND_SEPARATOR'
+ ['decimalMark']='ESPOCRM_DECIMAL_MARK'
+)
+
+for defaultParam in "${!DEFAULTS[@]}"
+do
+ if [ -z "${!defaultParam-}" ]; then
+ declare "${defaultParam}"="${DEFAULTS[$defaultParam]}"
+ fi
+done
+
+installationType=$(installationType)
+
+case $installationType in
+ install)
+ echo >&2 "Run \"install\" action."
+ actionInstall
+ chown -R $DEFAULT_OWNER:$DEFAULT_GROUP "$DOCUMENT_ROOT"
+ ;;
+
+ reinstall)
+ echo >&2 "Run \"reinstall\" action."
+ actionReinstall
+ chown -R $DEFAULT_OWNER:$DEFAULT_GROUP "$DOCUMENT_ROOT"
+ ;;
+
+ upgrade)
+ echo >&2 "Run \"upgrade\" action."
+
+ if verifyDatabaseReady ; then
+ UPGRADE_NUMBER=0
+ actionUpgrade
+ chown -R $DEFAULT_OWNER:$DEFAULT_GROUP "$DOCUMENT_ROOT"
+ else
+ echo "error: Unable to upgrade the instance. Starting the current version."
+ fi
+ ;;
+
+ skip)
+ ;;
+
+ *)
+ echo >&2 "error: Unknown installation type [$installationType]"
+ exit 1
+ ;;
+esac
+
+applyConfigEnvironments
+# ------------------------- END -------------------------------------
+
+exec "$@"
diff --git a/espocrm_8/docker-websocket.sh b/espocrm_8/docker-websocket.sh
new file mode 100755
index 0000000..acad517
--- /dev/null
+++ b/espocrm_8/docker-websocket.sh
@@ -0,0 +1,324 @@
+#!/bin/bash
+
+set -eu
+
+DOCUMENT_ROOT="/var/www/html"
+
+# entrypoint-utils.sh
+configPrefix="ESPOCRM_CONFIG_"
+
+declare -A configPrefixArrayList=(
+ [logger]="ESPOCRM_CONFIG_LOGGER_"
+ [database]="ESPOCRM_CONFIG_DATABASE_"
+)
+
+compareVersion() {
+ local version1="$1"
+ local version2="$2"
+ local operator="$3"
+
+ echo $(php -r "echo version_compare('$version1', '$version2', '$operator');")
+}
+
+join() {
+ local sep="$1"; shift
+ local out; printf -v out "${sep//%/%%}%s" "$@"
+ echo "${out#$sep}"
+}
+
+getConfigParamFromFile() {
+ local name="$1"
+
+ php -r "
+ if (file_exists('$DOCUMENT_ROOT/data/config-internal.php')) {
+ \$config=include('$DOCUMENT_ROOT/data/config-internal.php');
+
+ if (array_key_exists('$name', \$config)) {
+ die(\$config['$name']);
+ }
+ }
+
+ if (file_exists('$DOCUMENT_ROOT/data/config.php')) {
+ \$config=include('$DOCUMENT_ROOT/data/config.php');
+
+ if (array_key_exists('$name', \$config)) {
+ die(\$config['$name']);
+ }
+ }
+ "
+}
+
+getConfigParam() {
+ local name="$1"
+
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ echo \$config->get('$name');
+ "
+}
+
+# Bool: saveConfigParam "jobRunInParallel" "true"
+# String: saveConfigParam "language" "'en_US'"
+saveConfigParam() {
+ local name="$1"
+ local value="$2"
+
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ if (\$config->get('$name') === $value) {
+ return;
+ }
+
+ \$injectableFactory = \$app->getContainer()->get('injectableFactory');
+ \$configWriter = \$injectableFactory->create('\\Espo\\Core\\Utils\\Config\\ConfigWriter');
+
+ \$configWriter->set('$name', $value);
+ \$configWriter->save();
+ "
+}
+
+saveConfigArrayParam() {
+ local key1="$1"
+ local key2="$2"
+ local value="$3"
+
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ \$arrayValue = \$config->get('$key1') ?? [];
+
+ if (!is_array(\$arrayValue)) {
+ return;
+ }
+
+ if (array_key_exists('$key2', \$arrayValue) && \$arrayValue['$key2'] === $value) {
+ return;
+ }
+
+ \$injectableFactory = \$app->getContainer()->get('injectableFactory');
+ \$configWriter = \$injectableFactory->create('\\Espo\\Core\\Utils\\Config\\ConfigWriter');
+
+ \$arrayValue['$key2'] = $value;
+
+ \$configWriter->set('$key1', \$arrayValue);
+ \$configWriter->save();
+ "
+}
+
+checkInstanceReady() {
+ local isInstalled=$(getConfigParamFromFile "isInstalled")
+
+ if [ -z "$isInstalled" ] || [ "$isInstalled" != 1 ]; then
+ echo >&2 "Instance is not ready: waiting for the installation"
+ exit 0
+ fi
+
+ local maintenanceMode=$(getConfigParamFromFile "maintenanceMode")
+
+ if [ -n "$maintenanceMode" ] && [ "$maintenanceMode" = 1 ]; then
+ echo >&2 "Instance is not ready: waiting for the upgrade"
+ exit 0
+ fi
+
+ if ! verifyDatabaseReady ; then
+ exit 0
+ fi
+}
+
+isDatabaseReady() {
+ php -r "
+ require_once('$DOCUMENT_ROOT/bootstrap.php');
+
+ \$app = new \Espo\Core\Application();
+ \$config = \$app->getContainer()->get('config');
+
+ \$helper = new \Espo\Core\Utils\Database\Helper(\$config);
+
+ try {
+ \$helper->createPdoConnection();
+ }
+ catch (Exception \$e) {
+ die(false);
+ }
+
+ die(true);
+ "
+}
+
+verifyDatabaseReady() {
+ for i in {1..40}
+ do
+ isReady=$(isDatabaseReady 2>&1)
+
+ if [ -n "$isReady" ]; then
+ return 0 #true
+ fi
+
+ echo >&2 "Waiting Database for receiving connections..."
+ sleep 3
+ done
+
+ echo >&2 "error: Database is not available"
+ return 1 #false
+}
+
+applyConfigEnvironments() {
+ local envName
+ local envValue
+ local configParamName
+ local configParamValue
+
+ compgen -v | while read -r envName; do
+
+ if [[ $envName != "$configPrefix"* ]]; then
+ continue
+ fi
+
+ envValue="${!envName}"
+
+ if isConfigArrayParam "$envName" ; then
+ saveConfigArrayValue "$envName" "$envValue"
+ continue
+ fi
+
+ saveConfigValue "$envName" "$envValue"
+
+ done
+}
+
+isValueQuoted() {
+ local value="$1"
+
+ php -r "
+ echo isQuote('$value');
+
+ function isQuote (\$value) {
+ \$value = trim(\$value);
+
+ if (\$value === '0') {
+ return false;
+ }
+
+ if (empty(\$value)) {
+ return true;
+ }
+
+ if (filter_var(\$value, FILTER_VALIDATE_IP)) {
+ return true;
+ }
+
+ if (!preg_match('/[^0-9.]+/', \$value)) {
+ return false;
+ }
+
+ if (in_array(\$value, ['null', '1'], true)) {
+ return false;
+ }
+
+ if (in_array(\$value, ['true', 'false'])) {
+ return false;
+ }
+
+ return true;
+ }
+ "
+}
+
+normalizeConfigParamName() {
+ local value="$1"
+ local prefix=${2:-"$configPrefix"}
+
+ php -r "
+ \$value = str_ireplace('$prefix', '', '$value');
+ \$value = strtolower(\$value);
+
+ \$value = preg_replace_callback(
+ '/_([a-zA-Z])/',
+ function (\$matches) {
+ return strtoupper(\$matches[1]);
+ },
+ \$value
+ );
+
+ echo \$value;
+ "
+}
+
+normalizeConfigParamValue() {
+ local value=${1//\'/\\\'}
+
+ local isValueQuoted=$(isValueQuoted "$value")
+
+ if [ -n "$isValueQuoted" ] && [ "$isValueQuoted" = 1 ]; then
+ echo "'$value'"
+ return
+ fi
+
+ echo "$value"
+}
+
+isConfigArrayParam() {
+ local envName="$1"
+
+ for i in "${!configPrefixArrayList[@]}"
+ do
+ if [[ "$envName" != ${configPrefixArrayList[$i]}* ]]; then
+ continue
+ fi
+
+ return 0 #true
+ done
+
+ return 1 #false
+}
+
+saveConfigValue() {
+ local envName="$1"
+ local envValue="$2"
+
+ local key=$(normalizeConfigParamName "$envName")
+ local value=$(normalizeConfigParamValue "$envValue")
+
+ saveConfigParam "$key" "$value"
+}
+
+saveConfigArrayValue() {
+ local envName="$1"
+ local envValue="$2"
+
+ for i in "${!configPrefixArrayList[@]}"
+ do
+ if [[ "$envName" != ${configPrefixArrayList[$i]}* ]]; then
+ continue
+ fi
+
+ local key1="$i"
+ local key2=$(normalizeConfigParamName "$envName" "${configPrefixArrayList[$i]}")
+
+ break
+ done
+
+ local value=$(normalizeConfigParamValue "$envValue")
+
+ saveConfigArrayParam "$key1" "$key2" "$value"
+}
+# END: entrypoint-utils.sh
+
+checkInstanceReady
+
+applyConfigEnvironments
+
+/usr/local/bin/php /var/www/html/websocket.php
+
+exec "$@"
\ No newline at end of file |
We would like to add the EspoCRM to the official image repository.
Checklist for Review
NOTE: This checklist is intended for the use of the Official Images maintainers both to track the status of your PR and to help inform you and others of where we're at. As such, please leave the "checking" of items to the repository maintainers. If there is a point below for which you would like to provide additional information or note completion, please do so by commenting on the PR. Thanks! (and thanks for staying patient with us ❤️)
foobar
needs Node.js, hasFROM node:...
instead of grabbingnode
via other means been considered?)FROM scratch
, tarballs only exist in a single commit within the associated history?