├── .gitignore
├── .github
├── FUNDING.yml
└── workflows
│ └── docker-image.yml
├── docker-compose.apache.yml
├── php
├── image-files
│ ├── nginx
│ │ └── etc
│ │ │ ├── supervisor
│ │ │ ├── supervisord.conf
│ │ │ └── conf.d
│ │ │ │ ├── fpm.conf
│ │ │ │ └── nginx.conf
│ │ │ └── nginx
│ │ │ ├── conf.d
│ │ │ └── default.conf
│ │ │ ├── ssl
│ │ │ ├── nginx-selfsigned.crt
│ │ │ └── nginx-selfsigned.key
│ │ │ └── nginx.conf
│ ├── dev
│ │ └── usr
│ │ │ └── local
│ │ │ ├── bin
│ │ │ ├── composer
│ │ │ └── docker-php-entrypoint
│ │ │ └── etc
│ │ │ └── php
│ │ │ └── conf.d
│ │ │ └── xdebug.ini
│ └── min
│ │ ├── usr
│ │ └── local
│ │ │ ├── bin
│ │ │ └── docker-php-entrypoint
│ │ │ └── etc
│ │ │ └── php
│ │ │ └── conf.d
│ │ │ └── base.ini
│ │ ├── root
│ │ └── .bashrc
│ │ └── etc
│ │ └── apache2
│ │ └── sites-available
│ │ └── 000-default.conf
└── Dockerfile-debian
├── docker-compose.fpm-nginx.yml
├── docs
├── install-application-template.md
├── test-framework.md
├── gitlab-build.md
└── install-extensions.md
├── .env-dist
├── docker-compose.yml
├── tests
├── requirements
│ ├── views
│ │ ├── console
│ │ │ └── index.php
│ │ └── web
│ │ │ ├── index.php
│ │ │ └── css.php
│ ├── requirements.php
│ └── YiiRequirementChecker.php
└── requirements.php
├── LICENSE
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .env
2 | *.swp
3 | _host-volumes
4 |
5 | \.idea/
6 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [schmunk42]
4 | open_collective: yiisoft
5 |
--------------------------------------------------------------------------------
/docker-compose.apache.yml:
--------------------------------------------------------------------------------
1 | version: '2.2'
2 | services:
3 |
4 | php-min:
5 | ports:
6 | - '8101:80'
7 |
8 | php-dev:
9 | ports:
10 | - '8102:80'
11 |
--------------------------------------------------------------------------------
/php/image-files/nginx/etc/supervisor/supervisord.conf:
--------------------------------------------------------------------------------
1 | [supervisord]
2 | logfile = /dev/null
3 | loglevel = info
4 | pidfile = /var/run/supervisord.pid
5 | nodaemon = true
6 |
7 | [include]
8 | files = /etc/supervisor/conf.d/*.conf
9 |
10 |
--------------------------------------------------------------------------------
/php/image-files/nginx/etc/supervisor/conf.d/fpm.conf:
--------------------------------------------------------------------------------
1 | [program:php-fpm]
2 | command = php-fpm
3 | autostart=%(ENV_SUPERVISOR_START_FPM)s
4 | autorestart = true
5 | priority=40
6 | stdout_logfile = /dev/stdout
7 | stdout_logfile_maxbytes = 0
8 | stderr_logfile = /dev/stderr
9 | stderr_logfile_maxbytes = 0
10 |
--------------------------------------------------------------------------------
/php/image-files/dev/usr/local/bin/composer:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -e
4 |
5 | if [ -n "${GITHUB_API_TOKEN}" ]
6 | then
7 | composer.phar config -g github-oauth.github.com ${GITHUB_API_TOKEN}
8 | fi
9 |
10 | if [ -n "${GITLAB_ACCESS_TOKEN}" ]
11 | then
12 | composer.phar config -g gitlab-token.gitlab.com ${GITLAB_ACCESS_TOKEN}
13 | fi
14 |
15 | composer.phar "$@"
--------------------------------------------------------------------------------
/php/image-files/nginx/etc/supervisor/conf.d/nginx.conf:
--------------------------------------------------------------------------------
1 | [program:nginx]
2 | command=/usr/sbin/nginx -g 'daemon off;'
3 | autostart=%(ENV_SUPERVISOR_START_NGINX)s
4 | autorestart=true
5 | priority=50
6 | stdout_events_enabled=true
7 | stderr_events_enabled=true
8 | stdout_logfile = /dev/stdout
9 | stdout_logfile_maxbytes = 0
10 | stderr_logfile = /dev/stderr
11 | stderr_logfile_maxbytes = 0
12 |
--------------------------------------------------------------------------------
/php/image-files/dev/usr/local/etc/php/conf.d/xdebug.ini:
--------------------------------------------------------------------------------
1 | ;zend_extension=xdebug.so
2 | xdebug.mode=debug
3 | xdebug.start_with_request=yes
4 | ;;; if you are on macOS, use host.docker.internal to identify the host machine, due to a network limitation on mac (https://docs.docker.com/docker-for-mac/networking/#port-mapping)
5 | ;;; otherwise find host ip
6 | xdebug.client_host=host.docker.internal
7 | ;;; avoid standard port (9000) conflicts using 9005 port
8 | xdebug.client_port=9005
9 | xdebug.idekey=PHPStorm
10 |
--------------------------------------------------------------------------------
/docker-compose.fpm-nginx.yml:
--------------------------------------------------------------------------------
1 | version: '2.2'
2 | services:
3 |
4 | php-nginx-min:
5 | extends:
6 | file: docker-compose.yml
7 | service: php-min
8 | build:
9 | target: nginx-min
10 | image: ${PHP_IMAGE_NAME}:${PHP_BASE_IMAGE_VERSION}${PHP_IMAGE_VERSION_SUFFIX}-nginx-min
11 | ports:
12 | - '8201:80'
13 |
14 | php-nginx-dev:
15 | extends:
16 | file: docker-compose.yml
17 | service: php-dev
18 | build:
19 | target: nginx-dev
20 | image: ${PHP_IMAGE_NAME}:${PHP_BASE_IMAGE_VERSION}${PHP_IMAGE_VERSION_SUFFIX}-nginx
21 | ports:
22 | - '8202:80'
23 |
24 |
--------------------------------------------------------------------------------
/docs/install-application-template.md:
--------------------------------------------------------------------------------
1 | # Install an application template
2 |
3 | Enter the `php` container
4 |
5 | composer create-project yiisoft/yii2-app-basic /app
6 |
7 | Open in your browser
8 |
9 | http://127.0.0.1:8101
10 |
11 | When running Apache you need a configuration like the following to use `enablePrettyUrl` in `.htaccess` in your public `web` folder
12 |
13 | RewriteEngine on
14 | # If a directory or a file exists, use it directly
15 | RewriteCond %{REQUEST_FILENAME} !-f
16 | RewriteCond %{REQUEST_FILENAME} !-d
17 | # Otherwise forward it to index.php
18 | RewriteRule . index.php
19 |
--------------------------------------------------------------------------------
/php/image-files/min/usr/local/bin/docker-php-entrypoint:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | # Set permissions based on ENV variable (debian only)
5 | if [ -x "$(command -v usermod)" ] && [ $PHP_USER_ID -ne "0" ] ; then
6 | echo "Switching uid for 'www-data' to $PHP_USER_ID"
7 | usermod -u ${PHP_USER_ID} www-data
8 | fi
9 |
10 | # first arg is `-f` or `--some-option`
11 | if [ "${1#-}" != "$1" ]; then
12 | if [ -x "$(command -v apache2-foreground)" ]; then
13 | set -- apache2-foreground "$@"
14 | elif [ -x "$(command -v php-fpm)" ]; then
15 | set -- php-fpm "$@"
16 | else
17 | set -- php "$@"
18 | fi
19 | fi
20 |
21 | exec "$@"
22 |
--------------------------------------------------------------------------------
/php/image-files/min/usr/local/etc/php/conf.d/base.ini:
--------------------------------------------------------------------------------
1 | ; Required timezone
2 | date.timezone = UTC
3 |
4 | ; General settings
5 | memory_limit=128M
6 | max_execution_time=30
7 | sys_temp_dir=/tmp
8 | upload_max_filesize=512M
9 | upload_tmp_dir=/tmp
10 | post_max_size=512M
11 |
12 | ; Security, Debug & Logs
13 | expose_php=off
14 | cgi.fix_pathinfo=0
15 | log_errors=on
16 | error_reporting=E_ALL
17 | html_errors=on
18 | xdebug.default_enable=off
19 |
20 | ; Opcache
21 | opcache.memory_consumption=128
22 | opcache.interned_strings_buffer=8
23 | opcache.max_accelerated_files=4000
24 | ;opcache.validate_timestamps=off
25 | opcache.fast_shutdown=0
26 | opcache.enable_cli=1
27 |
28 | ; PHP language options
29 | short_open_tag=0
--------------------------------------------------------------------------------
/php/image-files/min/root/.bashrc:
--------------------------------------------------------------------------------
1 | cat <<'MSG'
2 | _ _ __ _
3 | (_|_)/ _| | |
4 | _ _ _ _| |_ _ __ __ _ _ __ ___ _____ _____ _ __| | __
5 | | | | | | | _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
6 | | |_| | | | | | | | (_| | | | | | | __/\ V V / (_) | | | <
7 | \__, |_|_|_| |_| \__,_|_| |_| |_|\___| \_/\_/ \___/|_| |_|\_\
8 | __/ |
9 | |___/
10 |
11 | MSG
12 |
13 | echo "PHP version: ${PHP_VERSION}"
14 |
15 | if ! shopt -oq posix; then
16 | if [ -f /usr/share/bash-completion/bash_completion ]; then
17 | . /usr/share/bash-completion/bash_completion
18 | elif [ -f /etc/bash_completion.d/yii ]; then
19 | . /etc/bash_completion.d/yii
20 | fi
21 | fi
22 |
--------------------------------------------------------------------------------
/docs/test-framework.md:
--------------------------------------------------------------------------------
1 | # Running framework tests
2 |
3 | Get the source and place it into a host-volume folder for mounting it into the container.
4 |
5 | git clone https://github.com/yiisoft/yii2 _host-volumes/yii2
6 |
7 | Enter the container with
8 |
9 | docker-compose run --rm -w /yii2 php bash
10 |
11 | Go into the container and install packages
12 |
13 | > composer install
14 |
15 | Run the tests
16 |
17 | > vendor/bin/phpunit tests/framework/ --exclude db
18 |
19 | Switching to another framework version
20 |
21 | > git checkout 2.0.12
22 |
23 |
24 | ## Using a specific PHP version
25 |
26 | DOCKERFILE_FLAVOUR=debian PHP_BASE_IMAGE_VERSION=7.1.2-fpm docker-compose build
27 | DOCKERFILE_FLAVOUR=debian PHP_BASE_IMAGE_VERSION=7.1.2-fpm docker-compose run --rm php bash
28 |
--------------------------------------------------------------------------------
/.env-dist:
--------------------------------------------------------------------------------
1 | ## Environment variables for docker-compose command
2 |
3 | ## Windows settings
4 | # COMPOSE_PATH_SEPARATOR=:
5 |
6 | ## Built image name
7 | PHP_IMAGE_NAME=local/yiisoftware/yii2-php
8 | PHP_IMAGE_VERSION_SUFFIX=
9 | PECL_XDEBUG_INSTALL_SUFFIX=
10 | PECL_MONGODB_INSTALL_SUFFIX=
11 |
12 | ## Apache
13 | COMPOSE_PROJECT_NAME=yii2apache
14 | COMPOSE_FILE=docker-compose.yml:docker-compose.apache.yml
15 | DOCKERFILE_FLAVOUR=debian
16 | PHP_BASE_IMAGE_VERSION=8.2-apache
17 | X_LEGACY_GD_LIB=0
18 |
19 | ## PHP-fpm & nginx
20 | #COMPOSE_PROJECT_NAME=yii2fpm
21 | #COMPOSE_FILE=docker-compose.yml:docker-compose.fpm-nginx.yml
22 | #DOCKERFILE_FLAVOUR=debian
23 | #PHP_BASE_IMAGE_VERSION=8.2-fpm
24 | #X_LEGACY_GD_LIB=1
25 |
26 | ## Runtime settings
27 | # Xdebug (calling the xdebug.remote_host on 9005 port)
28 | PHP_ENABLE_XDEBUG=0
29 |
--------------------------------------------------------------------------------
/php/image-files/dev/usr/local/bin/docker-php-entrypoint:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | # Set permissions based on ENV variable (debian only)
5 | if [ -x "$(command -v usermod)" ] && [ $PHP_USER_ID -ne "0" ] ; then
6 | echo "Switching uid for 'www-data' to $PHP_USER_ID"
7 | usermod -u ${PHP_USER_ID} www-data
8 | fi
9 |
10 | # first arg is `-f` or `--some-option`
11 | if [ "${1#-}" != "$1" ]; then
12 | if [ -x "$(command -v apache2-foreground)" ]; then
13 | set -- apache2-foreground "$@"
14 | elif [ -x "$(command -v php-fpm)" ]; then
15 | set -- php-fpm "$@"
16 | else
17 | set -- php "$@"
18 | fi
19 | fi
20 |
21 |
22 | # Enable xdebug by ENV variable
23 | if [ 0 -ne "${PHP_ENABLE_XDEBUG:-0}" ] ; then
24 | docker-php-ext-enable xdebug
25 | echo "Enabled xdebug"
26 | fi
27 |
28 | exec "$@"
29 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '2.2'
2 |
3 | networks:
4 | default:
5 |
6 | services:
7 |
8 | php-min:
9 | build:
10 | dockerfile: Dockerfile-${DOCKERFILE_FLAVOUR}
11 | context: 'php'
12 | target: min
13 | args:
14 | - PHP_BASE_IMAGE_VERSION
15 | - X_LEGACY_GD_LIB
16 | - PECL_XDEBUG_INSTALL_SUFFIX
17 | - PECL_MONGODB_INSTALL_SUFFIX
18 | - PECL_IMAGICK_INSTALL_SUFFIX
19 | image: ${PHP_IMAGE_NAME}:${PHP_BASE_IMAGE_VERSION}${PHP_IMAGE_VERSION_SUFFIX}-min
20 | environment:
21 | - GITHUB_API_TOKEN=${GITHUB_API_TOKEN}
22 | - PHP_ENABLE_XDEBUG
23 | - TEST_RUNTIME_PATH=/tmp/runtime
24 | volumes:
25 | - ./tests:/tests:delegated
26 | # Framework testing
27 | - ./_host-volumes/yii2:/yii2:delegated
28 | # Application testing
29 | - ./_host-volumes/app:/app:delegated
30 | # Composer cache
31 | - ~/.composer-docker/cache:/root/.composer/cache:delegated
32 | networks:
33 | default:
34 | aliases:
35 | - php
36 |
37 | php-dev:
38 | extends:
39 | service: php-min
40 | build:
41 | target: dev
42 | image: ${PHP_IMAGE_NAME}:${PHP_BASE_IMAGE_VERSION}${PHP_IMAGE_VERSION_SUFFIX}
43 |
--------------------------------------------------------------------------------
/php/image-files/nginx/etc/nginx/conf.d/default.conf:
--------------------------------------------------------------------------------
1 | server {
2 | charset utf-8;
3 | client_max_body_size 512M;
4 | server_name app;
5 |
6 | listen 80;
7 | listen 443 ssl http2 default_server;
8 |
9 | ssl_certificate /etc/nginx/ssl/nginx-selfsigned.crt;
10 | ssl_certificate_key /etc/nginx/ssl/nginx-selfsigned.key;
11 |
12 | root /app/web;
13 | index index.php index.html index.htm;
14 |
15 | location / {
16 | # Redirect everything that isn't a real file to index.php
17 | try_files $uri $uri/ /index.php?$args;
18 | }
19 |
20 | # define suffixes for static files
21 | # set caching header and avoid processing of non-existing files by Yii
22 | location ~ \.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar|svg|woff|woff2|eot|ttf|otf)$ {
23 |
24 | # set expire Header
25 | expires 6M;
26 | #add_header Cache-Control "public";
27 | add_header Last-Modified "";
28 |
29 | # keep logs clean
30 | log_not_found off;
31 |
32 | try_files $uri =404;
33 | }
34 |
35 | location ~ \.php$ {
36 | include /etc/nginx/fastcgi_params;
37 | fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
38 | fastcgi_pass 127.0.0.1:9000;
39 | try_files $uri =404;
40 | }
41 |
42 | location ~ /\.(ht|svn|git) {
43 | deny all;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/tests/requirements/views/console/index.php:
--------------------------------------------------------------------------------
1 | $requirement) {
18 | if ($requirement['condition']) {
19 | echo $requirement['name'].": OK\n";
20 | echo "\n";
21 | } else {
22 | echo $requirement['name'].': '.($requirement['mandatory'] ? 'FAILED!!!' : 'WARNING!!!')."\n";
23 | echo 'Required by: '.strip_tags($requirement['by'])."\n";
24 | $memo = strip_tags($requirement['memo']);
25 | if (!empty($memo)) {
26 | echo 'Memo: '.strip_tags($requirement['memo'])."\n";
27 | }
28 | echo "\n";
29 | }
30 | }
31 |
32 | $summaryString = 'Errors: '.$summary['errors'].' Warnings: '.$summary['warnings'].' Total checks: '.$summary['total'];
33 | echo str_pad('', strlen($summaryString), '-')."\n";
34 | echo $summaryString;
35 |
36 | echo "\n\n";
37 |
--------------------------------------------------------------------------------
/php/image-files/nginx/etc/nginx/ssl/nginx-selfsigned.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIID3zCCAsegAwIBAgIJAMoMt2gdriBpMA0GCSqGSIb3DQEBCwUAMIGFMQswCQYD
3 | VQQGEwJERTELMAkGA1UECAwCQlcxEjAQBgNVBAcMCVN0dXR0Z2FydDEOMAwGA1UE
4 | CgwFZG1zdHIxNzA1BgNVBAsMLnBocC15aWkyIC0gc2VsZiBzaWduZWQgY2VydGlm
5 | aWNhdGUgZm9yIHRlc3RpbmcxDDAKBgNVBAMMA2FwcDAeFw0xNzEwMDkwOTUxMjRa
6 | Fw0xODEwMDkwOTUxMjRaMIGFMQswCQYDVQQGEwJERTELMAkGA1UECAwCQlcxEjAQ
7 | BgNVBAcMCVN0dXR0Z2FydDEOMAwGA1UECgwFZG1zdHIxNzA1BgNVBAsMLnBocC15
8 | aWkyIC0gc2VsZiBzaWduZWQgY2VydGlmaWNhdGUgZm9yIHRlc3RpbmcxDDAKBgNV
9 | BAMMA2FwcDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALEel8/pjWaB
10 | n8y4wt6dK9Rd0QtOGHpYcjMbC1ALSbl7UN2GByXGtEAlgsCkH6XSt4qBoJSeuyhD
11 | zzVFir55kimk57DrBaDzQoXTF9wtoeJdpUjszwphfm8mbo+QYUTBeUQdIrZ/0Kjn
12 | 2mU85xVPPoDMMXWeCWHCob0Fhnv59II5pL5PeUbnz0mmOftM06wSI5THw5dx/cHM
13 | rt3DSenecQQK6SXRxuiOLyy1fWQ5nTTbG4IzW1gTfuD+PFXzQlDQNg94sPqDw2V9
14 | DGh/viP6bqm7C5HglnCaKvy3PAqWuSdWpxflfETKNeuyaflk3bOEoDx/AbmhgK5W
15 | 8RGw00VLYvkCAwEAAaNQME4wHQYDVR0OBBYEFK4tI2XnhxAPBSxkdUm+LJEq6Bdh
16 | MB8GA1UdIwQYMBaAFK4tI2XnhxAPBSxkdUm+LJEq6BdhMAwGA1UdEwQFMAMBAf8w
17 | DQYJKoZIhvcNAQELBQADggEBAABLbPdM2bt3n9eJUGdyvqmxT0YPZESl1OfR2CYV
18 | zyv+qBPeqxlrpuMzZwqBnRHKP4r+tinO6bIKRGuL65w1psr2gzVpe3365lZVABPT
19 | CqWiMP/6cR8rYPKRKhdvI7MVyDn2VItzVFAIc80RbMm7Gu4cTElOsiFeUmdoOEms
20 | o9qvhOuXSfDtlexzXqpxBMMjRw6PFhIfxAcGGZARWpyrNpBfUJGDJkWtu/qki8eE
21 | o5NTyQskkaT/DzmOFN3UwBA71DtSYfy2qWkHprI8kMOfEDRfAjU7p2W0lWKdZK9f
22 | 4SEY2g/oTgvmbI3Qbf6avaRRFJwLPzmMDMB7RDl0zqmptPQ=
23 | -----END CERTIFICATE-----
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2017, Yii Software LLC
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | * Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/php/image-files/min/etc/apache2/sites-available/000-default.conf:
--------------------------------------------------------------------------------
1 |
2 | Options Indexes FollowSymLinks
3 | AllowOverride All
4 | Require all granted
5 |
6 |
7 |
8 | # The ServerName directive sets the request scheme, hostname and port that
9 | # the server uses to identify itself. This is used when creating
10 | # redirection URLs. In the context of virtual hosts, the ServerName
11 | # specifies what hostname must appear in the request's Host: header to
12 | # match this virtual host. For the default virtual host (this file) this
13 | # value is not decisive as it is used as a last resort host regardless.
14 | # However, you must set it for any further virtual host explicitly.
15 | #ServerName www.example.com
16 |
17 | ServerAdmin webmaster@localhost
18 | DocumentRoot /app/web
19 |
20 | # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
21 | # error, crit, alert, emerg.
22 | # It is also possible to configure the loglevel for particular
23 | # modules, e.g.
24 | #LogLevel info ssl:warn
25 |
26 | ErrorLog ${APACHE_LOG_DIR}/error.log
27 | CustomLog ${APACHE_LOG_DIR}/access.log combined
28 |
29 | # For most configuration files from conf-available/, which are
30 | # enabled or disabled at a global level, it is possible to
31 | # include a line for only one particular virtual host. For example the
32 | # following line enables the CGI configuration for this host only
33 | # after it has been globally disabled with "a2disconf".
34 | #Include conf-available/serve-cgi-bin.conf
35 |
36 |
--------------------------------------------------------------------------------
/php/image-files/nginx/etc/nginx/ssl/nginx-selfsigned.key:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCxHpfP6Y1mgZ/M
3 | uMLenSvUXdELThh6WHIzGwtQC0m5e1DdhgclxrRAJYLApB+l0reKgaCUnrsoQ881
4 | RYq+eZIppOew6wWg80KF0xfcLaHiXaVI7M8KYX5vJm6PkGFEwXlEHSK2f9Co59pl
5 | POcVTz6AzDF1nglhwqG9BYZ7+fSCOaS+T3lG589Jpjn7TNOsEiOUx8OXcf3BzK7d
6 | w0np3nEECukl0cboji8stX1kOZ002xuCM1tYE37g/jxV80JQ0DYPeLD6g8NlfQxo
7 | f74j+m6puwuR4JZwmir8tzwKlrknVqcX5XxEyjXrsmn5ZN2zhKA8fwG5oYCuVvER
8 | sNNFS2L5AgMBAAECggEAdMVNoyZAMe+NsgOxfeCzD7yWYFSpcKe1Cppu1+PJRD7X
9 | rmR5e99H4O6aCHVr5ABLP0Z83t7TVxV1m5JwiWlPAqOUmKApwtX96oqkNWXkT4Ab
10 | wztUuGxUVeVJiN7QMes4Dr8Crr0PjPvmkU4Yr4TiGToF9ZwuZURTK3JkGoJNQDi1
11 | 09pNZ6VUc/kPXGByFROiRdhxMygyRQAXWgPl9vYJ04aOIaBG4MSS0Pety5Bo1V6o
12 | moXv6CzOYEq0deM84V/O14ajSNadv5W99oMErnwIYY+GJprlV1kFfuDkJnfb5MyL
13 | m/tPUv5Sw53X9pZjC+z9LhJSaFIMHfRLiFhPBEFvrQKBgQDapfI40guVlvD6bqe4
14 | P84Z2ILNS+xA3DYBE8OWHkIOI/MMOiyzu2vBlVYORma4qGzaBpNzgpqgy5YQbNLg
15 | LlGbVy3J3Chpba7VQL1JZsxq2N8vu20UpVonhxDt0/PqGnCZ+nCWtFmM98iWGrSB
16 | lC5dGBNiD8v/z+T4k3OQFsEpXwKBgQDPYHz0anCXhKNrBK4TJghsxLVOGvoQ7fDO
17 | rw/9fCg19HF2W7aP+sH75Ng+2axzAPpPb2RtoXt1milGB8Km2U+r43J7kls9xpuN
18 | wk/8CdzCvo6iawgCu0q+myuOziYuUGMnixAkEJxsVzrgseNeu8SH++0caOZMTvzL
19 | sM9RDgJapwKBgHtKlfJ6ZrPcYFgm64ZW3EXws5lGFZthUUZ8OY690yucE+IyL6DN
20 | r26CYfs8sZGwz2iFysGYxM6k3iK26pYlKDk7CIPKFDOW+L4helsYj240im2k91Zs
21 | AxFE9UPWf7TjYdlBwhkI63I1CrOxrVVgFGDEQbHLDJJcTVXp94Epg5RrAoGBALM1
22 | Y+ZoUVJvGjXyfmgn1uH//9o2b+HPbel+2aep8qnly2OIEDVOcvK2qbVusJtVvfqF
23 | fdlL0oAnsAFH1YwQgcw+KwHk0ZqKFoUj5bEd6LwWpvZu3iZWKlqbh8HKHq6pY3aZ
24 | s2InRLZPj577u0xzoXwOVrLVaCeLnuR7sD0QiTJDAoGAUewb/2gQNJPKKZCfy4mD
25 | OLXpT/IvV1YElXu8hL2OTElY/l+PCUFQLkmwNP0FXw0Gu4Q0ua05D+BloBWkEPl3
26 | WDheXYwIYiDoZuPAvFGx3WlftXyc7IusJarxY5LQ2q1tl1OwjRV2EeDm+YSTXlSg
27 | Dl+Wm2rCjL43qFrClv7Zjdc=
28 | -----END PRIVATE KEY-----
29 |
--------------------------------------------------------------------------------
/docs/gitlab-build.md:
--------------------------------------------------------------------------------
1 | # Build on GitLab
2 |
3 | ## Configuration
4 |
5 | Example build configuration
6 |
7 | ```yaml
8 | image: docker:latest
9 |
10 | services:
11 | - docker:dind
12 |
13 | variables:
14 | DOCKERFILE_FLAVOUR: debian
15 | PHP_BASE_IMAGE_VERSION: fpm
16 | PHP_IMAGE_NAME: yiiframework/php
17 | TEST_YII_VERSION: 11b14ea7df25c37ae262ce6b20167fe30a407367
18 |
19 | before_script:
20 | - env
21 | - apk add --no-cache git curl docker-compose
22 | - git clone https://github.com/yiisoft/yii2 _host-volumes/yii2
23 | - git -C _host-volumes/yii2 checkout ${TEST_YII_VERSION}
24 | - cp .env-dist .env
25 | - docker info
26 |
27 | build:
28 | environment:
29 | name: ${DOCKERFILE_FLAVOUR}/php-${PHP_BASE_IMAGE_VERSION}
30 | script:
31 | - docker-compose build
32 | - docker-compose run --rm php-min php -v
33 | - docker-compose run --rm php-min php /tests/requirements.php
34 | - docker-compose run --rm php-dev php /tests/requirements.php
35 | - docker-compose run --rm -w /yii2 php-dev composer install
36 | - docker-compose run --rm -w /yii2 php-dev php -d error_reporting="E_ALL ^ E_DEPRECATED" vendor/bin/phpunit tests/framework/ --exclude db
37 | ```
38 | ## Triggers
39 |
40 | Repo maintainers can trigger the build of a specific version via GitLab API
41 |
42 | curl -X POST \
43 | -F token=${GITLAB_YII2_DOCKER_TOKEN} \
44 | -F ref=master \
45 | -F "variables[DOCKERFILE_FLAVOUR]=debian" \
46 | -F "variables[PHP_BASE_IMAGE_VERSION]=7.1.3-apache" \
47 | -F "variables[TEST_YII_VERSION]=2.0.11" \
48 | https://gitlab.com/api/v4/projects/2858803/trigger/pipeline
49 |
50 | This can also be used to test pre-releases of PHP or other flavors, if there is a Dockerfile available for them.
51 |
52 | > Tokens are managed under [GitLab settings](https://gitlab.com/yiisoft/yii2-docker/settings/ci_cd).
53 |
--------------------------------------------------------------------------------
/php/image-files/nginx/etc/nginx/nginx.conf:
--------------------------------------------------------------------------------
1 |
2 | user www-data;
3 | worker_processes 1;
4 |
5 | error_log /var/log/nginx/error.log warn;
6 | pid /var/run/nginx.pid;
7 |
8 | events {
9 | worker_connections 1024;
10 | }
11 |
12 |
13 | http {
14 | include /etc/nginx/mime.types;
15 | default_type application/octet-stream;
16 |
17 | log_format main '$remote_addr - $remote_user [$time_local] "$request" '
18 | '$status $body_bytes_sent "$http_referer" '
19 | '"$http_user_agent" "$http_x_forwarded_for"';
20 |
21 | log_format extended '$remote_addr - $remote_user [$time_local] "$request" '
22 | '$status $body_bytes_sent "$http_referer" '
23 | '"$http_user_agent" "$http_x_forwarded_for" '
24 | '$request_time $request_method';
25 |
26 | log_format logstash_json '{ "@timestamp": "$time_iso8601", '
27 | '"@fields": { '
28 | '"remote_addr": "$remote_addr", '
29 | '"remote_user": "$remote_user", '
30 | '"body_bytes_sent": "$body_bytes_sent", '
31 | '"request_time": "$request_time", '
32 | '"status": "$status", '
33 | '"request": "$request", '
34 | '"request_method": "$request_method", '
35 | '"http_x_forwarded_for": "$http_x_forwarded_for", '
36 | '"http_referrer": "$http_referer", '
37 | '"http_user_agent": "$http_user_agent" } }';
38 |
39 | access_log /var/log/nginx/access.log extended;
40 |
41 | sendfile off;
42 | keepalive_timeout 10;
43 | fastcgi_temp_path /tmp/nginx_fastcgi_temp 1 2;
44 | client_body_temp_path /tmp/nginx_client_temp 1 2;
45 |
46 | # disable version in error messages and response header
47 | server_tokens off;
48 |
49 | gzip on;
50 | gzip_disable "msie6";
51 | gzip_comp_level 6;
52 | gzip_min_length 1100;
53 | gzip_buffers 16 8k;
54 | gzip_proxied any;
55 | gzip_types
56 | text/plain
57 | text/css
58 | text/js
59 | text/xml
60 | text/javascript
61 | application/javascript
62 | application/x-javascript
63 | application/json
64 | application/xml
65 | application/rss+xml
66 | image/svg+xml;
67 |
68 | # don't use etag with expire
69 | etag off;
70 |
71 | include /etc/nginx/conf.d/*.conf;
72 | }
73 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
Yii2 PHP Docker Image
3 |
4 |
5 |
6 | [](https://github.com/yiisoft/yii2-docker/actions/workflows/docker-image.yml)
7 |
8 | This is the repo of the official [Yii 2.0 Framework](http://www.yiiframework.com/) image on [DockerHub](https://hub.docker.com/r/yiisoftware/yii2-php/) for PHP.
9 |
10 | ## About
11 |
12 | These Docker images are built on top of the official PHP Docker image, they contain additional PHP extensions required to run Yii 2.0 framework, but no code of the framework itself.
13 | The `Dockerfile`(s) of this repository are designed to build from different PHP-versions by using *build arguments*.
14 |
15 | ### Available versions for `yiisoftware/yii2-php`
16 |
17 | The following images are built on a *weekly* basis for **arm64** and **amd64**. For regular commits on **master** we only build images for **amd64** suffixed with `-latest`/`-latest-min`.
18 |
19 | Minimal images
20 |
21 | ```
22 | 8.3-apache-min, 8.3-fpm-min, 8.3-fpm-nginx-min
23 | 8.2-apache-min, 8.2-fpm-min, 8.2-fpm-nginx-min
24 | 8.1-apache-min, 8.1-fpm-min, 8.1-fpm-nginx-min
25 | ```
26 |
27 | Development images
28 |
29 | ```
30 | 8.3-apache, 8.3-fpm, 8.3-fpm-nginx
31 | 8.2-apache, 8.2-fpm, 8.2-fpm-nginx
32 | 8.1-apache, 8.1-fpm, 8.1-fpm-nginx
33 | ```
34 |
35 | #### Deprecated or EOL versions
36 |
37 | ```
38 | 8.0-*
39 | 7.4-*
40 | 7.3-*
41 | 7.2-*
42 | 7.1-*
43 | 7.0-*
44 | 5.6-*
45 | ```
46 |
47 | ## Setup
48 |
49 | cp .env-dist .env
50 |
51 | Adjust the versions in `.env` if you want to build a specific version.
52 |
53 | > **Note:** Please make sure to use a matching combination of `DOCKERFILE_FLAVOUR` and `PHP_BASE_IMAGE_VERSION`
54 |
55 | ## Configuration
56 |
57 | - `GITHUB_API_TOKEN` access key for repositories on GitHub
58 | - `GITLAB_ACCESS_TOKEN` access key for repositories in GitLab
59 | - `PHP_ENABLE_XDEBUG` whether to load an enable Xdebug, defaults to `0` (false) *not available in `-min` images*
60 | - `PHP_USER_ID` (Debian only) user ID, when running commands as webserver (`www-data`), see also [#15](https://github.com/yiisoft/yii2-docker/issues/15)
61 |
62 | ## Building
63 |
64 | docker-compose build
65 |
66 | ## Testing
67 |
68 | docker-compose run --rm php php /tests/requirements.php
69 |
70 | ### Xdebug
71 |
72 | To enable Xdebug, set `PHP_ENABLE_XDEBUG=1` in .env file
73 |
74 | Xdebug is configured to call ip `xdebug.remote_host` on `9005` port (not use standard port to avoid conflicts),
75 | so you have to configure your IDE to receive connections from that ip.
76 |
77 | ## Documentation
78 |
79 | More information can be found in the [docs](/docs) folder.
80 |
81 | ## FAQ
82 |
83 | - We do not officially support Alpine images, due to numerous issues with PHP requirements and because framework tests are not passing.
84 | - Depending on the (Debian) base-image (usually PHP <7.4) you might need to set `X_LEGACY_GD_LIB=1`
85 | - test
86 |
--------------------------------------------------------------------------------
/tests/requirements/views/web/index.php:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 | Yii Application Requirement Checker
10 | renderViewFile(dirname(__FILE__) . '/css.php'); ?>
11 |
12 |
13 |
14 |
15 | Yii Application Requirement Checker
16 |
17 |
18 |
19 | Description
20 |
21 | This script checks if your server configuration meets the requirements
22 | for running Yii application.
23 | It checks if the server is running the right version of PHP,
24 | if appropriate PHP extensions have been loaded, and if php.ini file settings are correct.
25 |
26 |
27 | There are two kinds of requirements being checked. Mandatory requirements are those that have to be met
28 | to allow Yii to work as expected. There are also some optional requirements being checked which will
29 | show you a warning when they do not meet. You can use Yii framework without them but some specific
30 | functionality may be not available in this case.
31 |
32 |
33 | Conclusion
34 | 0): ?>
35 |
36 | Unfortunately your server configuration does not satisfy the requirements by this application.
Please refer to the table below for detailed explanation.
37 |
38 | 0): ?>
39 |
40 | Your server configuration satisfies the minimum requirements by this application.
Please pay attention to the warnings listed below and check if your application will use the corresponding features.
41 |
42 |
43 |
44 | Congratulations! Your server configuration satisfies all requirements.
45 |
46 |
47 |
48 | Details
49 |
50 |
51 | | Name | Result | Required By | Memo |
52 |
53 |
54 | |
55 |
56 | |
57 |
58 |
59 | |
60 |
61 |
62 | |
63 |
64 |
65 | |
66 |
67 |
68 |
69 |
70 |
71 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/docs/install-extensions.md:
--------------------------------------------------------------------------------
1 | ## Installing additional extensions
2 |
3 | *Note: Alpine images are not officially supported*
4 |
5 | ### Composer asset plugin
6 |
7 | RUN composer global require "fxp/composer-asset-plugin:^1.4.2"
8 |
9 | ### mcrypt
10 |
11 | #### Debian
12 |
13 | ```
14 | RUN apt-get update && \
15 | apt-get -y install \
16 | libmcrypt-dev && \
17 | docker-php-ext-install \
18 | mycrypt
19 | ```
20 |
21 |
22 | ### APC
23 |
24 | *TBD*
25 |
26 | RUN pecl install apc
27 | RUN echo "extension=apcu.so" > /usr/local/etc/php/conf.d/pecl-apcu.ini
28 |
29 | ### APC (>= PHP 7)
30 |
31 | RUN pecl install apcu_bc
32 | RUN echo "extension=apcu.so" > /usr/local/etc/php/conf.d/docker-php-ext-apc1.ini
33 | RUN echo "extension=apc.so" > /usr/local/etc/php/conf.d/docker-php-ext-apc2.ini
34 |
35 | ---
36 |
37 | RUN docker-php-ext-enable \
38 | imagick
39 |
40 | ### memcached
41 |
42 | #### Debian (PHP 7)
43 |
44 | # memcached
45 | ENV MEMCACHED_DEPS libmemcached-dev git
46 | RUN set -xe \
47 | && apt-get update \
48 | && apt-get install -y $MEMCACHED_DEPS \
49 | && curl https://codeload.github.com/php-memcached-dev/php-memcached/zip/php7 -o /tmp/memcached.zip \
50 | && mkdir -p /usr/src/php/ext \
51 | && unzip /tmp/memcached.zip -d /usr/src/php/ext \
52 | && docker-php-ext-configure /usr/src/php/ext/php-memcached-php7 \
53 | --disable-memcached-sasl \
54 | && docker-php-ext-install /usr/src/php/ext/php-memcached-php7 \
55 | && rm -rf /usr/src/php/ext/php-memcached-php7 /tmp/memcached.zip
56 |
57 | ### Xdebug
58 |
59 |
60 | ### oci8 / pdo_oci
61 | You need to download the oracle instant client for your distro here: https://www.oracle.com/technetwork/topics/linuxx86-64soft-092277.html
62 |
63 | #### Debian
64 | Put the basic, devel and odbc rpm packages in a folder (oracle_instant_client in this example)
65 |
66 | RUN mkdir /opt/oracle
67 | COPY oracle_instant_client/ /opt/oracle
68 |
69 | ENV LD_LIBRARY_PATH=/usr/lib/oracle/18.3/client64/lib/${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
70 | ENV ORACLE_HOME=/usr/lib/oracle/18.3/client64
71 | ENV C_INCLUDE_PATH=/usr/include/oracle/18.3/client64/
72 |
73 | RUN apt-get update && \
74 | apt-get install --no-install-recommends --assume-yes --quiet \
75 | rpm \
76 | libaio1 \
77 | alien \
78 | build-essential \
79 | apt-transport-https \
80 | libmcrypt-dev \
81 | zlib1g-dev \
82 | libxslt-dev \
83 | libpng-dev && \
84 | rm -rf /var/lib/apt/lists/*
85 | alien -i /opt/oracle/oracle-instantclient18.3-basic-18.3.0.0.0-1.x86_64.rpm && \
86 | alien -i /opt/oracle/oracle-instantclient18.3-devel-18.3.0.0.0-1.x86_64.rpm && \
87 | echo "/usr/lib/oracle/18.3/client64/lib/" > /etc/ld.so.conf.d/oracle.conf && \
88 | chmod o+r /etc/ld.so.conf.d/oracle.conf && \
89 | ln -s /usr/include/oracle/18.3/client64 $ORACLE_HOME/include && \
90 | docker-php-ext-install pdo oci8 pdo_oci && \
91 | rm -rf /opt/oracle
92 |
93 |
94 | ### igbinary
95 | Add faster serialization with the [igbinary](https://github.com/igbinary/igbinary) library.
96 |
97 | #### Debian
98 |
99 | RUN pecl install igbinary && \
100 | docker-php-ext-enable igbinary
101 |
102 |
103 | ### MsSQL
104 |
105 | RUN apt-get update \
106 | && apt-get install -y gnupg2
107 | RUN curl https://packages.microsoft.com/config/ubuntu/20.04/prod.list > /etc/apt/sources.list.d/mssql-release.list
108 | RUN curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
109 | RUN apt-get update \
110 | && ACCEPT_EULA=Y apt-get install -y \
111 | msodbcsql17 \
112 | unixodbc-dev
113 | RUN pecl install sqlsrv pdo_sqlsrv \
114 | && docker-php-ext-enable sqlsrv pdo_sqlsrv
115 |
--------------------------------------------------------------------------------
/tests/requirements/views/web/css.php:
--------------------------------------------------------------------------------
1 |
64 |
--------------------------------------------------------------------------------
/php/Dockerfile-debian:
--------------------------------------------------------------------------------
1 | # PHP Docker image for Yii 2.0 Framework runtime
2 | # ==============================================
3 |
4 | ARG PHP_BASE_IMAGE_VERSION
5 | FROM php:${PHP_BASE_IMAGE_VERSION} AS min
6 |
7 | # Install required system packages for PHP extensions for Yii 2.0 Framework
8 | COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/
9 | RUN install-php-extensions \
10 | intl
11 |
12 | # Environment settings
13 | ENV PHP_USER_ID=33 \
14 | PATH=/app:/app/vendor/bin:/root/.composer/vendor/bin:$PATH \
15 | TERM=linux
16 |
17 | # Add configuration files
18 | COPY image-files/min/ /
19 |
20 | # Enable mod_rewrite for images with apache
21 | RUN if command -v a2enmod >/dev/null 2>&1; then \
22 | a2enmod rewrite headers \
23 | ;fi
24 |
25 | # Install Yii framework bash autocompletion
26 | RUN mkdir /etc/bash_completion.d && \
27 | curl -L https://raw.githubusercontent.com/yiisoft/yii2/master/contrib/completion/bash/yii \
28 | -o /etc/bash_completion.d/yii
29 |
30 | # Application environment
31 | WORKDIR /app
32 |
33 | RUN chmod 755 \
34 | /usr/local/bin/docker-php-entrypoint
35 |
36 |
37 | FROM min AS dev
38 | ARG PECL_IMAGICK_INSTALL_SUFFIX
39 | ARG PECL_MONGODB_INSTALL_SUFFIX
40 | ARG PECL_XDEBUG_INSTALL_SUFFIX
41 |
42 | # Install system packages
43 | RUN apt-get update && \
44 | apt-get -y install \
45 | git \
46 | unzip \
47 | --no-install-recommends && \
48 | apt-get clean && \
49 | rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
50 |
51 | # Install common system packages for PHP extensions recommended for Yii 2.0 Framework
52 | COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/
53 | RUN install-php-extensions \
54 | imagick${PECL_IMAGICK_INSTALL_SUFFIX} \
55 | mongodb${PECL_MONGODB_INSTALL_SUFFIX} \
56 | xdebug${PECL_XDEBUG_INSTALL_SUFFIX} \
57 | pdo_mysql \
58 | pdo_pgsql \
59 | gd \
60 | pcntl \
61 | soap \
62 | zip \
63 | bcmath \
64 | exif \
65 | opcache
66 |
67 | # Add configuration files
68 | COPY image-files/dev/ /
69 |
70 | # Disable xdebug by default (see PHP_ENABLE_XDEBUG)
71 | RUN rm /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
72 |
73 | # Add GITHUB_API_TOKEN support for composer
74 | RUN chmod 755 \
75 | /usr/local/bin/docker-php-entrypoint \
76 | /usr/local/bin/composer
77 |
78 | # Install composer
79 | RUN curl -sS https://getcomposer.org/installer | php -- \
80 | --filename=composer.phar \
81 | --install-dir=/usr/local/bin && \
82 | composer clear-cache
83 |
84 | # Environment settings
85 | ENV COMPOSER_ALLOW_SUPERUSER=1 \
86 | PHP_ENABLE_XDEBUG=0
87 |
88 |
89 | FROM min AS nginx-min
90 |
91 | # Install nginx
92 | RUN apt-get update \
93 | && apt-get install -y --force-yes \
94 | nginx-full \
95 | cron \
96 | supervisor \
97 | procps \
98 | --no-install-recommends && \
99 | apt-get clean && \
100 | rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
101 |
102 | ENV SUPERVISOR_START_FPM=true \
103 | SUPERVISOR_START_NGINX=true
104 |
105 | # Add configuration files
106 | COPY image-files/nginx/ /
107 |
108 | # forward request and error logs to docker log collector
109 | RUN ln -sf /dev/stdout /var/log/nginx/access.log \
110 | && ln -sf /dev/stderr /var/log/nginx/error.log \
111 | && ln -sf /usr/sbin/cron /usr/sbin/crond
112 |
113 | CMD ["supervisord", "-c", "/etc/supervisor/supervisord.conf"]
114 |
115 | EXPOSE 80 443
116 |
117 |
118 | FROM dev AS nginx-dev
119 |
120 | # Install nginx
121 | RUN apt-get update \
122 | && apt-get install -y --force-yes \
123 | nginx-full \
124 | cron \
125 | supervisor \
126 | procps \
127 | --no-install-recommends && \
128 | apt-get clean && \
129 | rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
130 |
131 | ENV SUPERVISOR_START_FPM=true \
132 | SUPERVISOR_START_NGINX=true
133 |
134 | # Add configuration files
135 | COPY image-files/nginx/ /
136 |
137 | # forward request and error logs to docker log collector
138 | RUN ln -sf /dev/stdout /var/log/nginx/access.log \
139 | && ln -sf /dev/stderr /var/log/nginx/error.log \
140 | && ln -sf /usr/sbin/cron /usr/sbin/crond
141 |
142 | CMD ["supervisord", "-c", "/etc/supervisor/supervisord.conf"]
143 |
144 | EXPOSE 80 443
145 |
--------------------------------------------------------------------------------
/tests/requirements/requirements.php:
--------------------------------------------------------------------------------
1 | 'PHP version',
11 | 'mandatory' => true,
12 | 'condition' => version_compare(PHP_VERSION, '5.4.0', '>='),
13 | 'by' => 'Yii Framework',
14 | 'memo' => 'PHP 5.4.0 or higher is required.',
15 | ),
16 | array(
17 | 'name' => 'Reflection extension',
18 | 'mandatory' => true,
19 | 'condition' => class_exists('Reflection', false),
20 | 'by' => 'Yii Framework',
21 | ),
22 | array(
23 | 'name' => 'PCRE extension',
24 | 'mandatory' => true,
25 | 'condition' => extension_loaded('pcre'),
26 | 'by' => 'Yii Framework',
27 | ),
28 | array(
29 | 'name' => 'SPL extension',
30 | 'mandatory' => true,
31 | 'condition' => extension_loaded('SPL'),
32 | 'by' => 'Yii Framework',
33 | ),
34 | array(
35 | 'name' => 'Ctype extension',
36 | 'mandatory' => true,
37 | 'condition' => extension_loaded('ctype'),
38 | 'by' => 'Yii Framework'
39 | ),
40 | array(
41 | 'name' => 'MBString extension',
42 | 'mandatory' => true,
43 | 'condition' => extension_loaded('mbstring'),
44 | 'by' => 'Multibyte string processing',
45 | 'memo' => 'Required for multibyte encoding string processing.'
46 | ),
47 | array(
48 | 'name' => 'OpenSSL extension',
49 | 'mandatory' => false,
50 | 'condition' => extension_loaded('openssl'),
51 | 'by' => 'Security Component',
52 | 'memo' => 'Required by encrypt and decrypt methods.'
53 | ),
54 | array(
55 | 'name' => 'Intl extension',
56 | 'mandatory' => false,
57 | 'condition' => $this->checkPhpExtensionVersion('intl', '1.0.2', '>='),
58 | 'by' => 'Internationalization support',
59 | 'memo' => 'PHP Intl extension 1.0.2 or higher is required when you want to use advanced parameters formatting
60 | in Yii::t(), non-latin languages with Inflector::slug(),
61 | IDN-feature of
62 | EmailValidator or UrlValidator or the yii\i18n\Formatter class.'
63 | ),
64 | array(
65 | 'name' => 'ICU version',
66 | 'mandatory' => false,
67 | 'condition' => defined('INTL_ICU_VERSION') && version_compare(INTL_ICU_VERSION, '49', '>='),
68 | 'by' => 'Internationalization support',
69 | 'memo' => 'ICU 49.0 or higher is required when you want to use # placeholder in plural rules
70 | (for example, plural in
71 |
72 | Formatter::asRelativeTime()) in the yii\i18n\Formatter class. Your current ICU version is ' .
73 | (defined('INTL_ICU_VERSION') ? INTL_ICU_VERSION : '(ICU is missing)') . '.'
74 | ),
75 | array(
76 | 'name' => 'ICU Data version',
77 | 'mandatory' => false,
78 | 'condition' => defined('INTL_ICU_DATA_VERSION') && version_compare(INTL_ICU_DATA_VERSION, '49.1', '>='),
79 | 'by' => 'Internationalization support',
80 | 'memo' => 'ICU Data 49.1 or higher is required when you want to use # placeholder in plural rules
81 | (for example, plural in
82 |
83 | Formatter::asRelativeTime()) in the yii\i18n\Formatter class. Your current ICU Data version is ' .
84 | (defined('INTL_ICU_DATA_VERSION') ? INTL_ICU_DATA_VERSION : '(ICU Data is missing)') . '.'
85 | ),
86 | array(
87 | 'name' => 'Fileinfo extension',
88 | 'mandatory' => false,
89 | 'condition' => extension_loaded('fileinfo'),
90 | 'by' => 'File Information',
91 | 'memo' => 'Required for files upload to detect correct file mime-types.'
92 | ),
93 | array(
94 | 'name' => 'DOM extension',
95 | 'mandatory' => false,
96 | 'condition' => extension_loaded('dom'),
97 | 'by' => 'Document Object Model',
98 | 'memo' => 'Required for REST API to send XML responses via yii\web\XmlResponseFormatter.'
99 | ),
100 | );
101 |
--------------------------------------------------------------------------------
/tests/requirements.php:
--------------------------------------------------------------------------------
1 | Error';
18 | echo 'The path to yii framework seems to be incorrect.
';
19 | echo 'You need to install Yii framework via composer or adjust the framework path in file ' . basename(__FILE__) . '.
';
20 | echo 'Please refer to the README on how to install Yii.
';
21 | }
22 |
23 | require_once($frameworkPath . '/requirements/YiiRequirementChecker.php');
24 | $requirementsChecker = new YiiRequirementChecker();
25 |
26 | $gdMemo = $imagickMemo = 'Either GD PHP extension with FreeType support or ImageMagick PHP extension with PNG support is required for image CAPTCHA.';
27 | $gdOK = $imagickOK = false;
28 |
29 | if (extension_loaded('imagick')) {
30 | $imagick = new Imagick();
31 | $imagickFormats = $imagick->queryFormats('PNG');
32 | if (in_array('PNG', $imagickFormats)) {
33 | $imagickOK = true;
34 | } else {
35 | $imagickMemo = 'Imagick extension should be installed with PNG support in order to be used for image CAPTCHA.';
36 | }
37 | }
38 |
39 | if (extension_loaded('gd')) {
40 | $gdInfo = gd_info();
41 | if (!empty($gdInfo['FreeType Support'])) {
42 | $gdOK = true;
43 | } else {
44 | $gdMemo = 'GD extension should be installed with FreeType support in order to be used for image CAPTCHA.';
45 | }
46 | }
47 |
48 | /**
49 | * Adjust requirements according to your application specifics.
50 | */
51 | $requirements = array(
52 | // Database :
53 | array(
54 | 'name' => 'PDO extension',
55 | 'mandatory' => true,
56 | 'condition' => extension_loaded('pdo'),
57 | 'by' => 'All DB-related classes',
58 | ),
59 | array(
60 | 'name' => 'PDO SQLite extension',
61 | 'mandatory' => false,
62 | 'condition' => extension_loaded('pdo_sqlite'),
63 | 'by' => 'All DB-related classes',
64 | 'memo' => 'Required for SQLite database.',
65 | ),
66 | array(
67 | 'name' => 'PDO MySQL extension',
68 | 'mandatory' => false,
69 | 'condition' => extension_loaded('pdo_mysql'),
70 | 'by' => 'All DB-related classes',
71 | 'memo' => 'Required for MySQL database.',
72 | ),
73 | array(
74 | 'name' => 'PDO PostgreSQL extension',
75 | 'mandatory' => false,
76 | 'condition' => extension_loaded('pdo_pgsql'),
77 | 'by' => 'All DB-related classes',
78 | 'memo' => 'Required for PostgreSQL database.',
79 | ),
80 | array(
81 | 'name' => 'MongoDB extension',
82 | 'mandatory' => false,
83 | 'condition' => extension_loaded('mongodb'),
84 | 'by' => 'MongoDB',
85 | 'memo' => 'Required for MongoDB database.',
86 | ),
87 | // Cache :
88 | /*array(
89 | 'name' => 'Memcache extension',
90 | 'mandatory' => false,
91 | 'condition' => extension_loaded('memcache') || extension_loaded('memcached'),
92 | 'by' => 'MemCache',
93 | 'memo' => extension_loaded('memcached') ? 'To use memcached set MemCache::useMemcached to true.' : ''
94 | ),*/
95 | // CAPTCHA:
96 | array(
97 | 'name' => 'GD PHP extension with FreeType support',
98 | 'mandatory' => false,
99 | 'condition' => $gdOK,
100 | 'by' => 'Captcha',
101 | 'memo' => $gdMemo,
102 | ),
103 | array(
104 | 'name' => 'ImageMagick PHP extension with PNG support',
105 | 'mandatory' => false,
106 | 'condition' => $imagickOK,
107 | 'by' => 'Captcha',
108 | 'memo' => $imagickMemo,
109 | ),
110 | // PHP ini :
111 | 'phpExposePhp' => array(
112 | 'name' => 'Expose PHP',
113 | 'mandatory' => false,
114 | 'condition' => $requirementsChecker->checkPhpIniOff("expose_php"),
115 | 'by' => 'Security reasons',
116 | 'memo' => '"expose_php" should be disabled at php.ini',
117 | ),
118 | 'phpAllowUrlInclude' => array(
119 | 'name' => 'PHP allow url include',
120 | 'mandatory' => false,
121 | 'condition' => $requirementsChecker->checkPhpIniOff("allow_url_include"),
122 | 'by' => 'Security reasons',
123 | 'memo' => '"allow_url_include" should be disabled at php.ini',
124 | ),
125 | 'phpSmtp' => array(
126 | 'name' => 'PHP mail SMTP',
127 | 'mandatory' => false,
128 | 'condition' => strlen(ini_get('SMTP')) > 0,
129 | 'by' => 'Email sending',
130 | 'memo' => 'PHP mail SMTP server required',
131 | ),
132 | 'phpPcntl' => array(
133 | 'name' => 'PHP Process Control',
134 | 'mandatory' => false,
135 | 'condition' => extension_loaded('pcntl'),
136 | 'by' => 'Queue',
137 | 'memo' => '',
138 | ),
139 | );
140 |
141 | // OPcache check
142 | if (!version_compare(phpversion(), '5.5', '>=')) {
143 | $requirements[] = array(
144 | 'name' => 'APC extension',
145 | 'mandatory' => false,
146 | 'condition' => extension_loaded('apc'),
147 | 'by' => 'ApcCache',
148 | );
149 | }
150 |
151 | $requirementsChecker->checkYii()->check($requirements)->render();
152 |
--------------------------------------------------------------------------------
/.github/workflows/docker-image.yml:
--------------------------------------------------------------------------------
1 | name: Docker Image CI
2 |
3 | on:
4 | workflow_dispatch:
5 | push:
6 | pull_request:
7 | schedule:
8 | - cron: '0 3 * * 0'
9 |
10 | jobs:
11 |
12 | build:
13 |
14 | runs-on: ubuntu-latest
15 | continue-on-error: ${{ matrix.experimental }}
16 | strategy:
17 | matrix:
18 | # Example
19 | #
20 | # php-base-image-version: "x.y-type"
21 | # dockerfile-flavour: "debian"
22 | # legacy-gd-lib: ""
23 | # pecl-xdebug-suffix: ""
24 | # pecl-mongodb-suffix: ""
25 | # compose-file: "docker-compose.yml:..."
26 | include:
27 | - php-base-image-version: "8.1-fpm"
28 | dockerfile-flavour: "debian"
29 | compose-file: "docker-compose.yml,docker-compose.fpm-nginx.yml"
30 | experimental: false
31 | - php-base-image-version: "8.2-fpm"
32 | dockerfile-flavour: "debian"
33 | compose-file: "docker-compose.yml,docker-compose.fpm-nginx.yml"
34 | experimental: false
35 | - php-base-image-version: "8.3-fpm"
36 | dockerfile-flavour: "debian"
37 | compose-file: "docker-compose.yml,docker-compose.fpm-nginx.yml"
38 | pecl-imagick-suffix: "/imagick@master"
39 | experimental: false
40 | - php-base-image-version: "8.4-fpm"
41 | dockerfile-flavour: "debian"
42 | compose-file: "docker-compose.yml,docker-compose.fpm-nginx.yml"
43 | experimental: false
44 | - php-base-image-version: "8.5-fpm"
45 | dockerfile-flavour: "debian"
46 | compose-file: "docker-compose.yml,docker-compose.fpm-nginx.yml"
47 | pecl-xdebug-suffix: "-beta"
48 | pecl-imagick-suffix: "-beta"
49 | experimental: true
50 | - php-base-image-version: "8.1-apache"
51 | dockerfile-flavour: "debian"
52 | compose-file: "docker-compose.yml,docker-compose.apache.yml"
53 | experimental: false
54 | - php-base-image-version: "8.2-apache"
55 | dockerfile-flavour: "debian"
56 | compose-file: "docker-compose.yml,docker-compose.apache.yml"
57 | experimental: false
58 | - php-base-image-version: "8.3-apache"
59 | dockerfile-flavour: "debian"
60 | compose-file: "docker-compose.yml,docker-compose.apache.yml"
61 | pecl-imagick-suffix: "/imagick@master"
62 | experimental: false
63 | - php-base-image-version: "8.4-apache"
64 | dockerfile-flavour: "debian"
65 | compose-file: "docker-compose.yml,docker-compose.apache.yml"
66 | experimental: false
67 | - php-base-image-version: "8.5-apache"
68 | dockerfile-flavour: "debian"
69 | compose-file: "docker-compose.yml,docker-compose.apache.yml"
70 | pecl-xdebug-suffix: "-beta"
71 | pecl-imagick-suffix: "-beta"
72 | experimental: true
73 | fail-fast: false
74 | env:
75 | COMPOSE_FILE: ${{ matrix.compose-file }}
76 | COMPOSE_PATH_SEPARATOR: ","
77 | PHP_IMAGE_NAME: "yiisoftware/yii2-php"
78 | PHP_BASE_IMAGE_VERSION: ${{ matrix.php-base-image-version }}
79 | DOCKERFILE_FLAVOUR: ${{ matrix.dockerfile-flavour }}
80 | X_LEGACY_GD_LIB: ${{ matrix.legacy-gd-lib }}
81 | PECL_XDEBUG_INSTALL_SUFFIX: ${{ matrix.pecl-xdebug-suffix }}
82 | PECL_MONGODB_INSTALL_SUFFIX: ${{ matrix.pecl-mongodb-suffix }}
83 | PECL_IMAGICK_INSTALL_SUFFIX: ${{ matrix.pecl-imagick-suffix }}
84 | steps:
85 | - name: Checkout
86 | uses: actions/checkout@v3
87 | - name: Set up QEMU
88 | uses: docker/setup-qemu-action@v2
89 | with:
90 | platforms: 'amd64,arm64'
91 | - name: Set up Docker Buildx
92 | uses: docker/setup-buildx-action@v2
93 | - name: Set version suffix (tags)
94 | if: startsWith(github.ref, 'refs/tags/')
95 | run: echo "PHP_IMAGE_VERSION_SUFFIX=-${GITHUB_REF:10}" >> $GITHUB_ENV
96 | - name: Set version suffix (master/latest)
97 | if: (github.ref == 'refs/heads/master' && (github.event_name != 'workflow_dispatch' && github.event_name != 'schedule'))
98 | run: echo "PHP_IMAGE_VERSION_SUFFIX=-latest" >> $GITHUB_ENV
99 | - name: Install
100 | env:
101 | TEST_YII_VERSION: "5df412df2c9b4e60e7ec84008693b94ae472eae6"
102 | run: |
103 | git clone https://github.com/yiisoft/yii2 _host-volumes/yii2
104 | pushd _host-volumes/yii2 && git checkout ${TEST_YII_VERSION} && popd
105 | cp .env-dist .env
106 | - name: Print Info
107 | run: |
108 | pwd
109 | docker version
110 | docker info
111 | docker compose version
112 | - name: Build Image
113 | uses: docker/bake-action@v2
114 | with:
115 | files: ${{ matrix.compose-file }}
116 | load: true
117 | set: |
118 | *.platform=linux/amd64
119 | *.args.X_LEGACY_GD_LIB=${{ matrix.legacy-gd-lib }}
120 | - name: Test
121 | run: |
122 | docker compose run --rm php-min php -v
123 | docker compose run --rm php-min php -v | grep "Xdebug" && exit 1
124 | docker compose run --rm php-min php /tests/requirements.php
125 | docker compose run --rm php-dev php /tests/requirements.php
126 | docker compose run --rm -w /yii2 php-dev composer update --prefer-dist
127 | docker compose run --rm -w /yii2 php-dev php -d error_reporting="E_ALL ^ E_DEPRECATED" vendor/bin/phpunit tests/framework/ --exclude db
128 | docker compose run --rm -e PHP_ENABLE_XDEBUG=1 php-dev php -v | grep "Xdebug" || exit 1
129 | docker images
130 | - name: Login to Docker
131 | if: startsWith(github.ref, 'refs/tags/') || github.ref == 'refs/heads/master'
132 | uses: docker/login-action@v2
133 | with:
134 | username: ${{ secrets.DOCKERHUB_USER }}
135 | password: ${{ secrets.DOCKERHUB_PASS }}
136 | - name: Build and push docker image (amd64 master/latest)
137 | if: (github.ref == 'refs/heads/master' && (github.event_name != 'workflow_dispatch' && github.event_name != 'schedule'))
138 | uses: docker/bake-action@v2
139 | with:
140 | files: ${{ matrix.compose-file }}
141 | push: true
142 | set: |
143 | *.platform=linux/amd64
144 | - name: Build and push docker image (amd64,arm64)
145 | if: |
146 | startsWith(github.ref, 'refs/tags/') ||
147 | (github.ref == 'refs/heads/master' && (github.event_name == 'workflow_dispatch' || github.event_name == 'schedule'))
148 | uses: docker/bake-action@v2
149 | with:
150 | files: ${{ matrix.compose-file }}
151 | push: true
152 | set: |
153 | *.platform=linux/amd64,linux/arm64
154 |
--------------------------------------------------------------------------------
/tests/requirements/YiiRequirementChecker.php:
--------------------------------------------------------------------------------
1 | 'PHP Some Extension',
25 | * 'mandatory' => true,
26 | * 'condition' => extension_loaded('some_extension'),
27 | * 'by' => 'Some application feature',
28 | * 'memo' => 'PHP extension "some_extension" required',
29 | * ),
30 | * );
31 | * $requirementsChecker->checkYii()->check($requirements)->render();
32 | * ```
33 | *
34 | * If you wish to render the report with your own representation, use [[getResult()]] instead of [[render()]]
35 | *
36 | * Requirement condition could be in format "eval:PHP expression".
37 | * In this case specified PHP expression will be evaluated in the context of this class instance.
38 | * For example:
39 | *
40 | * ```php
41 | * $requirements = array(
42 | * array(
43 | * 'name' => 'Upload max file size',
44 | * 'condition' => 'eval:$this->checkUploadMaxFileSize("5M")',
45 | * ),
46 | * );
47 | * ```
48 | *
49 | * Note: this class definition does not match ordinary Yii style, because it should match PHP 4.3
50 | * and should not use features from newer PHP versions!
51 | *
52 | * @property array|null $result the check results, this property is for internal usage only.
53 | *
54 | * @author Paul Klimov
55 | * @since 2.0
56 | */
57 | class YiiRequirementChecker
58 | {
59 | /**
60 | * @var Check result
61 | */
62 | public $result;
63 |
64 | /**
65 | * Check the given requirements, collecting results into internal field.
66 | * This method can be invoked several times checking different requirement sets.
67 | * Use [[getResult()]] or [[render()]] to get the results.
68 | * @param array|string $requirements requirements to be checked.
69 | * If an array, it is treated as the set of requirements;
70 | * If a string, it is treated as the path of the file, which contains the requirements;
71 | * @return $this self instance.
72 | */
73 | function check($requirements)
74 | {
75 | if (is_string($requirements)) {
76 | $requirements = require($requirements);
77 | }
78 | if (!is_array($requirements)) {
79 | $this->usageError('Requirements must be an array, "' . gettype($requirements) . '" has been given!');
80 | }
81 | if (!isset($this->result) || !is_array($this->result)) {
82 | $this->result = array(
83 | 'summary' => array(
84 | 'total' => 0,
85 | 'errors' => 0,
86 | 'warnings' => 0,
87 | ),
88 | 'requirements' => array(),
89 | );
90 | }
91 | foreach ($requirements as $key => $rawRequirement) {
92 | $requirement = $this->normalizeRequirement($rawRequirement, $key);
93 | $this->result['summary']['total']++;
94 | if (!$requirement['condition']) {
95 | if ($requirement['mandatory']) {
96 | $requirement['error'] = true;
97 | $requirement['warning'] = true;
98 | $this->result['summary']['errors']++;
99 | } else {
100 | $requirement['error'] = false;
101 | $requirement['warning'] = true;
102 | $this->result['summary']['warnings']++;
103 | }
104 | } else {
105 | $requirement['error'] = false;
106 | $requirement['warning'] = false;
107 | }
108 | $this->result['requirements'][] = $requirement;
109 | }
110 |
111 | return $this;
112 | }
113 |
114 | /**
115 | * Performs the check for the Yii core requirements.
116 | * @return YiiRequirementChecker self instance.
117 | */
118 | function checkYii()
119 | {
120 | return $this->check(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'requirements.php');
121 | }
122 |
123 | /**
124 | * Return the check results.
125 | * @return array|null check results in format:
126 | *
127 | * ```php
128 | * array(
129 | * 'summary' => array(
130 | * 'total' => total number of checks,
131 | * 'errors' => number of errors,
132 | * 'warnings' => number of warnings,
133 | * ),
134 | * 'requirements' => array(
135 | * array(
136 | * ...
137 | * 'error' => is there an error,
138 | * 'warning' => is there a warning,
139 | * ),
140 | * ...
141 | * ),
142 | * )
143 | * ```
144 | */
145 | function getResult()
146 | {
147 | if (isset($this->result)) {
148 | return $this->result;
149 | } else {
150 | return null;
151 | }
152 | }
153 |
154 | /**
155 | * Renders the requirements check result.
156 | * The output will vary depending is a script running from web or from console.
157 | */
158 | function render()
159 | {
160 | if (!isset($this->result)) {
161 | $this->usageError('Nothing to render!');
162 | }
163 | $baseViewFilePath = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'views';
164 | if (!empty($_SERVER['argv'])) {
165 | $viewFileName = $baseViewFilePath . DIRECTORY_SEPARATOR . 'console' . DIRECTORY_SEPARATOR . 'index.php';
166 | } else {
167 | $viewFileName = $baseViewFilePath . DIRECTORY_SEPARATOR . 'web' . DIRECTORY_SEPARATOR . 'index.php';
168 | }
169 | $this->renderViewFile($viewFileName, $this->result);
170 | }
171 |
172 | /**
173 | * Checks if the given PHP extension is available and its version matches the given one.
174 | * @param string $extensionName PHP extension name.
175 | * @param string $version required PHP extension version.
176 | * @param string $compare comparison operator, by default '>='
177 | * @return boolean if PHP extension version matches.
178 | */
179 | function checkPhpExtensionVersion($extensionName, $version, $compare = '>=')
180 | {
181 | if (!extension_loaded($extensionName)) {
182 | return false;
183 | }
184 | $extensionVersion = phpversion($extensionName);
185 | if (empty($extensionVersion)) {
186 | return false;
187 | }
188 | if (strncasecmp($extensionVersion, 'PECL-', 5) === 0) {
189 | $extensionVersion = substr($extensionVersion, 5);
190 | }
191 |
192 | return version_compare($extensionVersion, $version, $compare);
193 | }
194 |
195 | /**
196 | * Checks if PHP configuration option (from php.ini) is on.
197 | * @param string $name configuration option name.
198 | * @return boolean option is on.
199 | */
200 | function checkPhpIniOn($name)
201 | {
202 | $value = ini_get($name);
203 | if (empty($value)) {
204 | return false;
205 | }
206 |
207 | return ((int) $value === 1 || strtolower($value) === 'on');
208 | }
209 |
210 | /**
211 | * Checks if PHP configuration option (from php.ini) is off.
212 | * @param string $name configuration option name.
213 | * @return boolean option is off.
214 | */
215 | function checkPhpIniOff($name)
216 | {
217 | $value = ini_get($name);
218 | if (empty($value)) {
219 | return true;
220 | }
221 |
222 | return (strtolower($value) === 'off');
223 | }
224 |
225 | /**
226 | * Compare byte sizes of values given in the verbose representation,
227 | * like '5M', '15K' etc.
228 | * @param string $a first value.
229 | * @param string $b second value.
230 | * @param string $compare comparison operator, by default '>='.
231 | * @return boolean comparison result.
232 | */
233 | function compareByteSize($a, $b, $compare = '>=')
234 | {
235 | $compareExpression = '(' . $this->getByteSize($a) . $compare . $this->getByteSize($b) . ')';
236 |
237 | return $this->evaluateExpression($compareExpression);
238 | }
239 |
240 | /**
241 | * Gets the size in bytes from verbose size representation.
242 | * For example: '5K' => 5*1024
243 | * @param string $verboseSize verbose size representation.
244 | * @return integer actual size in bytes.
245 | */
246 | function getByteSize($verboseSize)
247 | {
248 | if (empty($verboseSize)) {
249 | return 0;
250 | }
251 | if (is_numeric($verboseSize)) {
252 | return (int) $verboseSize;
253 | }
254 | $sizeUnit = trim($verboseSize, '0123456789');
255 | $size = str_replace($sizeUnit, '', $verboseSize);
256 | $size = trim($size);
257 | if (!is_numeric($size)) {
258 | return 0;
259 | }
260 | switch (strtolower($sizeUnit)) {
261 | case 'kb':
262 | case 'k':
263 | return $size * 1024;
264 | case 'mb':
265 | case 'm':
266 | return $size * 1024 * 1024;
267 | case 'gb':
268 | case 'g':
269 | return $size * 1024 * 1024 * 1024;
270 | default:
271 | return 0;
272 | }
273 | }
274 |
275 | /**
276 | * Checks if upload max file size matches the given range.
277 | * @param string|null $min verbose file size minimum required value, pass null to skip minimum check.
278 | * @param string|null $max verbose file size maximum required value, pass null to skip maximum check.
279 | * @return boolean success.
280 | */
281 | function checkUploadMaxFileSize($min = null, $max = null)
282 | {
283 | $postMaxSize = ini_get('post_max_size');
284 | $uploadMaxFileSize = ini_get('upload_max_filesize');
285 | if ($min !== null) {
286 | $minCheckResult = $this->compareByteSize($postMaxSize, $min, '>=') && $this->compareByteSize($uploadMaxFileSize, $min, '>=');
287 | } else {
288 | $minCheckResult = true;
289 | }
290 | if ($max !== null) {
291 | $maxCheckResult = $this->compareByteSize($postMaxSize, $max, '<=') && $this->compareByteSize($uploadMaxFileSize, $max, '<=');
292 | } else {
293 | $maxCheckResult = true;
294 | }
295 |
296 | return ($minCheckResult && $maxCheckResult);
297 | }
298 |
299 | /**
300 | * Renders a view file.
301 | * This method includes the view file as a PHP script
302 | * and captures the display result if required.
303 | * @param string $_viewFile_ view file
304 | * @param array $_data_ data to be extracted and made available to the view file
305 | * @param boolean $_return_ whether the rendering result should be returned as a string
306 | * @return string the rendering result. Null if the rendering result is not required.
307 | */
308 | function renderViewFile($_viewFile_, $_data_ = null, $_return_ = false)
309 | {
310 | // we use special variable names here to avoid conflict when extracting data
311 | if (is_array($_data_)) {
312 | extract($_data_, EXTR_PREFIX_SAME, 'data');
313 | } else {
314 | $data = $_data_;
315 | }
316 | if ($_return_) {
317 | ob_start();
318 | ob_implicit_flush(false);
319 | require($_viewFile_);
320 |
321 | return ob_get_clean();
322 | } else {
323 | require($_viewFile_);
324 | }
325 | }
326 |
327 | /**
328 | * Normalizes requirement ensuring it has correct format.
329 | * @param array $requirement raw requirement.
330 | * @param integer $requirementKey requirement key in the list.
331 | * @return array normalized requirement.
332 | */
333 | function normalizeRequirement($requirement, $requirementKey = 0)
334 | {
335 | if (!is_array($requirement)) {
336 | $this->usageError('Requirement must be an array!');
337 | }
338 | if (!array_key_exists('condition', $requirement)) {
339 | $this->usageError("Requirement '{$requirementKey}' has no condition!");
340 | } else {
341 | $evalPrefix = 'eval:';
342 | if (is_string($requirement['condition']) && strpos($requirement['condition'], $evalPrefix) === 0) {
343 | $expression = substr($requirement['condition'], strlen($evalPrefix));
344 | $requirement['condition'] = $this->evaluateExpression($expression);
345 | }
346 | }
347 | if (!array_key_exists('name', $requirement)) {
348 | $requirement['name'] = is_numeric($requirementKey) ? 'Requirement #' . $requirementKey : $requirementKey;
349 | }
350 | if (!array_key_exists('mandatory', $requirement)) {
351 | if (array_key_exists('required', $requirement)) {
352 | $requirement['mandatory'] = $requirement['required'];
353 | } else {
354 | $requirement['mandatory'] = false;
355 | }
356 | }
357 | if (!array_key_exists('by', $requirement)) {
358 | $requirement['by'] = 'Unknown';
359 | }
360 | if (!array_key_exists('memo', $requirement)) {
361 | $requirement['memo'] = '';
362 | }
363 |
364 | return $requirement;
365 | }
366 |
367 | /**
368 | * Displays a usage error.
369 | * This method will then terminate the execution of the current application.
370 | * @param string $message the error message
371 | */
372 | function usageError($message)
373 | {
374 | echo "Error: $message\n\n";
375 | exit(1);
376 | }
377 |
378 | /**
379 | * Evaluates a PHP expression under the context of this class.
380 | * @param string $expression a PHP expression to be evaluated.
381 | * @return mixed the expression result.
382 | */
383 | function evaluateExpression($expression)
384 | {
385 | return eval('return ' . $expression . ';');
386 | }
387 |
388 | /**
389 | * Returns the server information.
390 | * @return string server information.
391 | */
392 | function getServerInfo()
393 | {
394 | return isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : '';;
395 | }
396 |
397 | /**
398 | * Returns the now date if possible in string representation.
399 | * @return string now date.
400 | */
401 | function getNowDate()
402 | {
403 | return @strftime('%Y-%m-%d %H:%M', time());;
404 | }
405 | }
406 |
--------------------------------------------------------------------------------