+
= $text->title ?>
+
= $text->text ?>
+
+
+
текстов нет
+
diff --git a/frontend/views/site/about.php b/frontend/views/site/about.php
new file mode 100755
index 0000000..b40ea44
--- /dev/null
+++ b/frontend/views/site/about.php
@@ -0,0 +1,16 @@
+title = 'About';
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
= Html::encode($this->title) ?>
+
+
This is the About page. You may modify the following file to customize its content:
+
+
= __FILE__ ?>
+
diff --git a/frontend/views/site/contact.php b/frontend/views/site/contact.php
new file mode 100755
index 0000000..6e6b8ac
--- /dev/null
+++ b/frontend/views/site/contact.php
@@ -0,0 +1,45 @@
+title = 'Contact';
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
diff --git a/frontend/views/site/error.php b/frontend/views/site/error.php
new file mode 100755
index 0000000..1768747
--- /dev/null
+++ b/frontend/views/site/error.php
@@ -0,0 +1,27 @@
+title = $name;
+?>
+
+
+
= Html::encode($this->title) ?>
+
+
+ = nl2br(Html::encode($message)) ?>
+
+
+
+ The above error occurred while the Web server was processing your request.
+
+
+ Please contact us if you think this is a server error. Thank you.
+
+
+
diff --git a/frontend/views/site/index.php b/frontend/views/site/index.php
new file mode 100755
index 0000000..b489c8e
--- /dev/null
+++ b/frontend/views/site/index.php
@@ -0,0 +1,52 @@
+title = 'My Yii Application';
+?>
+
+
+
+
Congratulations!
+
You have successfully created your Yii-powered application.
+
Get started with Yii
+
+
+
+
+
+
+
+
Heading
+
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et
+ dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip
+ ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
+ fugiat nulla pariatur.
+
+
Yii Documentation »
+
+
+
Heading
+
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et
+ dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip
+ ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
+ fugiat nulla pariatur.
+
+
Yii Forum »
+
+
+
Heading
+
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et
+ dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip
+ ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
+ fugiat nulla pariatur.
+
+
Yii Extensions »
+
+
+
+
+
diff --git a/frontend/views/site/login.php b/frontend/views/site/login.php
new file mode 100755
index 0000000..6685b8c
--- /dev/null
+++ b/frontend/views/site/login.php
@@ -0,0 +1,41 @@
+title = 'Login';
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
= Html::encode($this->title) ?>
+
+
Please fill out the following fields to login:
+
+
+
+ 'login-form']); ?>
+
+ = $form->field($model, 'username')->textInput(['autofocus' => true]) ?>
+
+ = $form->field($model, 'password')->passwordInput() ?>
+
+ = $form->field($model, 'rememberMe')->checkbox() ?>
+
+
+ If you forgot your password you can = Html::a('reset it', ['site/request-password-reset']) ?>.
+
+ Need new verification email? = Html::a('Resend', ['site/resend-verification-email']) ?>
+
+
+
+ = Html::submitButton('Login', ['class' => 'btn btn-primary', 'name' => 'login-button']) ?>
+
+
+
+
+
+
diff --git a/frontend/views/site/requestPasswordResetToken.php b/frontend/views/site/requestPasswordResetToken.php
new file mode 100755
index 0000000..72f1693
--- /dev/null
+++ b/frontend/views/site/requestPasswordResetToken.php
@@ -0,0 +1,31 @@
+title = 'Request password reset';
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
= Html::encode($this->title) ?>
+
+
Please fill out your email. A link to reset password will be sent there.
+
+
+
+ 'request-password-reset-form']); ?>
+
+ = $form->field($model, 'email')->textInput(['autofocus' => true]) ?>
+
+
+ = Html::submitButton('Send', ['class' => 'btn btn-primary']) ?>
+
+
+
+
+
+
diff --git a/frontend/views/site/resendVerificationEmail.php b/frontend/views/site/resendVerificationEmail.php
new file mode 100755
index 0000000..23f5666
--- /dev/null
+++ b/frontend/views/site/resendVerificationEmail.php
@@ -0,0 +1,31 @@
+title = 'Resend verification email';
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
= Html::encode($this->title) ?>
+
+
Please fill out your email. A verification email will be sent there.
+
+
+
+ 'resend-verification-email-form']); ?>
+
+ = $form->field($model, 'email')->textInput(['autofocus' => true]) ?>
+
+
+ = Html::submitButton('Send', ['class' => 'btn btn-primary']) ?>
+
+
+
+
+
+
diff --git a/frontend/views/site/resetPassword.php b/frontend/views/site/resetPassword.php
new file mode 100755
index 0000000..61e15b4
--- /dev/null
+++ b/frontend/views/site/resetPassword.php
@@ -0,0 +1,31 @@
+title = 'Reset password';
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
= Html::encode($this->title) ?>
+
+
Please choose your new password:
+
+
+
+ 'reset-password-form']); ?>
+
+ = $form->field($model, 'password')->passwordInput(['autofocus' => true]) ?>
+
+
+ = Html::submitButton('Save', ['class' => 'btn btn-primary']) ?>
+
+
+
+
+
+
diff --git a/frontend/views/site/signup.php b/frontend/views/site/signup.php
new file mode 100755
index 0000000..3b005eb
--- /dev/null
+++ b/frontend/views/site/signup.php
@@ -0,0 +1,35 @@
+title = 'Signup';
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
= Html::encode($this->title) ?>
+
+
Please fill out the following fields to signup:
+
+
+
+ 'form-signup']); ?>
+
+ = $form->field($model, 'username')->textInput(['autofocus' => true]) ?>
+
+ = $form->field($model, 'email') ?>
+
+ = $form->field($model, 'password')->passwordInput() ?>
+
+
+ = Html::submitButton('Signup', ['class' => 'btn btn-primary', 'name' => 'signup-button']) ?>
+
+
+
+
+
+
diff --git a/frontend/web/assets/.gitignore b/frontend/web/assets/.gitignore
new file mode 100755
index 0000000..d6b7ef3
--- /dev/null
+++ b/frontend/web/assets/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/frontend/web/css/site.css b/frontend/web/css/site.css
new file mode 100755
index 0000000..4a65ca7
--- /dev/null
+++ b/frontend/web/css/site.css
@@ -0,0 +1,103 @@
+main > .container, main > .container-fluid
+{
+ padding: 70px 15px 20px;
+}
+
+.footer {
+ background-color: #f5f5f5;
+ font-size: .9em;
+ height: 60px;
+}
+
+.footer > .container, .footer > .container-fluid {
+ padding-right: 15px;
+ padding-left: 15px;
+}
+
+.not-set {
+ color: #c55;
+ font-style: italic;
+}
+
+/* add sorting icons to gridview sort links */
+a.asc:after, a.desc:after {
+ content: '';
+ left: 3px;
+ display: inline-block;
+ width: 0;
+ height: 0;
+ border: solid 5px transparent;
+ margin: 4px 4px 2px 4px;
+ background: transparent;
+}
+
+a.asc:after {
+ border-bottom: solid 7px #212529;
+ border-top-width: 0;
+}
+
+a.desc:after {
+ border-top: solid 7px #212529;
+ border-bottom-width: 0;
+}
+
+.grid-view th,
+.grid-view td:last-child {
+ white-space: nowrap;
+}
+
+.grid-view .filters input,
+.grid-view .filters select {
+ min-width: 50px;
+}
+
+.hint-block {
+ display: block;
+ margin-top: 5px;
+ color: #999;
+}
+
+.error-summary {
+ color: #a94442;
+ background: #fdf7f7;
+ border-left: 3px solid #eed3d7;
+ padding: 10px 20px;
+ margin: 0 0 15px 0;
+}
+
+/* align the logout "link" (button in form) of the navbar */
+.navbar form > button.logout {
+ padding-top: 7px;
+ color: rgba(255, 255, 255, 0.5);
+}
+
+@media(max-width:767px) {
+ .navbar form > button.logout {
+ display:block;
+ text-align: left;
+ width: 100%;
+ padding: 10px 0;
+ }
+}
+
+.navbar form > button.logout:focus,
+.navbar form > button.logout:hover {
+ text-decoration: none;
+ color: rgba(255, 255, 255, 0.75);
+}
+
+.navbar form > button.logout:focus {
+ outline: none;
+}
+
+/* style breadcrumb widget as in previous bootstrap versions */
+.breadcrumb {
+ background-color: var(--bs-gray-200);
+ border-radius: .25rem;
+ padding: .75rem 1rem;
+}
+
+.breadcrumb-item > a
+{
+ text-decoration: none;
+}
\ No newline at end of file
diff --git a/frontend/web/favicon.ico b/frontend/web/favicon.ico
new file mode 100755
index 0000000..580ed73
Binary files /dev/null and b/frontend/web/favicon.ico differ
diff --git a/frontend/web/uploads/image_2022-11-19_16-48-34.png b/frontend/web/uploads/image_2022-11-19_16-48-34.png
new file mode 100644
index 0000000..f31664a
Binary files /dev/null and b/frontend/web/uploads/image_2022-11-19_16-48-34.png differ
diff --git a/frontend/web/uploads/image_2022-12-22_17-22-19.png b/frontend/web/uploads/image_2022-12-22_17-22-19.png
new file mode 100644
index 0000000..b181549
Binary files /dev/null and b/frontend/web/uploads/image_2022-12-22_17-22-19.png differ
diff --git a/frontend/web/uploads/image_2023-01-19_19-48-33.png b/frontend/web/uploads/image_2023-01-19_19-48-33.png
new file mode 100755
index 0000000..b9226ef
Binary files /dev/null and b/frontend/web/uploads/image_2023-01-19_19-48-33.png differ
diff --git a/frontend/web/uploads/image_2023-01-23_21-38-25.png b/frontend/web/uploads/image_2023-01-23_21-38-25.png
new file mode 100755
index 0000000..d5c0ca7
Binary files /dev/null and b/frontend/web/uploads/image_2023-01-23_21-38-25.png differ
diff --git a/frontend/web/uploads/Снимок экрана от 2023-03-01 16-59-46.png b/frontend/web/uploads/Снимок экрана от 2023-03-01 16-59-46.png
new file mode 100755
index 0000000..a45ccc6
Binary files /dev/null and b/frontend/web/uploads/Снимок экрана от 2023-03-01 16-59-46.png differ
diff --git a/init b/init
new file mode 100755
index 0000000..cf472c9
--- /dev/null
+++ b/init
@@ -0,0 +1,356 @@
+#!/usr/bin/env php
+ $name) {
+ echo " [$i] $name\n";
+ }
+ echo "\n Your choice [0-" . (count($envs) - 1) . ', or "q" to quit] ';
+ $answer = trim(fgets(STDIN));
+
+ if (!ctype_digit($answer) || !in_array($answer, range(0, count($envs) - 1))) {
+ echo "\n Quit initialization.\n";
+ exit(0);
+ }
+
+ if (isset($envNames[$answer])) {
+ $envName = $envNames[$answer];
+ }
+} else {
+ $envName = $params['env'];
+}
+
+if (!in_array($envName, $envNames, true)) {
+ $envsList = implode(', ', $envNames);
+ echo "\n $envName is not a valid environment. Try one of the following: $envsList. \n";
+ exit(2);
+}
+
+$env = $envs[$envName];
+
+if (empty($params['env'])) {
+ echo "\n Initialize the application under '{$envNames[$answer]}' environment? [yes|no] ";
+ $answer = trim(fgets(STDIN));
+ if (strncasecmp($answer, 'y', 1)) {
+ echo "\n Quit initialization.\n";
+ exit(0);
+ }
+}
+
+$rootPath = "$root/environments/{$env['path']}";
+if (!is_dir($rootPath)) {
+ printError("$rootPath directory does not exist. Check path in $envName environment.");
+ exit(3);
+}
+
+echo "\n Start initialization ...\n\n";
+
+$files = getFileList($rootPath);
+if (isset($env['skipFiles'])) {
+ $skipFiles = $env['skipFiles'];
+ array_walk($skipFiles, function(&$value) use($env, $root) { $value = "$root/$value"; });
+ $files = array_diff($files, array_intersect_key($env['skipFiles'], array_filter($skipFiles, 'file_exists')));
+}
+$all = false;
+foreach ($files as $file) {
+ if (!copyFile($root, "environments/{$env['path']}/$file", $file, $all, $params)) {
+ break;
+ }
+}
+
+$filesToRemove = [];
+$skipFiles = !empty($env['skipFiles']) ? $env['skipFiles'] : [];
+foreach(array_column($envs, 'path') as $envPath) {
+ if ($env['path'] === $envPath) continue;
+
+ $filesToRemove =
+ array_merge(
+ $filesToRemove,
+ array_diff(getFileList("$root/environments/{$envPath}"), $files, $filesToRemove, $skipFiles)
+ );
+}
+$filesToRemove = array_filter($filesToRemove, 'file_exists');
+if ($filesToRemove) {
+ echo "\n Remove files from other environments ...\n\n";
+
+ $all = false;
+ foreach ($filesToRemove as $file) {
+ if (!removeFile($root, $file, $all, $params)) {
+ break;
+ }
+ }
+ echo "\n";
+}
+
+$callbacks = ['setCookieValidationKey', 'setWritable', 'setExecutable', 'createSymlink'];
+foreach ($callbacks as $callback) {
+ if (!empty($env[$callback])) {
+ $callback($root, $env[$callback]);
+ }
+}
+
+echo "\n ... initialization completed.\n\n";
+
+function getFileList($root, $basePath = '')
+{
+ $files = [];
+ $handle = opendir($root);
+ while (($path = readdir($handle)) !== false) {
+ if ($path === '.git' || $path === '.svn' || $path === '.' || $path === '..') {
+ continue;
+ }
+ $fullPath = "$root/$path";
+ $relativePath = $basePath === '' ? $path : "$basePath/$path";
+ if (is_dir($fullPath)) {
+ $files = array_merge($files, getFileList($fullPath, $relativePath));
+ } else {
+ $files[] = $relativePath;
+ }
+ }
+ closedir($handle);
+ return $files;
+}
+
+function copyFile($root, $source, $target, &$all, $params)
+{
+ if (!is_file($root . '/' . $source)) {
+ echo " skip $target ($source not exist)\n";
+ return true;
+ }
+ if (is_file($root . '/' . $target)) {
+ if (file_get_contents($root . '/' . $source) === file_get_contents($root . '/' . $target)) {
+ echo " unchanged $target\n";
+ return true;
+ }
+ if ($all) {
+ echo " overwrite $target\n";
+ } else {
+ echo " exist $target\n";
+ echo " ...overwrite? [Yes|No|All|Quit] ";
+
+
+ $answer = !empty($params['overwrite']) ? $params['overwrite'] : trim(fgets(STDIN));
+ if (!strncasecmp($answer, 'q', 1)) {
+ return false;
+ } else {
+ if (!strncasecmp($answer, 'y', 1)) {
+ echo " overwrite $target\n";
+ } else {
+ if (!strncasecmp($answer, 'a', 1)) {
+ echo " overwrite $target\n";
+ $all = true;
+ } else {
+ echo " skip $target\n";
+ return true;
+ }
+ }
+ }
+ }
+ file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source));
+ return true;
+ }
+ echo " generate $target\n";
+ @mkdir(dirname($root . '/' . $target), 0777, true);
+ file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source));
+ return true;
+}
+
+function removeFile($root, $target, &$all, $params)
+{
+ if (is_file($root . '/' . $target)) {
+ if ($all) {
+ echo " delete $target\n";
+ } else {
+ echo " delete $target\n";
+ echo " ...confirm? [Yes|No|All|Quit] ";
+
+ $answer = !empty($params['delete']) ? $params['delete'] : trim(fgets(STDIN));
+ if (!strncasecmp($answer, 'q', 1)) {
+ return false;
+ } else {
+ if (!strncasecmp($answer, 'y', 1)) {
+ echo " delete $target\n";
+ } else {
+ if (!strncasecmp($answer, 'a', 1)) {
+ echo " delete $target\n";
+ $all = true;
+ } else {
+ echo " skip $target\n";
+ return true;
+ }
+ }
+ }
+ }
+ return unlink($root . '/' . $target);
+ }
+
+ return true;
+}
+
+function getParams()
+{
+ $rawParams = [];
+ if (isset($_SERVER['argv'])) {
+ $rawParams = $_SERVER['argv'];
+ array_shift($rawParams);
+ }
+
+ $params = [];
+ foreach ($rawParams as $param) {
+ if (preg_match('/^--([\w-]*\w)(=(.*))?$/', $param, $matches)) {
+ $name = $matches[1];
+ $params[$name] = isset($matches[3]) ? $matches[3] : true;
+ } else {
+ $params[] = $param;
+ }
+ }
+ return $params;
+}
+
+function setWritable($root, $paths)
+{
+ foreach ($paths as $writable) {
+ if (is_dir("$root/$writable")) {
+ if (@chmod("$root/$writable", 0777)) {
+ echo " chmod 0777 $writable\n";
+ } else {
+ printError("Operation chmod not permitted for directory $writable.");
+ }
+ } else {
+ printError("Directory $writable does not exist.");
+ }
+ }
+}
+
+function setExecutable($root, $paths)
+{
+ foreach ($paths as $executable) {
+ if (file_exists("$root/$executable")) {
+ if (@chmod("$root/$executable", 0755)) {
+ echo " chmod 0755 $executable\n";
+ } else {
+ printError("Operation chmod not permitted for $executable.");
+ }
+ } else {
+ printError("$executable does not exist.");
+ }
+ }
+}
+
+function setCookieValidationKey($root, $paths)
+{
+ foreach ($paths as $file) {
+ echo " generate cookie validation key in $file\n";
+ $file = $root . '/' . $file;
+ $length = 32;
+ $bytes = openssl_random_pseudo_bytes($length);
+ $key = strtr(substr(base64_encode($bytes), 0, $length), '+/=', '_-.');
+ $content = preg_replace('/(("|\')cookieValidationKey("|\')\s*=>\s*)(""|\'\')/', "\\1'$key'", file_get_contents($file));
+ file_put_contents($file, $content);
+ }
+}
+
+function createSymlink($root, $links)
+{
+ foreach ($links as $link => $target) {
+ //first removing folders to avoid errors if the folder already exists
+ @rmdir($root . "/" . $link);
+ //next removing existing symlink in order to update the target
+ if (is_link($root . "/" . $link)) {
+ @unlink($root . "/" . $link);
+ }
+ if (@symlink($root . "/" . $target, $root . "/" . $link)) {
+ echo " symlink $root/$target $root/$link\n";
+ } else {
+ printError("Cannot create symlink $root/$target $root/$link.");
+ }
+ }
+}
+
+/**
+ * Prints error message.
+ * @param string $message message
+ */
+function printError($message)
+{
+ echo "\n " . formatMessage("Error. $message", ['fg-red']) . " \n";
+}
+
+/**
+ * Returns true if the stream supports colorization. ANSI colors are disabled if not supported by the stream.
+ *
+ * - windows without ansicon
+ * - not tty consoles
+ *
+ * @return boolean true if the stream supports ANSI colors, otherwise false.
+ */
+function ansiColorsSupported()
+{
+ return DIRECTORY_SEPARATOR === '\\'
+ ? getenv('ANSICON') !== false || getenv('ConEmuANSI') === 'ON'
+ : function_exists('posix_isatty') && @posix_isatty(STDOUT);
+}
+
+/**
+ * Get ANSI code of style.
+ * @param string $name style name
+ * @return integer ANSI code of style.
+ */
+function getStyleCode($name)
+{
+ $styles = [
+ 'bold' => 1,
+ 'fg-black' => 30,
+ 'fg-red' => 31,
+ 'fg-green' => 32,
+ 'fg-yellow' => 33,
+ 'fg-blue' => 34,
+ 'fg-magenta' => 35,
+ 'fg-cyan' => 36,
+ 'fg-white' => 37,
+ 'bg-black' => 40,
+ 'bg-red' => 41,
+ 'bg-green' => 42,
+ 'bg-yellow' => 43,
+ 'bg-blue' => 44,
+ 'bg-magenta' => 45,
+ 'bg-cyan' => 46,
+ 'bg-white' => 47,
+ ];
+ return $styles[$name];
+}
+
+/**
+ * Formats message using styles if STDOUT supports it.
+ * @param string $message message
+ * @param string[] $styles styles
+ * @return string formatted message.
+ */
+function formatMessage($message, $styles)
+{
+ if (empty($styles) || !ansiColorsSupported()) {
+ return $message;
+ }
+
+ return sprintf("\x1b[%sm", implode(';', array_map('getStyleCode', $styles))) . $message . "\x1b[0m";
+}
diff --git a/init.bat b/init.bat
new file mode 100755
index 0000000..1b92c19
--- /dev/null
+++ b/init.bat
@@ -0,0 +1,15 @@
+@echo off
+
+rem -------------------------------------------------------------
+rem Yii command line init script for Windows.
+rem -------------------------------------------------------------
+
+@setlocal
+
+set YII_PATH=%~dp0
+
+if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe
+
+"%PHP_COMMAND%" "%YII_PATH%init" %*
+
+@endlocal
diff --git a/requirements.php b/requirements.php
new file mode 100755
index 0000000..67b344b
--- /dev/null
+++ b/requirements.php
@@ -0,0 +1,155 @@
+Error\n\n"
+ . "
The path to yii framework seems to be incorrect.
\n"
+ . '
You need to install Yii framework via composer or adjust the framework path in file ' . basename(__FILE__) . ".
\n"
+ . '
Please refer to the README on how to install Yii.
\n";
+ if (!empty($_SERVER['argv'])) {
+ // do not print HTML when used in console mode
+ echo strip_tags($message);
+ } else {
+ echo $message;
+ }
+ exit(1);
+}
+
+require_once $frameworkPath . '/requirements/YiiRequirementChecker.php';
+$requirementsChecker = new YiiRequirementChecker();
+
+$gdMemo = $imagickMemo = 'Either GD PHP extension with FreeType support or ImageMagick PHP extension with PNG support is required for image CAPTCHA.';
+$gdOK = $imagickOK = false;
+
+if (extension_loaded('imagick')) {
+ $imagick = new Imagick();
+ $imagickFormats = $imagick->queryFormats('PNG');
+ if (in_array('PNG', $imagickFormats)) {
+ $imagickOK = true;
+ } else {
+ $imagickMemo = 'Imagick extension should be installed with PNG support in order to be used for image CAPTCHA.';
+ }
+}
+
+if (extension_loaded('gd')) {
+ $gdInfo = gd_info();
+ if (!empty($gdInfo['FreeType Support'])) {
+ $gdOK = true;
+ } else {
+ $gdMemo = 'GD extension should be installed with FreeType support in order to be used for image CAPTCHA.';
+ }
+}
+
+/**
+ * Adjust requirements according to your application specifics.
+ */
+$requirements = array(
+ // Database :
+ array(
+ 'name' => 'PDO extension',
+ 'mandatory' => true,
+ 'condition' => extension_loaded('pdo'),
+ 'by' => 'All DB-related classes',
+ ),
+ array(
+ 'name' => 'PDO SQLite extension',
+ 'mandatory' => false,
+ 'condition' => extension_loaded('pdo_sqlite'),
+ 'by' => 'All DB-related classes',
+ 'memo' => 'Required for SQLite database.',
+ ),
+ array(
+ 'name' => 'PDO MySQL extension',
+ 'mandatory' => false,
+ 'condition' => extension_loaded('pdo_mysql'),
+ 'by' => 'All DB-related classes',
+ 'memo' => 'Required for MySQL database.',
+ ),
+ array(
+ 'name' => 'PDO PostgreSQL extension',
+ 'mandatory' => false,
+ 'condition' => extension_loaded('pdo_pgsql'),
+ 'by' => 'All DB-related classes',
+ 'memo' => 'Required for PostgreSQL database.',
+ ),
+ // Cache :
+ array(
+ 'name' => 'Memcache extension',
+ 'mandatory' => false,
+ 'condition' => extension_loaded('memcache') || extension_loaded('memcached'),
+ 'by' => '
MemCache',
+ 'memo' => extension_loaded('memcached') ? 'To use memcached set
MemCache::useMemcached to
true
.' : ''
+ ),
+ array(
+ 'name' => 'APC extension',
+ 'mandatory' => false,
+ 'condition' => extension_loaded('apc'),
+ 'by' => '
ApcCache',
+ ),
+ // CAPTCHA:
+ array(
+ 'name' => 'GD PHP extension with FreeType support',
+ 'mandatory' => false,
+ 'condition' => $gdOK,
+ 'by' => '
Captcha',
+ 'memo' => $gdMemo,
+ ),
+ array(
+ 'name' => 'ImageMagick PHP extension with PNG support',
+ 'mandatory' => false,
+ 'condition' => $imagickOK,
+ 'by' => '
Captcha',
+ 'memo' => $imagickMemo,
+ ),
+ // PHP ini :
+ 'phpExposePhp' => array(
+ 'name' => 'Expose PHP',
+ 'mandatory' => false,
+ 'condition' => $requirementsChecker->checkPhpIniOff("expose_php"),
+ 'by' => 'Security reasons',
+ 'memo' => '"expose_php" should be disabled at php.ini',
+ ),
+ 'phpAllowUrlInclude' => array(
+ 'name' => 'PHP allow url include',
+ 'mandatory' => false,
+ 'condition' => $requirementsChecker->checkPhpIniOff("allow_url_include"),
+ 'by' => 'Security reasons',
+ 'memo' => '"allow_url_include" should be disabled at php.ini',
+ ),
+ 'phpSmtp' => array(
+ 'name' => 'PHP mail SMTP',
+ 'mandatory' => false,
+ 'condition' => strlen(ini_get('SMTP')) > 0,
+ 'by' => 'Email sending',
+ 'memo' => 'PHP mail SMTP server required',
+ ),
+);
+
+$result = $requirementsChecker->checkYii()->check($requirements)->getResult();
+$requirementsChecker->render();
+
+exit($result['summary']['errors'] === 0 ? 0 : 1);
diff --git a/vagrant/config/.gitignore b/vagrant/config/.gitignore
new file mode 100755
index 0000000..0685a56
--- /dev/null
+++ b/vagrant/config/.gitignore
@@ -0,0 +1,2 @@
+# local configuration
+vagrant-local.yml
\ No newline at end of file
diff --git a/vagrant/config/vagrant-local.example.yml b/vagrant/config/vagrant-local.example.yml
new file mode 100755
index 0000000..7b36400
--- /dev/null
+++ b/vagrant/config/vagrant-local.example.yml
@@ -0,0 +1,22 @@
+# Your personal GitHub token
+github_token:
+# Read more: https://github.com/blog/1509-personal-api-tokens
+# You can generate it here: https://github.com/settings/tokens
+
+# Guest OS timezone
+timezone: Europe/London
+
+# Are we need check box updates for every 'vagrant up'?
+box_check_update: false
+
+# Virtual machine name
+machine_name: y2aa
+
+# Virtual machine IP
+ip: 192.168.83.137
+
+# Virtual machine CPU cores number
+cpus: 1
+
+# Virtual machine RAM
+memory: 1024
diff --git a/vagrant/nginx/app.conf b/vagrant/nginx/app.conf
new file mode 100755
index 0000000..0462830
--- /dev/null
+++ b/vagrant/nginx/app.conf
@@ -0,0 +1,77 @@
+server {
+ charset utf-8;
+ client_max_body_size 128M;
+ sendfile off;
+
+ listen 80; ## listen for ipv4
+ #listen [::]:80 default_server ipv6only=on; ## listen for ipv6
+
+ server_name y2aa-frontend.test;
+ root /app/frontend/web/;
+ index index.php;
+
+ access_log /app/vagrant/nginx/log/frontend-access.log;
+ error_log /app/vagrant/nginx/log/frontend-error.log;
+
+ location / {
+ # Redirect everything that isn't a real file to index.php
+ try_files $uri $uri/ /index.php$is_args$args;
+ }
+
+ # uncomment to avoid processing of calls to non-existing static files by Yii
+ #location ~ \.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar)$ {
+ # try_files $uri =404;
+ #}
+ #error_page 404 /404.html;
+
+ location ~ \.php$ {
+ include fastcgi_params;
+ fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
+ #fastcgi_pass 127.0.0.1:9000;
+ fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
+ try_files $uri =404;
+ }
+
+ location ~ /\.(ht|svn|git) {
+ deny all;
+ }
+}
+
+server {
+ charset utf-8;
+ client_max_body_size 128M;
+ sendfile off;
+
+ listen 80; ## listen for ipv4
+ #listen [::]:80 default_server ipv6only=on; ## listen for ipv6
+
+ server_name y2aa-backend.test;
+ root /app/backend/web/;
+ index index.php;
+
+ access_log /app/vagrant/nginx/log/backend-access.log;
+ error_log /app/vagrant/nginx/log/backend-error.log;
+
+ location / {
+ # Redirect everything that isn't a real file to index.php
+ try_files $uri $uri/ /index.php$is_args$args;
+ }
+
+ # uncomment to avoid processing of calls to non-existing static files by Yii
+ #location ~ \.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar)$ {
+ # try_files $uri =404;
+ #}
+ #error_page 404 /404.html;
+
+ location ~ \.php$ {
+ include fastcgi_params;
+ fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
+ #fastcgi_pass 127.0.0.1:9000;
+ fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
+ try_files $uri =404;
+ }
+
+ location ~ /\.(ht|svn|git) {
+ deny all;
+ }
+}
diff --git a/vagrant/nginx/log/.gitignore b/vagrant/nginx/log/.gitignore
new file mode 100755
index 0000000..c15cedd
--- /dev/null
+++ b/vagrant/nginx/log/.gitignore
@@ -0,0 +1,5 @@
+# nginx logs
+backend-access.log
+backend-error.log
+frontend-access.log
+frontend-error.log
\ No newline at end of file
diff --git a/vagrant/provision/always-as-root.sh b/vagrant/provision/always-as-root.sh
new file mode 100755
index 0000000..cca9cfb
--- /dev/null
+++ b/vagrant/provision/always-as-root.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+source /app/vagrant/provision/common.sh
+
+#== Provision script ==
+
+info "Provision-script user: `whoami`"
+
+info "Restart web-stack"
+service php7.4-fpm restart
+service nginx restart
+service mysql restart
\ No newline at end of file
diff --git a/vagrant/provision/common.sh b/vagrant/provision/common.sh
new file mode 100755
index 0000000..ab5e1e0
--- /dev/null
+++ b/vagrant/provision/common.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+
+#== Bash helpers ==
+
+function info {
+ echo " "
+ echo "--> $1"
+ echo " "
+}
diff --git a/vagrant/provision/once-as-root.sh b/vagrant/provision/once-as-root.sh
new file mode 100755
index 0000000..4542a43
--- /dev/null
+++ b/vagrant/provision/once-as-root.sh
@@ -0,0 +1,74 @@
+#!/usr/bin/env bash
+
+source /app/vagrant/provision/common.sh
+
+#== Import script args ==
+
+timezone=$(echo "$1")
+readonly IP=$2
+
+#== Provision script ==
+
+info "Provision-script user: `whoami`"
+
+export DEBIAN_FRONTEND=noninteractive
+
+info "Configure timezone"
+timedatectl set-timezone ${timezone} --no-ask-password
+
+info "AWK initial replacement work"
+awk -v ip=$IP -f /app/vagrant/provision/provision.awk /app/environments/dev/*end/config/main-local.php
+
+info "Prepare root password for MySQL"
+debconf-set-selections <<< "mysql-community-server mysql-community-server/root-pass password \"''\""
+debconf-set-selections <<< "mysql-community-server mysql-community-server/re-root-pass password \"''\""
+echo "Done!"
+
+info "Update OS software"
+apt-get update
+apt-get upgrade -y
+
+info "Add ppa:ondrej/php"
+apt-get install -y python-software-properties
+apt-get update && apt-get upgrade -y
+add-apt-repository -y ppa:ondrej/php
+
+info "Install additional software"
+apt-get install -y php7.4-curl php7.4-cli php7.4-intl php7.4-mysqlnd php7.4-gd php7.4-fpm php7.4-mbstring php7.4-xml unzip nginx mysql-server-5.7 php7.4-xdebug
+
+info "Configure MySQL"
+sed -i "s/.*bind-address.*/bind-address = 0.0.0.0/" /etc/mysql/mysql.conf.d/mysqld.cnf
+mysql -uroot <<< "CREATE USER 'root'@'%' IDENTIFIED BY ''"
+mysql -uroot <<< "GRANT ALL PRIVILEGES ON *.* TO 'root'@'%'"
+mysql -uroot <<< "DROP USER 'root'@'localhost'"
+mysql -uroot <<< "FLUSH PRIVILEGES"
+echo "Done!"
+
+info "Configure PHP-FPM"
+sed -i 's/user = www-data/user = vagrant/g' /etc/php/7.4/fpm/pool.d/www.conf
+sed -i 's/group = www-data/group = vagrant/g' /etc/php/7.4/fpm/pool.d/www.conf
+sed -i 's/owner = www-data/owner = vagrant/g' /etc/php/7.4/fpm/pool.d/www.conf
+cat << EOF > /etc/php/7.4/mods-available/xdebug.ini
+zend_extension=xdebug.so
+xdebug.remote_enable=1
+xdebug.remote_connect_back=1
+xdebug.remote_port=9000
+xdebug.remote_autostart=1
+EOF
+echo "Done!"
+
+info "Configure NGINX"
+sed -i 's/user www-data/user vagrant/g' /etc/nginx/nginx.conf
+echo "Done!"
+
+info "Enabling site configuration"
+ln -s /app/vagrant/nginx/app.conf /etc/nginx/sites-enabled/app.conf
+echo "Done!"
+
+info "Initailize databases for MySQL"
+mysql -uroot <<< "CREATE DATABASE yii2advanced"
+mysql -uroot <<< "CREATE DATABASE yii2advanced_test"
+echo "Done!"
+
+info "Install composer"
+curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
\ No newline at end of file
diff --git a/vagrant/provision/once-as-vagrant.sh b/vagrant/provision/once-as-vagrant.sh
new file mode 100755
index 0000000..ffaa898
--- /dev/null
+++ b/vagrant/provision/once-as-vagrant.sh
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+
+source /app/vagrant/provision/common.sh
+
+#== Import script args ==
+
+github_token=$(echo "$1")
+
+#== Provision script ==
+
+info "Provision-script user: `whoami`"
+
+info "Configure composer"
+composer config --global github-oauth.github.com ${github_token}
+echo "Done!"
+
+info "Install project dependencies"
+cd /app
+composer --no-progress --prefer-dist install
+
+info "Init project"
+./init --env=Development --overwrite=y
+
+info "Apply migrations"
+./yii migrate --interactive=0
+./yii_test migrate --interactive=0
+
+info "Create bash-alias 'app' for vagrant user"
+echo 'alias app="cd /app"' | tee /home/vagrant/.bash_aliases
+
+info "Enabling colorized prompt for guest console"
+sed -i "s/#force_color_prompt=yes/force_color_prompt=yes/" /home/vagrant/.bashrc
diff --git a/vagrant/provision/provision.awk b/vagrant/provision/provision.awk
new file mode 100755
index 0000000..65e9bde
--- /dev/null
+++ b/vagrant/provision/provision.awk
@@ -0,0 +1,70 @@
+###
+# Modifying Yii2's files for initialize Vagrant VM
+#
+# @author HA3IK
+# @version 1.0.0
+
+BEGIN {
+ print "AWK BEGINs its work:"
+ IGNORECASE = 1
+ # Correct IP - wildcard last octet
+ match(ip, /(([0-9]+\.)+)/, arr)
+ ip = arr[1] "*"
+}
+BEGINFILE {
+ msg = "- Work with: " FILENAME
+ # Define array index for the file
+ switch (FILENAME) {
+ case /environments\/dev\/(back|front)end\/config\/main\-local\.php$/:
+ isFile["IsMainLocConf"] = 1
+ msg = msg " - allow VM IP for Gii and debug toolbar"
+ break
+ }
+ # Print the final message
+ print msg
+}
+# BODY
+{
+ # IF environments/dev/(back|front)end/config/main-local.php
+ if (isFile["IsMainLocConf"]) {
+ # IF the line[s] after yii\(debug|gii)\Module
+ if (FNR == nextLine["nubmer"]) {
+ # Prepare for next line
+ ++nextLine["nubmer"]
+ # IF line has "allowedIPs"
+ if (index($0, "allowedIPs")) {
+ # IF our IP is not there
+ if (!index($0, ip)) {
+ # Add it
+ match($0, /([^\]]+)(.+)/, arr)
+ $0 = sprintf("%s, '%s'%s", arr[1], ip, arr[2])
+ }
+ # Delete next line
+ delete nextLine
+ # IF "allowedIPs" are not set - search for the end of an array structure
+ } else if ($0 ~ /\];$/) {
+ # Rewrite line
+ $0 = nextLine["indent"] "'allowedIPs' => ['127.0.0.1', '::1', '" ip "'],\n" $0
+ delete nextLine
+ }
+ # IF line is done
+ if (!length(nextLine)) {
+ printf " Line %d: Allowed IP: %s\n", FNR, ip
+ }
+ # Search for yii\(debug|gii)\Module
+ } else if (match($0, /^(\s+).+yii\\(debug|gii)\\Module/, arr)) {
+ # Save next line and indent
+ nextLine["nubmer"] = FNR + 1
+ nextLine["indent"] = arr[1]
+ }
+ # Rewrite the file
+ print $0 > FILENAME
+ }
+}
+ENDFILE {
+ delete isFile
+ close(FILENAME)
+}
+END {
+ print "AWK ENDs its work."
+}
diff --git a/yii.bat b/yii.bat
new file mode 100755
index 0000000..3a68942
--- /dev/null
+++ b/yii.bat
@@ -0,0 +1,15 @@
+@echo off
+
+rem -------------------------------------------------------------
+rem Yii command line bootstrap script for Windows.
+rem -------------------------------------------------------------
+
+@setlocal
+
+set YII_PATH=%~dp0
+
+if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe
+
+"%PHP_COMMAND%" "%YII_PATH%yii" %*
+
+@endlocal