getMessage()); } $allowedAdminIps = array_values(array_filter(array_map(static fn($ip): string => trim((string)$ip), (array)($secrets['allowed_admin_ips'] ?? [])), static fn(string $ip): bool => $ip !== '')); $clientIp = (string)($_SERVER['REMOTE_ADDR'] ?? ''); if ($allowedAdminIps !== [] && !in_array($clientIp, $allowedAdminIps, true)) { http_response_code(403); exit('Forbidden'); } $basicUser = (string)($secrets['basic_auth_user'] ?? ''); $basicPass = (string)($secrets['basic_auth_pass'] ?? ''); if ($basicUser !== '' || $basicPass !== '') { $authUser = (string)($_SERVER['PHP_AUTH_USER'] ?? ''); $authPass = (string)($_SERVER['PHP_AUTH_PW'] ?? ''); if (!hash_equals($basicUser, $authUser) || !hash_equals($basicPass, $authPass)) { header('WWW-Authenticate: Basic realm="Admin"'); http_response_code(401); exit('Unauthorized'); } } $tokenExpected = (string)($secrets['admin_token'] ?? ''); $tokenIncoming = (string)($_REQUEST['token'] ?? ''); if ($tokenExpected === '' || !hash_equals($tokenExpected, $tokenIncoming)) { http_response_code(403); exit('Forbidden'); } $deployConfig = (array)($config['deploy'] ?? []); $deployRemoteName = trim((string)($deployConfig['remote_name'] ?? 'origin')); if ($deployRemoteName === '') { $deployRemoteName = 'origin'; } $deployRemoteUrl = trim((string)($deployConfig['remote_url'] ?? '')); $allowedDeployBranches = ['main', 'dev']; $defaultDeployBranch = trim((string)($deployConfig['branch'] ?? 'main')); if (!in_array($defaultDeployBranch, $allowedDeployBranches, true)) { $defaultDeployBranch = 'main'; } $requestedDeployBranch = trim((string)($_REQUEST['deploy_branch'] ?? '')); $deployBranch = in_array($requestedDeployBranch, $allowedDeployBranches, true) ? $requestedDeployBranch : $defaultDeployBranch; $deployScript = trim((string)($deployConfig['script'] ?? (__DIR__ . '/scripts/deploy.sh'))); if ($deployScript !== '' && !str_starts_with($deployScript, '/')) { $deployScript = __DIR__ . '/' . ltrim($deployScript, '/'); } $deployPhpBin = trim((string)($deployConfig['php_bin'] ?? 'php')); if ($deployPhpBin === '') { $deployPhpBin = 'php'; } $requestAction = (string)($_REQUEST['action'] ?? ''); if ($_SERVER['REQUEST_METHOD'] === 'GET') { adminHandleGetAction($requestAction); } $message = ''; $errors = []; $deployStatus = null; $deployOutput = ''; if ($_SERVER['REQUEST_METHOD'] === 'POST') { $action = (string)($_POST['action'] ?? ''); $isAjax = (string)($_POST['ajax'] ?? '') === '1' || strtolower((string)($_SERVER['HTTP_X_REQUESTED_WITH'] ?? '')) === 'xmlhttprequest'; try { $result = adminHandlePostAction($action, $isAjax, __DIR__, [ 'remote_name' => $deployRemoteName, 'remote_url' => $deployRemoteUrl, 'branch' => $deployBranch, 'script' => $deployScript, 'php_bin' => $deployPhpBin, ]); $message = (string)($result['message'] ?? ''); $deployStatus = $result['deploy_status'] ?? null; $deployOutput = (string)($result['deploy_output'] ?? ''); if (isset($result['errors']) && is_array($result['errors']) && $result['errors'] !== []) { $errors = array_merge($errors, $result['errors']); } } catch (Throwable $e) { if ($isAjax) { adminJsonResponse(['ok' => false, 'message' => $e->getMessage()], 400); } $errors[] = $e->getMessage(); } } $sections = sectionsAll(); $activeSectionId = (int)($_GET['section_id'] ?? ($_POST['section_id'] ?? ($sections[0]['id'] ?? 0))); $activeSection = $activeSectionId > 0 ? sectionById($activeSectionId) : null; if (!$activeSection && $sections !== []) { $activeSectionId = (int)$sections[0]['id']; $activeSection = sectionById($activeSectionId); } $photos = $activeSectionId > 0 ? photosBySection($activeSectionId) : []; $commenters = commentersAll(); $welcomeText = settingGet('welcome_text', 'Добро пожаловать в галерею. Выберите раздел слева, чтобы посмотреть фотографии.'); $watermarkText = settingGet('watermark_text', 'photo.andr33v.ru'); $watermarkBrightness = max(5, min(100, (int)settingGet('watermark_brightness', '35'))); $watermarkAngle = max(-75, min(75, (int)settingGet('watermark_angle', '-28'))); $adminMode = (string)($_GET['mode'] ?? 'photos'); if ($adminMode === 'media') { $adminMode = 'photos'; } if (!in_array($adminMode, ['sections', 'photos', 'topics', 'commenters', 'comments', 'welcome'], true)) { $adminMode = 'photos'; } $previewVersion = (string)time(); $commentPhotoQuery = trim((string)($_GET['comment_photo'] ?? ($_POST['comment_photo'] ?? ''))); $commentUserQuery = trim((string)($_GET['comment_user'] ?? ($_POST['comment_user'] ?? ''))); $filteredComments = commentsSearch($commentPhotoQuery, $commentUserQuery, 200); $photoCommentCounts = commentCountsByPhotoIds(array_map(static fn(array $p): int => (int)$p['id'], $photos)); $topics = []; $topicRoots = []; $photoTopicsMap = []; $topicTree = []; $topicsError = ''; try { $topics = topicsAllForSelect(); foreach ($topics as $topic) { if ((int)$topic['level'] === 0) { $topicRoots[] = $topic; } } $topicTree = buildTopicTree($topics); $photoTopicsMap = photoTopicsMapByPhotoIds(array_map(static fn(array $p): int => (int)$p['id'], $photos)); } catch (Throwable $e) { $topicsError = 'Тематики недоступны. Запусти миграции: php scripts/migrate.php'; } function h(string $v): string { return htmlspecialchars($v, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); } function assetUrl(string $path): string { $f=__DIR__ . '/' . ltrim($path,'/'); $v=is_file($f)?(string)filemtime($f):(string)time(); return $path . '?v=' . rawurlencode($v); } ?> Админка

Админка

Настройки


Водяной знак (фото "после")


Обновление проекта

Remote:

Выбери ветку для проверки и обновления:


Локально: · /: · behind: · ahead:

Создать раздел

Список разделов

Разделов пока нет.

Фото:

Создать тематику

Список тематик

Тематик пока нет.

Уровень 1

Уровень 2 · внутри «»

Загрузка фото “до” в выбранный раздел

0): ?>

После загрузки имя (code_name) заполняется автоматически из имени файла — затем можно отредактировать.

Сначала выбери раздел слева.

Фото в разделе

ДоПослеПоляДействия
Фото после не загружено

0): ?> Комментариев нет

Пользователи комментариев

ПользовательСсылкаДействия
Нет сохранённой ссылки (старый пользователь)

Комментарии

Комментарии не найдены.

ФотоПользовательКомментарийДата