Add EspoCRM official image
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 :heart:)
- [x] associated with or contacted upstream?
- https://github.com/espocrm/docker
- [x] does it fit into one of the common categories? ("service", "language stack", "base distribution")
- service
- [x] is it reasonably popular, or does it solve a particular use case well?
- [x] does a documentation PR exist? (should be reviewed and merged at roughly the same time so that we don't have an empty image page on the Hub for very long)
- https://github.com/docker-library/docs/pull/1672
- [x] dockerization review for best practices and cache gotchas/improvements (ala the official review guidelines)?
- [ ] 2+ dockerization review?
- [x] existing official images have been considered as a base? (ie, if
foobarneeds Node.js, hasFROM node:...instead of grabbingnodevia other means been considered?) - [x] if
FROM scratch, tarballs only exist in a single commit within the associated history? - [x] passes current tests? any simple new tests that might be appropriate to add? (https://github.com/docker-library/official-images/tree/master/test)
@tianon please have a look. Thanks
@tianon, @yosifkit, please take a look.
I would like to say that while creating the docker image we followed all the recommendations. For example:
- we created the Dockerfile easy to understand/read.
- using SHA256 checksum in the Dockerfile while image build.
- added and tested on different architectures.
- implemented recommendation about tags.
- updating the docker image after new versions are released.
@tianon, @yosifkit Is there any chance to review the image?
Is there any chance to review the image?
Hi @tianon, @yosifkit, thank you for your attention, if there something wrong, please write and we will fix it. Is there any possibility to speed up the process?
@tianon, @yosifkit, look the unofficial image has been installed 50K+ times, it makes sense to create official image

apk update; \
apk add --no-cache --virtual .build-deps \
The apk update here is redundant -- --no-cache implies updating the package lists.
php7-gd \
php7-exif \
This is definitely not right -- when you're FROM php:xxx, installing php-related packages via apk or apt-get will give you two versions of PHP (the version provided by the base image, and the version from Alpine or Debian). What you intended instead is probably to make use of docker-php-ext-install (and possibly docker-php-ext-configure) to get gd and exif installed for the PHP provided by the base image (exactly as is done lower down in this same Dockerfile).
# 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 zeromq from source? Alpine has a libzmq package (and the corresponding zeromq-dev package), and in Alpine 3.12 the version is the same 4.3.2 being installed here.
Additionally, why are we grabbing the latest master branch of https://github.com/zeromq/php-zmq.git ? I see the latest release on that repository is from 2013, so I could understand if that's not quite new enough, but just pulling directly from master is not going to be very reliable over time, and pulling from a specific commit would be better (likely also giving https://github.com/zeromq/php-zmq/issues/203 some attention -- it hasn't had a release because they're looking for new maintainers, so it might not be the best platform to be based on right now).
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 DEFAULT_OWNER but rather do some detection based on id -u / id -g so that users can run the image as an arbitrary user (especially since OpenStack and some Kubernetes configurations will require that ability).
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 /var/www/html in the image, and the VOLUME then defined to be only the specific directory or directories where EspoCRM actually stores mutable state, thus encouraging users to adopt the appropriate container-upgrade paradigms to update their instance of EspoCRM from version to version by updating to newer versions of the container image instead of having the image include complex logic to try and maintain and old-style installation of EspoCRM within a VOLUME for them?
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 crond as a completely separate process/container (there are several other PHP-based images that are good examples of what I mean, such as nextcloud).
# 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 VOLUME, we've seen that many users have been fairly vocal about them existing in many images since they can't be removed, so it could make sense to not have any volume and just document the mutable folders that should be saved -- e.g. drupal.
Thanks @tianon, @yosifkit for your reviews. We will implement your recommendations soon.
@tianon, @yosifkit thanks again for your reviews. We made changes to your recommendations. Please check it again. Thanks
apk update; \ apk add --no-cache --virtual .build-deps \The
apk updatehere is redundant ----no-cacheimplies updating the package lists.
Fixed
php7-gd \ php7-exif \This is definitely not right -- when you're
FROM php:xxx, installingphp-related packages viaapkorapt-getwill give you two versions of PHP (the version provided by the base image, and the version from Alpine or Debian). What you intended instead is probably to make use ofdocker-php-ext-install(and possiblydocker-php-ext-configure) to getgdandexifinstalled for the PHP provided by the base image (exactly as is done lower down in this sameDockerfile).
Fixed
# 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
zeromqfrom source? Alpine has alibzmqpackage (and the correspondingzeromq-devpackage), and in Alpine 3.12 the version is the same 4.3.2 being installed here.Additionally, why are we grabbing the latest
masterbranch of https://github.com/zeromq/php-zmq.git ? I see the latest release on that repository is from 2013, so I could understand if that's not quite new enough, but just pulling directly frommasteris not going to be very reliable over time, and pulling from a specific commit would be better (likely also giving zeromq/php-zmq#203 some attention -- it hasn't had a release because they're looking for new maintainers, so it might not be the best platform to be based on right now).
The installation of php-zmq is optimized. We cannot completely abandon its use, because it's required in EspoCRM.
ENV DOCUMENT_ROOT /var/www/html ENV DEFAULT_OWNER www-data ENV DEFAULT_GROUP www-dataWhat 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
DEFAULT_OWNERbut rather do some detection based onid -u/id -gso that users can run the image as an arbitrary user (especially since OpenStack and some Kubernetes configurations will require that ability).
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.
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 a04d4fdadd877d684abd885dc7356ea2f0593e8a805851d79d4a6f68b6168700This 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?
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 ESPOCRM_UPGRADE_VERSION and ESPOCRM_UPGRADE_URL is required only if we need to upgrade the EspoCRM files / database to the specified version ESPOCRM_VERSION.
Currently, we are saving a link of this upgrade. Also, we can download this upgrade while building the docker image itself. What way would you recommend?
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
/var/www/htmlin the image, and theVOLUMEthen defined to be only the specific directory or directories where EspoCRM actually stores mutable state, thus encouraging users to adopt the appropriate container-upgrade paradigms to update their instance of EspoCRM from version to version by updating to newer versions of the container image instead of having the image include complex logic to try and maintain and old-style installation of EspoCRM within aVOLUMEfor them?
Related to
VOLUME, we've seen that many users have been fairly vocal about them existing in many images since they can't be removed, so it could make sense to not have any volume and just document the mutable folders that should be saved -- e.g. drupal.
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?
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
crondas a completely separate process/container (there are several other PHP-based images that are good examples of what I mean, such asnextcloud).
Fixed, thanks for the example.
# Set timezone RUN echo "UTC" > /etc/timezone && dpkg-reconfigure --frontend noninteractive tzdataThis 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.
Fixed
We highly appreciate the feedback and recommendations you’ve previously shared with us. Since we have made all the changes you’ve mentioned, we would like to ask you to review the image again @tianon, @yosifkit.
Thank you for your patience. :bow:
The php-zmq installation looks a lot better now; I'd just add that it looks like /usr/php-zmq is unnecessary at the end of it, and could probably be deleted. :+1:
(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 git clone, but that's not strictly necessary.)
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?
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:
- run container
- copies EspoCRM code to volume
- performs database/application initialization
- runs Apache/EspoCRM
- recreate container with newer version
- downloads upgrade delta
- applies upgrade delta patching to code in volume (ignoring the already upgraded code that exists in the image)
- performs applicable database upgrades
- runs Apache/EspoCRM
Proposed flow:
- run container
- performs database/application initialization
- runs Apache/EspoCRM
- recreate container with newer version
- performs applicable database upgrades
- runs Apache/EspoCRM
In this simpler flow, instead of having all of /var/www/html be a volume, you would have that be part of the image and only specific subdirectories with content that needs to be persisted (user uploads, etc) would be explicit volumes. This way, the image provides a more "container-native" workflow of the image being the source-of-truth for which version of the application we're running instead of our data volume (which in Wordpress's case is a consequence of how Wordpress works / expects to work).
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. We will try to implement your recommendations soon.
@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:
application/Espo/Modulesclient/modulescustom/Espo/Customclient/custom
At this point I see 2 issues with the new process. For successful upgrade EspoCRM we have to do:
- Updating files. Copy new files and delete old ones.
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 application/Espo/Modules and client/modules directories. By default these directories are not empty and contain internal module Crm. So, when only mount the volumes of modules directories, the files of Crm module might not be updated or deleted.
- Updating database, configuration parameters via upgrade script.
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 custom and modules directories, the script will not be executed.
For example, the new process can be:
- We have espocrm-docker v6.0.0 container.
- Run espocrm-docker v6.1.0 container. In this case, our files in
Crmmodule and data in the database can be out of date.
The current process implemented in "entrypoint" script with the mounted volume /var/www/html are:
- We have espocrm-docker v6.0.0 container
- Run espocrm-docker v6.1.0 container. Files will be checked at the start and run an upgrade 6.1.0. The files will be updated and all scripts will be executed.
It would be great if you have any suggestions for resolving these issues. Thanks
@tianon , @yosifkit is there anything you need?
Diff for 7bb8f431222342aaa9549110eef02fdd4d96183f:
diff --git a/_bashbrew-cat b/_bashbrew-cat
index bdfae4a..bc630ca 100644
--- a/_bashbrew-cat
+++ b/_bashbrew-cat
@@ -1 +1,15 @@
-Maintainers: New Image! :D (@docker-library-bot)
+Maintainers: Taras Machyshyn <[email protected]> (@tmachyshyn)
+GitRepo: https://github.com/espocrm/espocrm-docker.git
+GitCommit: 2c06b0f3c1c130a3cceea429c6d8314bfa1f2308
+
+Tags: apache, 7.3.1-apache, 7.3-apache, 7-apache, latest, 7.3.1, 7.3, 7
+Architectures: amd64, arm32v7, i386, s390x
+Directory: apache
+
+Tags: fpm, 7.3.1-fpm, 7.3-fpm, 7-fpm
+Architectures: amd64, arm32v7, i386, s390x
+Directory: fpm
+
+Tags: fpm-alpine, 7.3.1-fpm-alpine, 7.3-fpm-alpine, 7-fpm-alpine
+Architectures: amd64, arm32v6, arm32v7, arm64v8, i386, ppc64le, s390x
+Directory: fpm-alpine
diff --git a/_bashbrew-list b/_bashbrew-list
index e69de29..c6e3f57 100644
--- a/_bashbrew-list
+++ b/_bashbrew-list
@@ -0,0 +1,16 @@
+espocrm:7
+espocrm:7-apache
+espocrm:7-fpm
+espocrm:7-fpm-alpine
+espocrm:7.3
+espocrm:7.3-apache
+espocrm:7.3-fpm
+espocrm:7.3-fpm-alpine
+espocrm:7.3.1
+espocrm:7.3.1-apache
+espocrm:7.3.1-fpm
+espocrm:7.3.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..db5c474 100644
--- a/_bashbrew-list-build-order
+++ b/_bashbrew-list-build-order
@@ -0,0 +1,3 @@
+espocrm:7
+espocrm:7-fpm
+espocrm:7-fpm-alpine
diff --git a/espocrm_7-fpm-alpine/Dockerfile b/espocrm_7-fpm-alpine/Dockerfile
new file mode 100644
index 0000000..e2fecb4
--- /dev/null
+++ b/espocrm_7-fpm-alpine/Dockerfile
@@ -0,0 +1,73 @@
+FROM php:8.1-fpm-alpine
+
+# Install php libs
+RUN set -ex; \
+ apk add --no-cache --virtual .build-deps \
+ libzip-dev \
+ libpng-dev \
+ libjpeg-turbo-dev \
+ libwebp-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; \
+ docker-php-ext-install gd; \
+ docker-php-ext-install exif; \
+ docker-php-ext-install ldap; \
+ docker-php-ext-install imap; \
+ docker-php-ext-install pcntl; \
+ docker-php-ext-install zip; \
+ docker-php-ext-install pdo_mysql; \
+ docker-php-ext-install pcntl; \
+ docker-php-ext-install posix; \
+ docker-php-ext-enable zmq; \
+ docker-php-ext-install bcmath
+
+# 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 7.3.1
+ENV ESPOCRM_SHA256 1ae8a0539ad5409a08e5e96b8ecdb31854089440de60a1647497cc3b956ce9ca
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-7.3.1.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-7.3.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_7-fpm-alpine/docker-daemon.sh b/espocrm_7-fpm-alpine/docker-daemon.sh
new file mode 100755
index 0000000..a087e93
--- /dev/null
+++ b/espocrm_7-fpm-alpine/docker-daemon.sh
@@ -0,0 +1,233 @@
+#!/bin/bash
+
+set -eu
+
+DOCUMENT_ROOT="/var/www/html"
+
+# entrypoint-utils.sh
+configPrefix="ESPOCRM_CONFIG_"
+
+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) {
+ \$injectableFactory = \$app->getContainer()->get('injectableFactory');
+ \$configWriter = \$injectableFactory->create('\\Espo\\Core\\Utils\\Config\\ConfigWriter');
+
+ \$configWriter->set('$name', $value);
+ \$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 MySQL for receiving connections..."
+ sleep 3
+ done
+
+ echo >&2 "error: MySQL 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
+
+ envValue="${!envName}"
+
+ configParamName=$(normalizeConfigParamName "$envName")
+ configParamValue=$(normalizeConfigParamValue "$envValue")
+
+ saveConfigParam "$configParamName" "$configParamValue"
+
+ fi
+
+ done
+}
+
+isQuoteValue() {
+ 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 (!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"
+
+ php -r "
+ \$value = str_ireplace('$configPrefix', '', '$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 isQuoteValue=$(isQuoteValue "$value")
+
+ if [ -n "$isQuoteValue" ] && [ "$isQuoteValue" = 1 ]; then
+ echo "'$value'"
+ return
+ fi
+
+ echo "$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_7-fpm-alpine/docker-entrypoint.sh b/espocrm_7-fpm-alpine/docker-entrypoint.sh
new file mode 100755
index 0000000..a83edcf
--- /dev/null
+++ b/espocrm_7-fpm-alpine/docker-entrypoint.sh
@@ -0,0 +1,463 @@
+#!/bin/bash
+
+set -euo pipefail
+
+# entrypoint-utils.sh
+configPrefix="ESPOCRM_CONFIG_"
+
+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) {
+ \$injectableFactory = \$app->getContainer()->get('injectableFactory');
+ \$configWriter = \$injectableFactory->create('\\Espo\\Core\\Utils\\Config\\ConfigWriter');
+
+ \$configWriter->set('$name', $value);
+ \$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 MySQL for receiving connections..."
+ sleep 3
+ done
+
+ echo >&2 "error: MySQL 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
+
+ envValue="${!envName}"
+
+ configParamName=$(normalizeConfigParamName "$envName")
+ configParamValue=$(normalizeConfigParamValue "$envValue")
+
+ saveConfigParam "$configParamName" "$configParamValue"
+
+ fi
+
+ done
+}
+
+isQuoteValue() {
+ 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 (!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"
+
+ php -r "
+ \$value = str_ireplace('$configPrefix', '', '$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 isQuoteValue=$(isQuoteValue "$value")
+
+ if [ -n "$isQuoteValue" ] && [ "$isQuoteValue" = 1 ]; then
+ echo "'$value'"
+ return
+ fi
+
+ echo "$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."
+
+ runUpgradeStep || {
+ return
+ }
+
+ 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"
+ exit 1
+ fi
+}
+
+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}"
+
+ for i in {1..20}
+ do
+ settingsTestResult=$(runInstallationStep "settingsTest" "hostName=${ESPOCRM_DATABASE_HOST}&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: Cannot connect to MySQL server. Continuing anyway"
+ return
+ fi
+
+ runInstallationStep "setupConfirmation" "host-name=${ESPOCRM_DATABASE_HOST}&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=100
+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_HOST']='mysql'
+ ['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: Uknown installation type [$installationType]"
+ exit 1
+ ;;
+esac
+
+applyConfigEnvironments
+# ------------------------- END -------------------------------------
+
+exec "$@"
diff --git a/espocrm_7-fpm-alpine/docker-websocket.sh b/espocrm_7-fpm-alpine/docker-websocket.sh
new file mode 100755
index 0000000..7b919a3
--- /dev/null
+++ b/espocrm_7-fpm-alpine/docker-websocket.sh
@@ -0,0 +1,233 @@
+#!/bin/bash
+
+set -eu
+
+DOCUMENT_ROOT="/var/www/html"
+
+# entrypoint-utils.sh
+configPrefix="ESPOCRM_CONFIG_"
+
+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) {
+ \$injectableFactory = \$app->getContainer()->get('injectableFactory');
+ \$configWriter = \$injectableFactory->create('\\Espo\\Core\\Utils\\Config\\ConfigWriter');
+
+ \$configWriter->set('$name', $value);
+ \$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 MySQL for receiving connections..."
+ sleep 3
+ done
+
+ echo >&2 "error: MySQL 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
+
+ envValue="${!envName}"
+
+ configParamName=$(normalizeConfigParamName "$envName")
+ configParamValue=$(normalizeConfigParamValue "$envValue")
+
+ saveConfigParam "$configParamName" "$configParamValue"
+
+ fi
+
+ done
+}
+
+isQuoteValue() {
+ 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 (!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"
+
+ php -r "
+ \$value = str_ireplace('$configPrefix', '', '$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 isQuoteValue=$(isQuoteValue "$value")
+
+ if [ -n "$isQuoteValue" ] && [ "$isQuoteValue" = 1 ]; then
+ echo "'$value'"
+ return
+ fi
+
+ echo "$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_7-fpm/Dockerfile b/espocrm_7-fpm/Dockerfile
new file mode 100644
index 0000000..ac840fa
--- /dev/null
+++ b/espocrm_7-fpm/Dockerfile
@@ -0,0 +1,99 @@
+FROM php:8.1-fpm
+
+# Install php libs
+RUN set -ex; \
+ \
+ aptMarkList="$(apt-mark showmanual)"; \
+ \
+ apt-get update; \
+ apt-get install -y --no-install-recommends \
+ libjpeg-dev \
+ libpng-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-install pdo_mysql; \
+ docker-php-ext-install zip; \
+ docker-php-ext-configure gd --with-jpeg; \
+ docker-php-ext-install gd; \
+ PHP_OPENSSL=yes docker-php-ext-configure imap --with-kerberos --with-imap-ssl; \
+ docker-php-ext-install imap; \
+ docker-php-ext-configure ldap --with-libdir="lib/$debMultiarch"; \
+ docker-php-ext-install ldap; \
+ docker-php-ext-install exif; \
+ docker-php-ext-install pcntl; \
+ docker-php-ext-install posix; \
+ docker-php-ext-enable zmq; \
+ docker-php-ext-install bcmath; \
+ \
+# 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 dpkg-query -S \
+ | cut -d: -f1 \
+ | sort -u \
+ | xargs -rt apt-mark manual; \
+ \
+ apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false
+
+# Install required libs
+RUN set -ex; \
+ 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 7.3.1
+ENV ESPOCRM_SHA256 1ae8a0539ad5409a08e5e96b8ecdb31854089440de60a1647497cc3b956ce9ca
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-7.3.1.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-7.3.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_7-fpm/docker-daemon.sh b/espocrm_7-fpm/docker-daemon.sh
new file mode 100755
index 0000000..a087e93
--- /dev/null
+++ b/espocrm_7-fpm/docker-daemon.sh
@@ -0,0 +1,233 @@
+#!/bin/bash
+
+set -eu
+
+DOCUMENT_ROOT="/var/www/html"
+
+# entrypoint-utils.sh
+configPrefix="ESPOCRM_CONFIG_"
+
+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) {
+ \$injectableFactory = \$app->getContainer()->get('injectableFactory');
+ \$configWriter = \$injectableFactory->create('\\Espo\\Core\\Utils\\Config\\ConfigWriter');
+
+ \$configWriter->set('$name', $value);
+ \$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 MySQL for receiving connections..."
+ sleep 3
+ done
+
+ echo >&2 "error: MySQL 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
+
+ envValue="${!envName}"
+
+ configParamName=$(normalizeConfigParamName "$envName")
+ configParamValue=$(normalizeConfigParamValue "$envValue")
+
+ saveConfigParam "$configParamName" "$configParamValue"
+
+ fi
+
+ done
+}
+
+isQuoteValue() {
+ 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 (!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"
+
+ php -r "
+ \$value = str_ireplace('$configPrefix', '', '$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 isQuoteValue=$(isQuoteValue "$value")
+
+ if [ -n "$isQuoteValue" ] && [ "$isQuoteValue" = 1 ]; then
+ echo "'$value'"
+ return
+ fi
+
+ echo "$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_7-fpm/docker-entrypoint.sh b/espocrm_7-fpm/docker-entrypoint.sh
new file mode 100755
index 0000000..a83edcf
--- /dev/null
+++ b/espocrm_7-fpm/docker-entrypoint.sh
@@ -0,0 +1,463 @@
+#!/bin/bash
+
+set -euo pipefail
+
+# entrypoint-utils.sh
+configPrefix="ESPOCRM_CONFIG_"
+
+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) {
+ \$injectableFactory = \$app->getContainer()->get('injectableFactory');
+ \$configWriter = \$injectableFactory->create('\\Espo\\Core\\Utils\\Config\\ConfigWriter');
+
+ \$configWriter->set('$name', $value);
+ \$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 MySQL for receiving connections..."
+ sleep 3
+ done
+
+ echo >&2 "error: MySQL 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
+
+ envValue="${!envName}"
+
+ configParamName=$(normalizeConfigParamName "$envName")
+ configParamValue=$(normalizeConfigParamValue "$envValue")
+
+ saveConfigParam "$configParamName" "$configParamValue"
+
+ fi
+
+ done
+}
+
+isQuoteValue() {
+ 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 (!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"
+
+ php -r "
+ \$value = str_ireplace('$configPrefix', '', '$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 isQuoteValue=$(isQuoteValue "$value")
+
+ if [ -n "$isQuoteValue" ] && [ "$isQuoteValue" = 1 ]; then
+ echo "'$value'"
+ return
+ fi
+
+ echo "$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."
+
+ runUpgradeStep || {
+ return
+ }
+
+ 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"
+ exit 1
+ fi
+}
+
+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}"
+
+ for i in {1..20}
+ do
+ settingsTestResult=$(runInstallationStep "settingsTest" "hostName=${ESPOCRM_DATABASE_HOST}&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: Cannot connect to MySQL server. Continuing anyway"
+ return
+ fi
+
+ runInstallationStep "setupConfirmation" "host-name=${ESPOCRM_DATABASE_HOST}&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=100
+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_HOST']='mysql'
+ ['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: Uknown installation type [$installationType]"
+ exit 1
+ ;;
+esac
+
+applyConfigEnvironments
+# ------------------------- END -------------------------------------
+
+exec "$@"
diff --git a/espocrm_7-fpm/docker-websocket.sh b/espocrm_7-fpm/docker-websocket.sh
new file mode 100755
index 0000000..7b919a3
--- /dev/null
+++ b/espocrm_7-fpm/docker-websocket.sh
@@ -0,0 +1,233 @@
+#!/bin/bash
+
+set -eu
+
+DOCUMENT_ROOT="/var/www/html"
+
+# entrypoint-utils.sh
+configPrefix="ESPOCRM_CONFIG_"
+
+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) {
+ \$injectableFactory = \$app->getContainer()->get('injectableFactory');
+ \$configWriter = \$injectableFactory->create('\\Espo\\Core\\Utils\\Config\\ConfigWriter');
+
+ \$configWriter->set('$name', $value);
+ \$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 MySQL for receiving connections..."
+ sleep 3
+ done
+
+ echo >&2 "error: MySQL 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
+
+ envValue="${!envName}"
+
+ configParamName=$(normalizeConfigParamName "$envName")
+ configParamValue=$(normalizeConfigParamValue "$envValue")
+
+ saveConfigParam "$configParamName" "$configParamValue"
+
+ fi
+
+ done
+}
+
+isQuoteValue() {
+ 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 (!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"
+
+ php -r "
+ \$value = str_ireplace('$configPrefix', '', '$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 isQuoteValue=$(isQuoteValue "$value")
+
+ if [ -n "$isQuoteValue" ] && [ "$isQuoteValue" = 1 ]; then
+ echo "'$value'"
+ return
+ fi
+
+ echo "$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_7/Dockerfile b/espocrm_7/Dockerfile
new file mode 100644
index 0000000..b8e6b85
--- /dev/null
+++ b/espocrm_7/Dockerfile
@@ -0,0 +1,101 @@
+FROM php:8.1-apache
+
+# Install php libs
+RUN set -ex; \
+ \
+ aptMarkList="$(apt-mark showmanual)"; \
+ \
+ apt-get update; \
+ apt-get install -y --no-install-recommends \
+ libjpeg-dev \
+ libpng-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-install pdo_mysql; \
+ docker-php-ext-install zip; \
+ docker-php-ext-configure gd --with-jpeg; \
+ docker-php-ext-install gd; \
+ PHP_OPENSSL=yes docker-php-ext-configure imap --with-kerberos --with-imap-ssl; \
+ docker-php-ext-install imap; \
+ docker-php-ext-configure ldap --with-libdir="lib/$debMultiarch"; \
+ docker-php-ext-install ldap; \
+ docker-php-ext-install exif; \
+ docker-php-ext-install pcntl; \
+ docker-php-ext-install posix; \
+ docker-php-ext-enable zmq; \
+ docker-php-ext-install bcmath; \
+ \
+# 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 dpkg-query -S \
+ | cut -d: -f1 \
+ | sort -u \
+ | xargs -rt apt-mark manual; \
+ \
+ apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false
+
+# Install required libs
+RUN set -ex; \
+ 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 7.3.1
+ENV ESPOCRM_SHA256 1ae8a0539ad5409a08e5e96b8ecdb31854089440de60a1647497cc3b956ce9ca
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-7.3.1.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-7.3.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_7/docker-daemon.sh b/espocrm_7/docker-daemon.sh
new file mode 100755
index 0000000..a087e93
--- /dev/null
+++ b/espocrm_7/docker-daemon.sh
@@ -0,0 +1,233 @@
+#!/bin/bash
+
+set -eu
+
+DOCUMENT_ROOT="/var/www/html"
+
+# entrypoint-utils.sh
+configPrefix="ESPOCRM_CONFIG_"
+
+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) {
+ \$injectableFactory = \$app->getContainer()->get('injectableFactory');
+ \$configWriter = \$injectableFactory->create('\\Espo\\Core\\Utils\\Config\\ConfigWriter');
+
+ \$configWriter->set('$name', $value);
+ \$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 MySQL for receiving connections..."
+ sleep 3
+ done
+
+ echo >&2 "error: MySQL 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
+
+ envValue="${!envName}"
+
+ configParamName=$(normalizeConfigParamName "$envName")
+ configParamValue=$(normalizeConfigParamValue "$envValue")
+
+ saveConfigParam "$configParamName" "$configParamValue"
+
+ fi
+
+ done
+}
+
+isQuoteValue() {
+ 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 (!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"
+
+ php -r "
+ \$value = str_ireplace('$configPrefix', '', '$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 isQuoteValue=$(isQuoteValue "$value")
+
+ if [ -n "$isQuoteValue" ] && [ "$isQuoteValue" = 1 ]; then
+ echo "'$value'"
+ return
+ fi
+
+ echo "$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_7/docker-entrypoint.sh b/espocrm_7/docker-entrypoint.sh
new file mode 100755
index 0000000..a83edcf
--- /dev/null
+++ b/espocrm_7/docker-entrypoint.sh
@@ -0,0 +1,463 @@
+#!/bin/bash
+
+set -euo pipefail
+
+# entrypoint-utils.sh
+configPrefix="ESPOCRM_CONFIG_"
+
+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) {
+ \$injectableFactory = \$app->getContainer()->get('injectableFactory');
+ \$configWriter = \$injectableFactory->create('\\Espo\\Core\\Utils\\Config\\ConfigWriter');
+
+ \$configWriter->set('$name', $value);
+ \$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 MySQL for receiving connections..."
+ sleep 3
+ done
+
+ echo >&2 "error: MySQL 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
+
+ envValue="${!envName}"
+
+ configParamName=$(normalizeConfigParamName "$envName")
+ configParamValue=$(normalizeConfigParamValue "$envValue")
+
+ saveConfigParam "$configParamName" "$configParamValue"
+
+ fi
+
+ done
+}
+
+isQuoteValue() {
+ 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 (!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"
+
+ php -r "
+ \$value = str_ireplace('$configPrefix', '', '$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 isQuoteValue=$(isQuoteValue "$value")
+
+ if [ -n "$isQuoteValue" ] && [ "$isQuoteValue" = 1 ]; then
+ echo "'$value'"
+ return
+ fi
+
+ echo "$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."
+
+ runUpgradeStep || {
+ return
+ }
+
+ 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"
+ exit 1
+ fi
+}
+
+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}"
+
+ for i in {1..20}
+ do
+ settingsTestResult=$(runInstallationStep "settingsTest" "hostName=${ESPOCRM_DATABASE_HOST}&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: Cannot connect to MySQL server. Continuing anyway"
+ return
+ fi
+
+ runInstallationStep "setupConfirmation" "host-name=${ESPOCRM_DATABASE_HOST}&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=100
+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_HOST']='mysql'
+ ['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: Uknown installation type [$installationType]"
+ exit 1
+ ;;
+esac
+
+applyConfigEnvironments
+# ------------------------- END -------------------------------------
+
+exec "$@"
diff --git a/espocrm_7/docker-websocket.sh b/espocrm_7/docker-websocket.sh
new file mode 100755
index 0000000..7b919a3
--- /dev/null
+++ b/espocrm_7/docker-websocket.sh
@@ -0,0 +1,233 @@
+#!/bin/bash
+
+set -eu
+
+DOCUMENT_ROOT="/var/www/html"
+
+# entrypoint-utils.sh
+configPrefix="ESPOCRM_CONFIG_"
+
+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) {
+ \$injectableFactory = \$app->getContainer()->get('injectableFactory');
+ \$configWriter = \$injectableFactory->create('\\Espo\\Core\\Utils\\Config\\ConfigWriter');
+
+ \$configWriter->set('$name', $value);
+ \$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 MySQL for receiving connections..."
+ sleep 3
+ done
+
+ echo >&2 "error: MySQL 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
+
+ envValue="${!envName}"
+
+ configParamName=$(normalizeConfigParamName "$envName")
+ configParamValue=$(normalizeConfigParamValue "$envValue")
+
+ saveConfigParam "$configParamName" "$configParamValue"
+
+ fi
+
+ done
+}
+
+isQuoteValue() {
+ 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 (!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"
+
+ php -r "
+ \$value = str_ireplace('$configPrefix', '', '$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 isQuoteValue=$(isQuoteValue "$value")
+
+ if [ -n "$isQuoteValue" ] && [ "$isQuoteValue" = 1 ]; then
+ echo "'$value'"
+ return
+ fi
+
+ echo "$value"
+}
+# END: entrypoint-utils.sh
+
+checkInstanceReady
+
+applyConfigEnvironments
+
+/usr/local/bin/php /var/www/html/websocket.php
+
+exec "$@"
\ No newline at end of file
Diff for 8362304605e95c22e93609bb489612496f5a0637:
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..77edc92 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.2.1-apache, 8.2-apache, 8-apache, latest, 8.2.1, 8.2, 8
+Architectures: amd64, arm32v7, arm64v8, i386, s390x
+GitCommit: 71016fcc7437ab85e290f0367ef0827d163edfa7
+Directory: apache
+
+Tags: fpm, 8.2.1-fpm, 8.2-fpm, 8-fpm
+Architectures: amd64, arm32v7, arm64v8, i386, s390x
+GitCommit: 71016fcc7437ab85e290f0367ef0827d163edfa7
+Directory: fpm
+
+Tags: fpm-alpine, 8.2.1-fpm-alpine, 8.2-fpm-alpine, 8-fpm-alpine
+Architectures: amd64, arm32v6, arm32v7, arm64v8, i386, ppc64le, s390x
+GitCommit: 71016fcc7437ab85e290f0367ef0827d163edfa7
+Directory: fpm-alpine
diff --git a/_bashbrew-list b/_bashbrew-list
index e69de29..73cb790 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.2
+espocrm:8.2-apache
+espocrm:8.2-fpm
+espocrm:8.2-fpm-alpine
+espocrm:8.2.1
+espocrm:8.2.1-apache
+espocrm:8.2.1-fpm
+espocrm:8.2.1-fpm-alpine
+espocrm:apache
+espocrm:fpm
+espocrm:fpm-alpine
+espocrm:latest
diff --git a/espocrm_8-fpm-alpine/Dockerfile b/espocrm_8-fpm-alpine/Dockerfile
new file mode 100644
index 0000000..4b961e5
--- /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.2.1
+ENV ESPOCRM_SHA256 7f76e4f243d6a431f5eb120106d99158cfb2f18034ca46bf089cf1b46e7b771c
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.2.1.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.2.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..24341c1
--- /dev/null
+++ b/espocrm_8-fpm-alpine/docker-entrypoint.sh
@@ -0,0 +1,558 @@
+#!/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}"
+
+ for i in {1..20}
+ do
+ settingsTestResult=$(runInstallationStep "settingsTest" "dbPlatform=${ESPOCRM_DATABASE_PLATFORM}&hostName=${ESPOCRM_DATABASE_HOST}&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=${ESPOCRM_DATABASE_HOST}&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_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..6e23785
--- /dev/null
+++ b/espocrm_8-fpm/Dockerfile
@@ -0,0 +1,116 @@
+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."
+
+# Install php libs
+RUN set -ex; \
+ \
+ aptMarkList="$(apt-mark showmanual)"; \
+ \
+ apt-get update; \
+ 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
+ \
+ pecl install imagick-3.6.0; \
+ 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 \
+ imagick \
+ ; \
+ \
+ rm -r /tmp/pear; \
+ \
+# 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
+RUN set -ex; \
+ 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.2.1
+ENV ESPOCRM_SHA256 7f76e4f243d6a431f5eb120106d99158cfb2f18034ca46bf089cf1b46e7b771c
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.2.1.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.2.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..24341c1
--- /dev/null
+++ b/espocrm_8-fpm/docker-entrypoint.sh
@@ -0,0 +1,558 @@
+#!/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}"
+
+ for i in {1..20}
+ do
+ settingsTestResult=$(runInstallationStep "settingsTest" "dbPlatform=${ESPOCRM_DATABASE_PLATFORM}&hostName=${ESPOCRM_DATABASE_HOST}&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=${ESPOCRM_DATABASE_HOST}&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_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..afc9efb
--- /dev/null
+++ b/espocrm_8/Dockerfile
@@ -0,0 +1,118 @@
+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."
+
+# Install php libs
+RUN set -ex; \
+ \
+ aptMarkList="$(apt-mark showmanual)"; \
+ \
+ apt-get update; \
+ 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
+ \
+ pecl install imagick-3.6.0; \
+ 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 \
+ imagick \
+ ; \
+ \
+ rm -r /tmp/pear; \
+ \
+# 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
+RUN set -ex; \
+ 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.2.1
+ENV ESPOCRM_SHA256 7f76e4f243d6a431f5eb120106d99158cfb2f18034ca46bf089cf1b46e7b771c
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.2.1.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.2.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..24341c1
--- /dev/null
+++ b/espocrm_8/docker-entrypoint.sh
@@ -0,0 +1,558 @@
+#!/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}"
+
+ for i in {1..20}
+ do
+ settingsTestResult=$(runInstallationStep "settingsTest" "dbPlatform=${ESPOCRM_DATABASE_PLATFORM}&hostName=${ESPOCRM_DATABASE_HOST}&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=${ESPOCRM_DATABASE_HOST}&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_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
Diff for 2f62d7793176a2c34df16678f676acdb3fd008ca:
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..d1c896c 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.2.2-apache, 8.2-apache, 8-apache, latest, 8.2.2, 8.2, 8
+Architectures: amd64, arm32v7, arm64v8, i386, s390x
+GitCommit: d185324fc72edec65246b54082173698a751a6dc
+Directory: apache
+
+Tags: fpm, 8.2.2-fpm, 8.2-fpm, 8-fpm
+Architectures: amd64, arm32v7, arm64v8, i386, s390x
+GitCommit: d185324fc72edec65246b54082173698a751a6dc
+Directory: fpm
+
+Tags: fpm-alpine, 8.2.2-fpm-alpine, 8.2-fpm-alpine, 8-fpm-alpine
+Architectures: amd64, arm32v6, arm32v7, arm64v8, i386, ppc64le, s390x
+GitCommit: d185324fc72edec65246b54082173698a751a6dc
+Directory: fpm-alpine
diff --git a/_bashbrew-list b/_bashbrew-list
index e69de29..6525bad 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.2
+espocrm:8.2-apache
+espocrm:8.2-fpm
+espocrm:8.2-fpm-alpine
+espocrm:8.2.2
+espocrm:8.2.2-apache
+espocrm:8.2.2-fpm
+espocrm:8.2.2-fpm-alpine
+espocrm:apache
+espocrm:fpm
+espocrm:fpm-alpine
+espocrm:latest
diff --git a/espocrm_8-fpm-alpine/Dockerfile b/espocrm_8-fpm-alpine/Dockerfile
new file mode 100644
index 0000000..30e55a9
--- /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.2.2
+ENV ESPOCRM_SHA256 8895c52b67c3df76a2cf98136415cce162a48123adc0b9388e1ed815e14c4c8d
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.2.2.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.2.2" /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..24341c1
--- /dev/null
+++ b/espocrm_8-fpm-alpine/docker-entrypoint.sh
@@ -0,0 +1,558 @@
+#!/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}"
+
+ for i in {1..20}
+ do
+ settingsTestResult=$(runInstallationStep "settingsTest" "dbPlatform=${ESPOCRM_DATABASE_PLATFORM}&hostName=${ESPOCRM_DATABASE_HOST}&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=${ESPOCRM_DATABASE_HOST}&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_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..04c2c84
--- /dev/null
+++ b/espocrm_8-fpm/Dockerfile
@@ -0,0 +1,116 @@
+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."
+
+# Install php libs
+RUN set -ex; \
+ \
+ aptMarkList="$(apt-mark showmanual)"; \
+ \
+ apt-get update; \
+ 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
+ \
+ pecl install imagick-3.6.0; \
+ 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 \
+ imagick \
+ ; \
+ \
+ rm -r /tmp/pear; \
+ \
+# 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
+RUN set -ex; \
+ 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.2.2
+ENV ESPOCRM_SHA256 8895c52b67c3df76a2cf98136415cce162a48123adc0b9388e1ed815e14c4c8d
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.2.2.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.2.2" /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..24341c1
--- /dev/null
+++ b/espocrm_8-fpm/docker-entrypoint.sh
@@ -0,0 +1,558 @@
+#!/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}"
+
+ for i in {1..20}
+ do
+ settingsTestResult=$(runInstallationStep "settingsTest" "dbPlatform=${ESPOCRM_DATABASE_PLATFORM}&hostName=${ESPOCRM_DATABASE_HOST}&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=${ESPOCRM_DATABASE_HOST}&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_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..45a0ea6
--- /dev/null
+++ b/espocrm_8/Dockerfile
@@ -0,0 +1,118 @@
+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."
+
+# Install php libs
+RUN set -ex; \
+ \
+ aptMarkList="$(apt-mark showmanual)"; \
+ \
+ apt-get update; \
+ 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
+ \
+ pecl install imagick-3.6.0; \
+ 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 \
+ imagick \
+ ; \
+ \
+ rm -r /tmp/pear; \
+ \
+# 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
+RUN set -ex; \
+ 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.2.2
+ENV ESPOCRM_SHA256 8895c52b67c3df76a2cf98136415cce162a48123adc0b9388e1ed815e14c4c8d
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.2.2.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.2.2" /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..24341c1
--- /dev/null
+++ b/espocrm_8/docker-entrypoint.sh
@@ -0,0 +1,558 @@
+#!/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}"
+
+ for i in {1..20}
+ do
+ settingsTestResult=$(runInstallationStep "settingsTest" "dbPlatform=${ESPOCRM_DATABASE_PLATFORM}&hostName=${ESPOCRM_DATABASE_HOST}&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=${ESPOCRM_DATABASE_HOST}&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_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
Diff for f5fcff212923e93c981d2727da5ddfc40db9e947:
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..81ec77f 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.2.3-apache, 8.2-apache, 8-apache, latest, 8.2.3, 8.2, 8
+Architectures: amd64, arm32v7, arm64v8, i386, s390x
+GitCommit: 62a3d665d8a8fa3d0d17a23cb4f40a9748fe6c7f
+Directory: apache
+
+Tags: fpm, 8.2.3-fpm, 8.2-fpm, 8-fpm
+Architectures: amd64, arm32v7, arm64v8, i386, s390x
+GitCommit: 62a3d665d8a8fa3d0d17a23cb4f40a9748fe6c7f
+Directory: fpm
+
+Tags: fpm-alpine, 8.2.3-fpm-alpine, 8.2-fpm-alpine, 8-fpm-alpine
+Architectures: amd64, arm32v6, arm32v7, arm64v8, i386, ppc64le, s390x
+GitCommit: 62a3d665d8a8fa3d0d17a23cb4f40a9748fe6c7f
+Directory: fpm-alpine
diff --git a/_bashbrew-list b/_bashbrew-list
index e69de29..b701cce 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.2
+espocrm:8.2-apache
+espocrm:8.2-fpm
+espocrm:8.2-fpm-alpine
+espocrm:8.2.3
+espocrm:8.2.3-apache
+espocrm:8.2.3-fpm
+espocrm:8.2.3-fpm-alpine
+espocrm:apache
+espocrm:fpm
+espocrm:fpm-alpine
+espocrm:latest
diff --git a/espocrm_8-fpm-alpine/Dockerfile b/espocrm_8-fpm-alpine/Dockerfile
new file mode 100644
index 0000000..921bc2d
--- /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.2.3
+ENV ESPOCRM_SHA256 104d31e7ebadcd11e160a2f21a30d22f4af7d7483e5fc56e58064fb1e244281d
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.2.3.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.2.3" /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..24341c1
--- /dev/null
+++ b/espocrm_8-fpm-alpine/docker-entrypoint.sh
@@ -0,0 +1,558 @@
+#!/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}"
+
+ for i in {1..20}
+ do
+ settingsTestResult=$(runInstallationStep "settingsTest" "dbPlatform=${ESPOCRM_DATABASE_PLATFORM}&hostName=${ESPOCRM_DATABASE_HOST}&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=${ESPOCRM_DATABASE_HOST}&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_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..0442331
--- /dev/null
+++ b/espocrm_8-fpm/Dockerfile
@@ -0,0 +1,116 @@
+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."
+
+# Install php libs
+RUN set -ex; \
+ \
+ aptMarkList="$(apt-mark showmanual)"; \
+ \
+ apt-get update; \
+ 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
+ \
+ pecl install imagick-3.6.0; \
+ 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 \
+ imagick \
+ ; \
+ \
+ rm -r /tmp/pear; \
+ \
+# 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
+RUN set -ex; \
+ 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.2.3
+ENV ESPOCRM_SHA256 104d31e7ebadcd11e160a2f21a30d22f4af7d7483e5fc56e58064fb1e244281d
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.2.3.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.2.3" /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..24341c1
--- /dev/null
+++ b/espocrm_8-fpm/docker-entrypoint.sh
@@ -0,0 +1,558 @@
+#!/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}"
+
+ for i in {1..20}
+ do
+ settingsTestResult=$(runInstallationStep "settingsTest" "dbPlatform=${ESPOCRM_DATABASE_PLATFORM}&hostName=${ESPOCRM_DATABASE_HOST}&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=${ESPOCRM_DATABASE_HOST}&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_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..181d613
--- /dev/null
+++ b/espocrm_8/Dockerfile
@@ -0,0 +1,118 @@
+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."
+
+# Install php libs
+RUN set -ex; \
+ \
+ aptMarkList="$(apt-mark showmanual)"; \
+ \
+ apt-get update; \
+ 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
+ \
+ pecl install imagick-3.6.0; \
+ 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 \
+ imagick \
+ ; \
+ \
+ rm -r /tmp/pear; \
+ \
+# 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
+RUN set -ex; \
+ 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.2.3
+ENV ESPOCRM_SHA256 104d31e7ebadcd11e160a2f21a30d22f4af7d7483e5fc56e58064fb1e244281d
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.2.3.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.2.3" /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..24341c1
--- /dev/null
+++ b/espocrm_8/docker-entrypoint.sh
@@ -0,0 +1,558 @@
+#!/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}"
+
+ for i in {1..20}
+ do
+ settingsTestResult=$(runInstallationStep "settingsTest" "dbPlatform=${ESPOCRM_DATABASE_PLATFORM}&hostName=${ESPOCRM_DATABASE_HOST}&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=${ESPOCRM_DATABASE_HOST}&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_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
@tmachyshyn I opened a PR to optimize the layers and the size a bit: https://github.com/espocrm/espocrm-docker/pull/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.
Diff for 18509bfecf35c5727709bc25f829ae05ff64892f:
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..e221d16 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.2.4-apache, 8.2-apache, 8-apache, latest, 8.2.4, 8.2, 8
+Architectures: amd64, arm32v7, arm64v8, i386, s390x
+GitCommit: b0b555425c5aa0b4e357a8fe431e06249f1489f5
+Directory: apache
+
+Tags: fpm, 8.2.4-fpm, 8.2-fpm, 8-fpm
+Architectures: amd64, arm32v7, arm64v8, i386, s390x
+GitCommit: b0b555425c5aa0b4e357a8fe431e06249f1489f5
+Directory: fpm
+
+Tags: fpm-alpine, 8.2.4-fpm-alpine, 8.2-fpm-alpine, 8-fpm-alpine
+Architectures: amd64, arm32v6, arm32v7, arm64v8, i386, ppc64le, s390x
+GitCommit: b0b555425c5aa0b4e357a8fe431e06249f1489f5
+Directory: fpm-alpine
diff --git a/_bashbrew-list b/_bashbrew-list
index e69de29..485bd5d 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.2
+espocrm:8.2-apache
+espocrm:8.2-fpm
+espocrm:8.2-fpm-alpine
+espocrm:8.2.4
+espocrm:8.2.4-apache
+espocrm:8.2.4-fpm
+espocrm:8.2.4-fpm-alpine
+espocrm:apache
+espocrm:fpm
+espocrm:fpm-alpine
+espocrm:latest
diff --git a/espocrm_8-fpm-alpine/Dockerfile b/espocrm_8-fpm-alpine/Dockerfile
new file mode 100644
index 0000000..41fdcb1
--- /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.2.4
+ENV ESPOCRM_SHA256 db911f9f58a93e72bc73ecb556aa1568944e68a6f69a32fde4d769be8ea45aa9
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.2.4.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.2.4" /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..24341c1
--- /dev/null
+++ b/espocrm_8-fpm-alpine/docker-entrypoint.sh
@@ -0,0 +1,558 @@
+#!/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}"
+
+ for i in {1..20}
+ do
+ settingsTestResult=$(runInstallationStep "settingsTest" "dbPlatform=${ESPOCRM_DATABASE_PLATFORM}&hostName=${ESPOCRM_DATABASE_HOST}&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=${ESPOCRM_DATABASE_HOST}&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_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..e105e11
--- /dev/null
+++ b/espocrm_8-fpm/Dockerfile
@@ -0,0 +1,114 @@
+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
+ \
+ pecl install imagick-3.6.0; \
+ 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 \
+ imagick \
+ ; \
+ \
+ rm -r /tmp/pear; \
+ \
+# 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.2.4
+ENV ESPOCRM_SHA256 db911f9f58a93e72bc73ecb556aa1568944e68a6f69a32fde4d769be8ea45aa9
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.2.4.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.2.4" /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..24341c1
--- /dev/null
+++ b/espocrm_8-fpm/docker-entrypoint.sh
@@ -0,0 +1,558 @@
+#!/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}"
+
+ for i in {1..20}
+ do
+ settingsTestResult=$(runInstallationStep "settingsTest" "dbPlatform=${ESPOCRM_DATABASE_PLATFORM}&hostName=${ESPOCRM_DATABASE_HOST}&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=${ESPOCRM_DATABASE_HOST}&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_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..42643c1
--- /dev/null
+++ b/espocrm_8/Dockerfile
@@ -0,0 +1,116 @@
+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
+ \
+ pecl install imagick-3.6.0; \
+ 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 \
+ imagick \
+ ; \
+ \
+ rm -r /tmp/pear; \
+ \
+# 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.2.4
+ENV ESPOCRM_SHA256 db911f9f58a93e72bc73ecb556aa1568944e68a6f69a32fde4d769be8ea45aa9
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.2.4.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.2.4" /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..24341c1
--- /dev/null
+++ b/espocrm_8/docker-entrypoint.sh
@@ -0,0 +1,558 @@
+#!/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}"
+
+ for i in {1..20}
+ do
+ settingsTestResult=$(runInstallationStep "settingsTest" "dbPlatform=${ESPOCRM_DATABASE_PLATFORM}&hostName=${ESPOCRM_DATABASE_HOST}&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=${ESPOCRM_DATABASE_HOST}&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_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
Would you be able to squash down to 1 commit for each repo?
Diff for 18464d8e0995def12c1fb69033d9fdfd0f44b02a:
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..e221d16 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.2.4-apache, 8.2-apache, 8-apache, latest, 8.2.4, 8.2, 8
+Architectures: amd64, arm32v7, arm64v8, i386, s390x
+GitCommit: b0b555425c5aa0b4e357a8fe431e06249f1489f5
+Directory: apache
+
+Tags: fpm, 8.2.4-fpm, 8.2-fpm, 8-fpm
+Architectures: amd64, arm32v7, arm64v8, i386, s390x
+GitCommit: b0b555425c5aa0b4e357a8fe431e06249f1489f5
+Directory: fpm
+
+Tags: fpm-alpine, 8.2.4-fpm-alpine, 8.2-fpm-alpine, 8-fpm-alpine
+Architectures: amd64, arm32v6, arm32v7, arm64v8, i386, ppc64le, s390x
+GitCommit: b0b555425c5aa0b4e357a8fe431e06249f1489f5
+Directory: fpm-alpine
diff --git a/_bashbrew-list b/_bashbrew-list
index e69de29..485bd5d 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.2
+espocrm:8.2-apache
+espocrm:8.2-fpm
+espocrm:8.2-fpm-alpine
+espocrm:8.2.4
+espocrm:8.2.4-apache
+espocrm:8.2.4-fpm
+espocrm:8.2.4-fpm-alpine
+espocrm:apache
+espocrm:fpm
+espocrm:fpm-alpine
+espocrm:latest
diff --git a/espocrm_8-fpm-alpine/Dockerfile b/espocrm_8-fpm-alpine/Dockerfile
new file mode 100644
index 0000000..41fdcb1
--- /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.2.4
+ENV ESPOCRM_SHA256 db911f9f58a93e72bc73ecb556aa1568944e68a6f69a32fde4d769be8ea45aa9
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.2.4.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.2.4" /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..24341c1
--- /dev/null
+++ b/espocrm_8-fpm-alpine/docker-entrypoint.sh
@@ -0,0 +1,558 @@
+#!/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}"
+
+ for i in {1..20}
+ do
+ settingsTestResult=$(runInstallationStep "settingsTest" "dbPlatform=${ESPOCRM_DATABASE_PLATFORM}&hostName=${ESPOCRM_DATABASE_HOST}&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=${ESPOCRM_DATABASE_HOST}&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_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..e105e11
--- /dev/null
+++ b/espocrm_8-fpm/Dockerfile
@@ -0,0 +1,114 @@
+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
+ \
+ pecl install imagick-3.6.0; \
+ 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 \
+ imagick \
+ ; \
+ \
+ rm -r /tmp/pear; \
+ \
+# 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.2.4
+ENV ESPOCRM_SHA256 db911f9f58a93e72bc73ecb556aa1568944e68a6f69a32fde4d769be8ea45aa9
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.2.4.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.2.4" /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..24341c1
--- /dev/null
+++ b/espocrm_8-fpm/docker-entrypoint.sh
@@ -0,0 +1,558 @@
+#!/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}"
+
+ for i in {1..20}
+ do
+ settingsTestResult=$(runInstallationStep "settingsTest" "dbPlatform=${ESPOCRM_DATABASE_PLATFORM}&hostName=${ESPOCRM_DATABASE_HOST}&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=${ESPOCRM_DATABASE_HOST}&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_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..42643c1
--- /dev/null
+++ b/espocrm_8/Dockerfile
@@ -0,0 +1,116 @@
+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
+ \
+ pecl install imagick-3.6.0; \
+ 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 \
+ imagick \
+ ; \
+ \
+ rm -r /tmp/pear; \
+ \
+# 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.2.4
+ENV ESPOCRM_SHA256 db911f9f58a93e72bc73ecb556aa1568944e68a6f69a32fde4d769be8ea45aa9
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.2.4.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.2.4" /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..24341c1
--- /dev/null
+++ b/espocrm_8/docker-entrypoint.sh
@@ -0,0 +1,558 @@
+#!/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}"
+
+ for i in {1..20}
+ do
+ settingsTestResult=$(runInstallationStep "settingsTest" "dbPlatform=${ESPOCRM_DATABASE_PLATFORM}&hostName=${ESPOCRM_DATABASE_HOST}&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=${ESPOCRM_DATABASE_HOST}&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_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
@LaurentGoderre Done for this and for the documentation repositories. If any other action is required, please let me know.
Diff for 575b030cd6678b49b237288882378f287b5cf90d:
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..6aa3596 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.2.5-apache, 8.2-apache, 8-apache, latest, 8.2.5, 8.2, 8
+Architectures: amd64, arm32v7, arm64v8, i386, s390x
+GitCommit: 541e2ead27a98bffa809f9302bf4e78262c902c6
+Directory: apache
+
+Tags: fpm, 8.2.5-fpm, 8.2-fpm, 8-fpm
+Architectures: amd64, arm32v7, arm64v8, i386, s390x
+GitCommit: 541e2ead27a98bffa809f9302bf4e78262c902c6
+Directory: fpm
+
+Tags: fpm-alpine, 8.2.5-fpm-alpine, 8.2-fpm-alpine, 8-fpm-alpine
+Architectures: amd64, arm32v6, arm32v7, arm64v8, i386, ppc64le, s390x
+GitCommit: 541e2ead27a98bffa809f9302bf4e78262c902c6
+Directory: fpm-alpine
diff --git a/_bashbrew-list b/_bashbrew-list
index e69de29..473533c 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.2
+espocrm:8.2-apache
+espocrm:8.2-fpm
+espocrm:8.2-fpm-alpine
+espocrm:8.2.5
+espocrm:8.2.5-apache
+espocrm:8.2.5-fpm
+espocrm:8.2.5-fpm-alpine
+espocrm:apache
+espocrm:fpm
+espocrm:fpm-alpine
+espocrm:latest
diff --git a/espocrm_8-fpm-alpine/Dockerfile b/espocrm_8-fpm-alpine/Dockerfile
new file mode 100644
index 0000000..1e0a63c
--- /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.2.5
+ENV ESPOCRM_SHA256 c48b57369d08805eb8b7b2180b5afd567fcf39b622a9239ceda70193fe29186c
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.2.5.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.2.5" /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..e1c26de
--- /dev/null
+++ b/espocrm_8-fpm/Dockerfile
@@ -0,0 +1,114 @@
+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
+ \
+ pecl install imagick-3.6.0; \
+ 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 \
+ imagick \
+ ; \
+ \
+ rm -r /tmp/pear; \
+ \
+# 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.2.5
+ENV ESPOCRM_SHA256 c48b57369d08805eb8b7b2180b5afd567fcf39b622a9239ceda70193fe29186c
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.2.5.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.2.5" /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..134eca6
--- /dev/null
+++ b/espocrm_8/Dockerfile
@@ -0,0 +1,116 @@
+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
+ \
+ pecl install imagick-3.6.0; \
+ 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 \
+ imagick \
+ ; \
+ \
+ rm -r /tmp/pear; \
+ \
+# 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.2.5
+ENV ESPOCRM_SHA256 c48b57369d08805eb8b7b2180b5afd567fcf39b622a9239ceda70193fe29186c
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.2.5.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.2.5" /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
Diff for 071e3e18d85b55839015db6274e784cd3628509c:
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..2aada40 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.3.0-apache, 8.3-apache, 8-apache, latest, 8.3.0, 8.3, 8
+Architectures: amd64, arm32v7, arm64v8, i386, s390x
+GitCommit: 062527a437bbabb8d5712970938d5defdc937a04
+Directory: apache
+
+Tags: fpm, 8.3.0-fpm, 8.3-fpm, 8-fpm
+Architectures: amd64, arm32v7, arm64v8, i386, s390x
+GitCommit: 062527a437bbabb8d5712970938d5defdc937a04
+Directory: fpm
+
+Tags: fpm-alpine, 8.3.0-fpm-alpine, 8.3-fpm-alpine, 8-fpm-alpine
+Architectures: amd64, arm32v6, arm32v7, arm64v8, i386, ppc64le, s390x
+GitCommit: 062527a437bbabb8d5712970938d5defdc937a04
+Directory: fpm-alpine
diff --git a/_bashbrew-list b/_bashbrew-list
index e69de29..216f211 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.3
+espocrm:8.3-apache
+espocrm:8.3-fpm
+espocrm:8.3-fpm-alpine
+espocrm:8.3.0
+espocrm:8.3.0-apache
+espocrm:8.3.0-fpm
+espocrm:8.3.0-fpm-alpine
+espocrm:apache
+espocrm:fpm
+espocrm:fpm-alpine
+espocrm:latest
diff --git a/espocrm_8-fpm-alpine/Dockerfile b/espocrm_8-fpm-alpine/Dockerfile
new file mode 100644
index 0000000..97982b5
--- /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.3.0
+ENV ESPOCRM_SHA256 941c542742356cd6db4023f8e3fe85fcc8ba2c51e0e60bf0a85fb5ca14376816
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.3.0.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.3.0" /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..28b68fe
--- /dev/null
+++ b/espocrm_8-fpm/Dockerfile
@@ -0,0 +1,114 @@
+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
+ \
+ pecl install imagick-3.6.0; \
+ 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 \
+ imagick \
+ ; \
+ \
+ rm -r /tmp/pear; \
+ \
+# 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.3.0
+ENV ESPOCRM_SHA256 941c542742356cd6db4023f8e3fe85fcc8ba2c51e0e60bf0a85fb5ca14376816
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.3.0.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.3.0" /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..94186b1
--- /dev/null
+++ b/espocrm_8/Dockerfile
@@ -0,0 +1,116 @@
+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
+ \
+ pecl install imagick-3.6.0; \
+ 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 \
+ imagick \
+ ; \
+ \
+ rm -r /tmp/pear; \
+ \
+# 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.3.0
+ENV ESPOCRM_SHA256 941c542742356cd6db4023f8e3fe85fcc8ba2c51e0e60bf0a85fb5ca14376816
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.3.0.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.3.0" /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
Diff for b084cd73d5378272d492e38eaadc881f9c54fa88:
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..b91d0a6 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.3.1-apache, 8.3-apache, 8-apache, latest, 8.3.1, 8.3, 8
+Architectures: amd64, arm32v7, arm64v8, i386, s390x
+GitCommit: 12856eaa14480e6adec6420e9a294ff1a6ab41ea
+Directory: apache
+
+Tags: fpm, 8.3.1-fpm, 8.3-fpm, 8-fpm
+Architectures: amd64, arm32v7, arm64v8, i386, s390x
+GitCommit: 12856eaa14480e6adec6420e9a294ff1a6ab41ea
+Directory: fpm
+
+Tags: fpm-alpine, 8.3.1-fpm-alpine, 8.3-fpm-alpine, 8-fpm-alpine
+Architectures: amd64, arm32v6, arm32v7, arm64v8, i386, ppc64le, s390x
+GitCommit: 12856eaa14480e6adec6420e9a294ff1a6ab41ea
+Directory: fpm-alpine
diff --git a/_bashbrew-list b/_bashbrew-list
index e69de29..1b85d3f 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.3
+espocrm:8.3-apache
+espocrm:8.3-fpm
+espocrm:8.3-fpm-alpine
+espocrm:8.3.1
+espocrm:8.3.1-apache
+espocrm:8.3.1-fpm
+espocrm:8.3.1-fpm-alpine
+espocrm:apache
+espocrm:fpm
+espocrm:fpm-alpine
+espocrm:latest
diff --git a/espocrm_8-fpm-alpine/Dockerfile b/espocrm_8-fpm-alpine/Dockerfile
new file mode 100644
index 0000000..7a8540e
--- /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.3.1
+ENV ESPOCRM_SHA256 263e4189e1017646c3af5216da429695e759fc39ec9589df556cd695b3a94ed0
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.3.1.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.3.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..6cb5b6a
--- /dev/null
+++ b/espocrm_8-fpm/Dockerfile
@@ -0,0 +1,114 @@
+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
+ \
+ pecl install imagick-3.6.0; \
+ 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 \
+ imagick \
+ ; \
+ \
+ rm -r /tmp/pear; \
+ \
+# 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.3.1
+ENV ESPOCRM_SHA256 263e4189e1017646c3af5216da429695e759fc39ec9589df556cd695b3a94ed0
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.3.1.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.3.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..24293b4
--- /dev/null
+++ b/espocrm_8/Dockerfile
@@ -0,0 +1,116 @@
+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
+ \
+ pecl install imagick-3.6.0; \
+ 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 \
+ imagick \
+ ; \
+ \
+ rm -r /tmp/pear; \
+ \
+# 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.3.1
+ENV ESPOCRM_SHA256 263e4189e1017646c3af5216da429695e759fc39ec9589df556cd695b3a94ed0
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.3.1.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.3.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
Diff for 9b97532df0ad697463ab8cf019d60aff9cf9a918:
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..a28321d 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.3.2-apache, 8.3-apache, 8-apache, latest, 8.3.2, 8.3, 8
+Architectures: amd64, arm32v7, arm64v8, i386, s390x
+GitCommit: 1029b7a4cbc7bce1494c97383e04fc96d9c29ae0
+Directory: apache
+
+Tags: fpm, 8.3.2-fpm, 8.3-fpm, 8-fpm
+Architectures: amd64, arm32v7, arm64v8, i386, s390x
+GitCommit: 1029b7a4cbc7bce1494c97383e04fc96d9c29ae0
+Directory: fpm
+
+Tags: fpm-alpine, 8.3.2-fpm-alpine, 8.3-fpm-alpine, 8-fpm-alpine
+Architectures: amd64, arm32v6, arm32v7, arm64v8, i386, ppc64le, s390x
+GitCommit: 1029b7a4cbc7bce1494c97383e04fc96d9c29ae0
+Directory: fpm-alpine
diff --git a/_bashbrew-list b/_bashbrew-list
index e69de29..399f89c 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.3
+espocrm:8.3-apache
+espocrm:8.3-fpm
+espocrm:8.3-fpm-alpine
+espocrm:8.3.2
+espocrm:8.3.2-apache
+espocrm:8.3.2-fpm
+espocrm:8.3.2-fpm-alpine
+espocrm:apache
+espocrm:fpm
+espocrm:fpm-alpine
+espocrm:latest
diff --git a/espocrm_8-fpm-alpine/Dockerfile b/espocrm_8-fpm-alpine/Dockerfile
new file mode 100644
index 0000000..053c8f7
--- /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.3.2
+ENV ESPOCRM_SHA256 ca2d11a3091408d6845231a66441c753bd4096290aa3d6c3eae24d19b7efbfe4
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.3.2.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.3.2" /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..e126ab2
--- /dev/null
+++ b/espocrm_8-fpm/Dockerfile
@@ -0,0 +1,114 @@
+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
+ \
+ pecl install imagick-3.6.0; \
+ 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 \
+ imagick \
+ ; \
+ \
+ rm -r /tmp/pear; \
+ \
+# 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.3.2
+ENV ESPOCRM_SHA256 ca2d11a3091408d6845231a66441c753bd4096290aa3d6c3eae24d19b7efbfe4
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.3.2.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.3.2" /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..548ea85
--- /dev/null
+++ b/espocrm_8/Dockerfile
@@ -0,0 +1,116 @@
+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
+ \
+ pecl install imagick-3.6.0; \
+ 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 \
+ imagick \
+ ; \
+ \
+ rm -r /tmp/pear; \
+ \
+# 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.3.2
+ENV ESPOCRM_SHA256 ca2d11a3091408d6845231a66441c753bd4096290aa3d6c3eae24d19b7efbfe4
+
+WORKDIR /var/www/html
+
+RUN set -ex; \
+ curl -fSL "https://www.espocrm.com/downloads/EspoCRM-8.3.2.zip" -o EspoCRM.zip; \
+ echo "${ESPOCRM_SHA256} *EspoCRM.zip" | sha256sum -c -; \
+ unzip -q EspoCRM.zip -d /usr/src; \
+ mv "/usr/src/EspoCRM-8.3.2" /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