From 59e88ae9641a1624a7fde15de331e75db3b30af6 Mon Sep 17 00:00:00 2001 From: Panfilov Konstantin Date: Mon, 5 Oct 2026 18:34:06 +0300 Subject: [PATCH] =?UTF-8?q?README:=20=D1=87=D1=82=D0=BE=20=D1=8D=D1=82?= =?UTF-8?q?=D0=BE,=20=D0=BA=D0=B0=D0=BA=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=B0=D0=B5=D1=82=20(=D0=BC=D0=B5=D1=82=D0=BA=D0=B8,=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=B3=D1=80=D1=83=D0=B7=D0=BA=D0=B0,=20=D0=BF=D0=B5?= =?UTF-8?q?=D1=80=D0=B5=D0=B4=D0=B0=D1=87=D0=B0=20=D0=BD=D0=B0=20=D1=81?= =?UTF-8?q?=D0=B0=D0=B9=D1=82=20=D1=87=D0=B5=D1=80=D0=B5=D0=B7=20claim),?= =?UTF-8?q?=20=D1=84=D0=B0=D0=B9=D0=BB=D1=8B,=20config.json,=20=D0=B4?= =?UTF-8?q?=D0=B5=D0=BF=D0=BB=D0=BE=D0=B9=20=D0=BD=D0=B0=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D0=B8=D0=B7=D0=B2=D0=BE=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9=20?= =?UTF-8?q?=D0=B4=D0=BE=D0=BC=D0=B5=D0=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- README.md | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..b8b6b7a --- /dev/null +++ b/README.md @@ -0,0 +1,125 @@ +# Преленд zoomzilla + +Одностраничный лендинг перед основным сайтом (`zoomzilla.ru`): посетитель с рекламы выбирает фото прямо на +преленде, файл сразу уходит в API сайта, а сам посетитель переходит на сайт — на страницу обработки этого фото. +Варианты страницы и сайта (A/B) задаются метками в адресе. Код — обычный PHP без фреймворка и сборки; переводы — +маленькая заглушка `Yii::t` в `i18n.php`. + +Боевой экземпляр: `https://preland.anton.barbariskatest.ru` (хостинг beget). Пример ссылки входа: +`https://preland.anton.barbariskatest.ru/?indpic=1&theme=dark°r=2®istration=after&bchoice=a&tp=1&utm_source=test&subid=CLICK1`. + +## Как работает + +### Метки + +`index.php` разбирает параметры адреса по разделу `utm` из `config.json`. Для каждой настроенной метки: + +- значение из адреса принимается, если оно есть в `weights`; +- `rnd` — случайное значение по весам (`weights`), так делится трафик между вариантами; +- неизвестное значение отбрасывается, отсутствующее — заменяется на `default`. + +Ненастроенные параметры (`utm_source`, `keyword`, `subid` и любые другие) проходят как есть. Все метки уходят дальше +в адрес сайта: сайт сохраняет их на воронку и шлёт в Keitaro. + +| Метка | Что задаёт | Где | +|---|---|---| +| `indpic` | картинка-пример на преленде | `images/demo//` | +| `theme` | `light` / `dark` | преленд и сайт | +| `degr` | пресет ухудшения превью «До» | сайт (#42) | +| `registration` | `before` — PIN до оплаты, `after` — после | сайт, страница результата | +| `bchoice` | попап выбора банка (`a` — показать) | сайт, оплата (#44) | +| `chb` | галочки согласия на странице оплаты (`no` — не обязательны) | сайт, оплата | +| `tp` | группа тарифов | сайт, cpanel «Группы тарифов (tp)» | + +### Загрузка и переход на сайт + +1. Браузер проверяет файл: изображение, не больше 6000 px по большей стороне. +2. XHR `POST https:///api/images/public/create` (`multipart/form-data`: `file` и `client_key` — случайный UUID + загрузки, `crypto.randomUUID()`), `Accept: application/json`. Ответ — JSON с id обработки. +3. Браузер переходит на `https:///api/images/public/claim?key=&<метки>`. Сайт кладёт загрузку + в сессию посетителя и отвечает 302 на `/public/upscale?id=<обработка>&<метки>` (уже без ключа); страница сама + запускает обработку. + +Почему не сразу `/public/upscale`: XHR с преленда кросс-доменный, и сессия, в которой сайт запомнил загрузку, +посетителю на сайте недоступна — браузеры изолируют или не принимают куки третьей стороны. Страница обработки +пускает только владельца загрузки, поэтому без передачи по ключу посетитель видел 404. Ключ одноразовый и годен +30 минут после загрузки. + +`` — домен сайта из `config.json`. API сайта принимает загрузку с любого домена (CORS отражает `Origin`), так +что для нового домена преленда на сайте ничего настраивать не нужно. + +### Файлы + +| Путь | Назначение | +|---|---| +| `index.php` | вход: конфиг, разбор меток, адреса API и перехода, общие переменные, `renderComponent()` | +| `template.php` | разметка страницы: шапка, блок загрузки, примеры, подвал с реквизитами | +| `components/form.php` | форма выбора файла и загрузка (XHR, `client_key`, переход на `claim`) | +| `components/preview.php`, `process.php`, `examples.php` | превью файла, индикатор загрузки, примеры «до/после» | +| `i18n.php`, `messages/{ru,en}/` | заглушка `Yii::t` и переводы; язык сейчас всегда `ru` (определение языка закомментировано) | +| `docs/` | `logo.svg`, `logo-alt.svg` и документы в PDF: тарифы, оферта, соглашение, политика | +| `requisites.html` | реквизиты для подвала (HTML). Пустой или отсутствующий — выводится **заглушка «ИП Иванов Иван Иванович»** из `template.php`: на боевом заполнить | +| `images/`, `fonts/`, `favicon/`, `*.css` | статика; `style.min.css` встраивается в страницу | +| `.htaccess` | только сроки кэширования статики (Apache) | +| `config.json.example` | образец конфига; рабочий `config.json` в git не хранится | + +### `config.json` + +| Ключ | Обязательный | Что задаёт | +|---|:---:|---| +| `host` | **да** | домен сайта, куда идут загрузка и переход (`zoomzilla.ru`). Без него берётся домен самого преленда — запросы уходят на преленд и получают 404 | +| `utm` | да | метки: `weights` (значение → доля трафика для `rnd`) и `default` | +| `assetsUriPrefix` | нет | откуда брать статику. Пусто — из своего каталога; если на хостинге нет каталога `images`, статика берётся с сайта (`https://`) | +| `fontsUrl`, `faviconUrl`, `spritePath` | нет | адреса шрифтов, иконок и SVG-спрайта, если они не в `assetsUriPrefix` | +| `logoAltExt` | нет | расширение второго логотипа (`svg` по умолчанию) | +| `title` | нет | заголовок страницы («Улучшение изображения») | +| `default_language` | нет | сейчас не действует: язык всегда `ru` | + +## Деплой на произвольный домен + +**Требования.** PHP 8.0+ (боевой хостинг — 8.2), веб-сервер с `index.php` в роли индексного файла и **HTTPS**: +`crypto.randomUUID()` работает только в защищённом контексте, а сайт отвечает по https. + +1. **Домен.** Запись A (или CNAME) на хостинг, сертификат (Let's Encrypt или от хостинга); открыть `https://<домен>/`. +2. **Файлы.** Содержимое репозитория — в корень сайта, без `.git` и служебного (`README.md`, `.gitea/`): + ```bash + git clone http://git.dira89kv.beget.tech:3000/anton/preland.git && cd preland + # дальше — загрузка на хостинг: rsync/scp по SSH или FTP-клиент + ``` +3. **Конфиг и реквизиты.** На сервере, рядом с `index.php` (и заполнить `requisites.html` — иначе в подвале заглушка): + ```bash + cp config.json.example config.json # host — домен сайта, метки — по кампании + ``` + `config.json` не в git: при обновлении файлов **не удалять** его (не синхронизировать каталог «зеркалом» без + исключения `config.json`). 2026-10-05 после заливки он пропал, и преленд слал загрузку на собственный домен. +4. **nginx без Apache** (если хостинг не обрабатывает `.htaccess`): + ```nginx + server { + server_name <домен>; + root /var/www/<домен>; + index index.php; + location ~ /(\.git|config\.json|README\.md) { deny all; } + location ~ \.php$ { + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_pass unix:/run/php/php8.2-fpm.sock; + } + location ~* \.(avif|webp|jpe?g|png|svg|ico|woff2?|css|js)$ { expires 1y; add_header Cache-Control "public, immutable"; } + } + ``` +5. **Сайт (по желанию).** Домен преленда сайт определяет сам — по `Referer` первого захода. Свои умолчания меток + для этого домена: cpanel → «Метки (UTM)» → «Умолчания по домену прелендинга». +6. **Проверка.** + ```bash + curl -s 'https://<домен>/?nc=1' | grep -o 'const createApiUrl = [^;]*;\|const redirectUrlBase = [^;]*;' + # оба адреса — https:///api/images/public/…, а не домен преленда + curl -s -o /dev/null -w '%{http_code} %{redirect_url}\n' 'https:///api/images/public/claim?key=x' + # 302 на https:/// — точка передачи на сайте есть + ``` + В браузере: открыть `https://<домен>/?indpic=1&theme=dark&subid=TEST`, выбрать фото — адрес сменится на + `https:///public/upscale?id=…&indpic=1&theme=dark&subid=TEST…` (без `key=`), пойдёт обработка. + Это настоящая загрузка и обработка на сайте. + +**Откат.** Перед заменой файлов — копия изменяемых файлов (`index.php`, `components/*`) с хостинга; вернуть их той же +загрузкой. Новый преленд требует на сайте `/api/images/public/claim` (api с 2026-10-05): со старым api переход +по ключу отдаст 404.