├── .env-dist ├── .gitignore ├── .gitlab-ci.yml ├── Makefile ├── README.md ├── docker-compose.yml ├── nginx ├── Dockerfile-fpm-nginx └── image-files │ ├── etc │ ├── nginx │ │ ├── conf.d │ │ │ └── default.conf │ │ ├── nginx.conf │ │ └── ssl │ │ │ ├── nginx-selfsigned.crt │ │ │ └── nginx-selfsigned.key │ └── supervisor │ │ ├── conf.d │ │ ├── fpm.conf │ │ └── nginx.conf │ │ └── supervisord.conf │ ├── root │ └── .bashrc │ └── usr │ └── local │ ├── bin │ ├── composer │ ├── docker-entrypoint.sh │ └── docker-run.sh │ └── etc │ └── php │ ├── conf.d │ └── base.ini │ ├── php-fpm.conf │ └── pool.d │ └── www.conf └── test ├── app └── web │ └── index.php ├── debug.sh ├── dev.sh ├── prod.sh ├── requirements.php └── requirements ├── YiiRequirementChecker.php ├── requirements.php └── views ├── console └── index.php └── web ├── css.php └── index.php /.env-dist: -------------------------------------------------------------------------------- 1 | PHP_IMAGE_NAME=local/dmstr/php-yii2 2 | GITHUB_API_TOKEN=0000000000000000000000000000000000000000 3 | 4 | PHP_BASE_IMAGE_VERSION=8.0 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | stages: 2 | - build 3 | - test 4 | - release 5 | - cleanup 6 | 7 | variables: 8 | PHP_IMAGE_NAME: dmstr/php-yii2 9 | 10 | before_script: 11 | - export ISOLATION=buildpipeline${CI_PIPELINE_ID} 12 | - export COMPOSE_PROJECT_NAME=${ISOLATION}${CI_BUILD_NAME} 13 | - export PHP_BASE_IMAGE_VERSION=8.1 14 | - export STACK_PHP_IMAGE=${PHP_IMAGE_NAME}:${PHP_BASE_IMAGE_VERSION} 15 | - export REGISTRY_PHP_IMAGE=${PHP_IMAGE_NAME}:${CI_BUILD_REF_NAME} 16 | - export REGISTRY_PHP_IMAGE_LATEST=${PHP_IMAGE_NAME}:latest 17 | - echo "Build-environment information" 18 | # Docker >= 17.05 required for dynamic FROM references 19 | - docker version 20 | - docker-compose config 21 | - docker images ${PHP_IMAGE_NAME} 22 | 23 | after_script: 24 | - export ISOLATION=buildpipeline${CI_PIPELINE_ID} 25 | - export COMPOSE_PROJECT_NAME=${ISOLATION}${CI_BUILD_NAME} 26 | - docker-compose down -v 27 | 28 | 29 | test:php: 30 | stage: test 31 | script: 32 | - export PHP_SERVICE=php-nginx 33 | - sh test/prod.sh 34 | - sh test/dev.sh 35 | - sh test/debug.sh 36 | - docker-compose run --rm php-nginx php /test/requirements.php 37 | 38 | test:php:allow-fail: 39 | stage: test 40 | script: 41 | - docker-compose run --rm php-nginx sh -c 'composer diagnose' 42 | allow_failure: true 43 | except: 44 | - tags 45 | 46 | 47 | build:php-nginx: 48 | stage: build 49 | script: 50 | - cd nginx 51 | # use locally built image 52 | - docker-compose build php-nginx 53 | 54 | test:php-nginx: 55 | stage: test 56 | script: 57 | - docker-compose run --rm php-nginx nginx -v 58 | 59 | release:nginx:latest: 60 | stage: release 61 | only: 62 | - master 63 | script: 64 | - docker login --username ${REGISTRY_USER} --password ${REGISTRY_PASS} ${REGISTRY_HOST} 65 | - docker tag ${STACK_PHP_IMAGE}-nginx ${REGISTRY_PHP_IMAGE_LATEST}-nginx 66 | - docker push ${REGISTRY_PHP_IMAGE_LATEST}-nginx 67 | - docker logout ${REGISTRY_HOST} 68 | 69 | release:nginx:tags: 70 | stage: release 71 | only: 72 | - tags 73 | script: 74 | - docker login --username ${REGISTRY_USER} --password ${REGISTRY_PASS} ${REGISTRY_HOST} 75 | - docker tag ${STACK_PHP_IMAGE}-nginx ${REGISTRY_PHP_IMAGE}-nginx 76 | - docker push ${REGISTRY_PHP_IMAGE}-nginx 77 | - docker logout ${REGISTRY_HOST} 78 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | docker-compose build --pull php-nginx 3 | 4 | push-all: 5 | git remote | xargs -L1 git push --all 6 | 7 | lint: 8 | docker run -it --rm -v "$(PWD)/php/Dockerfile-fpm":/Dockerfile:ro redcoolbeans/dockerlint 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > :rotating_light: This repository is abandoned, please use https://github.com/yiisoft/yii2-docker 2 | 3 | 4 | Supported tags and respective `Dockerfile` links 5 | ================================================ 6 | 7 | - `7.x-fpm-x.x`, `latest` ([Dockerfile](php/Dockerfile-fpm)) 8 | - `7.x-fpm-x.x-nginx`, `latest-nginx` ([Dockerfile](nginx/Dockerfile-fpm-nginx)) 9 | 10 | :information_source: See repository tags for full version numbers 11 | 12 | See all available [image tags](https://hub.docker.com/r/dmstr/php-yii2/tags/) 13 | 14 | [![build status](https://git.hrzg.de/dmstr/docker-php-yii2/badges/master/build.svg)](https://git.hrzg.de/dmstr/docker-php-yii2/commits/master) 15 | 16 | 17 | Changelog 18 | --------- 19 | 20 | ### 8.x 21 | 22 | - using updated yii2 images 23 | - different system package installation 24 | - composer 2 25 | - removed standalone `fpm` image 26 | 27 | ### 7.x 28 | 29 | - switched to PHP 7.4 30 | 31 | ### 6.x 32 | 33 | - Alpine support has been dropped 34 | - Forego has been replace with supervisord 35 | - Removed Linkchecker 36 | 37 | ### 5.x 38 | 39 | *no stable release* 40 | 41 | ### 4.x 42 | 43 | - added bash-autocompletion 44 | - removed separate xdebug flavour 45 | 46 | 47 | Introduction 48 | ------------ 49 | 50 | This is a Docker PHP image containing PHP extensions and composer packages and libraries for *Yii 2.0 Framework*. 51 | It is primarily intended to build Yii 2.0 applications `FROM` this image, see below for available application templates. 52 | 53 | There is also an `nginx` flavour available for this image, in which PHP and nginx are managed with [supervisor](http://supervisord.org/). 54 | 55 | In older versions of the `nginx` images, forego was used for process control. 56 | However, since forego is no longer actively maintained and problems can arise if one of the started processes terminates unsuspectedly, 57 | we decided to switch to supervisor. 58 | 59 | 60 | Features 61 | -------- 62 | 63 | ### CLI commands 64 | 65 | - `composer` 66 | - `codecept` 67 | - `phpunit` 68 | - `npm` 69 | 70 | #### Extensions 71 | 72 | - soap 73 | - zip 74 | - curl 75 | - bcmath 76 | - exif 77 | - gd 78 | - iconv 79 | - intl 80 | - mbstring 81 | - opcache 82 | - pdo_mysql 83 | - pdo_pgsql 84 | - memcache 85 | - xdebug - *installed, but not loaded by default* 86 | 87 | 88 | Configuration 89 | ------------- 90 | 91 | ### ENV variables 92 | 93 | - `GITHUB_API_TOKEN` 94 | - `PHP_ENABLE_XDEBUG` 95 | - `PHP_USER_ID` (debian only) 96 | 97 | 98 | Development 99 | ----------- 100 | 101 | Building the images 102 | 103 | docker-compose build 104 | 105 | Development bash 106 | 107 | docker run -it dmstr/php-yii2 bash 108 | 109 | 110 | Resources 111 | --------- 112 | 113 | - [GitHub project](https://github.com/dmstr/docker-php-yii2) 114 | - [GitLab build](https://git.hrzg.de/dmstr/docker-php-yii2/builds) 115 | - [DockerHub image](https://hub.docker.com/r/dmstr/php-yii2/) 116 | - [yii2-app](https://github.com/dmstr/docker-yii2-app) minimal application tempplate 117 | - [phd5](https://github.com/dmstr/phd5-app) standard application template 118 | - [phd5](https://github.com/dmstr/docs-phd5) documentation 119 | 120 | --- 121 | 122 | #### ![dmstr logo](http://t.phundament.com/dmstr-16-cropped.png) Built by [dmstr](http://diemeisterei.de) 123 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | 4 | php-nginx: 5 | build: 6 | dockerfile: Dockerfile-fpm-nginx 7 | context: 'nginx' 8 | args: 9 | - PHP_BASE_IMAGE_VERSION=${PHP_BASE_IMAGE_VERSION} 10 | image: ${PHP_IMAGE_NAME}:${PHP_BASE_IMAGE_VERSION}-nginx 11 | environment: 12 | - GITHUB_API_TOKEN=${GITHUB_API_TOKEN} 13 | - PHP_ENABLE_XDEBUG=${PHP_ENABLE_XDEBUG} 14 | volumes: 15 | - ./test:/test 16 | - ./test/app/web:/app/web 17 | ports: 18 | - 80 19 | - 443 20 | -------------------------------------------------------------------------------- /nginx/Dockerfile-fpm-nginx: -------------------------------------------------------------------------------- 1 | # PHP Docker image for Yii 2.0 Framework runtime 2 | # ============================================== 3 | 4 | ARG PHP_BASE_IMAGE_VERSION 5 | FROM yiisoftware/yii2-php:${PHP_BASE_IMAGE_VERSION}-fpm 6 | 7 | # Install system packages for PHP extensions recommended for Yii 2.0 Framework 8 | ENV DEBIAN_FRONTEND=noninteractive 9 | RUN apt-get update && \ 10 | apt-get -y install \ 11 | gnupg2 && \ 12 | apt-key update && \ 13 | apt-get update && \ 14 | apt-get -y install \ 15 | git \ 16 | nano \ 17 | npm \ 18 | default-mysql-client \ 19 | nginx-full \ 20 | cron \ 21 | supervisor \ 22 | procps \ 23 | --no-install-recommends && \ 24 | apt-get clean && \ 25 | rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 26 | 27 | # Install less-compiler 28 | RUN npm -g install \ 29 | less \ 30 | lesshint \ 31 | uglify-js \ 32 | uglifycss 33 | 34 | # Install Yii framework bash autocompletion 35 | RUN curl -L https://raw.githubusercontent.com/yiisoft/yii2/master/contrib/completion/bash/yii \ 36 | -o /etc/bash_completion.d/yii 37 | 38 | # Add configuration files 39 | COPY image-files/ / 40 | 41 | # Add GITHUB_API_TOKEN support for composer 42 | RUN chmod 700 \ 43 | /usr/local/bin/docker-entrypoint.sh \ 44 | /usr/local/bin/docker-run.sh \ 45 | /usr/local/bin/composer 46 | 47 | WORKDIR /app 48 | 49 | # Startup script for FPM 50 | ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] 51 | 52 | # forward request and error logs to docker log collector 53 | RUN ln -sf /dev/stdout /var/log/nginx/access.log \ 54 | && ln -sf /dev/stderr /var/log/nginx/error.log \ 55 | && ln -sf /usr/sbin/cron /usr/sbin/crond 56 | 57 | CMD ["supervisord", "-c", "/etc/supervisor/supervisord.conf"] 58 | 59 | EXPOSE 80 443 60 | -------------------------------------------------------------------------------- /nginx/image-files/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 | } -------------------------------------------------------------------------------- /nginx/image-files/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 | -------------------------------------------------------------------------------- /nginx/image-files/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 | -------------------------------------------------------------------------------- /nginx/image-files/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 | -------------------------------------------------------------------------------- /nginx/image-files/etc/supervisor/conf.d/fpm.conf: -------------------------------------------------------------------------------- 1 | [program:php-fpm] 2 | command = php-fpm 3 | autostart = true 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 | -------------------------------------------------------------------------------- /nginx/image-files/etc/supervisor/conf.d/nginx.conf: -------------------------------------------------------------------------------- 1 | [program:nginx] 2 | command=/usr/sbin/nginx -g 'daemon off;' 3 | autostart=true 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 | -------------------------------------------------------------------------------- /nginx/image-files/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 | -------------------------------------------------------------------------------- /nginx/image-files/root/.bashrc: -------------------------------------------------------------------------------- 1 | PS1="\e[0;35m[$APP_NAME] $APP_VERSION \e[0;0m\w \e[0;37m\u \h \e[0;0m\n$ " 2 | 3 | cat <<'MSG' 4 | ___________ 5 | | | 6 | | _ | _ _ 7 | | /\| |/\ | | | | | 8 | | \ ` ' / | __| |_ __ ___ ___| |_ _ __ 9 | | |_ _| | / _` | '_ ` _ \/ __| __| '__| 10 | | / , . \ | | (_| | | | | | \__ \ |_| | 11 | | \/|_|\/ | \__,_|_| |_| |_|___/\__|_| 12 | \ / 13 | \_______/ 14 | 15 | Docker image dmstr/php-yii2 16 | 17 | Console commands: composer, codecept, phpunit, yii 18 | 19 | MSG 20 | 21 | echo "PHP version: ${PHP_VERSION}" 22 | 23 | if ! shopt -oq posix; then 24 | if [ -f /usr/share/bash-completion/bash_completion ]; then 25 | . /usr/share/bash-completion/bash_completion 26 | elif [ -f /etc/bash_completion.d/yii ]; then 27 | . /etc/bash_completion.d/yii 28 | fi 29 | fi -------------------------------------------------------------------------------- /nginx/image-files/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 | composer.phar "$@" -------------------------------------------------------------------------------- /nginx/image-files/usr/local/bin/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script is run within the php containers on start 4 | 5 | # Fail on any error 6 | set -o errexit 7 | 8 | # Set permissions based on ENV variable (debian only) 9 | if [ -x "usermod" ] ; then 10 | usermod -u ${PHP_USER_ID} www-data 11 | fi 12 | 13 | # Enable xdebug by ENV variable 14 | if [ 0 -ne "${PHP_ENABLE_XDEBUG:-0}" ] ; then 15 | docker-php-ext-enable xdebug 16 | echo "Enabled xdebug" 17 | fi 18 | 19 | # Execute CMD 20 | exec "$@" -------------------------------------------------------------------------------- /nginx/image-files/usr/local/bin/docker-run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script is run within the php containers on start 4 | # docker-run.sh is available for legacy setups 5 | 6 | # Fail on any error 7 | set -o errexit 8 | 9 | # Run the command sent as command line arguments 10 | php-fpm 11 | -------------------------------------------------------------------------------- /nginx/image-files/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 -------------------------------------------------------------------------------- /nginx/image-files/usr/local/etc/php/php-fpm.conf: -------------------------------------------------------------------------------- 1 | ; This file was initially adapated from the output of: (on PHP 5.6) 2 | ; grep -vE '^;|^ *$' php-fpm.conf.default 3 | 4 | [global] 5 | 6 | error_log = /proc/self/fd/2 7 | daemonize = no 8 | 9 | include=/usr/local/etc/php/pool.d/*.conf 10 | -------------------------------------------------------------------------------- /nginx/image-files/usr/local/etc/php/pool.d/www.conf: -------------------------------------------------------------------------------- 1 | [www] 2 | 3 | ; if we send this to /proc/self/fd/1, it never appears 4 | access.log = /proc/self/fd/2 5 | 6 | user = www-data 7 | group = www-data 8 | 9 | listen = [::]:9000 10 | 11 | pm = dynamic 12 | pm.max_children = 10 13 | pm.start_servers = 2 14 | pm.min_spare_servers = 1 15 | pm.max_spare_servers = 2 16 | pm.max_requests = 500 17 | 18 | ; send worker output to stdout/stderr 19 | catch_workers_output = yes 20 | 21 | ; make all environment variables available to php-fpm at runtime 22 | clear_env = no 23 | -------------------------------------------------------------------------------- /test/app/web/index.php: -------------------------------------------------------------------------------- 1 | /dev/null || exit 1 11 | 12 | echo "Checking opcache..." 13 | docker-compose run --rm ${PHP_SERVICE} php -m | grep -i opcache 1>/dev/null || exit 1 14 | 15 | echo "Checking composer auth..." 16 | docker-compose run -e GITHUB_API_TOKEN=abcd12345 --rm ${PHP_SERVICE} sh -c '\ 17 | composer && \ 18 | [ -f ~/.composer/auth.json ] || exit 1 \ 19 | ' 20 | 21 | echo "Done." 22 | -------------------------------------------------------------------------------- /test/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 | // Cache : 81 | array( 82 | 'name' => 'Memcache extension', 83 | 'mandatory' => false, 84 | 'condition' => extension_loaded('memcache') || extension_loaded('memcached'), 85 | 'by' => 'MemCache', 86 | 'memo' => extension_loaded('memcached') ? 'To use memcached set MemCache::useMemcached to true.' : '' 87 | ), 88 | // CAPTCHA: 89 | array( 90 | 'name' => 'GD PHP extension with FreeType support', 91 | 'mandatory' => false, 92 | 'condition' => $gdOK, 93 | 'by' => 'Captcha', 94 | 'memo' => $gdMemo, 95 | ), 96 | array( 97 | 'name' => 'ImageMagick PHP extension with PNG support', 98 | 'mandatory' => false, 99 | 'condition' => $imagickOK, 100 | 'by' => 'Captcha', 101 | 'memo' => $imagickMemo, 102 | ), 103 | // PHP ini : 104 | 'phpExposePhp' => array( 105 | 'name' => 'Expose PHP', 106 | 'mandatory' => false, 107 | 'condition' => $requirementsChecker->checkPhpIniOff("expose_php"), 108 | 'by' => 'Security reasons', 109 | 'memo' => '"expose_php" should be disabled at php.ini', 110 | ), 111 | 'phpAllowUrlInclude' => array( 112 | 'name' => 'PHP allow url include', 113 | 'mandatory' => false, 114 | 'condition' => $requirementsChecker->checkPhpIniOff("allow_url_include"), 115 | 'by' => 'Security reasons', 116 | 'memo' => '"allow_url_include" should be disabled at php.ini', 117 | ), 118 | 'phpSmtp' => array( 119 | 'name' => 'PHP mail SMTP', 120 | 'mandatory' => false, 121 | 'condition' => strlen(ini_get('SMTP')) > 0, 122 | 'by' => 'Email sending', 123 | 'memo' => 'PHP mail SMTP server required', 124 | ), 125 | ); 126 | 127 | // OPcache check 128 | if (!version_compare(phpversion(), '5.5', '>=')) { 129 | $requirements[] = array( 130 | 'name' => 'APC extension', 131 | 'mandatory' => false, 132 | 'condition' => extension_loaded('apc'), 133 | 'by' => 'ApcCache', 134 | ); 135 | } 136 | 137 | $requirementsChecker->checkYii()->check($requirements)->render(); -------------------------------------------------------------------------------- /test/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 | * Check the given requirements, collecting results into internal field. 61 | * This method can be invoked several times checking different requirement sets. 62 | * Use [[getResult()]] or [[render()]] to get the results. 63 | * @param array|string $requirements requirements to be checked. 64 | * If an array, it is treated as the set of requirements; 65 | * If a string, it is treated as the path of the file, which contains the requirements; 66 | * @return $this self instance. 67 | */ 68 | function check($requirements) 69 | { 70 | if (is_string($requirements)) { 71 | $requirements = require($requirements); 72 | } 73 | if (!is_array($requirements)) { 74 | $this->usageError('Requirements must be an array, "' . gettype($requirements) . '" has been given!'); 75 | } 76 | if (!isset($this->result) || !is_array($this->result)) { 77 | $this->result = array( 78 | 'summary' => array( 79 | 'total' => 0, 80 | 'errors' => 0, 81 | 'warnings' => 0, 82 | ), 83 | 'requirements' => array(), 84 | ); 85 | } 86 | foreach ($requirements as $key => $rawRequirement) { 87 | $requirement = $this->normalizeRequirement($rawRequirement, $key); 88 | $this->result['summary']['total']++; 89 | if (!$requirement['condition']) { 90 | if ($requirement['mandatory']) { 91 | $requirement['error'] = true; 92 | $requirement['warning'] = true; 93 | $this->result['summary']['errors']++; 94 | } else { 95 | $requirement['error'] = false; 96 | $requirement['warning'] = true; 97 | $this->result['summary']['warnings']++; 98 | } 99 | } else { 100 | $requirement['error'] = false; 101 | $requirement['warning'] = false; 102 | } 103 | $this->result['requirements'][] = $requirement; 104 | } 105 | 106 | return $this; 107 | } 108 | 109 | /** 110 | * Performs the check for the Yii core requirements. 111 | * @return YiiRequirementChecker self instance. 112 | */ 113 | function checkYii() 114 | { 115 | return $this->check(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'requirements.php'); 116 | } 117 | 118 | /** 119 | * Return the check results. 120 | * @return array|null check results in format: 121 | * 122 | * ```php 123 | * array( 124 | * 'summary' => array( 125 | * 'total' => total number of checks, 126 | * 'errors' => number of errors, 127 | * 'warnings' => number of warnings, 128 | * ), 129 | * 'requirements' => array( 130 | * array( 131 | * ... 132 | * 'error' => is there an error, 133 | * 'warning' => is there a warning, 134 | * ), 135 | * ... 136 | * ), 137 | * ) 138 | * ``` 139 | */ 140 | function getResult() 141 | { 142 | if (isset($this->result)) { 143 | return $this->result; 144 | } else { 145 | return null; 146 | } 147 | } 148 | 149 | /** 150 | * Renders the requirements check result. 151 | * The output will vary depending is a script running from web or from console. 152 | */ 153 | function render() 154 | { 155 | if (!isset($this->result)) { 156 | $this->usageError('Nothing to render!'); 157 | } 158 | $baseViewFilePath = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'views'; 159 | if (!empty($_SERVER['argv'])) { 160 | $viewFileName = $baseViewFilePath . DIRECTORY_SEPARATOR . 'console' . DIRECTORY_SEPARATOR . 'index.php'; 161 | } else { 162 | $viewFileName = $baseViewFilePath . DIRECTORY_SEPARATOR . 'web' . DIRECTORY_SEPARATOR . 'index.php'; 163 | } 164 | $this->renderViewFile($viewFileName, $this->result); 165 | } 166 | 167 | /** 168 | * Checks if the given PHP extension is available and its version matches the given one. 169 | * @param string $extensionName PHP extension name. 170 | * @param string $version required PHP extension version. 171 | * @param string $compare comparison operator, by default '>=' 172 | * @return boolean if PHP extension version matches. 173 | */ 174 | function checkPhpExtensionVersion($extensionName, $version, $compare = '>=') 175 | { 176 | if (!extension_loaded($extensionName)) { 177 | return false; 178 | } 179 | $extensionVersion = phpversion($extensionName); 180 | if (empty($extensionVersion)) { 181 | return false; 182 | } 183 | if (strncasecmp($extensionVersion, 'PECL-', 5) === 0) { 184 | $extensionVersion = substr($extensionVersion, 5); 185 | } 186 | 187 | return version_compare($extensionVersion, $version, $compare); 188 | } 189 | 190 | /** 191 | * Checks if PHP configuration option (from php.ini) is on. 192 | * @param string $name configuration option name. 193 | * @return boolean option is on. 194 | */ 195 | function checkPhpIniOn($name) 196 | { 197 | $value = ini_get($name); 198 | if (empty($value)) { 199 | return false; 200 | } 201 | 202 | return ((int) $value === 1 || strtolower($value) === 'on'); 203 | } 204 | 205 | /** 206 | * Checks if PHP configuration option (from php.ini) is off. 207 | * @param string $name configuration option name. 208 | * @return boolean option is off. 209 | */ 210 | function checkPhpIniOff($name) 211 | { 212 | $value = ini_get($name); 213 | if (empty($value)) { 214 | return true; 215 | } 216 | 217 | return (strtolower($value) === 'off'); 218 | } 219 | 220 | /** 221 | * Compare byte sizes of values given in the verbose representation, 222 | * like '5M', '15K' etc. 223 | * @param string $a first value. 224 | * @param string $b second value. 225 | * @param string $compare comparison operator, by default '>='. 226 | * @return boolean comparison result. 227 | */ 228 | function compareByteSize($a, $b, $compare = '>=') 229 | { 230 | $compareExpression = '(' . $this->getByteSize($a) . $compare . $this->getByteSize($b) . ')'; 231 | 232 | return $this->evaluateExpression($compareExpression); 233 | } 234 | 235 | /** 236 | * Gets the size in bytes from verbose size representation. 237 | * For example: '5K' => 5*1024 238 | * @param string $verboseSize verbose size representation. 239 | * @return integer actual size in bytes. 240 | */ 241 | function getByteSize($verboseSize) 242 | { 243 | if (empty($verboseSize)) { 244 | return 0; 245 | } 246 | if (is_numeric($verboseSize)) { 247 | return (int) $verboseSize; 248 | } 249 | $sizeUnit = trim($verboseSize, '0123456789'); 250 | $size = str_replace($sizeUnit, '', $verboseSize); 251 | $size = trim($size); 252 | if (!is_numeric($size)) { 253 | return 0; 254 | } 255 | switch (strtolower($sizeUnit)) { 256 | case 'kb': 257 | case 'k': 258 | return $size * 1024; 259 | case 'mb': 260 | case 'm': 261 | return $size * 1024 * 1024; 262 | case 'gb': 263 | case 'g': 264 | return $size * 1024 * 1024 * 1024; 265 | default: 266 | return 0; 267 | } 268 | } 269 | 270 | /** 271 | * Checks if upload max file size matches the given range. 272 | * @param string|null $min verbose file size minimum required value, pass null to skip minimum check. 273 | * @param string|null $max verbose file size maximum required value, pass null to skip maximum check. 274 | * @return boolean success. 275 | */ 276 | function checkUploadMaxFileSize($min = null, $max = null) 277 | { 278 | $postMaxSize = ini_get('post_max_size'); 279 | $uploadMaxFileSize = ini_get('upload_max_filesize'); 280 | if ($min !== null) { 281 | $minCheckResult = $this->compareByteSize($postMaxSize, $min, '>=') && $this->compareByteSize($uploadMaxFileSize, $min, '>='); 282 | } else { 283 | $minCheckResult = true; 284 | } 285 | if ($max !== null) { 286 | $maxCheckResult = $this->compareByteSize($postMaxSize, $max, '<=') && $this->compareByteSize($uploadMaxFileSize, $max, '<='); 287 | } else { 288 | $maxCheckResult = true; 289 | } 290 | 291 | return ($minCheckResult && $maxCheckResult); 292 | } 293 | 294 | /** 295 | * Renders a view file. 296 | * This method includes the view file as a PHP script 297 | * and captures the display result if required. 298 | * @param string $_viewFile_ view file 299 | * @param array $_data_ data to be extracted and made available to the view file 300 | * @param boolean $_return_ whether the rendering result should be returned as a string 301 | * @return string the rendering result. Null if the rendering result is not required. 302 | */ 303 | function renderViewFile($_viewFile_, $_data_ = null, $_return_ = false) 304 | { 305 | // we use special variable names here to avoid conflict when extracting data 306 | if (is_array($_data_)) { 307 | extract($_data_, EXTR_PREFIX_SAME, 'data'); 308 | } else { 309 | $data = $_data_; 310 | } 311 | if ($_return_) { 312 | ob_start(); 313 | ob_implicit_flush(false); 314 | require($_viewFile_); 315 | 316 | return ob_get_clean(); 317 | } else { 318 | require($_viewFile_); 319 | } 320 | } 321 | 322 | /** 323 | * Normalizes requirement ensuring it has correct format. 324 | * @param array $requirement raw requirement. 325 | * @param integer $requirementKey requirement key in the list. 326 | * @return array normalized requirement. 327 | */ 328 | function normalizeRequirement($requirement, $requirementKey = 0) 329 | { 330 | if (!is_array($requirement)) { 331 | $this->usageError('Requirement must be an array!'); 332 | } 333 | if (!array_key_exists('condition', $requirement)) { 334 | $this->usageError("Requirement '{$requirementKey}' has no condition!"); 335 | } else { 336 | $evalPrefix = 'eval:'; 337 | if (is_string($requirement['condition']) && strpos($requirement['condition'], $evalPrefix) === 0) { 338 | $expression = substr($requirement['condition'], strlen($evalPrefix)); 339 | $requirement['condition'] = $this->evaluateExpression($expression); 340 | } 341 | } 342 | if (!array_key_exists('name', $requirement)) { 343 | $requirement['name'] = is_numeric($requirementKey) ? 'Requirement #' . $requirementKey : $requirementKey; 344 | } 345 | if (!array_key_exists('mandatory', $requirement)) { 346 | if (array_key_exists('required', $requirement)) { 347 | $requirement['mandatory'] = $requirement['required']; 348 | } else { 349 | $requirement['mandatory'] = false; 350 | } 351 | } 352 | if (!array_key_exists('by', $requirement)) { 353 | $requirement['by'] = 'Unknown'; 354 | } 355 | if (!array_key_exists('memo', $requirement)) { 356 | $requirement['memo'] = ''; 357 | } 358 | 359 | return $requirement; 360 | } 361 | 362 | /** 363 | * Displays a usage error. 364 | * This method will then terminate the execution of the current application. 365 | * @param string $message the error message 366 | */ 367 | function usageError($message) 368 | { 369 | echo "Error: $message\n\n"; 370 | exit(1); 371 | } 372 | 373 | /** 374 | * Evaluates a PHP expression under the context of this class. 375 | * @param string $expression a PHP expression to be evaluated. 376 | * @return mixed the expression result. 377 | */ 378 | function evaluateExpression($expression) 379 | { 380 | return eval('return ' . $expression . ';'); 381 | } 382 | 383 | /** 384 | * Returns the server information. 385 | * @return string server information. 386 | */ 387 | function getServerInfo() 388 | { 389 | return isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : '';; 390 | } 391 | 392 | /** 393 | * Returns the now date if possible in string representation. 394 | * @return string now date. 395 | */ 396 | function getNowDate() 397 | { 398 | return @strftime('%Y-%m-%d %H:%M', time());; 399 | } 400 | } 401 | -------------------------------------------------------------------------------- /test/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 | -------------------------------------------------------------------------------- /test/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 | -------------------------------------------------------------------------------- /test/requirements/views/web/css.php: -------------------------------------------------------------------------------- 1 | 64 | -------------------------------------------------------------------------------- /test/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 | 52 | 53 | 54 | 57 | 60 | 63 | 66 | 67 | 68 |
NameResultRequired ByMemo
55 | 56 | 58 | 59 | 61 | 62 | 64 | 65 |
69 |
70 |
71 | 75 |
76 | 77 | 78 | --------------------------------------------------------------------------------