/TestTask

Форма регистрации+авторизации с валидацией полей как на клиенте, так и на сервере, со страницей профиля и возможностью переключать язык. Написано на PHP+MySQL+JS (подробнее в README.MD)

Primary LanguagePHP

Содержание

  1. Описание
  2. Возможности
  3. Стукрура проекта и разработка
  4. Настройки сайта
  5. Шаблонизатор
  6. Мультиязычность
  7. Маршрутизация
  8. Демонстрационный сайт
  9. Системные требования для запуска на веб-сервере
  10. Запуск проекта с помощью Docker-Compose

Описание

Это тестовый проект, реализующий форму регистрации/входа средствами PHP, MySQL и JS с валидацией данных и поддержкой мультиязычности.
Но по сути, данный проект может использоваться как стартовый набор для создания полноценного сайта, т.к. есть базовая структура, возможность задавать настройки для разнах сред исполнения (dev, prod), легко добавлять маршруты, переводы языков (строки и части шаблонов) и сами шаблоны.

Проект не использует какие-либо PHP-фреймворки, но в нём используются следующие библиотеки:

  • Twig-шаблонизатор
  • SafeMySQL как основа для создания класса для безопасного и удобного доступа к БД (не ORM)
  • SimpleImage для обрезки изображений на стороне сервера
  • Google reCAPTCHA для дополнительной проверки клиентов и защиты от автоматических регистраций и перебора паролей

А на стороне клиента используется:

Возможности

  • Регистрация пользователей
  • Валидация входных полей (длина, формат, доступность email, дополнительная проверка с помощью Google reCAPTCHA) на клиентской и серверной сторонах
  • Выбор, обрезка и загрузка изображения (аватарки) пользователя на клиентской стороне, но с верификацией на стороне сервера и уменьшением размера, если он превысит
    максимально разрешённый размер изображения (задаётся в настройках, уменьшение размера происходит пропорционально)
  • Авторизация с защитой от перебора (после пары неудачных попыток дополнительная проверка через reCAPTCHA, ещё после нскольких блокировка по IP на какое-то время)
  • Просмотр своего профиля и возможность выбрать, обрезать и загрузить другую аватарку
  • Переключение языка (на любой странице сайта). Смена языка касается как элементов оформления страницы, так и возвращаемых сообщений с сервера
  • Автоопределение языка по параметрам браузера клиента, а в случае невозможности определить, будет использован язык по-умолчанию, который определён в настройках
  • Есть пример главной страницы и страницы 404 (можно из верхнего меню перейти на страницу "О нас" или ввести любой несуществующий путь)
  • Удобное расширение функционала, добавление новых страниц, маршрутов, обработчиков, языков

Подробное описание и как это работает

  • Сайт использует единую точку входа (index.php), поэтому веб-сервер должен быть специальным образом настроен (примеры настроек для популярных веб-серверов указаны ниже)
  • У сайта есть верхнее меню, откуда можно перейти на главную страницу, на страницу "О нас", которая вызовет ошибку 404 (т.к. этой страницы нарочно нет),
    поменять язык(выбрав из доступных на текущий момент языков), перейти на страницу авторизации или регистрации.
  • Главная страница сайта доступна для всех пользователей, однако, если пользователь зарегистрирован и авторизован, то он увидит приветствие и своё имя, а иначе предложение зарегистрироваться и авторизоваться. Остальная часть страницы одинакова для всех пользователей.
  • На странице регистрации работает автоматическая валидация полей (при потере фокуса на поле), а результат проверки введённых данных отображается
    соответствующей иконкой внутри поля и подписью под полем. Также поле для вввода email автоматически проверяется на доступность данного адреса, ведь если
    он уже занят, лучше пользователю об этом узнать заранее, а не после нажатия кнопки. При выборе изображения есть возможность сразу же его обрезать.
    Но не смотря на проверки на клиентской стороне, те же самые проверки проводятся и на стороне сервера (вдруг кто-то сделает запрос в обход страницы регистрации),
    а в случае возникновения ошибок, регистрация не будет совершена, а пользователю снова предоставится возможность ввести данные (поля будут иметь прежние значения)
    и выведен список возникших ошибок. После успешной регистрации об этом так же будет сообщено пользователю и он сразу же будет перенаправлен на страницу авторизации.
  • На странице авторизации всего два поля: email и пароль. В настройках сайта можно задать количество возможных неудачных попыток авторизации. Если это число
    будет превышено, то появится дополнительная проверка с помощью Google reCAPTCHA (если она настроена и включена). Если и после этого будет произведено какое-то
    количество неудачных попыток авторизации (что тоже настраивается в настройках), то вход с текущего IP-адреса будет запрещён на некоторое время, которое так же
    можно настроить администратору сайта. В случае же успешной авторизации пользователь сразу попадает на страницу своего профиля.
  • На странице профиля отображается информация о пользователе, которую он указал при регистрации, плюс время и IP адрес регистрации,
    а также время и IP адрес последнего обращения к сайту. Также есть возможность обновить аватарку, как и при регистрации, сразу же обрезав.
    Процесс загрузкий новой аватарки отображается спиннером на кнопке выбора аватарки. Очень удобно.

Структура проекта и дальнейшее развитие

В таблице представлен список основных директорий и файлов и их назначение:

Директория Файл Назначение
bootstrap/ app.php Инициализация основных компонентов приложения и добавление глобальных переменных шаблонизатора
configs/ configs_default.php Базовые настройки. Будут считываться в первую очередь. О формате и особенностях настроек ниже
configs/ configs_dev.php Настройки для DEV-окружения. Если этот файл будет найден и загружен, загрузка настроек прекратится
configs/ configs_prod.php Настройки для production-окружения. Считывается, если не найдены настройки Dev-окружения
public/ index.php Точка входа в приложение. Нужно располагать в публичной директории сайта. Там же происходит маршрутизация запросов
resources/templates/ *.twig Директория шаблонов. Базовый шаблон в файле layout.twig
resources/templates/langs/{lang}/ *.twig Здесь можно располагать куски шаблонов, содержащих много текста, чтоб не помещать этот контент в файл перевода. Выбор файлов зависит от текущего языка, важно соблюдать структуру и наличие файлов
resources/langs/ *.ini Директория переводов. Файлы формата {lang}.ini
src/libs/ *.php Здесь располагаются PHP-классы, которые загружаются автоматически с помощью composer
src/routes/ *.php Директория маршрутов. При запросе к сайту вида /profile будет исполнен файл profile.php из этой директории (если найден будет, иначе 404)

Настройки

Файл настроек должен возвращать массив с ключами и значениями:

return [  
  'project_title' => 'app name', // название проекта. будет отображаться в Title и брэнде  
    'db' => [  
    'host' => 'localhost',  
    'user' => '',  
    'pass' => '',  
    'db' => '',  
    'charset' => 'utf8mb4'  
  ],  
  
  // google reRECAPTCHA. Создать ключ тут: https://www.google.com/recaptcha/admin  
  'use_recaptcha' => false,  
  'recaptcha_site_key' => '',  
  'recaptcha_secret_key' => '',  
  
  // настройки блокировки неудачных попыток авторизации  
  'use_auth_block' => true, // использовать ли вообще блокировку неудачных попыток входа  
  'auth_check_after' => 3, // после стольких неудачных попыток будет показана reCAPTCHA (если включена)  
  'auth_block_after' => 6, // после стольких неудачных попыток будет заблокирован на указанное далее время  
  'auth_block_time' => 30, // время блокировки входа для текущего IP (в минутах)  
  
  // настройки загружаемых изображений  
  'auto_resize_image' => true, // использовать ли автоизменение размера изображений при превышении его?  
  'max_image_width' => 1024, // мааксимальная ширина изображения. Если будет больше, то урежется до этого значения  
];

Изначально загружается файл configs_default.php, в нём можно расположить основные настройки, а вот в файлах configs_dev.php или configs_prod.php указать только отличающиеся настройки, которые будут применены в зависимости от среды. Например, для разных сред можно задать разные настройки подключения к базе. Или использовать разные настройки блокировки входа, оставив всё остальное как в настройках по-умолчанию.

Шаблонизатор

Используется шаблонизатор Twig, за основу берётся файл layout.twig из директории с шаблонами. На его основе строятся остальные страницы, расширяющие основной шаблон, которые не переписывают всё содержимое, а лишь контент, заголовок и стили с JS-скриптами, которые касаются именно этой страницы. Например, в коде шаблона регистрации есть секция js, в которой написаны скрипты, касающиеся только регистрации. Эти скрипты не нужны больше нигде, кроме этой страницы, поэтому они располагаются в самом файле шаблона регистрации. Также можно подключать файлы других шаблонов, в зависимости от текущего языка. Пример этого можно обнаружить в шаблоне главной страницы index.twig. В шаблонах доступны некоторые переменные, которые можно использовать в любом месте. Возможно использование как простых переменных, так и массивов. Например, {{ cfg.project_title }} заменится на текущее название проекта, заданное в настройках, то есть, из массива cfg будет взято значение project_title. Ниже приведён список доступных переменных (их можно добавлять в файле bootstrap/app.php):

Имя переменной Тип Назначение
SERVER Массив PHP-массив $_SERVER
REMOTE_ADDR Строка IP-адрес клиента (учитывая прокси)
cfg Массив Содержит актуальные совмещённые настройки (от configs_defaults до configs_prod)
lang Массив Массив строк текущего сформированного языка. Например {{ lang.page_404_title }}
langs Массив Массив текущих доступных языков. Используется для вывода списка языков на странице
current_lang Строка Текущий автоматически определённый или вручную выбранный язык
RECAPTCHA_BLOCK Строка Содержит готовый код Google reCAPTCHA для вставки в нужное место на страницу. Если в настройках отключено использование reCAPTCHA, то значение будет пустым
GET Массив PHP-массив $_GET
POST Массив PHP-массив $_POST (можно использовать для установки value полей формы, которую необходимо ещё раз вывести в случае ошибки, например: {{ POST.username }}
is_auth Булево Если пользователь авторизован, то true, иначе false
user Массив Если пользователь авторизован, то содержит информацию о пользователе, загруженную из базы (кроме пароля). Поэтому можно вставлять на странице обращение к пользователю, например: {{ user.name }}, и это будет заменено на его имя

Мультиязычность

Файлы переводов располагаются в директории resources/langs, именуются как {имя_языка}.ini и представляют собой обычный ini-файл, но без секций. Поэтому можно давать любые имена строкам и указывать сразу же значение, а затем использовать это значение в шаблонизаторе через {{ lang.string_name }} или в коде PHP-скриптов, получая нужную строку через функцию getLangStr('string_name') или __('string_name'), что является псевдонимом и сокращённой записью для getLangStr().

Важно, чтобы файл языка содержал параметр lang со значением, равным этому языку (например: lang=en), иначе этот файл языка будет считаться невалидным и будет пропущен менеджером языков.

Порядок загрузки языков: сначала загружается язык по-умолчанию (изначально это en, но можно задать в менеджере языков), а затем загружается выбранный или автоматически определённый язык. Нужно это для того, чтоб те строки, которых нет в текущем файле языка, загрузились из языка по-умолчанию (если они там есть). Иначе будет пустая строка.

Изначально, при первом заходе пользователя на сайт, язык определяется автоматически на основе заголовка Accept-Language браузера. Но можно на любую страницу в GET-запросе указать ?lang={lang}, тогда язык переключится на указанный (если существует такой, иначе на дефолтный), а сам язык будет сохранён в cookie браузера, чтобы при следующих запросах сразу активировался выбранный язык.

Маршрутизация

В отличие от привычной схемы работы всяких фреймворков, где нужно вручную задавать маршруты и контроллеры, в данном проекте используется сильно упрощённая, но автоматическая система маршрутизации.

Когда приходит запрос, например, /profile, тогда ищется файл profile.php в директории с маршрутами. Естественно, перед этим запрос фильтруется и проходит проверки. Если такого файла не обнаружится, то в ответ будет послан код 404 и выведен соответствующий шаблон. Если же такой файл будет обнаружен, то он будет тут же загружен. А уже в нём можно обрабатывать запрос, выполнять какие-то действия, запросы к базе, и выводить нужный шаблон с какими-переменными.

Также для удобства имеется статический класс Utils, который предоставляет некоторые функции для облегчения работы с запросами, получением данных, авторизацией и т.д. (все возможности можно узнать, изучив файл Utils.php

Демо сайт

Посмотреть рабочее демо проекта можно по этому адресу: http://testtask.karamush.ru/

Системные требования для запуска проекта

Для работы сайта необходимы:

  • Веб-сервер (любой, но с поддержкой PHP)
  • PHP версии >=7.0
  • MySQL версии >=5.5

Так как сайт использует единую точку входа, веб-сервер нужно настроить таким образом, чтобы все запросы направлялись на файл public/index.php, который уже сам будет заниматься маршрутизацией вызовов по своему алгоритму. Директорию public/ нужно сделать корневой директорией виртуального хоста. Остальные директории и файлы проекта не должны быть публичными.

Также необходимо создать базу в MySQL и любым удобным способом импортировать дамп базы, находящийся в sql/db_structure.sql.

После этого необходимо в файле настроек указать данные для подключения к базе.

Пример конфига для веб-сервера Nginx

        ...

        root /var/www/your-virtual-host/public/;
        index index.php index.html;

        location / {
                try_files $uri $uri/ /index.php$is_args$args;
        }

        ...

Пример настройки или файла .htaccess для веб-сервера Apache (должен быть включен mod rewrite)

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . index.php [L]

Запуск проекта с помощью Docker-compose

TODO