https://github.com/07rinat07/myblog
Website development using the Yii framework (Yii2 --> Yes It Is -2)
https://github.com/07rinat07/myblog
gii-crud mysql php8 phpmyadmin-database yii2-framework
Last synced: 3 months ago
JSON representation
Website development using the Yii framework (Yii2 --> Yes It Is -2)
- Host: GitHub
- URL: https://github.com/07rinat07/myblog
- Owner: 07Rinat07
- License: bsd-3-clause
- Created: 2023-11-25T09:16:55.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2024-01-08T13:18:28.000Z (over 2 years ago)
- Last Synced: 2025-02-16T18:18:14.739Z (over 1 year ago)
- Topics: gii-crud, mysql, php8, phpmyadmin-database, yii2-framework
- Language: PHP
- Homepage:
- Size: 5.07 MB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
README
# MyBlog (Yii2)
Проект после рефакторинга и обновления зависимостей. Находится в активной разработке.
## Участие в разработке
Приветствуются пулл-реквесты (PR) и сообщения об ошибках. Пожалуйста, добавляйте тесты для нового функционала.
Блог-приложение на Yii2 с публичной частью и административной панелью.
## Что уже реализовано
- Публичные страницы: список статей, просмотр статьи, категории, контактная форма.
- Переключение языка на всех страницах: English / Русский (публичная часть + админка).
- Регистрация/авторизация пользователей (`/auth/signup`, `/auth/login`).
- Регистрация с подтверждением email:
- после регистрации отправляется письмо с ссылкой подтверждения
- после перехода по ссылке аккаунт активируется, пользователь автоматически логинится и попадает на главную
- Личный кабинет пользователя (`/cabinet/profile`) с редактированием профиля (имя, email, пароль, аватар).
- Комментарии к статьям и лайки/снятие лайка (для авторизованных пользователей).
- Загрузка изображений в статьи (админ и пользовательский кабинет).
- Встроенный редактор текста в форме статьи (форматирование, шрифты, цвета, стили).
- Админ-панель (`/admin`) с разделами:
- Dashboard
- Articles
- Categories
- Tags
- Comments
- Users
- Feedback (сообщения из формы `/contact`)
- Усиленная безопасность:
- проверка роли администратора для админ-модуля
- ограничение доступа к чужим записям для обычных пользователей
- хеширование паролей
- CSRF/cookie-настройки
- экранирование вывода и очистка HTML-контента
- Обновлённый UI (публичная часть, админка и кабинет) и адаптивная вёрстка для mobile/tablet/desktop.
- Обновлённый стек зависимостей (Yii 2.0.54 и актуальные пакеты ветки 2.x).
## Требования
- PHP `>= 8.1`
- Composer 2
- MySQL/MariaDB
- Docker Engine + Docker Compose v2 (или Docker Desktop)
- Рекомендуемые расширения PHP:
- `pdo_mysql`
- `gd` (или `imagick`) для captcha
### Проверка `pdo_mysql` (локально и в Docker)
Проверить, что расширение загружено:
```bash
php -m | grep -E "PDO|pdo_mysql|mysqli"
```
Если локально (Linux/WSL) `pdo_mysql` нет:
```bash
sudo apt-get update
sudo apt-get install -y php8.1-mysql
```
Для OSPanel (Windows): в `C:\OSPanel\modules\PHP-8.1\php.ini` должны быть активны строки:
- `extension=mysqli`
- `extension=pdo_mysql`
После изменений перезапустите OSPanel (или PHP-модуль).
В Docker `pdo_mysql` уже устанавливается в `docker/php/Dockerfile` через:
- `docker-php-ext-install ... pdo_mysql ...`
Проверка в контейнере:
```bash
docker compose run --rm app php -m | grep -E "PDO|pdo_mysql"
```
## Установка
1. Установить зависимости:
```bash
composer install
```
2. Настроить подключение к БД (через переменные окружения или `config/db.php`):
- `DB_DSN` (если не задан, собирается из `DB_HOST`/`DB_PORT`/`DB_NAME`, по умолчанию `127.0.0.1:3306/myblog`)
- `DB_USERNAME` (по умолчанию: `root`)
- `DB_PASSWORD` (по умолчанию: `newpassword`)
- `COOKIE_VALIDATION_KEY` (рекомендуется задать свой)
Если БД запущена в Docker (`docker-compose`), для локального запуска приложения удобно использовать:
```bash
export DB_HOST=127.0.0.1
export DB_PORT=3307
export DB_USERNAME=myblog
export DB_PASSWORD=myblog_password
```
3. Применить миграции:
```bash
php yii migrate
```
4. Запустить приложение (вариант для локальной разработки):
```bash
php yii serve --port=8080
```
Или настроить веб-сервер так, чтобы document root указывал на папку `web/`.
## Запуск в Docker (Windows/Linux/macOS)
1. Подготовить переменные окружения:
```bash
# Linux/macOS
cp .env.example .env
# Windows PowerShell
Copy-Item .env.example .env
```
Рекомендуется сразу заменить в `.env` секреты:
- `COOKIE_VALIDATION_KEY`
- `MYSQL_ROOT_PASSWORD`
- `WEBHOOK_INCOMING_GENERIC_SECRET`
2. Запустить контейнеры:
```bash
docker compose up -d --build
```
3. Открыть сайт:
- `http://localhost:8080` (или ваш `APP_PORT` из `.env`)
4. Проверить логи:
```bash
docker compose logs -f app
```
Что настроено для стабильного запуска:
- `restart: unless-stopped` для `app`, `db`, `selenium` (контейнеры автоматически поднимаются после перезагрузки сервера/демона Docker)
- ожидание готовности БД перед стартом приложения
- автоматическая установка зависимостей (если нет `vendor/autoload.php`)
- автоматический запуск миграций при старте (`AUTO_MIGRATE=1`, можно выключить в `.env`)
- автоматический запуск миграций тестовой БД (`AUTO_MIGRATE_TEST_DB=1`)
- автоматическая загрузка фикстур в основной и тестовой БД при пустой таблице `user` (`AUTO_LOAD_FIXTURES=1`, список через `FIXTURES_LIST`)
- постоянное хранилище БД в docker volume `db-data`
- Selenium WebDriver для `acceptance` тестов (порт `4444`)
Команды для фикстур в Docker:
```bash
# загрузить фикстуры вручную
docker compose exec app php yii fixture/load "Category,Tag,User,Article,ArticleTag" --interactive=0
# полностью пересобрать проект с "чистой" БД (и авто-фикстурами)
docker compose down -v
docker compose up -d --build
```
Важно для автозапуска после reboot:
- Linux: включите автозапуск Docker демона (`sudo systemctl enable --now docker`)
- Windows/macOS: включите опцию автозапуска Docker Desktop при входе в систему
## Админ-доступ
Админка доступна по адресу:
- `/admin`
Пользователь должен иметь `isAdmin = 1` в таблице `user`.
Личный кабинет пользователя:
- `/cabinet/profile`
## MVP API (`/api/v1`)
В проект добавлен базовый JSON API для интеграций.
OpenAPI спецификация:
- `web/openapi/swagger.json`
- после запуска проекта доступна по URL: `/openapi/swagger.json`
- Swagger UI доступен по URL: `/docs/`
Аутентификация:
- Bearer token
- токен выдаётся через `POST /api/v1/auth/login`
- токены имеют срок жизни (`expiresAt`)
- для login включён rate limit (защита от brute-force)
- поддержаны отзыв и ротация токена
Эндпоинты:
- `GET /api/v1/health` — статус API
- `POST /api/v1/auth/login` — логин по `email`/`password`, выдаёт `accessToken`
- `POST /api/v1/auth/rotate` — ротация текущего токена (нужен Bearer token)
- `POST /api/v1/auth/logout` — отзыв текущего токена (нужен Bearer token)
- `POST /api/v1/auth/logout-all` — отзыв всех активных токенов пользователя
- `GET /api/v1/me` — профиль текущего пользователя (нужен Bearer token)
- `GET /api/v1/categories` — список категорий + количество опубликованных статей
- `GET /api/v1/articles` — список опубликованных статей (параметры: `page`, `per_page`, `category_id`, `q`)
- `GET /api/v1/articles/{id}` — одна опубликованная статья
- `GET /api/v1/articles/{id}/comments` — комментарии к статье
- `POST /api/v1/articles/{id}/comments` — добавить комментарий (нужен Bearer token, параметр `text`)
- `POST /api/v1/articles/{id}/like` — лайк/анлайк (нужен Bearer token)
- `POST /api/v1/webhooks/incoming/{source}` — входящий webhook с HMAC-подписью и idempotency key
Пример получения токена:
```bash
curl -X POST "http://localhost:8080/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"user12345"}'
```
Пример защищённого запроса:
```bash
curl "http://localhost:8080/api/v1/me" \
-H "Authorization: Bearer "
```
Пример ротации токена:
```bash
curl -X POST "http://localhost:8080/api/v1/auth/rotate" \
-H "Authorization: Bearer "
```
Пример logout (отзыва текущего токена):
```bash
curl -X POST "http://localhost:8080/api/v1/auth/logout" \
-H "Authorization: Bearer "
```
## Webhooks (incoming + outgoing)
### Входящие webhook
Эндпоинт:
- `POST /api/v1/webhooks/incoming/generic`
Обязательные заголовки:
- `Idempotency-Key: `
- `X-Webhook-Signature: sha256=`
Опционально:
- `X-Webhook-Event: `
Секрет для source `generic` задаётся через `.env`:
- `WEBHOOK_INCOMING_GENERIC_SECRET=...`
В `prod` без секрета endpoint вернёт `503` (безопасный fail-close).
Подпись считается как `HMAC-SHA256` по raw body запроса.
Все входящие доставки логируются в таблицу `webhook_incoming_delivery`.
Пример:
```bash
BODY='{"event":"ping"}'
SIG=$(php -r "echo hash_hmac('sha256', '$BODY', getenv('WEBHOOK_INCOMING_GENERIC_SECRET') ?: 'change-me-incoming-secret');")
curl -X POST "http://localhost:8080/api/v1/webhooks/incoming/generic" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: incoming-1" \
-H "X-Webhook-Event: ping" \
-H "X-Webhook-Signature: sha256=$SIG" \
-d "$BODY"
```
### Исходящие webhook (outbox + worker)
События, которые ставятся в очередь автоматически:
- `article.published` (когда статья становится published)
- `comment.created`
- `contact.created`
Таблицы:
- `webhook_endpoint` — получатели webhook
- `webhook_delivery` — очередь и история попыток доставки
Команды:
```bash
# добавить/обновить endpoint
php yii webhook/create-endpoint "crm" "https://example.com/webhooks" "super-secret" "article.published,comment.created,contact.created" 10
# показать endpoint'ы
php yii webhook/list-endpoints
# обработать очередь (воркер)
php yii webhook/dispatch 100
```
Для фоновой обработки добавьте cron, например каждую минуту:
```bash
* * * * * /usr/bin/php /path/to/project/yii webhook/dispatch 100 >> /var/log/myblog-webhooks.log 2>&1
```
## Загрузка больших фото
В проекте уже настроены лимиты для больших изображений:
- application limit: `128 MB` (`config/params.php -> upload.maxImageSize`)
- Apache (`web/.htaccess`) и PHP-FPM/CGI (`web/.user.ini`)
- Docker (`docker/php/uploads.ini`)
- Vagrant/Nginx: `client_max_body_size 128M` + правка `php.ini` в provision-скрипте
Если меняете лимит, обновляйте его одновременно в:
- `config/params.php`
- `web/.user.ini`
- `web/.htaccess` (для mod_php)
- `docker/php/uploads.ini` (если используете Docker)
- `vagrant/nginx/app.conf` и `vagrant/provision/once-as-root.sh` (если используете Vagrant)
## Важные миграции
- `m260203_000001_harden_blog_schema`:
- добавляет `auth_key` и `access_token` в `user`
- нормализует/усиливает данные и ограничения
- добавляет индексы и внешние ключи
- приводит старые пароли к безопасному хешу (если это не хеш)
- `m260204_000006_create_webhook_tables`:
- создаёт таблицы для входящих и исходящих webhook
- добавляет индексы и FK для outbox-очереди
- `m260204_000007_optimize_query_indexes` и `m260204_000008_add_article_category_status_index`:
- добавляют индексы под API/воркер запросы
- ускоряют выборки статей, комментариев и webhook-delivery
## Тесты
Основная команда для прогона всех уровней тестов (acceptance + functional + unit):
```bash
docker compose exec app vendor/bin/codecept run
```
Если контейнеры ещё не запущены:
```bash
docker compose up -d
```
Команды по отдельным уровням:
```bash
docker compose exec app vendor/bin/codecept run acceptance
docker compose exec app vendor/bin/codecept run functional
docker compose exec app vendor/bin/codecept run unit
```
Локальный запуск (без Docker):
```bash
vendor/bin/codecept run
```
Если в окружении нет `pdo_mysql` и/или `gd`/`imagick`, часть тестов будет пропущена (skipped).
В Docker-конфигурации используется отдельная тестовая БД `myblog_test`.
`acceptance` suite работает через `tests/acceptance.suite.yml` и контейнер `selenium`.
### Фикстуры для проверки (admin + user)
В проект добавлены фикстуры:
- `admin@example.com / admin12345` (админ)
- `user@example.com / user12345` (обычный пользователь)
- демо-категории, теги и статьи для корректного рендера главной страницы
Загрузка фикстур:
```bash
php yii fixture/load "Category,Tag,User,Article,ArticleTag" --interactive=0
```
## Полезные переменные окружения
- `APP_PORT` — внешний порт приложения в Docker (по умолчанию `8080`)
- `YII_ENV` (`dev`/`prod`, по умолчанию `prod`)
- `YII_DEBUG` (`true`/`false`, по умолчанию `false`)
- `DB_HOST`, `DB_PORT`, `DB_NAME` — параметры основной БД (если `DB_DSN` не задан)
- `DB_TEST_DSN` или `DB_TEST_HOST`/`DB_TEST_PORT`/`DB_TEST_NAME` — тестовая БД
- `MYSQL_DATABASE`, `MYSQL_TEST_DATABASE`, `MYSQL_USER`, `MYSQL_PASSWORD`, `MYSQL_ROOT_PASSWORD` — переменные MySQL в Docker
- `DB_PORT` в `.env` также используется для проброса порта MySQL контейнера наружу (`:3306`, по умолчанию `3307`)
- `SELENIUM_PORT` (по умолчанию `4444`) — порт Selenium WebDriver
- `AUTO_MIGRATE` (`1`/`0`) — авто-применение миграций в Docker
- `AUTO_MIGRATE_TEST_DB` (`1`/`0`) — авто-применение миграций в тестовой БД
- `AUTO_LOAD_FIXTURES` (`1`/`0`) — авто-загрузка фикстур при пустой таблице `user`
- `FIXTURES_LIST` (по умолчанию `Category,Tag,User,Article,ArticleTag`) — какие фикстуры грузить автоматически
- `WAIT_FOR_DB`, `DB_WAIT_TIMEOUT` — ожидание готовности БД в Docker entrypoint
- `WEBHOOK_INCOMING_GENERIC_SECRET`, `WEBHOOK_OUTGOING_MAX_ATTEMPTS` — настройки webhook
- `API_ALLOWED_ORIGINS` — CORS origins для API (список через запятую)
- `API_ACCESS_TOKEN_TTL` — TTL access token в секундах (по умолчанию `43200`)
- `API_REVOKE_EXISTING_TOKENS_ON_LOGIN` — при логине отзывать прошлые активные токены (`1`/`0`)
- `API_LEGACY_ACCESS_TOKEN_FALLBACK` — временный fallback на старый `user.access_token` (`1`/`0`, по умолчанию `0`)
## Структура проекта (основное)
- `controllers/` — контроллеры публичной части
- `models/` — модели и search-модели
- `modules/admin/` — админ-модуль
- `views/` — шаблоны
- `migrations/` — миграции БД
- `config/` — конфиги приложения
- `tests/` — unit/functional/acceptance тесты