diff --git a/.env.dist b/.env.dist
new file mode 100644
index 000000000..0b6b05c67
--- /dev/null
+++ b/.env.dist
@@ -0,0 +1,5 @@
+COMPOSE_FILE=docker/docker-compose.yaml:docker/docker-compose.yaml
+MYSQL_ROOT_PASSWORD=
+MYSQL_DATABASE=
+MYSQL_USER=
+MYSQL_PASSWORD=
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 000000000..120c1b6ad
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+.env
+vendor
+mysql-data
+.idea
+composer.lock
diff --git a/composer.json b/composer.json
new file mode 100644
index 000000000..c06643eec
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,12 @@
+{
+ "name": "aleksandrdolgov/otus_php_2023",
+ "type": "project",
+ "autoload": {
+ "psr-4": {
+ "App\\": "src/"
+ }
+ },
+ "require-dev": {
+ "squizlabs/php_codesniffer": "^3.7"
+ }
+}
diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml
new file mode 100644
index 000000000..3ad1585c1
--- /dev/null
+++ b/docker/docker-compose.yaml
@@ -0,0 +1,90 @@
+version: '3'
+
+services:
+ nginx-root:
+ image: nginx:stable-alpine
+ container_name: nginx-root
+ working_dir: /app
+ ports:
+ - "80:80"
+ networks:
+ - app-network
+ volumes:
+ - ../docker/nginx-root/application.local.conf:/etc/nginx/conf.d/application.local.conf
+
+ nginx-child-1:
+ image: nginx:stable-alpine
+ container_name: nginx-child-1
+ working_dir: /app
+ volumes:
+ - ../docker/nginx-child/application.local.conf:/etc/nginx/conf.d/application.local.conf
+ - ../app:/app
+ networks:
+ - app-network
+
+ nginx-child-2:
+ image: nginx:stable-alpine
+ container_name: nginx-child-2
+ working_dir: /app
+ volumes:
+ - ../docker/nginx-child/application.local.conf:/etc/nginx/conf.d/application.local.conf
+ - ..app:/app
+ networks:
+ - app-network
+
+ nginx-child-3:
+ image: nginx:stable-alpine
+ container_name: nginx-child-3
+ working_dir: /app
+ volumes:
+ - ../docker/nginx-child/application.local.conf:/etc/nginx/conf.d/application.local.conf
+ - ..app:/app
+ networks:
+ - app-network
+
+ memcached:
+ image: memcached:latest
+ ports:
+ - "11211:11211"
+ container_name: app-memcached
+ networks:
+ - app-network
+
+ php-fpm-1:
+ build:
+ context: ./..
+ dockerfile: docker/fpm/Dockerfile
+ container_name: php-fpm-1
+ volumes:
+ - ../:/app
+ working_dir: /app
+ networks:
+ - app-network
+
+ # second php-fpm
+ php-fpm-2:
+ build:
+ context: ./..
+ dockerfile: docker/fpm/Dockerfile
+ container_name: php-fpm-2
+ volumes:
+ - ../:/app
+ working_dir: /app
+ networks:
+ - app-network
+
+ # third php-fpm
+ php-fpm-3:
+ build:
+ context: ./..
+ dockerfile: docker/fpm/Dockerfile
+ container_name: php-fpm-3
+ volumes:
+ - ../:/app
+ working_dir: /app
+ networks:
+ - app-network
+
+networks:
+ app-network:
+ driver: bridge
diff --git a/docker/fpm/Dockerfile b/docker/fpm/Dockerfile
new file mode 100644
index 000000000..8ee90ae19
--- /dev/null
+++ b/docker/fpm/Dockerfile
@@ -0,0 +1,36 @@
+FROM php:8.2-fpm
+
+# ставим необходимые для нормальной работы модули
+ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/
+
+RUN apt-get update && apt-get install -y \
+ libfreetype6-dev \
+ libjpeg62-turbo-dev \
+ libpng-dev \
+ libonig-dev \
+ libzip-dev \
+ libmemcached11 \
+ zlib1g-dev libssl-dev \
+ libmemcached-dev \
+ libmcrypt-dev \
+ && pecl install mcrypt \
+ && docker-php-ext-enable mcrypt \
+ && docker-php-ext-install -j$(nproc) iconv mbstring mysqli pdo_mysql zip \
+ && docker-php-ext-configure gd --with-freetype --with-jpeg \
+ && docker-php-ext-install -j$(nproc) gd \
+ && chmod +x /usr/local/bin/install-php-extensions \
+ && install-php-extensions redis \
+ && install-php-extensions @composer-2.2.0 \
+ && install-php-extensions memcached
+
+COPY docker/fpm/php.ini /usr/local/etc/php/conf.d/php-custom.ini
+
+COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
+
+USER www-data:www-data
+
+COPY composer.json composer.json
+
+RUN composer install
+
+CMD ["php-fpm"]
diff --git a/docker/fpm/php.ini b/docker/fpm/php.ini
new file mode 100644
index 000000000..ed0de8695
--- /dev/null
+++ b/docker/fpm/php.ini
@@ -0,0 +1,2 @@
+session.save_handler = memcache
+session.save_path = "tcp://memcache:11211"
diff --git a/docker/nginx-child/Dockerfile b/docker/nginx-child/Dockerfile
new file mode 100644
index 000000000..6e89f863d
--- /dev/null
+++ b/docker/nginx-child/Dockerfile
@@ -0,0 +1,11 @@
+FROM nginx
+
+COPY ./application.local.conf /etc/nginx/conf.d/application.local.conf
+
+WORKDIR /app
+
+VOLUME /app
+
+EXPOSE 7878
+
+#CMD ["nginx", "-g", "daemon off;"]
diff --git a/docker/nginx-child/application.local.conf b/docker/nginx-child/application.local.conf
new file mode 100644
index 000000000..48e6a48dd
--- /dev/null
+++ b/docker/nginx-child/application.local.conf
@@ -0,0 +1,25 @@
+upstream backend {
+ least_conn;
+ server php-fpm-1:9000;
+ server php-fpm-2:9000;
+ server php-fpm-3:9000;
+}
+
+server {
+ listen 80;
+
+ root /app/public;
+ index index.php index.html;
+
+ location / {
+ try_files $uri $uri/ /index.php?$query_string;
+ }
+
+ # и наконец правило обращения к php-fpm
+ location ~* .php$ {
+ fastcgi_pass backend;
+ try_files $uri = 404;
+ include fastcgi_params;
+ fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
+ }
+}
diff --git a/docker/nginx-root/Dockerfile b/docker/nginx-root/Dockerfile
new file mode 100644
index 000000000..bbff36fc5
--- /dev/null
+++ b/docker/nginx-root/Dockerfile
@@ -0,0 +1,11 @@
+#FROM nginx
+#
+#COPY ./application.local.conf /etc/nginx/conf.d/application.local.conf
+#
+#WORKDIR /app
+#
+#VOLUME /app
+#
+#EXPOSE 80
+
+#CMD ["nginx", "-g", "daemon off;"]
diff --git a/docker/nginx-root/application.local.conf b/docker/nginx-root/application.local.conf
new file mode 100644
index 000000000..3502e0ecc
--- /dev/null
+++ b/docker/nginx-root/application.local.conf
@@ -0,0 +1,14 @@
+upstream nginx-balancer{
+ server nginx-child-1:80;
+ server nginx-child-2:80;
+ server nginx-child-3:80;
+}
+
+server {
+ listen 80;
+ server_name application.local;
+
+ location / {
+ proxy_pass http://nginx-balancer;
+ }
+}
diff --git a/public/index.php b/public/index.php
new file mode 100644
index 000000000..f4e5ebb20
--- /dev/null
+++ b/public/index.php
@@ -0,0 +1,10 @@
+runApp();
diff --git a/src/AppValidator.php b/src/AppValidator.php
new file mode 100644
index 000000000..64f74b80c
--- /dev/null
+++ b/src/AppValidator.php
@@ -0,0 +1,36 @@
+This is " . $_SERVER['HOSTNAME'] . "";
+ echo sprintf('Валидация скобок в строке "%s" прошла успешно', $string);
+ phpinfo();
+ } else {
+ echo sprintf('Строка "%s" не прошла валидацию на скобки', $string);
+ }
+ } catch (Exception $exception) {
+ header("HTTP/1.1 {$exception->getCode()} {$exception->getMessage()}");
+ }
+ }
+}
diff --git a/src/Validators/BracketValidator.php b/src/Validators/BracketValidator.php
new file mode 100644
index 000000000..abd056261
--- /dev/null
+++ b/src/Validators/BracketValidator.php
@@ -0,0 +1,17 @@
+