feat: готовый бренд ZoomStage и минимальный доменный подвал (refs #12)
deploy-preland / deploy zoomstage.online (push) Successful in 44s

This commit is contained in:
Panfilov Konstantin committed 2026-10-21 17:24:14 +03:00
1 parent a2c3197a16
commit ec087ea636
24 files changed
+313 -185

No files matched your search

+28 -11
View File
@@ -65,16 +65,32 @@ jobs:
SSHPASS="$SFTP_PASS" sshpass -e sftp -oBatchMode=no -oStrictHostKeyChecking=yes -oUserKnownHostsFile="$known_hosts" -b "$batch" "$SFTP_USER@$SFTP_HOST" ;;
*) exit "$changed" ;;
esac
# preland#11: отдельное прямое разрешение21.10 на актуальные реквизиты.
changed=0
php bin/ensure-requisites-config.php "$config" || changed=$?
case "$changed" in
0) ;;
10) printf '%s\n' "put -p $config $REMOTE_DIR/config.json" > "$batch"
SSHPASS="$SFTP_PASS" sshpass -e sftp -oBatchMode=no -oStrictHostKeyChecking=yes -oUserKnownHostsFile="$known_hosts" -b "$batch" "$SFTP_USER@$SFTP_HOST" ;;
*) exit "$changed" ;;
esac
- name: Apply approved domain brand only if needed
env:
SFTP_HOST: ${{ secrets.ZOOMPIXEL_SFTP_HOST }}
SFTP_USER: ${{ secrets.ZOOMPIXEL_SFTP_USER }}
SFTP_PASS: ${{ secrets.ZOOMPIXEL_SFTP_PASS }}
SFTP_KNOWN_HOSTS: ${{ secrets.ZOOMPIXEL_SFTP_KNOWN_HOSTS }}
run: |
set -eu
status=0
php bin/release-brand.php --status "$PRELAND_URL" || status=$?
case "$status" in 0) exit 0 ;; 10) ;; *) exit "$status" ;; esac
# Только точная ранее согласованная пара заменяется по preland#12.
# Обычные выпуски с правильным брендом сюда не доходят.
umask 077
known_hosts=$(mktemp); batch=$(mktemp); files=$(mktemp)
trap 'rm -f "$known_hosts" "$batch" "$files"' EXIT
printf '%s\n' "$SFTP_KNOWN_HOSTS" > "$known_hosts"
php bin/release-brand.php --files "$PRELAND_URL" > "$files"
revision=$(git rev-parse HEAD)
while read -r source target; do
# Оборванный put не должен оставлять усечённый действующий SVG.
printf '%s\n' "put -p $source $REMOTE_DIR/$target.upload-$revision" >> "$batch"
printf '%s\n' "rename $REMOTE_DIR/$target.upload-$revision $REMOTE_DIR/$target" >> "$batch"
done < "$files"
SSHPASS="$SFTP_PASS" sshpass -e sftp -oBatchMode=no -oStrictHostKeyChecking=yes -oUserKnownHostsFile="$known_hosts" -b "$batch" "$SFTP_USER@$SFTP_HOST"
php bin/release-brand.php --status "$PRELAND_URL"
- name: Upload over SFTP
env:
SFTP_HOST: ${{ secrets.ZOOMPIXEL_SFTP_HOST }}
@@ -126,7 +142,7 @@ jobs:
page2=$(curl -fsS --max-time 30 "$PRELAND_URL/?indpic=2&nc=$(date +%s)")
printf '%s' "$page2" | grep -q '2/01_mob_1-source.avif' || { echo "indpic=2 не использует второй набор примеров"; exit 1; }
php bin/release-assets.php --remote "$PRELAND_URL"
php bin/release-assets.php --stage-requisites "$PRELAND_URL"
php bin/release-brand.php --status "$PRELAND_URL"
- name: Remove previously published internal files
env:
@@ -141,6 +157,7 @@ jobs:
trap 'rm -f "$known_hosts" "$batch"' EXIT
printf '%s\n' "$SFTP_KNOWN_HOSTS" > "$known_hosts"
# Только точно известные служебные файлы прежнего deploy, без рекурсии.
printf '%s\n' "-rm $REMOTE_DIR/requisites.html" > "$batch"
git ls-files tests bin docs/superpowers | while read -r file; do
printf '%s\n' "-rm $REMOTE_DIR/$file" >> "$batch"
done
+12
View File
@@ -55,3 +55,15 @@
- /N/ по-прежнему редактируется на stage и не перезаписывается обычной кодовой доставкой; все150файлов перед выкатом сверяются с Git. Drift блокирует выпуск до импорта актуального набора. При полном переносе репозитория набор уже должен быть правильным.
- SFTP берёт положительный список из bin/release-assets.php --files: никакие tests/bin/release/plans не публикуются. Старые известные служебные файлы удаляются только по точному списку git ls-files, без рекурсивной очистки. После выпуска --remote сверяет все184ресурса.
- Production-преленды остаются замороженными по preland#4. Push main ничего не публикует; staging обновляет только zoomstage.online из точного event SHA.
## Доменный бренд и минимальный подвал (21.10.2026, preland#12)
Новое поручение владельца заменяет часть требований #11: в подвале остаются логотип и копирайт, без реквизитов и платёжных значков. Копирайт использует текущий HTTP_HOST без порта/trailing-dot, отдельно от config.host API; непроверенные Host и X-Forwarded-Host не выводятся.
Логотипы — готовые SVG-контуры, не текст на лету. Для zoomstage.online утверждено имя ZoomStage, слитно без зоны, обе темы. Источники лежат в brands/zoomstage.online/light.svg и dark.svg; release/brands.json содержит явную цель, имя и SHA. В docs/logo.svg и logo-alt.svg хранятся правильные canonical stage-копии для полного переноса. Их размеры182×47 совпадают с viewBox, чтобы загрузка SVG не меняла геометрию.
Обычный bin/release-assets.php --files исключает оба logo-alias из записи; runtime cache-version рассчитывается по реальному файлу хоста. Отдельный шаг release-brand.php --status разрешает только заранее согласованную миграцию #12:0 — оба SVG уже правильные, записи нет;10 — каждый файл имеет свой известный старый или новый SHA, можно закончить миграцию (включая частичный put);1 — неизвестный домен/хеш, остановка без подмены. --files выдаёт ровно утверждённые source→target. Иные логотипы не перезаписывать общим выкатом. Новые production-домены требуют отдельного добавления готовых пар и явного первоначального размещения; текущий stage-процесс их не активирует.
primary guard теперь сверяет PDF/favicon, а не заставляет возвращать Zoomzilla и реквизиты на преленд. Реквизиты не отображаются и больше автоматически не синхронизируются; хостовый config и его существующие значения не меняются этим поручением. Устаревшие requisites.html и patch-скрипт удалены из поставки. Статический manifest183, отдельный каталог брендов проверяется по собственным SHA. История #11 сохранена; её прежние инструкции о видимом бренде/реквизитах заменены этим датированным решением.
Перед выпуском: девять tests/check-*.php и lint, --check/--primary/--stage-sets, оба бренда шапки/подвала на desktop/mobile, перенос Host, отсутствие карт/реквизитов, холодная/медленная загрузка, реальные локальные Preland→Tour→Join/error/retry и геометрия. Production-преленды по #4 не включать; выпускать только staging→zoomstage.online. API продуктовый код не меняется.
+12
View File
@@ -52,3 +52,15 @@
- /N/ по-прежнему редактируется на stage и не перезаписывается обычной кодовой доставкой; все150файлов перед выкатом сверяются с Git. Drift блокирует выпуск до импорта актуального набора. При полном переносе репозитория набор уже должен быть правильным.
- SFTP берёт положительный список из bin/release-assets.php --files: никакие tests/bin/release/plans не публикуются. Старые известные служебные файлы удаляются только по точному списку git ls-files, без рекурсивной очистки. После выпуска --remote сверяет все184ресурса.
- Production-преленды остаются замороженными по preland#4. Push main ничего не публикует; staging обновляет только zoomstage.online из точного event SHA.
## Доменный бренд и минимальный подвал (21.10.2026, preland#12)
Новое поручение владельца заменяет часть требований #11: в подвале остаются логотип и копирайт, без реквизитов и платёжных значков. Копирайт использует текущий HTTP_HOST без порта/trailing-dot, отдельно от config.host API; непроверенные Host и X-Forwarded-Host не выводятся.
Логотипы — готовые SVG-контуры, не текст на лету. Для zoomstage.online утверждено имя ZoomStage, слитно без зоны, обе темы. Источники лежат в brands/zoomstage.online/light.svg и dark.svg; release/brands.json содержит явную цель, имя и SHA. В docs/logo.svg и logo-alt.svg хранятся правильные canonical stage-копии для полного переноса. Их размеры182×47 совпадают с viewBox, чтобы загрузка SVG не меняла геометрию.
Обычный bin/release-assets.php --files исключает оба logo-alias из записи; runtime cache-version рассчитывается по реальному файлу хоста. Отдельный шаг release-brand.php --status разрешает только заранее согласованную миграцию #12:0 — оба SVG уже правильные, записи нет;10 — каждый файл имеет свой известный старый или новый SHA, можно закончить миграцию (включая частичный put);1 — неизвестный домен/хеш, остановка без подмены. --files выдаёт ровно утверждённые source→target. Иные логотипы не перезаписывать общим выкатом. Новые production-домены требуют отдельного добавления готовых пар и явного первоначального размещения; текущий stage-процесс их не активирует.
primary guard теперь сверяет PDF/favicon, а не заставляет возвращать Zoomzilla и реквизиты на преленд. Реквизиты не отображаются и больше автоматически не синхронизируются; хостовый config и его существующие значения не меняются этим поручением. Устаревшие requisites.html и patch-скрипт удалены из поставки. Статический manifest183, отдельный каталог брендов проверяется по собственным SHA. История #11 сохранена; её прежние инструкции о видимом бренде/реквизитах заменены этим датированным решением.
Перед выпуском: девять tests/check-*.php и lint, --check/--primary/--stage-sets, оба бренда шапки/подвала на desktop/mobile, перенос Host, отсутствие карт/реквизитов, холодная/медленная загрузка, реальные локальные Preland→Tour→Join/error/retry и геометрия. Production-преленды по #4 не включать; выпускать только staging→zoomstage.online. API продуктовый код не меняется.
+12
View File
@@ -185,3 +185,15 @@ Workflow `.gitea/workflows/deploy.yml` содержит единственную
- Production-преленды остаются замороженными по preland#4. Push main ничего не публикует; staging обновляет только zoomstage.online из точного event SHA.
Повторная проверка выпуска: php bin/release-assets.php --stage-requisites https://zoomstage.online проверяет именно runtime config; успешная загрузка requisites.html сама по себе недостаточна. Все обязательные SFTP-команды выполняются через batch -b и прекращают выкат при ошибке put.
## Доменный бренд и минимальный подвал (21.10.2026, preland#12)
Новое поручение владельца заменяет часть требований #11: в подвале остаются логотип и копирайт, без реквизитов и платёжных значков. Копирайт использует текущий HTTP_HOST без порта/trailing-dot, отдельно от config.host API; непроверенные Host и X-Forwarded-Host не выводятся.
Логотипы — готовые SVG-контуры, не текст на лету. Для zoomstage.online утверждено имя ZoomStage, слитно без зоны, обе темы. Источники лежат в brands/zoomstage.online/light.svg и dark.svg; release/brands.json содержит явную цель, имя и SHA. В docs/logo.svg и logo-alt.svg хранятся правильные canonical stage-копии для полного переноса. Их размеры182×47 совпадают с viewBox, чтобы загрузка SVG не меняла геометрию.
Обычный bin/release-assets.php --files исключает оба logo-alias из записи; runtime cache-version рассчитывается по реальному файлу хоста. Отдельный шаг release-brand.php --status разрешает только заранее согласованную миграцию #12:0 — оба SVG уже правильные, записи нет;10 — каждый файл имеет свой известный старый или новый SHA, можно закончить миграцию (включая частичный put);1 — неизвестный домен/хеш, остановка без подмены. --files выдаёт ровно утверждённые source→target. Иные логотипы не перезаписывать общим выкатом. Новые production-домены требуют отдельного добавления готовых пар и явного первоначального размещения; текущий stage-процесс их не активирует.
primary guard теперь сверяет PDF/favicon, а не заставляет возвращать Zoomzilla и реквизиты на преленд. Реквизиты не отображаются и больше автоматически не синхронизируются; хостовый config и его существующие значения не меняются этим поручением. Устаревшие requisites.html и patch-скрипт удалены из поставки. Статический manifest183, отдельный каталог брендов проверяется по собственным SHA. История #11 сохранена; её прежние инструкции о видимом бренде/реквизитах заменены этим датированным решением.
Перед выпуском: девять tests/check-*.php и lint, --check/--primary/--stage-sets, оба бренда шапки/подвала на desktop/mobile, перенос Host, отсутствие карт/реквизитов, холодная/медленная загрузка, реальные локальные Preland→Tour→Join/error/retry и геометрия. Production-преленды по #4 не включать; выпускать только staging→zoomstage.online. API продуктовый код не меняется.
+27
View File
@@ -0,0 +1,27 @@
<?php
/** Готовые доменные SVG, без генерации логотипа при запросе страницы. */
declare(strict_types=1);
function prelandBrand(string $root, string $domain): array
{
$catalog = json_decode(file_get_contents($root . '/release/brands.json'), true, 512, JSON_THROW_ON_ERROR);
if (!isset($catalog[$domain])) throw new RuntimeException('Для домена не утверждён бренд: ' . $domain);
$brand = $catalog[$domain];
if (array_keys($brand['logos']) !== ['docs/logo.svg', 'docs/logo-alt.svg']) throw new RuntimeException('Нужна полная пара SVG');
foreach ($brand['logos'] as $target => $record) {
if (!preg_match('~^brands/' . preg_quote($domain, '~') . '/(?:light|dark)\.svg$~D', $record['file'])) throw new RuntimeException('Некорректный путь бренда');
$body = str_replace("\r\n", "\n", file_get_contents($root . '/' . $record['file']));
if (hash('sha256', $body) !== $record['sha256'] || str_contains($body, '<text') || !str_contains($body, '<title>' . $brand['label'] . '</title>')) throw new RuntimeException('Не совпал утверждённый готовый SVG: ' . $target);
}
return $brand;
}
function prelandBrandState(array $actual, array $brand): int
{
$expected = array_map(static fn(array $record): string => $record['sha256'], $brand['logos']);
if ($actual === $expected) return 0;
if (array_keys($actual) !== array_keys($expected)) return 1;
foreach ($expected as $path => $hash) {
if ($actual[$path] !== $hash && $actual[$path] !== ($brand['replace_from'][$path] ?? null)) return 1;
}
return 10;
}
-60
View File
@@ -1,60 +0,0 @@
<?php
/** preland#11: владелец21.10 согласовал только requisites из текущей zoomzilla.ru. */
declare(strict_types=1);
function replaceRequisites(string $raw, string $encoded): string
{
$depth = 0; $length = strlen($raw);
for ($i = 0; $i < $length; $i++) {
if ($raw[$i] === '"') {
$start = $i++;
for (; $i < $length; $i++) {
if ($raw[$i] === '\\') { $i++; continue; }
if ($raw[$i] === '"') break;
}
if ($depth !== 1 || json_decode(substr($raw, $start, $i - $start + 1)) !== 'requisites') continue;
$cursor = $i + 1;
while ($cursor < $length && ctype_space($raw[$cursor])) $cursor++;
if (($raw[$cursor] ?? '') !== ':') continue;
$cursor++;
while ($cursor < $length && ctype_space($raw[$cursor])) $cursor++;
$valueStart = $cursor; $nested = 0; $quoted = false;
for (; $cursor < $length; $cursor++) {
$char = $raw[$cursor];
if ($quoted) {
if ($char === '\\') $cursor++;
elseif ($char === '"') $quoted = false;
continue;
}
if ($char === '"') { $quoted = true; continue; }
if (($char === ',' || $char === '}') && $nested === 0) break;
if ($char === '[' || $char === '{') $nested++;
elseif ($char === ']' || $char === '}') $nested--;
}
return substr($raw, 0, $valueStart) . $encoded . substr($raw, $cursor);
}
if ($raw[$i] === '{' || $raw[$i] === '[') $depth++;
elseif ($raw[$i] === '}' || $raw[$i] === ']') $depth--;
}
$end = strrpos($raw, '}');
$prefix = substr($raw, 0, $end);
return $prefix . (count(json_decode($raw, true)) ? ',' : '') . '"requisites":' . $encoded . substr($raw, $end);
}
try {
if ($argc !== 2) throw new RuntimeException('Требуется путь к текущему host config');
$path = $argv[1];
$raw = file_get_contents($path);
$config = json_decode($raw, true, 512, JSON_THROW_ON_ERROR);
if (!is_array($config) || !str_starts_with(ltrim($raw), '{')) throw new RuntimeException('Требуется объект config');
$expected = json_decode(file_get_contents(dirname(__DIR__) . '/release/requisites.json'), true, 512, JSON_THROW_ON_ERROR);
if (!is_array($expected) || !$expected || array_filter($expected, static fn($line) => !is_string($line) || trim($line) === '')) throw new RuntimeException('Некорректный согласованный источник requisites');
if (($config['requisites'] ?? null) === $expected) { echo "requisites актуальны: конфиг не изменён\n"; exit(0); }
$patched = replaceRequisites($raw, json_encode($expected, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR));
$actual = json_decode($patched, true, 512, JSON_THROW_ON_ERROR);
$config['requisites'] = $expected;
// JSON-порядок ключей не меняет контракт, остальные значения должны совпасть.
if ($actual != $config) throw new RuntimeException('Изменились несогласованные поля');
if (file_put_contents($path, $patched, LOCK_EX) === false) throw new RuntimeException('Запись config не удалась');
echo "Изменён только requisites по решению владельца preland#11\n"; exit(10);
} catch (Throwable $error) { fwrite(STDERR, $error->getMessage() . "\n"); exit(2); }
+12 -23
View File
@@ -1,6 +1,7 @@
<?php
/** preland#11: проверенный состав ресурсов; исполняется до SFTP. */
declare(strict_types=1);
require_once __DIR__ . '/brand-contract.php';
function releaseAssetBytes(string $path, string $bytes): string
{
@@ -20,7 +21,7 @@ function releaseStaticFiles(string $root): array
if ($name === 'docs' && !preg_match('~^docs/[^/]+\.(svg|pdf)$~', $path)) continue;
if ($entry->isFile()) $files[] = $path;
}
} elseif (preg_match('/\.css$/', $name) || $name === 'requisites.html') {
} elseif (preg_match('/\.css$/', $name)) {
$files[] = $name;
}
}
@@ -32,7 +33,9 @@ function validateReleaseAssets(string $root): array
{
$manifest = json_decode((string) file_get_contents($root . '/release/assets.json'), true, 512, JSON_THROW_ON_ERROR);
$files = $manifest['files'] ?? [];
$required = ['docs/logo.svg', 'docs/logo-alt.svg', 'docs/privacy_policy.pdf', 'docs/public_offer.pdf', 'docs/tariffs.pdf', 'docs/user_agreement.pdf', 'requisites.html'];
$brands = json_decode(file_get_contents($root . '/release/brands.json'), true, 512, JSON_THROW_ON_ERROR);
foreach (array_keys($brands) as $domain) prelandBrand($root, $domain);
$required = ['docs/logo.svg', 'docs/logo-alt.svg', 'docs/privacy_policy.pdf', 'docs/public_offer.pdf', 'docs/tariffs.pdf', 'docs/user_agreement.pdf'];
foreach ($required as $path) {
if (!isset($files[$path])) throw new RuntimeException('В manifest отсутствует обязательный ресурс ' . $path);
}
@@ -52,7 +55,7 @@ function validateReleaseAssets(string $root): array
function releaseFiles(string $root): array
{
$files = array_values(array_filter(releaseStaticFiles($root), static fn(string $path): bool => !preg_match('~^[0-9]+/~', $path)));
$files = array_values(array_filter(releaseStaticFiles($root), static fn(string $path): bool => !preg_match('~^(?:[0-9]+/|docs/logo(?:-alt)?\.svg$)~', $path)));
foreach (['.htaccess', 'index.php', 'i18n.php', 'template.php'] as $path) $files[] = $path;
foreach (['components', 'messages'] as $directory) {
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($root . '/' . $directory, FilesystemIterator::SKIP_DOTS));
@@ -67,6 +70,10 @@ function releaseFiles(string $root): array
function verifyRemoteReleaseAssets(array $files, string $base, bool $setsOnly): void
{
if (!preg_match('~^https://[A-Za-z0-9.-]+$~', $base)) throw new RuntimeException('Требуется HTTPS origin');
if (!$setsOnly) {
$brand = prelandBrand(dirname(__DIR__), (string) parse_url($base, PHP_URL_HOST));
foreach ($brand['logos'] as $path => $record) $files[$path]['sha256'] = $record['sha256'];
}
$count = 0;
foreach ($files as $path => $record) {
if ($setsOnly && !preg_match('~^[0-9]+/~', $path)) continue;
@@ -88,6 +95,7 @@ function verifyPrimaryAssets(string $root, array $files): void
$html = @file_get_contents($origin . '/?theme=light&preland_asset_check=1', false, $context);
if ($html === false) throw new RuntimeException('Основной сайт недоступен для сверки ресурсов');
foreach ($files as $path => $record) {
if (str_starts_with($path, 'docs/logo')) continue;
if (!str_starts_with($path, 'docs/') && !str_starts_with($path, 'favicon/')) continue;
$name = basename($path === 'docs/logo.svg' ? 'logo-light.svg' : $path);
$pattern = '~(?:src|href)=["\']([^"\']*/' . preg_quote($name, '~') . '(?:\?[^"\']*)?)["\']~';
@@ -103,17 +111,7 @@ function verifyPrimaryAssets(string $root, array $files): void
throw new RuntimeException('Основной сайт обновлён: синхронизируйте ' . $path . ' в Git перед выпуском');
}
}
if (!preg_match('~<div[^>]*class=["\'][^"\']*\bh5\b[^"\']*["\'][^>]*>\s*Наши реквизиты\s*</div>(.*?)</div>~su', $html, $block)) throw new RuntimeException('Не найдены текущие реквизиты основного сайта');
preg_match_all('~<p\b[^>]*>(.*?)</p>~su', $block[1], $paragraphs);
$actual = [];
foreach ($paragraphs[1] as $paragraph) {
$paragraph = preg_replace('/\s+/u', ' ', $paragraph);
$text = html_entity_decode(strip_tags(preg_replace('~</?br\b[^>]*>~i', "\n", $paragraph)), ENT_QUOTES, 'UTF-8');
foreach (explode("\n", $text) as $line) if (trim($line) !== '') $actual[] = trim($line);
}
$expected = json_decode(file_get_contents($root . '/release/requisites.json'), true, 512, JSON_THROW_ON_ERROR);
if ($actual !== $expected) throw new RuntimeException('Основной сайт обновил реквизиты; сначала синхронизируйте Git');
fwrite(STDERR, "OK: primary logos/PDF/favicon/requisites актуальны\n");
fwrite(STDERR, "OK: primary PDF/favicon актуальны\n");
}
if (realpath($_SERVER['SCRIPT_FILENAME'] ?? '') === __FILE__) {
@@ -123,15 +121,6 @@ if (realpath($_SERVER['SCRIPT_FILENAME'] ?? '') === __FILE__) {
$mode = $argv[1] ?? '--check';
if ($mode === '--files') echo implode("\n", releaseFiles($root)), "\n";
elseif ($mode === '--primary') verifyPrimaryAssets($root, $files);
elseif ($mode === '--stage-requisites') {
$base = $argv[2] ?? '';
if (!preg_match('~^https://[A-Za-z0-9.-]+$~', $base)) throw new RuntimeException('Требуется HTTPS origin');
$context = stream_context_create(['http' => ['timeout' => 30, 'header' => "Cache-Control: no-cache\r\n"]]);
$actual = json_decode((string) file_get_contents($base . '/config.json?requisites_check=1', false, $context), true, 512, JSON_THROW_ON_ERROR);
$expected = json_decode(file_get_contents($root . '/release/requisites.json'), true, 512, JSON_THROW_ON_ERROR);
if (($actual['requisites'] ?? null) !== $expected) throw new RuntimeException('Host config не получил актуальные requisites');
echo "OK: runtime requisites актуальны\n";
}
elseif ($mode === '--remote' || $mode === '--stage-sets') verifyRemoteReleaseAssets($files, $argv[2] ?? '', $mode === '--stage-sets');
elseif ($mode === '--check') echo 'OK: release assets ', count($files), "\n";
else throw new RuntimeException('Неизвестный режим');
+26
View File
@@ -0,0 +1,26 @@
<?php
/** Отдельная явно согласованная миграция бренда. Обычная code-поставка SVG не пишет. */
declare(strict_types=1);
require __DIR__ . '/brand-contract.php';
try {
$mode = $argv[1] ?? ''; $url = $argv[2] ?? '';
if (!preg_match('~^https://([a-z0-9.-]+)$~D', $url, $match)) throw new RuntimeException('Требуется HTTPS origin цели');
$brand = prelandBrand(dirname(__DIR__), $match[1]);
if ($mode === '--files') {
foreach ($brand['logos'] as $target => $record) echo $record['file'], ' ', $target, "\n";
exit(0);
}
if ($mode !== '--status') throw new RuntimeException('Неизвестный режим бренда');
$actual = []; $expected = [];
foreach ($brand['logos'] as $target => $record) {
$context = stream_context_create(['http' => ['timeout' => 30, 'header' => "Cache-Control: no-cache\r\n"]]);
$body = @file_get_contents($url . '/' . $target . '?brand_check=' . $record['sha256'], false, $context);
if ($body === false) throw new RuntimeException('Не удалось прочитать бренд цели: ' . $target);
$actual[$target] = hash('sha256', str_replace("\r\n", "\n", $body));
$expected[$target] = $record['sha256'];
}
$state = prelandBrandState($actual, $brand);
if ($state === 0) { echo "OK: доменный бренд совпал; SVG не перезаписываются\n"; exit(0); }
if ($state === 10) { echo "Разрешена точная миграция бренда по preland#12\n"; exit(10); }
throw new RuntimeException('На хосте другой бренд: обычный deploy не имеет права его менять');
} catch (Throwable $error) { fwrite(STDERR, $error->getMessage() . "\n"); exit(1); }
+46
View File
@@ -0,0 +1,46 @@
<svg width="182" height="47" viewBox="0 0 182 47" fill="none" xmlns="http://www.w3.org/2000/svg">
<title>ZoomStage</title>
<g opacity="0.18" filter="url(#filter0_f_241_1963)">
<path d="M23.5 37C30.9558 37 37 30.9558 37 23.5C37 16.0442 30.9558 10 23.5 10C16.0442 10 10 16.0442 10 23.5C10 30.9558 16.0442 37 23.5 37Z" fill="url(#paint0_linear_241_1963)" />
</g>
<path d="M8.11627 23.5001C11.4128 16.2164 16.8442 12.5117 23.5 12.5117C30.1558 12.5117 35.5872 16.2164 38.8837 23.5001C35.5872 30.7838 30.1558 34.4885 23.5 34.4885C16.8442 34.4885 11.4128 30.7838 8.11627 23.5001Z" fill="#090812" stroke="url(#paint1_linear_241_1963)" stroke-width="2.6" stroke-linejoin="round" />
<path d="M23.5 29.7791C26.9678 29.7791 29.7791 26.9679 29.7791 23.5C29.7791 20.0322 26.9678 17.2209 23.5 17.2209C20.0322 17.2209 17.2209 20.0322 17.2209 23.5C17.2209 26.9679 20.0322 29.7791 23.5 29.7791Z" fill="url(#paint2_linear_241_1963)" />
<path d="M23.5 26.3255C25.0605 26.3255 26.3256 25.0604 26.3256 23.4999C26.3256 21.9394 25.0605 20.6743 23.5 20.6743C21.9395 20.6743 20.6744 21.9394 20.6744 23.4999C20.6744 25.0604 21.9395 26.3255 23.5 26.3255Z" fill="#090812" />
<path d="M28.8372 15.0232L29.936 17.6918L32.6046 18.7906L29.936 19.8895L28.8372 22.5581L27.7384 19.8895L25.0698 18.7906L27.7384 17.6918L28.8372 15.0232Z" fill="white" />
<path d="M14.7093 27.2673H13.7674C13.4206 27.2673 13.1395 27.5485 13.1395 27.8952V28.8371C13.1395 29.1839 13.4206 29.465 13.7674 29.465H14.7093C15.0561 29.465 15.3372 29.1839 15.3372 28.8371V27.8952C15.3372 27.5485 15.0561 27.2673 14.7093 27.2673Z" fill="#6AA7FF" />
<path d="M18.9477 29.1511H17.6919C17.2584 29.1511 16.907 29.5025 16.907 29.936V31.1918C16.907 31.6253 17.2584 31.9767 17.6919 31.9767H18.9477C19.3812 31.9767 19.7326 31.6253 19.7326 31.1918V29.936C19.7326 29.5025 19.3812 29.1511 18.9477 29.1511Z" fill="#7B5CFF" />
<path d="M23.814 30.407H21.9302C21.4101 30.407 20.9884 30.8287 20.9884 31.3488V33.2326C20.9884 33.7527 21.4101 34.1744 21.9302 34.1744H23.814C24.3341 34.1744 24.7558 33.7527 24.7558 33.2326V31.3488C24.7558 30.8287 24.3341 30.407 23.814 30.407Z" fill="#D21BCE" />
<path d="M31.3488 29.7791L36.0581 34.4884" stroke="url(#paint3_linear_241_1963)" stroke-width="2.6" stroke-linecap="round" />
<path d="M48.3163 34V33.604L56.8363 19.432H48.9163V16.72H61.8403V17.128L53.3683 31.276H61.6363V34H48.3163ZM70.4343 34.36C69.1383 34.36 68.0063 34.068 67.0383 33.484C66.0703 32.9 65.3183 32.096 64.7823 31.072C64.2543 30.04 63.9903 28.856 63.9903 27.52C63.9903 26.16 64.2623 24.968 64.8063 23.944C65.3503 22.92 66.1063 22.12 67.0743 21.544C68.0423 20.968 69.1623 20.68 70.4343 20.68C71.7383 20.68 72.8743 20.972 73.8423 21.556C74.8103 22.14 75.5623 22.948 76.0983 23.98C76.6343 25.004 76.9023 26.184 76.9023 27.52C76.9023 28.864 76.6303 30.052 76.0863 31.084C75.5503 32.108 74.7983 32.912 73.8303 33.496C72.8623 34.072 71.7303 34.36 70.4343 34.36ZM70.4343 31.648C71.5863 31.648 72.4423 31.264 73.0023 30.496C73.5623 29.728 73.8423 28.736 73.8423 27.52C73.8423 26.264 73.5583 25.264 72.9903 24.52C72.4223 23.768 71.5703 23.392 70.4343 23.392C69.6583 23.392 69.0183 23.568 68.5143 23.92C68.0183 24.264 67.6503 24.748 67.4103 25.372C67.1703 25.988 67.0503 26.704 67.0503 27.52C67.0503 28.776 67.3343 29.78 67.9023 30.532C68.4783 31.276 69.3223 31.648 70.4343 31.648ZM85.2703 34.36C83.9743 34.36 82.8423 34.068 81.8743 33.484C80.9063 32.9 80.1543 32.096 79.6183 31.072C79.0903 30.04 78.8263 28.856 78.8263 27.52C78.8263 26.16 79.0983 24.968 79.6423 23.944C80.1863 22.92 80.9423 22.12 81.9103 21.544C82.8783 20.968 83.9983 20.68 85.2703 20.68C86.5743 20.68 87.7103 20.972 88.6783 21.556C89.6463 22.14 90.3983 22.948 90.9343 23.98C91.4703 25.004 91.7383 26.184 91.7383 27.52C91.7383 28.864 91.4663 30.052 90.9223 31.084C90.3863 32.108 89.6343 32.912 88.6663 33.496C87.6983 34.072 86.5663 34.36 85.2703 34.36ZM85.2703 31.648C86.4223 31.648 87.2783 31.264 87.8383 30.496C88.3983 29.728 88.6783 28.736 88.6783 27.52C88.6783 26.264 88.3943 25.264 87.8263 24.52C87.2583 23.768 86.4063 23.392 85.2703 23.392C84.4943 23.392 83.8543 23.568 83.3503 23.92C82.8543 24.264 82.4863 24.748 82.2463 25.372C82.0063 25.988 81.8863 26.704 81.8863 27.52C81.8863 28.776 82.1703 29.78 82.7383 30.532C83.3143 31.276 84.1583 31.648 85.2703 31.648ZM109.946 34V26.128C109.946 25.24 109.726 24.548 109.286 24.052C108.846 23.548 108.25 23.296 107.498 23.296C107.034 23.296 106.618 23.404 106.25 23.62C105.882 23.828 105.59 24.14 105.374 24.556C105.158 24.964 105.05 25.452 105.05 26.02L103.766 25.264C103.758 24.368 103.958 23.58 104.366 22.9C104.782 22.212 105.342 21.676 106.046 21.292C106.75 20.908 107.534 20.716 108.398 20.716C109.83 20.716 110.926 21.148 111.686 22.012C112.454 22.868 112.838 23.996 112.838 25.396V34H109.946ZM94.3582 34V21.04H96.9142V25.06H97.2742V34H94.3582ZM102.17 34V26.164C102.17 25.26 101.95 24.556 101.51 24.052C101.07 23.548 100.47 23.296 99.7102 23.296C98.9742 23.296 98.3822 23.548 97.9342 24.052C97.4942 24.556 97.2742 25.212 97.2742 26.02L95.9782 25.156C95.9782 24.316 96.1862 23.56 96.6022 22.888C97.0182 22.216 97.5782 21.688 98.2822 21.304C98.9942 20.912 99.7902 20.716 100.67 20.716C101.638 20.716 102.446 20.924 103.094 21.34C103.75 21.748 104.238 22.308 104.558 23.02C104.886 23.724 105.05 24.52 105.05 25.408V34H102.17ZM124.7833 21.4703C124.7046 20.7334 124.3741 20.1597 123.7919 19.7491C123.2097 19.3384 122.4546 19.1331 121.5264 19.1331C120.8739 19.1331 120.3142 19.2316 119.8474 19.4284C119.3805 19.6253 119.0233 19.8925 118.7758 20.23C118.5283 20.5675 118.4017 20.9528 118.3961 21.3859C118.3961 21.7459 118.4791 22.0581 118.645 22.3225C118.811 22.5869 119.0374 22.8105 119.3242 22.9933C119.6111 23.1761 119.9289 23.3294 120.2777 23.4531C120.6264 23.5769 120.978 23.6809 121.3324 23.7653L122.9524 24.1703C123.6049 24.3222 124.2335 24.5275 124.8382 24.7863C125.4428 25.045 125.9857 25.3713 126.4666 25.765C126.9475 26.1588 127.3286 26.6341 127.6099 27.1909C127.8911 27.7478 128.0317 28.4003 128.0317 29.1484C128.0317 30.1609 127.773 31.0511 127.2555 31.8189C126.738 32.5867 125.9913 33.1858 125.0153 33.6161C124.0394 34.0464 122.8596 34.2616 121.4758 34.2616C120.1314 34.2616 118.9657 34.0534 117.9785 33.6372C116.9913 33.2209 116.2207 32.6134 115.6666 31.8147C115.1125 31.0159 114.813 30.0428 114.768 28.8953L117.8477 28.8953C117.8927 29.4972 118.0783 29.9978 118.4046 30.3972C118.7308 30.7966 119.1569 31.0947 119.6828 31.2916C120.2088 31.4884 120.798 31.5869 121.4505 31.5869C122.1311 31.5869 122.7288 31.4842 123.2435 31.2789C123.7582 31.0736 124.1618 30.7867 124.4542 30.4183C124.7467 30.0498 124.8958 29.6181 124.9014 29.1231C124.8958 28.6731 124.7636 28.3005 124.5049 28.0052C124.2461 27.7098 123.8847 27.4623 123.4207 27.2627C122.9566 27.063 122.4152 26.8844 121.7964 26.7269L119.8305 26.2206C118.4074 25.855 117.2838 25.2995 116.4597 24.5542C115.6357 23.8089 115.2236 22.8175 115.2236 21.58C115.2236 20.5619 115.5007 19.6703 116.0547 18.9053C116.6088 18.1403 117.3639 17.5455 118.3202 17.1208C119.2764 16.6961 120.3592 16.4838 121.5686 16.4838C122.7949 16.4838 123.8707 16.6961 124.796 17.1208C125.7213 17.5455 126.4483 18.1333 126.9771 18.8842C127.5058 19.6352 127.7786 20.4972 127.7955 21.4703ZM137.1474 21.04L137.1474 23.4025L129.6971 23.4025L129.6971 21.04ZM131.5365 17.935L134Line truncated
<defs>
<filter id="filter0_f_241_1963" x="0" y="0" width="47" height="47" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
<feGaussianBlur stdDeviation="5" result="effect1_foregroundBlur_241_1963" />
</filter>
<linearGradient id="paint0_linear_241_1963" x1="7.80233" y1="9.05814" x2="40.4535" y2="38.5698" gradientUnits="userSpaceOnUse">
<stop stop-color="#6AA7FF" />
<stop offset="0.5" stop-color="#7B5CFF" />
<stop offset="1" stop-color="#D21BCE" />
</linearGradient>
<linearGradient id="paint1_linear_241_1963" x1="7.80232" y1="9.05823" x2="40.4535" y2="38.5699" gradientUnits="userSpaceOnUse">
<stop stop-color="#6AA7FF" />
<stop offset="0.5" stop-color="#7B5CFF" />
<stop offset="1" stop-color="#D21BCE" />
</linearGradient>
<linearGradient id="paint2_linear_241_1963" x1="7.80231" y1="9.05816" x2="40.4535" y2="38.5698" gradientUnits="userSpaceOnUse">
<stop stop-color="#6AA7FF" />
<stop offset="0.5" stop-color="#7B5CFF" />
<stop offset="1" stop-color="#D21BCE" />
</linearGradient>
<linearGradient id="paint3_linear_241_1963" x1="7.8023" y1="9.05812" x2="40.4535" y2="38.5698" gradientUnits="userSpaceOnUse">
<stop stop-color="#6AA7FF" />
<stop offset="0.5" stop-color="#7B5CFF" />
<stop offset="1" stop-color="#D21BCE" />
</linearGradient>
<linearGradient id="paint4_linear_241_1963" x1="47.1163" y1="24.5" x2="180" y2="24.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#F9F9F9" />
<stop offset="1" stop-color="#8EA2D9" />
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 14 KiB

+46
View File
@@ -0,0 +1,46 @@
<svg width="182" height="47" viewBox="0 0 182 47" fill="none" xmlns="http://www.w3.org/2000/svg">
<title>ZoomStage</title>
<g opacity="0.18" filter="url(#filter0_f_241_2041)">
<path d="M23.5 37C30.9558 37 37 30.9558 37 23.5C37 16.0442 30.9558 10 23.5 10C16.0442 10 10 16.0442 10 23.5C10 30.9558 16.0442 37 23.5 37Z" fill="url(#paint0_linear_241_2041)" />
</g>
<path d="M8.11628 23.5001C11.4128 16.2164 16.8442 12.5117 23.5 12.5117C30.1558 12.5117 35.5872 16.2164 38.8837 23.5001C35.5872 30.7838 30.1558 34.4885 23.5 34.4885C16.8442 34.4885 11.4128 30.7838 8.11628 23.5001Z" fill="#090812" stroke="url(#paint1_linear_241_2041)" stroke-width="2.6" stroke-linejoin="round" />
<path d="M23.5 29.7791C26.9678 29.7791 29.7791 26.9679 29.7791 23.5C29.7791 20.0322 26.9678 17.2209 23.5 17.2209C20.0322 17.2209 17.2209 20.0322 17.2209 23.5C17.2209 26.9679 20.0322 29.7791 23.5 29.7791Z" fill="url(#paint2_linear_241_2041)" />
<path d="M23.5 26.3255C25.0605 26.3255 26.3256 25.0604 26.3256 23.4999C26.3256 21.9394 25.0605 20.6743 23.5 20.6743C21.9395 20.6743 20.6744 21.9394 20.6744 23.4999C20.6744 25.0604 21.9395 26.3255 23.5 26.3255Z" fill="#090812" />
<path d="M28.8372 15.0232L29.936 17.6918L32.6047 18.7906L29.936 19.8895L28.8372 22.5581L27.7384 19.8895L25.0698 18.7906L27.7384 17.6918L28.8372 15.0232Z" fill="white" />
<path d="M14.7093 27.2673H13.7674C13.4207 27.2673 13.1395 27.5485 13.1395 27.8952V28.8371C13.1395 29.1839 13.4207 29.465 13.7674 29.465H14.7093C15.0561 29.465 15.3372 29.1839 15.3372 28.8371V27.8952C15.3372 27.5485 15.0561 27.2673 14.7093 27.2673Z" fill="#6AA7FF" />
<path d="M18.9477 29.1511H17.6919C17.2584 29.1511 16.907 29.5025 16.907 29.936V31.1918C16.907 31.6253 17.2584 31.9767 17.6919 31.9767H18.9477C19.3812 31.9767 19.7326 31.6253 19.7326 31.1918V29.936C19.7326 29.5025 19.3812 29.1511 18.9477 29.1511Z" fill="#7B5CFF" />
<path d="M23.814 30.407H21.9302C21.4101 30.407 20.9884 30.8287 20.9884 31.3488V33.2326C20.9884 33.7527 21.4101 34.1744 21.9302 34.1744H23.814C24.3341 34.1744 24.7558 33.7527 24.7558 33.2326V31.3488C24.7558 30.8287 24.3341 30.407 23.814 30.407Z" fill="#D21BCE" />
<path d="M31.3488 29.7791L36.0581 34.4884" stroke="url(#paint3_linear_241_2041)" stroke-width="2.6" stroke-linecap="round" />
<path d="M48.3163 34V33.604L56.8363 19.432H48.9163V16.72H61.8403V17.128L53.3683 31.276H61.6363V34H48.3163ZM70.4343 34.36C69.1383 34.36 68.0063 34.068 67.0383 33.484C66.0703 32.9 65.3183 32.096 64.7823 31.072C64.2543 30.04 63.9903 28.856 63.9903 27.52C63.9903 26.16 64.2623 24.968 64.8063 23.944C65.3503 22.92 66.1063 22.12 67.0743 21.544C68.0423 20.968 69.1623 20.68 70.4343 20.68C71.7383 20.68 72.8743 20.972 73.8423 21.556C74.8103 22.14 75.5623 22.948 76.0983 23.98C76.6343 25.004 76.9023 26.184 76.9023 27.52C76.9023 28.864 76.6303 30.052 76.0863 31.084C75.5503 32.108 74.7983 32.912 73.8303 33.496C72.8623 34.072 71.7303 34.36 70.4343 34.36ZM70.4343 31.648C71.5863 31.648 72.4423 31.264 73.0023 30.496C73.5623 29.728 73.8423 28.736 73.8423 27.52C73.8423 26.264 73.5583 25.264 72.9903 24.52C72.4223 23.768 71.5703 23.392 70.4343 23.392C69.6583 23.392 69.0183 23.568 68.5143 23.92C68.0183 24.264 67.6503 24.748 67.4103 25.372C67.1703 25.988 67.0503 26.704 67.0503 27.52C67.0503 28.776 67.3343 29.78 67.9023 30.532C68.4783 31.276 69.3223 31.648 70.4343 31.648ZM85.2703 34.36C83.9743 34.36 82.8423 34.068 81.8743 33.484C80.9063 32.9 80.1543 32.096 79.6183 31.072C79.0903 30.04 78.8263 28.856 78.8263 27.52C78.8263 26.16 79.0983 24.968 79.6423 23.944C80.1863 22.92 80.9423 22.12 81.9103 21.544C82.8783 20.968 83.9983 20.68 85.2703 20.68C86.5743 20.68 87.7103 20.972 88.6783 21.556C89.6463 22.14 90.3983 22.948 90.9343 23.98C91.4703 25.004 91.7383 26.184 91.7383 27.52C91.7383 28.864 91.4663 30.052 90.9223 31.084C90.3863 32.108 89.6343 32.912 88.6663 33.496C87.6983 34.072 86.5663 34.36 85.2703 34.36ZM85.2703 31.648C86.4223 31.648 87.2783 31.264 87.8383 30.496C88.3983 29.728 88.6783 28.736 88.6783 27.52C88.6783 26.264 88.3943 25.264 87.8263 24.52C87.2583 23.768 86.4063 23.392 85.2703 23.392C84.4943 23.392 83.8543 23.568 83.3503 23.92C82.8543 24.264 82.4863 24.748 82.2463 25.372C82.0063 25.988 81.8863 26.704 81.8863 27.52C81.8863 28.776 82.1703 29.78 82.7383 30.532C83.3143 31.276 84.1583 31.648 85.2703 31.648ZM109.946 34V26.128C109.946 25.24 109.726 24.548 109.286 24.052C108.846 23.548 108.25 23.296 107.498 23.296C107.034 23.296 106.618 23.404 106.25 23.62C105.882 23.828 105.59 24.14 105.374 24.556C105.158 24.964 105.05 25.452 105.05 26.02L103.766 25.264C103.758 24.368 103.958 23.58 104.366 22.9C104.782 22.212 105.342 21.676 106.046 21.292C106.75 20.908 107.534 20.716 108.398 20.716C109.83 20.716 110.926 21.148 111.686 22.012C112.454 22.868 112.838 23.996 112.838 25.396V34H109.946ZM94.3582 34V21.04H96.9142V25.06H97.2742V34H94.3582ZM102.17 34V26.164C102.17 25.26 101.95 24.556 101.51 24.052C101.07 23.548 100.47 23.296 99.7102 23.296C98.9742 23.296 98.3822 23.548 97.9342 24.052C97.4942 24.556 97.2742 25.212 97.2742 26.02L95.9782 25.156C95.9782 24.316 96.1862 23.56 96.6022 22.888C97.0182 22.216 97.5782 21.688 98.2822 21.304C98.9942 20.912 99.7902 20.716 100.67 20.716C101.638 20.716 102.446 20.924 103.094 21.34C103.75 21.748 104.238 22.308 104.558 23.02C104.886 23.724 105.05 24.52 105.05 25.408V34H102.17ZM124.7833 21.4703C124.7046 20.7334 124.3741 20.1597 123.7919 19.7491C123.2097 19.3384 122.4546 19.1331 121.5264 19.1331C120.8739 19.1331 120.3142 19.2316 119.8474 19.4284C119.3805 19.6253 119.0233 19.8925 118.7758 20.23C118.5283 20.5675 118.4017 20.9528 118.3961 21.3859C118.3961 21.7459 118.4791 22.0581 118.645 22.3225C118.811 22.5869 119.0374 22.8105 119.3242 22.9933C119.6111 23.1761 119.9289 23.3294 120.2777 23.4531C120.6264 23.5769 120.978 23.6809 121.3324 23.7653L122.9524 24.1703C123.6049 24.3222 124.2335 24.5275 124.8382 24.7863C125.4428 25.045 125.9857 25.3713 126.4666 25.765C126.9475 26.1588 127.3286 26.6341 127.6099 27.1909C127.8911 27.7478 128.0317 28.4003 128.0317 29.1484C128.0317 30.1609 127.773 31.0511 127.2555 31.8189C126.738 32.5867 125.9913 33.1858 125.0153 33.6161C124.0394 34.0464 122.8596 34.2616 121.4758 34.2616C120.1314 34.2616 118.9657 34.0534 117.9785 33.6372C116.9913 33.2209 116.2207 32.6134 115.6666 31.8147C115.1125 31.0159 114.813 30.0428 114.768 28.8953L117.8477 28.8953C117.8927 29.4972 118.0783 29.9978 118.4046 30.3972C118.7308 30.7966 119.1569 31.0947 119.6828 31.2916C120.2088 31.4884 120.798 31.5869 121.4505 31.5869C122.1311 31.5869 122.7288 31.4842 123.2435 31.2789C123.7582 31.0736 124.1618 30.7867 124.4542 30.4183C124.7467 30.0498 124.8958 29.6181 124.9014 29.1231C124.8958 28.6731 124.7636 28.3005 124.5049 28.0052C124.2461 27.7098 123.8847 27.4623 123.4207 27.2627C122.9566 27.063 122.4152 26.8844 121.7964 26.7269L119.8305 26.2206C118.4074 25.855 117.2838 25.2995 116.4597 24.5542C115.6357 23.8089 115.2236 22.8175 115.2236 21.58C115.2236 20.5619 115.5007 19.6703 116.0547 18.9053C116.6088 18.1403 117.3639 17.5455 118.3202 17.1208C119.2764 16.6961 120.3592 16.4838 121.5686 16.4838C122.7949 16.4838 123.8707 16.6961 124.796 17.1208C125.7213 17.5455 126.4483 18.1333 126.9771 18.8842C127.5058 19.6352 127.7786 20.4972 127.7955 21.4703ZM137.1474 21.04L137.1474 23.4025L129.6971 23.4025L129.6971 21.04ZM131.5365 17.935L134Line truncated
<defs>
<filter id="filter0_f_241_2041" x="0" y="0" width="47" height="47" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
<feGaussianBlur stdDeviation="5" result="effect1_foregroundBlur_241_2041" />
</filter>
<linearGradient id="paint0_linear_241_2041" x1="7.80233" y1="9.05814" x2="40.4535" y2="38.5698" gradientUnits="userSpaceOnUse">
<stop stop-color="#6AA7FF" />
<stop offset="0.5" stop-color="#7B5CFF" />
<stop offset="1" stop-color="#D21BCE" />
</linearGradient>
<linearGradient id="paint1_linear_241_2041" x1="7.80233" y1="9.05823" x2="40.4535" y2="38.5699" gradientUnits="userSpaceOnUse">
<stop stop-color="#6AA7FF" />
<stop offset="0.5" stop-color="#7B5CFF" />
<stop offset="1" stop-color="#D21BCE" />
</linearGradient>
<linearGradient id="paint2_linear_241_2041" x1="7.80233" y1="9.05816" x2="40.4535" y2="38.5698" gradientUnits="userSpaceOnUse">
<stop stop-color="#6AA7FF" />
<stop offset="0.5" stop-color="#7B5CFF" />
<stop offset="1" stop-color="#D21BCE" />
</linearGradient>
<linearGradient id="paint3_linear_241_2041" x1="7.80233" y1="9.05812" x2="40.4535" y2="38.5698" gradientUnits="userSpaceOnUse">
<stop stop-color="#6AA7FF" />
<stop offset="0.5" stop-color="#7B5CFF" />
<stop offset="1" stop-color="#D21BCE" />
</linearGradient>
<linearGradient id="paint4_linear_241_2041" x1="47.1163" y1="24.5" x2="180" y2="24.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#0F0911" />
<stop offset="1" stop-color="#960A97" />
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 14 KiB

+2 -2
View File
@@ -2,8 +2,8 @@
/** Версия логотипа по содержимому исключает старый бренд из браузерного кеша. */
function prelandAssetUrl(string $path): string
{
global $assetsUriPrefix;
$file = dirname(__DIR__) . '/' . $path;
$version = is_file($file) ? substr(hash_file('sha256', $file), 0, 16) : 'missing';
return htmlspecialchars(rtrim($assetsUriPrefix, '/') . '/' . $path . '?v=' . $version, ENT_QUOTES, 'UTF-8');
// Бренд всегда принадлежит текущему преленду, даже если общая статика на CDN/API.
return htmlspecialchars('/' . $path . '?v=' . $version, ENT_QUOTES, 'UTF-8');
}
+11
View File
@@ -0,0 +1,11 @@
<?php
/** Домен преленда не связан с config.host основного сайта/API. */
function prelandSiteDomain(array $server): string
{
foreach ([$server['HTTP_HOST'] ?? '', $server['SERVER_NAME'] ?? ''] as $candidate) {
if (!is_string($candidate) || preg_match('/[\s\/@?#<>]/', $candidate)) continue;
$host = strtolower(rtrim(preg_replace('/:\d+$/', '', $candidate), '.'));
if (strlen($host) <= 253 && preg_match('/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)*[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/D', $host)) return $host;
}
return '';
}
+3 -3
View File
@@ -1,4 +1,5 @@
<svg width="182" height="47" viewBox="0 0 182 47" fill="none" xmlns="http://www.w3.org/2000/svg">
<title>ZoomStage</title>
<g opacity="0.18" filter="url(#filter0_f_241_1963)">
<path d="M23.5 37C30.9558 37 37 30.9558 37 23.5C37 16.0442 30.9558 10 23.5 10C16.0442 10 10 16.0442 10 23.5C10 30.9558 16.0442 37 23.5 37Z" fill="url(#paint0_linear_241_1963)" />
</g>
@@ -10,8 +11,7 @@
<path d="M18.9477 29.1511H17.6919C17.2584 29.1511 16.907 29.5025 16.907 29.936V31.1918C16.907 31.6253 17.2584 31.9767 17.6919 31.9767H18.9477C19.3812 31.9767 19.7326 31.6253 19.7326 31.1918V29.936C19.7326 29.5025 19.3812 29.1511 18.9477 29.1511Z" fill="#7B5CFF" />
<path d="M23.814 30.407H21.9302C21.4101 30.407 20.9884 30.8287 20.9884 31.3488V33.2326C20.9884 33.7527 21.4101 34.1744 21.9302 34.1744H23.814C24.3341 34.1744 24.7558 33.7527 24.7558 33.2326V31.3488C24.7558 30.8287 24.3341 30.407 23.814 30.407Z" fill="#D21BCE" />
<path d="M31.3488 29.7791L36.0581 34.4884" stroke="url(#paint3_linear_241_1963)" stroke-width="2.6" stroke-linecap="round" />
<path d="M48.3163 34V33.604L56.8363 19.432H48.9163V16.72H61.8403V17.128L53.3683 31.276H61.6363V34H48.3163ZM70.4343 34.36C69.1383 34.36 68.0063 34.068 67.0383 33.484C66.0703 32.9 65.3183 32.096 64.7823 31.072C64.2543 30.04 63.9903 28.856 63.9903 27.52C63.9903 26.16 64.2623 24.968 64.8063 23.944C65.3503 22.92 66.1063 22.12 67.0743 21.544C68.0423 20.968 69.1623 20.68 70.4343 20.68C71.7383 20.68 72.8743 20.972 73.8423 21.556C74.8103 22.14 75.5623 22.948 76.0983 23.98C76.6343 25.004 76.9023 26.184 76.9023 27.52C76.9023 28.864 76.6303 30.052 76.0863 31.084C75.5503 32.108 74.7983 32.912 73.8303 33.496C72.8623 34.072 71.7303 34.36 70.4343 34.36ZM70.4343 31.648C71.5863 31.648 72.4423 31.264 73.0023 30.496C73.5623 29.728 73.8423 28.736 73.8423 27.52C73.8423 26.264 73.5583 25.264 72.9903 24.52C72.4223 23.768 71.5703 23.392 70.4343 23.392C69.6583 23.392 69.0183 23.568 68.5143 23.92C68.0183 24.264 67.6503 24.748 67.4103 25.372C67.1703 25.988 67.0503 26.704 67.0503 27.52C67.0503 28.776 67.3343 29.78 67.9023 30.532C68.4783 31.276 69.3223 31.648 70.4343 31.648ZM85.2703 34.36C83.9743 34.36 82.8423 34.068 81.8743 33.484C80.9063 32.9 80.1543 32.096 79.6183 31.072C79.0903 30.04 78.8263 28.856 78.8263 27.52C78.8263 26.16 79.0983 24.968 79.6423 23.944C80.1863 22.92 80.9423 22.12 81.9103 21.544C82.8783 20.968 83.9983 20.68 85.2703 20.68C86.5743 20.68 87.7103 20.972 88.6783 21.556C89.6463 22.14 90.3983 22.948 90.9343 23.98C91.4703 25.004 91.7383 26.184 91.7383 27.52C91.7383 28.864 91.4663 30.052 90.9223 31.084C90.3863 32.108 89.6343 32.912 88.6663 33.496C87.6983 34.072 86.5663 34.36 85.2703 34.36ZM85.2703 31.648C86.4223 31.648 87.2783 31.264 87.8383 30.496C88.3983 29.728 88.6783 28.736 88.6783 27.52C88.6783 26.264 88.3943 25.264 87.8263 24.52C87.2583 23.768 86.4063 23.392 85.2703 23.392C84.4943 23.392 83.8543 23.568 83.3503 23.92C82.8543 24.264 82.4863 24.748 82.2463 25.372C82.0063 25.988 81.8863 26.704 81.8863 27.52C81.8863 28.776 82.1703 29.78 82.7383 30.532C83.3143 31.276 84.1583 31.648 85.2703 31.648ZM109.946 34V26.128C109.946 25.24 109.726 24.548 109.286 24.052C108.846 23.548 108.25 23.296 107.498 23.296C107.034 23.296 106.618 23.404 106.25 23.62C105.882 23.828 105.59 24.14 105.374 24.556C105.158 24.964 105.05 25.452 105.05 26.02L103.766 25.264C103.758 24.368 103.958 23.58 104.366 22.9C104.782 22.212 105.342 21.676 106.046 21.292C106.75 20.908 107.534 20.716 108.398 20.716C109.83 20.716 110.926 21.148 111.686 22.012C112.454 22.868 112.838 23.996 112.838 25.396V34H109.946ZM94.3582 34V21.04H96.9142V25.06H97.2742V34H94.3582ZM102.17 34V26.164C102.17 25.26 101.95 24.556 101.51 24.052C101.07 23.548 100.47 23.296 99.7102 23.296C98.9742 23.296 98.3822 23.548 97.9342 24.052C97.4942 24.556 97.2742 25.212 97.2742 26.02L95.9782 25.156C95.9782 24.316 96.1862 23.56 96.6022 22.888C97.0182 22.216 97.5782 21.688 98.2822 21.304C98.9942 20.912 99.7902 20.716 100.67 20.716C101.638 20.716 102.446 20.924 103.094 21.34C103.75 21.748 104.238 22.308 104.558 23.02C104.886 23.724 105.05 24.52 105.05 25.408V34H102.17ZM114.768 34V33.604L121.632 23.572H115.464V21.04H126.132V21.448L119.292 31.468H125.844V34H114.768ZM129.005 19.072V16.42H131.897V19.072H129.005ZM129.005 34V21.04H131.897V34H129.005ZM135.732 34V16.36H138.624V34H135.732ZM142.458 34V16.36H145.35V34H142.458ZM152.569 34.36C151.633 34.36 150.841 34.184 150.193 33.832C149.545 33.472 149.053 32.996 148.717 32.404C148.389 31.812 148.225 31.16 148.225 30.448C148.225 29.824 148.329 29.264 148.537 28.768C148.745 28.264 149.065 27.832 149.497 27.472C149.929 27.104 150.489 26.804 151.177 26.572C151.697 26.404 152.305 26.252 153.001 26.116C153.705 25.98 154.465 25.856 155.281 25.744C156.105 25.624 156.965 25.496 157.861 25.36L156.829 25.948C156.837 25.052 156.637 24.392 156.229 23.968C155.821 23.544 155.133 23.332 154.165 23.332C153.581 23.332 153.017 23.468 152.473 23.74C151.929 24.012 151.549 24.48 151.333 25.144L148.693 24.316C149.013 23.22 149.621 22.34 150.517 21.676C151.421 21.012 152.637 20.68 154.165 20.68C155.317 20.68 156.329 20.868 157.201 21.244C158.081 21.62 158.733 22.236 159.157 23.092C159.389 23.548 159.529 24.016 159.577 24.496C159.625 24.968 159.649 25.484 159.649 26.044V34H157.117V31.192L157.537 31.648C156.953 32.584 156.269 33.272 155.485 33.712C154.709 34.144 153.737 34.36 152.569 34.36ZM153.145 32.056C153.801 32.056 154.361 31.94 154.825 31.708C155.289 31.476 155.657 31.192 155.929 30.856C156.209 30.52 156.397 30.204 156.493 29.908C156.645 29.54 156.729 29.12 156.745 28.648C156.769 28.168 156.781 27.78 156.781 27.484L157.669 27.748C156.797 27.884 156.049 28.004 155.425 28.108C154.801 28.212 154.265 28.312 153.817 28.408C153.369 28.496 152.973 28.596 152.629 28.708C152.293 28.828 152.009 28.968 151.777 29.128C151.545 29.288 151.365 29.472 151.237 29.68C151.117 29.888 151.057 30.132 151.057 30.412C151.057 30.732 151.137 31.016 151.297 31.264C151.457 31.504 151.689 31.696 151.993 31.84C152.305 31.984 152.689 32.056 153.145 32.056Z" fill="url(#paint4_linear_241_1963)"/>
<path d="M162.466 34.5V32.6475H164.319V34.5H162.466ZM166.722 34.5V26.4H168.319V28.3725L168.124 28.1175C168.224 27.8475 168.357 27.6025 168.522 27.3825C168.692 27.1575 168.894 26.9725 169.129 26.8275C169.329 26.6925 169.549 26.5875 169.789 26.5125C170.034 26.4325 170.284 26.385 170.539 26.37C170.794 26.35 171.042 26.36 171.282 26.4V28.0875C171.042 28.0175 170.764 27.995 170.449 28.02C170.139 28.045 169.859 28.1325 169.609 28.2825C169.359 28.4175 169.154 28.59 168.994 28.8C168.839 29.01 168.724 29.25 168.649 29.52C168.574 29.785 168.537 30.0725 168.537 30.3825V34.5H166.722ZM175.751 34.7325C175.151 34.7325 174.656 34.6325 174.266 34.4325C173.876 34.2325 173.566 33.9775 173.336 33.6675C173.106 33.3575 172.936 33.0275 172.826 32.6775C172.716 32.3275 172.643 31.9975 172.608 31.6875C172.578 31.3725 172.563 31.1175 172.563 30.9225V26.4H174.393V30.3C174.393 30.55 174.411 30.8325 174.446 31.1475C174.481 31.4575 174.561 31.7575 174.686 32.0475C174.816 32.3325 175.006 32.5675 175.256 32.7525C175.511 32.9375 175.853 33.03 176.283 33.03C176.513 33.03 176.741 32.9925 176.966 32.9175C177.191 32.8425 177.393 32.715 177.573 32.535C177.758 32.35 177.906 32.0975 178.016 31.7775C178.126 31.4575 178.181 31.0525 178.181 30.5625L179.253 31.02C179.253 31.71 179.118 32.335 178.848 32.895C178.583 33.455 178.191 33.9025 177.671 34.2375C177.151 34.5675 176.511 34.7325 175.751 34.7325ZM178.398 34.5V31.9875H178.181V26.4H179.996V34.5H178.398Z" fill="#8EA2D9"/>
<path d="M48.3163 34V33.604L56.8363 19.432H48.9163V16.72H61.8403V17.128L53.3683 31.276H61.6363V34H48.3163ZM70.4343 34.36C69.1383 34.36 68.0063 34.068 67.0383 33.484C66.0703 32.9 65.3183 32.096 64.7823 31.072C64.2543 30.04 63.9903 28.856 63.9903 27.52C63.9903 26.16 64.2623 24.968 64.8063 23.944C65.3503 22.92 66.1063 22.12 67.0743 21.544C68.0423 20.968 69.1623 20.68 70.4343 20.68C71.7383 20.68 72.8743 20.972 73.8423 21.556C74.8103 22.14 75.5623 22.948 76.0983 23.98C76.6343 25.004 76.9023 26.184 76.9023 27.52C76.9023 28.864 76.6303 30.052 76.0863 31.084C75.5503 32.108 74.7983 32.912 73.8303 33.496C72.8623 34.072 71.7303 34.36 70.4343 34.36ZM70.4343 31.648C71.5863 31.648 72.4423 31.264 73.0023 30.496C73.5623 29.728 73.8423 28.736 73.8423 27.52C73.8423 26.264 73.5583 25.264 72.9903 24.52C72.4223 23.768 71.5703 23.392 70.4343 23.392C69.6583 23.392 69.0183 23.568 68.5143 23.92C68.0183 24.264 67.6503 24.748 67.4103 25.372C67.1703 25.988 67.0503 26.704 67.0503 27.52C67.0503 28.776 67.3343 29.78 67.9023 30.532C68.4783 31.276 69.3223 31.648 70.4343 31.648ZM85.2703 34.36C83.9743 34.36 82.8423 34.068 81.8743 33.484C80.9063 32.9 80.1543 32.096 79.6183 31.072C79.0903 30.04 78.8263 28.856 78.8263 27.52C78.8263 26.16 79.0983 24.968 79.6423 23.944C80.1863 22.92 80.9423 22.12 81.9103 21.544C82.8783 20.968 83.9983 20.68 85.2703 20.68C86.5743 20.68 87.7103 20.972 88.6783 21.556C89.6463 22.14 90.3983 22.948 90.9343 23.98C91.4703 25.004 91.7383 26.184 91.7383 27.52C91.7383 28.864 91.4663 30.052 90.9223 31.084C90.3863 32.108 89.6343 32.912 88.6663 33.496C87.6983 34.072 86.5663 34.36 85.2703 34.36ZM85.2703 31.648C86.4223 31.648 87.2783 31.264 87.8383 30.496C88.3983 29.728 88.6783 28.736 88.6783 27.52C88.6783 26.264 88.3943 25.264 87.8263 24.52C87.2583 23.768 86.4063 23.392 85.2703 23.392C84.4943 23.392 83.8543 23.568 83.3503 23.92C82.8543 24.264 82.4863 24.748 82.2463 25.372C82.0063 25.988 81.8863 26.704 81.8863 27.52C81.8863 28.776 82.1703 29.78 82.7383 30.532C83.3143 31.276 84.1583 31.648 85.2703 31.648ZM109.946 34V26.128C109.946 25.24 109.726 24.548 109.286 24.052C108.846 23.548 108.25 23.296 107.498 23.296C107.034 23.296 106.618 23.404 106.25 23.62C105.882 23.828 105.59 24.14 105.374 24.556C105.158 24.964 105.05 25.452 105.05 26.02L103.766 25.264C103.758 24.368 103.958 23.58 104.366 22.9C104.782 22.212 105.342 21.676 106.046 21.292C106.75 20.908 107.534 20.716 108.398 20.716C109.83 20.716 110.926 21.148 111.686 22.012C112.454 22.868 112.838 23.996 112.838 25.396V34H109.946ZM94.3582 34V21.04H96.9142V25.06H97.2742V34H94.3582ZM102.17 34V26.164C102.17 25.26 101.95 24.556 101.51 24.052C101.07 23.548 100.47 23.296 99.7102 23.296C98.9742 23.296 98.3822 23.548 97.9342 24.052C97.4942 24.556 97.2742 25.212 97.2742 26.02L95.9782 25.156C95.9782 24.316 96.1862 23.56 96.6022 22.888C97.0182 22.216 97.5782 21.688 98.2822 21.304C98.9942 20.912 99.7902 20.716 100.67 20.716C101.638 20.716 102.446 20.924 103.094 21.34C103.75 21.748 104.238 22.308 104.558 23.02C104.886 23.724 105.05 24.52 105.05 25.408V34H102.17ZM124.7833 21.4703C124.7046 20.7334 124.3741 20.1597 123.7919 19.7491C123.2097 19.3384 122.4546 19.1331 121.5264 19.1331C120.8739 19.1331 120.3142 19.2316 119.8474 19.4284C119.3805 19.6253 119.0233 19.8925 118.7758 20.23C118.5283 20.5675 118.4017 20.9528 118.3961 21.3859C118.3961 21.7459 118.4791 22.0581 118.645 22.3225C118.811 22.5869 119.0374 22.8105 119.3242 22.9933C119.6111 23.1761 119.9289 23.3294 120.2777 23.4531C120.6264 23.5769 120.978 23.6809 121.3324 23.7653L122.9524 24.1703C123.6049 24.3222 124.2335 24.5275 124.8382 24.7863C125.4428 25.045 125.9857 25.3713 126.4666 25.765C126.9475 26.1588 127.3286 26.6341 127.6099 27.1909C127.8911 27.7478 128.0317 28.4003 128.0317 29.1484C128.0317 30.1609 127.773 31.0511 127.2555 31.8189C126.738 32.5867 125.9913 33.1858 125.0153 33.6161C124.0394 34.0464 122.8596 34.2616 121.4758 34.2616C120.1314 34.2616 118.9657 34.0534 117.9785 33.6372C116.9913 33.2209 116.2207 32.6134 115.6666 31.8147C115.1125 31.0159 114.813 30.0428 114.768 28.8953L117.8477 28.8953C117.8927 29.4972 118.0783 29.9978 118.4046 30.3972C118.7308 30.7966 119.1569 31.0947 119.6828 31.2916C120.2088 31.4884 120.798 31.5869 121.4505 31.5869C122.1311 31.5869 122.7288 31.4842 123.2435 31.2789C123.7582 31.0736 124.1618 30.7867 124.4542 30.4183C124.7467 30.0498 124.8958 29.6181 124.9014 29.1231C124.8958 28.6731 124.7636 28.3005 124.5049 28.0052C124.2461 27.7098 123.8847 27.4623 123.4207 27.2627C122.9566 27.063 122.4152 26.8844 121.7964 26.7269L119.8305 26.2206C118.4074 25.855 117.2838 25.2995 116.4597 24.5542C115.6357 23.8089 115.2236 22.8175 115.2236 21.58C115.2236 20.5619 115.5007 19.6703 116.0547 18.9053C116.6088 18.1403 117.3639 17.5455 118.3202 17.1208C119.2764 16.6961 120.3592 16.4838 121.5686 16.4838C122.7949 16.4838 123.8707 16.6961 124.796 17.1208C125.7213 17.5455 126.4483 18.1333 126.9771 18.8842C127.5058 19.6352 127.7786 20.4972 127.7955 21.4703ZM137.1474 21.04L137.1474 23.4025L129.6971 23.4025L129.6971 21.04ZM131.5365 17.935L134Line truncated
<defs>
<filter id="filter0_f_241_1963" x="0" y="0" width="47" height="47" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix" />
@@ -38,7 +38,7 @@
<stop offset="0.5" stop-color="#7B5CFF" />
<stop offset="1" stop-color="#D21BCE" />
</linearGradient>
<linearGradient id="paint4_linear_241_1963" x1="47.1163" y1="24.5" x2="161.116" y2="24.5" gradientUnits="userSpaceOnUse">
<linearGradient id="paint4_linear_241_1963" x1="47.1163" y1="24.5" x2="180" y2="24.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#F9F9F9" />
<stop offset="1" stop-color="#8EA2D9" />
</linearGradient>

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 14 KiB

+3 -3
View File
@@ -1,4 +1,5 @@
<svg width="182" height="47" viewBox="0 0 182 47" fill="none" xmlns="http://www.w3.org/2000/svg">
<title>ZoomStage</title>
<g opacity="0.18" filter="url(#filter0_f_241_2041)">
<path d="M23.5 37C30.9558 37 37 30.9558 37 23.5C37 16.0442 30.9558 10 23.5 10C16.0442 10 10 16.0442 10 23.5C10 30.9558 16.0442 37 23.5 37Z" fill="url(#paint0_linear_241_2041)" />
</g>
@@ -10,8 +11,7 @@
<path d="M18.9477 29.1511H17.6919C17.2584 29.1511 16.907 29.5025 16.907 29.936V31.1918C16.907 31.6253 17.2584 31.9767 17.6919 31.9767H18.9477C19.3812 31.9767 19.7326 31.6253 19.7326 31.1918V29.936C19.7326 29.5025 19.3812 29.1511 18.9477 29.1511Z" fill="#7B5CFF" />
<path d="M23.814 30.407H21.9302C21.4101 30.407 20.9884 30.8287 20.9884 31.3488V33.2326C20.9884 33.7527 21.4101 34.1744 21.9302 34.1744H23.814C24.3341 34.1744 24.7558 33.7527 24.7558 33.2326V31.3488C24.7558 30.8287 24.3341 30.407 23.814 30.407Z" fill="#D21BCE" />
<path d="M31.3488 29.7791L36.0581 34.4884" stroke="url(#paint3_linear_241_2041)" stroke-width="2.6" stroke-linecap="round" />
<path d="M48.3163 34V33.604L56.8363 19.432H48.9163V16.72H61.8403V17.128L53.3683 31.276H61.6363V34H48.3163ZM70.4343 34.36C69.1383 34.36 68.0063 34.068 67.0383 33.484C66.0703 32.9 65.3183 32.096 64.7823 31.072C64.2543 30.04 63.9903 28.856 63.9903 27.52C63.9903 26.16 64.2623 24.968 64.8063 23.944C65.3503 22.92 66.1063 22.12 67.0743 21.544C68.0423 20.968 69.1623 20.68 70.4343 20.68C71.7383 20.68 72.8743 20.972 73.8423 21.556C74.8103 22.14 75.5623 22.948 76.0983 23.98C76.6343 25.004 76.9023 26.184 76.9023 27.52C76.9023 28.864 76.6303 30.052 76.0863 31.084C75.5503 32.108 74.7983 32.912 73.8303 33.496C72.8623 34.072 71.7303 34.36 70.4343 34.36ZM70.4343 31.648C71.5863 31.648 72.4423 31.264 73.0023 30.496C73.5623 29.728 73.8423 28.736 73.8423 27.52C73.8423 26.264 73.5583 25.264 72.9903 24.52C72.4223 23.768 71.5703 23.392 70.4343 23.392C69.6583 23.392 69.0183 23.568 68.5143 23.92C68.0183 24.264 67.6503 24.748 67.4103 25.372C67.1703 25.988 67.0503 26.704 67.0503 27.52C67.0503 28.776 67.3343 29.78 67.9023 30.532C68.4783 31.276 69.3223 31.648 70.4343 31.648ZM85.2703 34.36C83.9743 34.36 82.8423 34.068 81.8743 33.484C80.9063 32.9 80.1543 32.096 79.6183 31.072C79.0903 30.04 78.8263 28.856 78.8263 27.52C78.8263 26.16 79.0983 24.968 79.6423 23.944C80.1863 22.92 80.9423 22.12 81.9103 21.544C82.8783 20.968 83.9983 20.68 85.2703 20.68C86.5743 20.68 87.7103 20.972 88.6783 21.556C89.6463 22.14 90.3983 22.948 90.9343 23.98C91.4703 25.004 91.7383 26.184 91.7383 27.52C91.7383 28.864 91.4663 30.052 90.9223 31.084C90.3863 32.108 89.6343 32.912 88.6663 33.496C87.6983 34.072 86.5663 34.36 85.2703 34.36ZM85.2703 31.648C86.4223 31.648 87.2783 31.264 87.8383 30.496C88.3983 29.728 88.6783 28.736 88.6783 27.52C88.6783 26.264 88.3943 25.264 87.8263 24.52C87.2583 23.768 86.4063 23.392 85.2703 23.392C84.4943 23.392 83.8543 23.568 83.3503 23.92C82.8543 24.264 82.4863 24.748 82.2463 25.372C82.0063 25.988 81.8863 26.704 81.8863 27.52C81.8863 28.776 82.1703 29.78 82.7383 30.532C83.3143 31.276 84.1583 31.648 85.2703 31.648ZM109.946 34V26.128C109.946 25.24 109.726 24.548 109.286 24.052C108.846 23.548 108.25 23.296 107.498 23.296C107.034 23.296 106.618 23.404 106.25 23.62C105.882 23.828 105.59 24.14 105.374 24.556C105.158 24.964 105.05 25.452 105.05 26.02L103.766 25.264C103.758 24.368 103.958 23.58 104.366 22.9C104.782 22.212 105.342 21.676 106.046 21.292C106.75 20.908 107.534 20.716 108.398 20.716C109.83 20.716 110.926 21.148 111.686 22.012C112.454 22.868 112.838 23.996 112.838 25.396V34H109.946ZM94.3582 34V21.04H96.9142V25.06H97.2742V34H94.3582ZM102.17 34V26.164C102.17 25.26 101.95 24.556 101.51 24.052C101.07 23.548 100.47 23.296 99.7102 23.296C98.9742 23.296 98.3822 23.548 97.9342 24.052C97.4942 24.556 97.2742 25.212 97.2742 26.02L95.9782 25.156C95.9782 24.316 96.1862 23.56 96.6022 22.888C97.0182 22.216 97.5782 21.688 98.2822 21.304C98.9942 20.912 99.7902 20.716 100.67 20.716C101.638 20.716 102.446 20.924 103.094 21.34C103.75 21.748 104.238 22.308 104.558 23.02C104.886 23.724 105.05 24.52 105.05 25.408V34H102.17ZM114.768 34V33.604L121.632 23.572H115.464V21.04H126.132V21.448L119.292 31.468H125.844V34H114.768ZM129.005 19.072V16.42H131.897V19.072H129.005ZM129.005 34V21.04H131.897V34H129.005ZM135.732 34V16.36H138.624V34H135.732ZM142.458 34V16.36H145.35V34H142.458ZM152.569 34.36C151.633 34.36 150.841 34.184 150.193 33.832C149.545 33.472 149.053 32.996 148.717 32.404C148.389 31.812 148.225 31.16 148.225 30.448C148.225 29.824 148.329 29.264 148.537 28.768C148.745 28.264 149.065 27.832 149.497 27.472C149.929 27.104 150.489 26.804 151.177 26.572C151.697 26.404 152.305 26.252 153.001 26.116C153.705 25.98 154.465 25.856 155.281 25.744C156.105 25.624 156.965 25.496 157.861 25.36L156.829 25.948C156.837 25.052 156.637 24.392 156.229 23.968C155.821 23.544 155.133 23.332 154.165 23.332C153.581 23.332 153.017 23.468 152.473 23.74C151.929 24.012 151.549 24.48 151.333 25.144L148.693 24.316C149.013 23.22 149.621 22.34 150.517 21.676C151.421 21.012 152.637 20.68 154.165 20.68C155.317 20.68 156.329 20.868 157.201 21.244C158.081 21.62 158.733 22.236 159.157 23.092C159.389 23.548 159.529 24.016 159.577 24.496C159.625 24.968 159.649 25.484 159.649 26.044V34H157.117V31.192L157.537 31.648C156.953 32.584 156.269 33.272 155.485 33.712C154.709 34.144 153.737 34.36 152.569 34.36ZM153.145 32.056C153.801 32.056 154.361 31.94 154.825 31.708C155.289 31.476 155.657 31.192 155.929 30.856C156.209 30.52 156.397 30.204 156.493 29.908C156.645 29.54 156.729 29.12 156.745 28.648C156.769 28.168 156.781 27.78 156.781 27.484L157.669 27.748C156.797 27.884 156.049 28.004 155.425 28.108C154.801 28.212 154.265 28.312 153.817 28.408C153.369 28.496 152.973 28.596 152.629 28.708C152.293 28.828 152.009 28.968 151.777 29.128C151.545 29.288 151.365 29.472 151.237 29.68C151.117 29.888 151.057 30.132 151.057 30.412C151.057 30.732 151.137 31.016 151.297 31.264C151.457 31.504 151.689 31.696 151.993 31.84C152.305 31.984 152.689 32.056 153.145 32.056Z" fill="url(#paint4_linear_241_2041)"/>
<path d="M162.466 34.5V32.6475H164.319V34.5H162.466ZM166.722 34.5V26.4H168.319V28.3725L168.124 28.1175C168.224 27.8475 168.357 27.6025 168.522 27.3825C168.692 27.1575 168.894 26.9725 169.129 26.8275C169.329 26.6925 169.549 26.5875 169.789 26.5125C170.034 26.4325 170.284 26.385 170.539 26.37C170.794 26.35 171.042 26.36 171.282 26.4V28.0875C171.042 28.0175 170.764 27.995 170.449 28.02C170.139 28.045 169.859 28.1325 169.609 28.2825C169.359 28.4175 169.154 28.59 168.994 28.8C168.839 29.01 168.724 29.25 168.649 29.52C168.574 29.785 168.537 30.0725 168.537 30.3825V34.5H166.722ZM175.751 34.7325C175.151 34.7325 174.656 34.6325 174.266 34.4325C173.876 34.2325 173.566 33.9775 173.336 33.6675C173.106 33.3575 172.936 33.0275 172.826 32.6775C172.716 32.3275 172.643 31.9975 172.608 31.6875C172.578 31.3725 172.563 31.1175 172.563 30.9225V26.4H174.393V30.3C174.393 30.55 174.411 30.8325 174.446 31.1475C174.481 31.4575 174.561 31.7575 174.686 32.0475C174.816 32.3325 175.006 32.5675 175.256 32.7525C175.511 32.9375 175.853 33.03 176.283 33.03C176.513 33.03 176.741 32.9925 176.966 32.9175C177.191 32.8425 177.393 32.715 177.573 32.535C177.758 32.35 177.906 32.0975 178.016 31.7775C178.126 31.4575 178.181 31.0525 178.181 30.5625L179.253 31.02C179.253 31.71 179.118 32.335 178.848 32.895C178.583 33.455 178.191 33.9025 177.671 34.2375C177.151 34.5675 176.511 34.7325 175.751 34.7325ZM178.398 34.5V31.9875H178.181V26.4H179.996V34.5H178.398Z" fill="#8F139C"/>
<path d="M48.3163 34V33.604L56.8363 19.432H48.9163V16.72H61.8403V17.128L53.3683 31.276H61.6363V34H48.3163ZM70.4343 34.36C69.1383 34.36 68.0063 34.068 67.0383 33.484C66.0703 32.9 65.3183 32.096 64.7823 31.072C64.2543 30.04 63.9903 28.856 63.9903 27.52C63.9903 26.16 64.2623 24.968 64.8063 23.944C65.3503 22.92 66.1063 22.12 67.0743 21.544C68.0423 20.968 69.1623 20.68 70.4343 20.68C71.7383 20.68 72.8743 20.972 73.8423 21.556C74.8103 22.14 75.5623 22.948 76.0983 23.98C76.6343 25.004 76.9023 26.184 76.9023 27.52C76.9023 28.864 76.6303 30.052 76.0863 31.084C75.5503 32.108 74.7983 32.912 73.8303 33.496C72.8623 34.072 71.7303 34.36 70.4343 34.36ZM70.4343 31.648C71.5863 31.648 72.4423 31.264 73.0023 30.496C73.5623 29.728 73.8423 28.736 73.8423 27.52C73.8423 26.264 73.5583 25.264 72.9903 24.52C72.4223 23.768 71.5703 23.392 70.4343 23.392C69.6583 23.392 69.0183 23.568 68.5143 23.92C68.0183 24.264 67.6503 24.748 67.4103 25.372C67.1703 25.988 67.0503 26.704 67.0503 27.52C67.0503 28.776 67.3343 29.78 67.9023 30.532C68.4783 31.276 69.3223 31.648 70.4343 31.648ZM85.2703 34.36C83.9743 34.36 82.8423 34.068 81.8743 33.484C80.9063 32.9 80.1543 32.096 79.6183 31.072C79.0903 30.04 78.8263 28.856 78.8263 27.52C78.8263 26.16 79.0983 24.968 79.6423 23.944C80.1863 22.92 80.9423 22.12 81.9103 21.544C82.8783 20.968 83.9983 20.68 85.2703 20.68C86.5743 20.68 87.7103 20.972 88.6783 21.556C89.6463 22.14 90.3983 22.948 90.9343 23.98C91.4703 25.004 91.7383 26.184 91.7383 27.52C91.7383 28.864 91.4663 30.052 90.9223 31.084C90.3863 32.108 89.6343 32.912 88.6663 33.496C87.6983 34.072 86.5663 34.36 85.2703 34.36ZM85.2703 31.648C86.4223 31.648 87.2783 31.264 87.8383 30.496C88.3983 29.728 88.6783 28.736 88.6783 27.52C88.6783 26.264 88.3943 25.264 87.8263 24.52C87.2583 23.768 86.4063 23.392 85.2703 23.392C84.4943 23.392 83.8543 23.568 83.3503 23.92C82.8543 24.264 82.4863 24.748 82.2463 25.372C82.0063 25.988 81.8863 26.704 81.8863 27.52C81.8863 28.776 82.1703 29.78 82.7383 30.532C83.3143 31.276 84.1583 31.648 85.2703 31.648ZM109.946 34V26.128C109.946 25.24 109.726 24.548 109.286 24.052C108.846 23.548 108.25 23.296 107.498 23.296C107.034 23.296 106.618 23.404 106.25 23.62C105.882 23.828 105.59 24.14 105.374 24.556C105.158 24.964 105.05 25.452 105.05 26.02L103.766 25.264C103.758 24.368 103.958 23.58 104.366 22.9C104.782 22.212 105.342 21.676 106.046 21.292C106.75 20.908 107.534 20.716 108.398 20.716C109.83 20.716 110.926 21.148 111.686 22.012C112.454 22.868 112.838 23.996 112.838 25.396V34H109.946ZM94.3582 34V21.04H96.9142V25.06H97.2742V34H94.3582ZM102.17 34V26.164C102.17 25.26 101.95 24.556 101.51 24.052C101.07 23.548 100.47 23.296 99.7102 23.296C98.9742 23.296 98.3822 23.548 97.9342 24.052C97.4942 24.556 97.2742 25.212 97.2742 26.02L95.9782 25.156C95.9782 24.316 96.1862 23.56 96.6022 22.888C97.0182 22.216 97.5782 21.688 98.2822 21.304C98.9942 20.912 99.7902 20.716 100.67 20.716C101.638 20.716 102.446 20.924 103.094 21.34C103.75 21.748 104.238 22.308 104.558 23.02C104.886 23.724 105.05 24.52 105.05 25.408V34H102.17ZM124.7833 21.4703C124.7046 20.7334 124.3741 20.1597 123.7919 19.7491C123.2097 19.3384 122.4546 19.1331 121.5264 19.1331C120.8739 19.1331 120.3142 19.2316 119.8474 19.4284C119.3805 19.6253 119.0233 19.8925 118.7758 20.23C118.5283 20.5675 118.4017 20.9528 118.3961 21.3859C118.3961 21.7459 118.4791 22.0581 118.645 22.3225C118.811 22.5869 119.0374 22.8105 119.3242 22.9933C119.6111 23.1761 119.9289 23.3294 120.2777 23.4531C120.6264 23.5769 120.978 23.6809 121.3324 23.7653L122.9524 24.1703C123.6049 24.3222 124.2335 24.5275 124.8382 24.7863C125.4428 25.045 125.9857 25.3713 126.4666 25.765C126.9475 26.1588 127.3286 26.6341 127.6099 27.1909C127.8911 27.7478 128.0317 28.4003 128.0317 29.1484C128.0317 30.1609 127.773 31.0511 127.2555 31.8189C126.738 32.5867 125.9913 33.1858 125.0153 33.6161C124.0394 34.0464 122.8596 34.2616 121.4758 34.2616C120.1314 34.2616 118.9657 34.0534 117.9785 33.6372C116.9913 33.2209 116.2207 32.6134 115.6666 31.8147C115.1125 31.0159 114.813 30.0428 114.768 28.8953L117.8477 28.8953C117.8927 29.4972 118.0783 29.9978 118.4046 30.3972C118.7308 30.7966 119.1569 31.0947 119.6828 31.2916C120.2088 31.4884 120.798 31.5869 121.4505 31.5869C122.1311 31.5869 122.7288 31.4842 123.2435 31.2789C123.7582 31.0736 124.1618 30.7867 124.4542 30.4183C124.7467 30.0498 124.8958 29.6181 124.9014 29.1231C124.8958 28.6731 124.7636 28.3005 124.5049 28.0052C124.2461 27.7098 123.8847 27.4623 123.4207 27.2627C122.9566 27.063 122.4152 26.8844 121.7964 26.7269L119.8305 26.2206C118.4074 25.855 117.2838 25.2995 116.4597 24.5542C115.6357 23.8089 115.2236 22.8175 115.2236 21.58C115.2236 20.5619 115.5007 19.6703 116.0547 18.9053C116.6088 18.1403 117.3639 17.5455 118.3202 17.1208C119.2764 16.6961 120.3592 16.4838 121.5686 16.4838C122.7949 16.4838 123.8707 16.6961 124.796 17.1208C125.7213 17.5455 126.4483 18.1333 126.9771 18.8842C127.5058 19.6352 127.7786 20.4972 127.7955 21.4703ZM137.1474 21.04L137.1474 23.4025L129.6971 23.4025L129.6971 21.04ZM131.5365 17.935L134Line truncated
<defs>
<filter id="filter0_f_241_2041" x="0" y="0" width="47" height="47" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix" />
@@ -38,7 +38,7 @@
<stop offset="0.5" stop-color="#7B5CFF" />
<stop offset="1" stop-color="#D21BCE" />
</linearGradient>
<linearGradient id="paint4_linear_241_2041" x1="47.1163" y1="24.5" x2="168.241" y2="24.5" gradientUnits="userSpaceOnUse">
<linearGradient id="paint4_linear_241_2041" x1="47.1163" y1="24.5" x2="180" y2="24.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#0F0911" />
<stop offset="1" stop-color="#960A97" />
</linearGradient>

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 14 KiB

+1
View File
@@ -2,6 +2,7 @@
require_once __DIR__ . '/i18n.php';
require_once __DIR__ . '/components/asset-url.php';
require_once __DIR__ . '/components/site-domain.php';
$configFile = __DIR__ . '/config.json';
$config = file_exists($configFile) ? json_decode(file_get_contents($configFile), true) : [];
+5 -9
View File
@@ -1,5 +1,5 @@
{
"issue": "anton/preland#11",
"issue": "anton/preland#12",
"captured": "2026-10-21",
"hashing": "SHA-256; SVG/CSS/HTML/webmanifest CRLF normalized to LF",
"files": {
@@ -612,12 +612,12 @@
"source": "https://zoomstage.online/bootstrap.min.css"
},
"docs/logo-alt.svg": {
"sha256": "919b0a436e6ffea1ec833a28e5b8c6f4d26029944a7d555ca4d61da63ea1f86f",
"source": "https://zoomzilla.ru/assets/6fd2ff6b/docs/logo-alt.svg"
"sha256": "bf31f25bd0cb636b0a4625747be4a0e4a7cd8f9d5c4e1fc43580556e039d32e8",
"source": "brands/zoomstage.online/dark.svg"
},
"docs/logo.svg": {
"sha256": "1be54a2f9aa40b6d8740fd3367f045c5edf1cdea87c26d67b60cf663d4a2436f",
"source": "https://zoomzilla.ru/assets/6fd2ff6b/docs/logo-light.svg"
"sha256": "cce6e077430eab850b7f4409d1c42f95347459efe753d0d65415d65b6f3a5b01",
"source": "brands/zoomstage.online/light.svg"
},
"docs/privacy_policy.pdf": {
"sha256": "61b483911be875810a7920efa5ddb9c9a132633cfe1d5d9efeb8f9d487cacf83",
@@ -723,10 +723,6 @@
"sha256": "36c7e1c142c883f746eb5851278a34249897ec16aadfbbb9d9bbf5b11336459b",
"source": "https://zoomstage.online/images/sprite.svg"
},
"requisites.html": {
"sha256": "5d7d42da0029f2a90bebb2fc10bb507be3725a4be3fb8237f3afe21cfb485c88",
"source": "https://zoomzilla.ru/"
},
"style.css": {
"sha256": "102aee00546d897dd94887d69b35fec0b3430448ef6a21e072f5b7d76964ce06",
"source": "https://zoomstage.online/style.css"
+20
View File
@@ -0,0 +1,20 @@
{
"zoomstage.online": {
"label": "ZoomStage",
"issue": 12,
"logos": {
"docs/logo.svg": {
"file": "brands/zoomstage.online/light.svg",
"sha256": "cce6e077430eab850b7f4409d1c42f95347459efe753d0d65415d65b6f3a5b01"
},
"docs/logo-alt.svg": {
"file": "brands/zoomstage.online/dark.svg",
"sha256": "bf31f25bd0cb636b0a4625747be4a0e4a7cd8f9d5c4e1fc43580556e039d32e8"
}
},
"replace_from": {
"docs/logo.svg": "1be54a2f9aa40b6d8740fd3367f045c5edf1cdea87c26d67b60cf663d4a2436f",
"docs/logo-alt.svg": "919b0a436e6ffea1ec833a28e5b8c6f4d26029944a7d555ca4d61da63ea1f86f"
}
}
}
-7
View File
@@ -1,7 +0,0 @@
[
"ИП Кардаполова Яна Виталийсовна",
"346886, Ростовская обл., г. Батайск,",
"ДНТ «Труд», ул. 11-я линия, д. 1195",
"ИНН: 616202304132,",
"ОГРНИП: 326619600205915"
]
-5
View File
@@ -1,5 +0,0 @@
<p class="mb-0">ИП Кардаполова Яна Виталийсовна</p>
<p class="mb-0">346886, Ростовская обл., г. Батайск,</p>
<p class="mb-0">ДНТ «Труд», ул. 11-я линия, д. 1195</p>
<p class="mb-0">ИНН: 616202304132,</p>
<p class="mb-0">ОГРНИП: 326619600205915</p>
+5 -32
View File
@@ -57,8 +57,8 @@
<nav class="navbar navbar-dark py-1 py-md-3 px-0">
<div class="container">
<span class="navbar-brand" href="<?= $apiHost ?: '/' ?>" >
<img src="<?= prelandAssetUrl('docs/logo.svg') ?>" width="160" height="40" alt="Zoomzilla">
<img src="<?= prelandAssetUrl('docs/logo-alt.svg') ?>" width="160" height="40" alt="Zoomzilla">
<img src="<?= prelandAssetUrl('docs/logo.svg') ?>" width="182" height="47" alt="Логотип <?= htmlspecialchars(prelandSiteDomain($_SERVER), ENT_QUOTES, 'UTF-8') ?>">
<img src="<?= prelandAssetUrl('docs/logo-alt.svg') ?>" width="182" height="47" alt="Логотип <?= htmlspecialchars(prelandSiteDomain($_SERVER), ENT_QUOTES, 'UTF-8') ?>">
</span>
<div class="d-flex align-items-center">
</div>
@@ -99,41 +99,14 @@
<div class="row py-5 footer-main">
<div class="col-md-4 mb-4 mb-md-0">
<div class="footer-logo">
<img src="<?= prelandAssetUrl('docs/logo.svg') ?>" width="240" height="60" alt="Zoomzilla">
<img src="<?= prelandAssetUrl('docs/logo-alt.svg') ?>" width="240" height="60" alt="Zoomzilla">
<img src="<?= prelandAssetUrl('docs/logo.svg') ?>" width="182" height="47" alt="Логотип <?= htmlspecialchars(prelandSiteDomain($_SERVER), ENT_QUOTES, 'UTF-8') ?>">
<img src="<?= prelandAssetUrl('docs/logo-alt.svg') ?>" width="182" height="47" alt="Логотип <?= htmlspecialchars(prelandSiteDomain($_SERVER), ENT_QUOTES, 'UTF-8') ?>">
</div>
</div>
<div class="col-md-4 mb-4 mb-md-0">
</div>
<div class="col-md-4">
<div class="h5 mb-3"><?= Yii::t('app', 'Наши реквизиты') ?></div>
<?php
// реквизиты: config.json (requisites — строки) → requisites.html → образец
$requisites = array_filter((array) ($config['requisites'] ?? []), fn ($line) => is_scalar($line) && trim((string) $line) !== '');
$requisitesFile = __DIR__ . '/requisites.html';
if ($requisites) {
foreach ($requisites as $line) {
?><p class="mb-0"><?= htmlspecialchars((string) $line, ENT_QUOTES, 'UTF-8') ?></p>
<?php }
} elseif (file_exists($requisitesFile) && filesize($requisitesFile) > 0) {
echo file_get_contents($requisitesFile);
} else {
?>
<p class="mb-0">ИП Иванов Иван Иванович</p>
<p class="mb-0">123123, г. Москва, Пресненская наб., 12</p>
<p class="mb-0">ИНН: 123404385406</p>
<p class="mb-0">ОГРНИП: 123420000019175</p>
<?php
}
?>
<?php if (Yii::t('app', 'system.hide.footer') == 'false') { ?>
<img src="<?= $assetsUriPrefix; ?>/images/payment.svg" width="272" height="40" alt="" class="mt-4">
<?php } ?>
</div>
</div>
<div class="row footer-bottom py-3">
<div class="col-6">
<p class="m-0"><?= date('Y') ?>© <?= parse_url($apiHost, PHP_URL_HOST) ?: Yii::$app->request->hostName ?></p>
<p class="m-0"><?= date('Y') ?>© <?= htmlspecialchars(prelandSiteDomain($_SERVER), ENT_QUOTES, 'UTF-8') ?></p>
</div>
<?php if (Yii::t('app', 'system.hide.footer') == 'false') { ?>
<div class="col-6">
+20
View File
@@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
$root = dirname(__DIR__);
foreach (['light', 'dark'] as $theme) foreach ([
'zoomstage.online' => 'zoomstage.online',
'New-Preland.example:8080' => 'new-preland.example',
'www.example.test.' => 'www.example.test',
'<script>alert(1)</script>' => 'fixture.local',
] as $host => $expected) {
$html = shell_exec(PHP_BINARY . ' ' . escapeshellarg(__DIR__ . '/render-preland.php') . ' ' . escapeshellarg($host) . ' ' . escapeshellarg($theme));
if (!preg_match('~<footer\b.*?</footer>~s', $html, $match)) throw new RuntimeException('Подвал не найден');
$footer = $match[0];
foreach (['Наши реквизиты', 'payment.svg', 'ИНН:', 'ОГРНИП:', 'ИП Иванов', 'ИП Кардаполова'] as $forbidden) {
if (str_contains($footer, $forbidden)) throw new RuntimeException('В подвале остался ' . $forbidden);
}
if (!str_contains($footer, date('Y') . '© ' . $expected)) throw new RuntimeException('Неправильный домен копирайта: ' . $host);
if (substr_count($footer, '<img ') !== 2) throw new RuntimeException('Нужны только два тематических SVG логотипа');
if (str_contains($footer, '<script>')) throw new RuntimeException('Host попал в HTML без проверки');
}
echo "OK: минимальный подвал, две темы, перенос домена/порт/trailing-dot и invalid-host\n";
+16 -2
View File
@@ -2,6 +2,9 @@
/** preland#11: старый бренд запрещён независимо от обновления manifest. */
declare(strict_types=1);
$root = dirname(__DIR__);
require_once $root . '/components/asset-url.php';
$assetsUriPrefix = 'https://zoomzilla.ru';
if (!str_starts_with(prelandAssetUrl('docs/logo.svg'), '/docs/logo.svg?v=')) throw new RuntimeException('Доменный логотип не должен браться с общего assets/API хоста');
$oldBlob = '91267982e1ad373b6ebd5fb2b761b34fe2a0c2a5';
foreach (['docs/logo.svg', 'docs/logo-alt.svg'] as $file) {
$body = str_replace("\r\n", "\n", file_get_contents($root . '/' . $file));
@@ -13,11 +16,11 @@ foreach (['docs/logo.svg', 'docs/logo-alt.svg'] as $file) {
require $root . '/bin/release-assets.php';
validateReleaseAssets($root);
$files = releaseFiles($root);
foreach (['docs/logo.svg', 'docs/logo-alt.svg', 'docs/privacy_policy.pdf', 'template.php'] as $file) {
foreach (['docs/privacy_policy.pdf', 'template.php'] as $file) {
if (!in_array($file, $files, true)) throw new RuntimeException('Не включён ' . $file);
}
foreach ($files as $file) {
if (preg_match('~^(tests/|bin/|release/|docs/superpowers/|config\.json$|[0-9]+/)~', $file)) {
if (preg_match('~^(tests/|bin/|release/|docs/superpowers/|config\.json$|[0-9]+/|docs/logo(?:-alt)?\.svg$)~', $file)) {
throw new RuntimeException('В кодовую поставку попал защищённый/служебный файл ' . $file);
}
}
@@ -32,6 +35,17 @@ $copy = static function (string $relative) use ($root, $fixture): void {
$manifest = json_decode(file_get_contents($root . '/release/assets.json'), true, 512, JSON_THROW_ON_ERROR);
foreach (array_keys($manifest['files']) as $file) $copy($file);
$copy('release/assets.json');
$copy('release/brands.json');
$brands = json_decode(file_get_contents($root . '/release/brands.json'), true, 512, JSON_THROW_ON_ERROR);
foreach ($brands as $brand) foreach ($brand['logos'] as $record) $copy($record['file']);
$brand = prelandBrand($root, 'zoomstage.online');
$new = array_map(static fn(array $record): string => $record['sha256'], $brand['logos']);
$old = $brand['replace_from'];
foreach ([[$old, 10], [$new, 0], [['docs/logo.svg' => $new['docs/logo.svg'], 'docs/logo-alt.svg' => $old['docs/logo-alt.svg']], 10], [['docs/logo.svg' => $old['docs/logo.svg'], 'docs/logo-alt.svg' => $new['docs/logo-alt.svg']], 10], [['docs/logo.svg' => 'unknown', 'docs/logo-alt.svg' => $new['docs/logo-alt.svg']], 1]] as [$actual, $state]) {
if (prelandBrandState($actual, $brand) !== $state) throw new RuntimeException('Миграция бренда не восстанавливается после частичного put');
}
try { prelandBrand($root, 'unregistered.example'); throw new LogicException('Неизвестная цель принята'); }
catch (RuntimeException $expected) {}
try {
validateReleaseAssets($fixture);
$mustFail = static function (callable $mutate) use ($fixture): void {
-28
View File
@@ -1,28 +0,0 @@
<?php
/** preland#11: разрешено менять только согласованный ключ requisites. */
declare(strict_types=1);
$root = dirname(__DIR__);
$expected = json_decode(file_get_contents($root . '/release/requisites.json'), true, 512, JSON_THROW_ON_ERROR);
$saved = json_decode(file_get_contents($root . '/config.json'), true, 512, JSON_THROW_ON_ERROR);
if (($saved['requisites'] ?? null) !== $expected) {
fwrite(STDERR, "FAILED: Git config содержит старые реквизиты\n"); exit(1);
}
$raw = "{\n \"host\" : \"custom.example\", \"nested\":{\"requisites\":[\"do not change\"]},\n \"requisites\": [\"old\",\"escaped \\\"quote\"], \"utm\" : {\"focus\":\"custom\"}, \"unknown\":\"\\u0041\"\n}\n";
$path = tempnam(sys_get_temp_dir(), 'requs-');
try {
foreach ([$raw, '{"host":"other.example","unknown":{"a":1}}'] as $fixture) {
file_put_contents($path, $fixture);
exec(PHP_BINARY . ' ' . escapeshellarg($root . '/bin/ensure-requisites-config.php') . ' ' . escapeshellarg($path), $output, $code);
if ($code !== 10) throw new RuntimeException('Ожидалась точечная замена requisites');
$after = file_get_contents($path);
$beforeData = json_decode($fixture, true, 512, JSON_THROW_ON_ERROR);
$afterData = json_decode($after, true, 512, JSON_THROW_ON_ERROR);
if ($afterData['requisites'] !== $expected) throw new RuntimeException('Реквизиты не заменены');
unset($beforeData['requisites'], $afterData['requisites']);
if ($beforeData !== $afterData) throw new RuntimeException('Другие значения изменены');
if (isset($afterData['nested']) && !str_contains($after, '"unknown":"\\u0041"')) throw new RuntimeException('Изменены байты чужих полей');
exec(PHP_BINARY . ' ' . escapeshellarg($root . '/bin/ensure-requisites-config.php') . ' ' . escapeshellarg($path), $output, $code);
if ($code !== 0 || file_get_contents($path) !== $after) throw new RuntimeException('Повторная операция не идемпотентна');
}
} finally { unlink($path); }
echo "OK: requisites-only, чужие поля/байты сохранены, повторный запуск без изменений\n";
+6
View File
@@ -0,0 +1,6 @@
<?php
if (PHP_SAPI !== 'cli') { http_response_code(404); exit; }
$_SERVER['HTTP_HOST'] = $argv[1] ?? 'zoomstage.online';
$_SERVER['SERVER_NAME'] = 'fixture.local';
$_GET = ['theme' => $argv[2] ?? 'light', 'indpic' => '1'];
require dirname(__DIR__) . '/index.php';