<?php

declare(strict_types=1);

namespace Acms\Services\Installer;

/**
 * インストーラーで入力される DB 名・テーブル接頭辞の検証。
 *
 * install の Database ステップは `CREATE DATABASE \`{db_name}\`` / `ALTER DATABASE ...` を
 * バッククォートで囲むだけで発行しており、バッククォートを含む値を渡すと SQL を抜けられる。
 * 接頭辞（db_prefix）は全テーブル名に連結されるため同様に危険。ここで許可リスト方式に倒し、
 * 想定外の文字を含む入力を CREATE/ALTER 前に弾く。判定のみの純粋ロジックとする。
 */
final class DatabaseNameValidator
{
    /**
     * DB 名の許可パターン。英数字・アンダースコア・ハイフンを許可する。
     * バッククォート/空白/記号を排除して識別子エスケープの不備を無害化する。
     * さくらインターネット等、契約者アカウント名（ハイフンを含みうる）が DB 名の先頭に
     * 自動付与されるレンタルサーバー環境に対応するため、2 文字目以降のハイフンを許可する。
     * 先頭文字だけは CLI ツールへの引数渡し時にオプションと誤解釈されるのを避けるため
     * 英数字・アンダースコアのみに制限する。
     */
    private const DATABASE_NAME_PATTERN = '/\A[A-Za-z0-9_][A-Za-z0-9_-]*\z/';

    /**
     * テーブル接頭辞の許可パターン。テーブル名に連結されるためハイフンは許可しない。
     * 空文字（接頭辞なし運用）も許可する。
     */
    private const PREFIX_PATTERN = '/\A[A-Za-z0-9_]*\z/';

    /**
     * MySQL の識別子最大長。
     */
    private const MAX_IDENTIFIER_LENGTH = 64;

    public function isValidDatabaseName(string $name): bool
    {
        if ($name === '' || strlen($name) > self::MAX_IDENTIFIER_LENGTH) {
            return false;
        }

        return preg_match(self::DATABASE_NAME_PATTERN, $name) === 1;
    }

    public function isValidPrefix(string $prefix): bool
    {
        if (strlen($prefix) > self::MAX_IDENTIFIER_LENGTH) {
            return false;
        }

        return preg_match(self::PREFIX_PATTERN, $prefix) === 1;
    }
}
