#!/bin/bash set -euo pipefail PHPMYADMIN_PRIVATE_DIR="${PHPMYADMIN_PRIVATE_DIR:-${PHPMYADMIN_DIR:-/var/www/html/alt-mysql-phpmyadmin}}" PHPMYADMIN_VERSION="${PHPMYADMIN_VERSION:-5.2.3}" PHPMYADMIN_TARBALL_URL="${PHPMYADMIN_TARBALL_URL:-https://files.phpmyadmin.net/phpMyAdmin/5.2.3/phpMyAdmin-5.2.3-all-languages.tar.gz}" PHPMYADMIN_DOWNLOAD_DIR="${PHPMYADMIN_DOWNLOAD_DIR:-/usr/local/src}" PHPMYADMIN_SOURCE_DIR="${PHPMYADMIN_SOURCE_DIR:-}" RUNTIME_DIR="${PHPMYADMIN_PRIVATE_DIR}/runtime" TICKETS_DIR="${RUNTIME_DIR}/tickets" CONFIG_INC="${PHPMYADMIN_PRIVATE_DIR}/config.inc.php" SIGNON_SCRIPT="${PHPMYADMIN_PRIVATE_DIR}/da_signon.php" SIGNON_URL_PAGE="${PHPMYADMIN_PRIVATE_DIR}/da_login.php" BLOWFISH_SECRET_FILE="${RUNTIME_DIR}/blowfish_secret" if [ "${PHPMYADMIN_INSTALL_ASSUME_ROOT:-0}" != "1" ] && [ "${EUID:-$(id -u)}" -ne 0 ]; then echo "Skrypt musi być uruchomiony jako root." >&2 exit 1 fi log() { printf 'phpMyAdmin alt-mysql: %s\n' "$*" } die() { printf 'phpMyAdmin alt-mysql: %s\n' "$*" >&2 exit 1 } install_private_copy_from_source() { local source_dir="$1" [ -d "$source_dir" ] || die "Katalog źródłowy phpMyAdmin nie istnieje: $source_dir" [ -f "$source_dir/index.php" ] || die "Katalog źródłowy nie wygląda jak phpMyAdmin: $source_dir" mkdir -p "$PHPMYADMIN_PRIVATE_DIR" cp -a "$source_dir"/. "$PHPMYADMIN_PRIVATE_DIR"/ } download_private_copy() { local tarball extracted tmp_dir command -v curl >/dev/null 2>&1 || die "Brak curl; ustaw PHPMYADMIN_SOURCE_DIR albo doinstaluj curl." command -v tar >/dev/null 2>&1 || die "Brak tar." mkdir -p "$PHPMYADMIN_DOWNLOAD_DIR" tarball="$PHPMYADMIN_DOWNLOAD_DIR/phpMyAdmin-${PHPMYADMIN_VERSION}-all-languages.tar.gz" if [ ! -s "$tarball" ]; then log "Pobieram prywatny phpMyAdmin ${PHPMYADMIN_VERSION}." curl -fL --retry 3 --connect-timeout 20 -o "$tarball" "$PHPMYADMIN_TARBALL_URL" fi tmp_dir="$(mktemp -d)" tar -xzf "$tarball" -C "$tmp_dir" extracted="$(find "$tmp_dir" -mindepth 1 -maxdepth 1 -type d -name 'phpMyAdmin-*' -print -quit)" [ -n "$extracted" ] || { rm -rf "$tmp_dir" die "Tarball phpMyAdmin nie zawiera oczekiwanego katalogu." } install_private_copy_from_source "$extracted" rm -rf "$tmp_dir" } ensure_private_copy() { if [ -f "$PHPMYADMIN_PRIVATE_DIR/index.php" ]; then return 0 fi rm -rf "$PHPMYADMIN_PRIVATE_DIR" if [ -n "$PHPMYADMIN_SOURCE_DIR" ]; then install_private_copy_from_source "$PHPMYADMIN_SOURCE_DIR" else download_private_copy fi } generate_secret() { if [ -r "$BLOWFISH_SECRET_FILE" ]; then local existing existing="$(tr -d '\r\n' < "$BLOWFISH_SECRET_FILE")" if [ -n "$existing" ]; then printf '%s\n' "$existing" return 0 fi fi if command -v openssl >/dev/null 2>&1; then openssl rand -hex 32 return 0 fi tr -dc 'a-f0-9' "$BLOWFISH_SECRET_FILE" chmod 600 "$BLOWFISH_SECRET_FILE" 2>/dev/null || true cat > "$RUNTIME_DIR/.htaccess" <<'EOF' Require all denied Deny from all EOF cat > "$TICKETS_DIR/.htaccess" <<'EOF' Require all denied Deny from all EOF printf '%s\n' '
' . $safe . '
'; echo ''; exit; } function da_mysql_login_consume_ticket(array $runtimeConfig): array { $token = strtolower((string)($_GET['ticket'] ?? '')); if (preg_match('/\A[a-f0-9]{64}\z/', $token) !== 1) { da_mysql_login_error('Missing or invalid phpMyAdmin login ticket.'); } $path = da_mysql_login_ticket_dir($runtimeConfig) . '/' . $token . '.json'; if (!is_readable($path)) { da_mysql_login_error('The phpMyAdmin login ticket is not available or has already been used.'); } $raw = file_get_contents($path); @unlink($path); $ticket = is_string($raw) ? json_decode($raw, true) : null; if (!is_array($ticket)) { da_mysql_login_error('The phpMyAdmin login ticket is invalid.'); } if ((int)($ticket['expires_at'] ?? 0) < time()) { da_mysql_login_error('The phpMyAdmin login ticket has expired.'); } $auth = $ticket['auth'] ?? []; if (!is_array($auth) || (string)($auth['user'] ?? '') === '' || (string)($auth['password'] ?? '') === '') { da_mysql_login_error('The phpMyAdmin login ticket does not contain credentials.'); } return $ticket; } function da_mysql_login_redirect_target(array $ticket): string { $route = (string)($ticket['route'] ?? '/database/structure'); if (preg_match('#^/[A-Za-z0-9_./-]+$#', $route) !== 1 || strpos($route, '//') !== false) { $route = '/'; } $query = ['route' => $route]; $db = (string)($ticket['db'] ?? ($ticket['auth']['db'] ?? '')); if ($db !== '') { $query['db'] = $db; } return 'index.php?' . http_build_query($query); } $runtimeConfig = da_mysql_login_runtime_config(); $ticket = da_mysql_login_consume_ticket($runtimeConfig); $secure = false; $https = strtolower((string)($_SERVER['HTTPS'] ?? '')); if ($https !== '' && $https !== 'off' && $https !== '0') { $secure = true; } elseif (strtolower((string)($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '')) === 'https') { $secure = true; } session_name(DA_MYSQL_SESSION); session_set_cookie_params([ 'lifetime' => 0, 'path' => da_mysql_login_url_path($runtimeConfig), 'secure' => $secure, 'httponly' => true, 'samesite' => 'Lax', ]); session_start(); $_SESSION['DA_MYSQL_PHPMYADMIN_AUTH'] = $ticket['auth']; session_write_close(); header('Cache-Control: no-store, no-cache, must-revalidate'); header('Pragma: no-cache'); header('Location: ' . da_mysql_login_redirect_target($ticket), true, 302); exit; PHP cat > "$SIGNON_SCRIPT" <<'PHP' /dev/null || true chmod 755 "$RUNTIME_DIR" "$TICKETS_DIR" "$RUNTIME_DIR/tmp" 2>/dev/null || true chmod 644 "$CONFIG_INC" "$SIGNON_SCRIPT" "$SIGNON_URL_PAGE" "$RUNTIME_DIR/.htaccess" "$TICKETS_DIR/.htaccess" "$RUNTIME_DIR/index.html" "$TICKETS_DIR/index.html" 2>/dev/null || true } ensure_private_copy write_private_config log "Prywatna kopia phpMyAdmin dla alt-mysql jest gotowa w ${PHPMYADMIN_PRIVATE_DIR}."