<?php

/************************************************************************************** 
 * initialize.php
 * 本システム利用開始時の初期化処理を行います
 *
 * env ディレクトリ内の「system_setting.php」「user_setting.php」の存在を確認して
 * 処理モードが変更されます。
 *
 *「system_setting.php」が存在しない場合：完全初期化モード
 *「user_setting.php」が存在しない場合  ：ユーザーID・パスワード変更モード
 *
 ***************************************************************************************/

use const pictpostpersonal\SYSTEM_SETTING_PATH;
use const pictpostpersonal\USER_PATH;

if (defined('pictpostpersonal\PPP_PATH') === false) {
    exit();
}

require_once 'autoload.php';

$SYSTEM_SETTING_FILE = SYSTEM_SETTING_PATH;
$USER_SETTING_FILE = USER_PATH;

$DEMO_USER = '';
$DEMO_PASSWORD = '';

$message = '';

//HTTPでアクセスされた場合、本サーバーがHTTPS接続可能か確認する。HTTPS接続可能な場合はリダイレクトする
if (empty($_SERVER['HTTPS']) && !strstr($_SERVER['HTTP_HOST'], '127.0.0.1') && !strstr($_SERVER['HTTP_HOST'], '192.168.')) {
    $url = 'https://' . $_SERVER['HTTP_HOST'] . dirname($_SERVER['REQUEST_URI']) . '/system_resource/index.html';
    $context = stream_context_create([
        'ssl' => [
            'verify_peer' => true,
            'verify_peer_name' => true,
        ],
        'http' => [
            'method'  => 'GET',
            'timeout' => 2, // タイムアウト時間
        ],
    ]);
    $response = @file_get_contents($url, false, $context);
    if ($response !== false) {
        $url = 'https://' . $_SERVER['HTTP_HOST'] . dirname($_SERVER['REQUEST_URI']) . '/initialize.php';
        header("Location: $url");
        exit();
    }
}

// stepなし：操作画面表示 
// stepあり:stepに応じた処理実行
$step = filter_input(INPUT_POST, 'step') ?? '';
$next_step = '';
if (file_exists($SYSTEM_SETTING_FILE) && file_exists($USER_SETTING_FILE)) {
    //設定ファイルが両方ある場合は初期化済み
    echo '初期化済みです';
    return;
} else if (file_exists($SYSTEM_SETTING_FILE) && !file_exists($USER_SETTING_FILE)) {
    //ユーザー / パスワード変更モード
    $message = '<span style="color:red">ユーザーID・パスワードを再設定します</span><br>';
    $next_step = 'user_initialize';
} else {
    $message = '<img src="./system_resource/initlogo.png"><br>Simple Blog System PictPostPersonal 2 へようこそ。<br>最初にユーザーIDとパスワードを設定します。<br>';
    $next_step = 'all_initialize';
}




if ($step) {
    if ($step === 'user_initialize' || $step === 'all_initialize') {
        //フォルダ作成
        createDirectory('./env', true);
        createDirectory('./themes', true);
        createDirectory('./env/templates', true);
        createDirectory('./env/systemlog', true);
        createDirectory('./env/template_cache', true);
        createDirectory('./user_resource', false, true);
        createDirectory('./user_resource/thumbnails');
        createDirectory('./images', false, true);

        //ユーザーID・パスワードの初期化
        $username = filter_input(INPUT_POST, 'username');
        $password = filter_input(INPUT_POST, 'password');
        $re_password = filter_input(INPUT_POST, 're_password');
        $errors = validatePassword($username, $password, $re_password);
        if ($errors) {
            echo ("設定値が不正です。<br>$errors<br>");
            echo ("<a href=\"javascript:history.back()\">戻る</a>");
            exit();
        }

        //パスワード設定
        try {
            $fp = fopen($USER_SETTING_FILE, 'w');
            fwrite($fp, "<?php\n");
            fwrite($fp, 'const SYS_USERNAME="' .  preg_replace('/[\'"$]/', '\\\\$0', $username) . '";' . "\r\n");
            fwrite($fp, 'const SYS_PASSWORD="' .   preg_replace('/[\'"$]/', '\\\\$0', password_hash($password, PASSWORD_DEFAULT)) . '";' . "\r\n");
            fwrite($fp, 'const LOCK_MODE=false;' . "\r\n");
            fclose($fp);
        } catch (Exception $ex) {
            echo ('設定ファイルの書き込みに失敗しました。<br>');
            echo ("<a href=\"javascript:history.back()\">戻る</a>");
            exit();
        }

        //ログインを実行
        $auth = new pictpostpersonal\Authentification();
        $auth->login($username, $password);
    }

    if ($step === 'all_initialize') {
        //サムネイルファイル配置
        copyFolderContents('./system_resource/thumbnails', './user_resource/thumbnails');

        //USER CSSの初期化
        if (!file_exists('./user_resource/user.css')) {
            copy('./core/resource/default_user.css', './user_resource/user.css');
        }

        //データベースの初期化
        $db_file_path = filter_input(INPUT_POST, 'dbfilepath');
        if (!$db_file_path) {
            // 指定がない場合はランダムなファイル名を生成
            $db_file_path = './env/' . bin2hex(random_bytes(rand(15, 20))) . '.db';
        } else {
            if (file_exists($db_file_path)) {
                echo ('指定されたパスにはすでにファイルが存在します。<br>別のパスを指定してください。');
                echo ("<a href=\"javascript:history.back()\">戻る</a>");
                exit();
            }
        }

        //DB構築
        $db = new \PDO("sqlite:$db_file_path");
        $db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
        $retry = 0;
        while ($retry < 10) {
            try {
                $db->exec('PRAGMA journal_mode=wal');
                $retry = 99;
            } catch (Exception $ex) {
                sleep(1000);
                $retry++;
            }
        }
        if ($retry != 99) {
            echo '失敗';
            exit;
        }

        $sql_crud = new pictpostpersonal\SQLiteCRUD($db);
        //各モデルの初期化
        pictpostpersonal\model\Account::initialize($sql_crud);
        pictpostpersonal\model\Media::initialize($sql_crud);
        pictpostpersonal\model\Article::initialize($sql_crud);
        pictpostpersonal\model\Message::initialize($sql_crud);
        pictpostpersonal\model\Setting::initialize($sql_crud);
        pictpostpersonal\model\Activity::initialize($sql_crud);
        pictpostpersonal\model\SystemActivity::initialize($sql_crud);
        pictpostpersonal\model\Template::initialize($sql_crud);
        pictpostpersonal\model\ThemeSetting::initialize($sql_crud);

        //設定ファイルにDBへのパスを記録
        $fp = fopen($SYSTEM_SETTING_FILE, 'w');
        fwrite($fp, "<?php\n");
        fwrite($fp, '$system_db_file="' . $db_file_path . '";' . "\r\n");
        fclose($fp);

        //設定用モデルからテーブルを構築
        $setting = new pictpostpersonal\model\Setting($db);
        if (empty($_SERVER['HTTPS']) === false) {
            //HTTPS接続で初期化された場合はSSL-ON
            $setting->setValue('always_on_ssl', true);
        }
        $setting->save();

        //タグクラウドファイル生成
        $fp = fopen('./env/tagcloud.php', 'w');
        fwrite($fp, "<?php\n");
        fwrite($fp, '$tagcloud_links = "";' . "\n");
        fwrite($fp, '$tagcloud_nolink = "";' . "\n");
        fwrite($fp, '$tagcloud_links_more = "";' . "\n");
        fwrite($fp, '$tagcloud_nolink_more = "";' . "\n");
        fwrite($fp, '$tagcloud_nolink_sys = "";' . "\n");
        fwrite($fp, '$tagcloud_nolink_more_sys = "";' . "\n");
        fwrite($fp, '$tagcloud_list = "";' . "\n");
        fclose($fp);

        //トークンファイル作成
        $fp = fopen('./env/token.php', 'w');
        fwrite($fp, "<?php exit(); ?>\n");
        fclose($fp);

        //.htaccessファイル配置
        if (file_exists('./.htaccess')) {
            //既存のファイルがある場合はリネーム
            rename('./.htaccess', './.htaccess.old.' . bin2hex(random_bytes(rand(5, 8))));
        };
        copy('./core/resource/htaccess_base.txt', './.htaccess');
        chmod('./.htaccess', 0604);

        //mod_rewriteが機能しているか確認する
        $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https://' : 'http://';
        $url = $protocol . $_SERVER['HTTP_HOST'] . dirname($_SERVER['REQUEST_URI']) . '/mod_rewrite_check';
        $context = stream_context_create([
            'ssl' => [
                'verify_peer' => true,
                'verify_peer_name' => true,
            ],
            'http' => [
                'method'  => 'GET',
                'timeout' => 2, // タイムアウト時間
            ],
        ]);

        $headers = get_headers($url, false, $context);
        $http_code = substr($headers[0], 9, 3);
        if ($headers == "" || $http_code == 404) {
            //rewriteが動作していない場合はフラグをOFFに
            $setting->setValue('use_rewrite', 0);
        } else {
            //rewriteが動作している場合はフラグをONに
            $setting->setValue('use_rewrite', 1);
        }
        $setting->save();

        //初期化プラグイン
        if (file_exists('./plugin/plugin2_startup.php')) {
            require_once('./plugin/plugin2_startup.php');
            $plugin_func = 'plugin2_startup\initialize';
            $plugin_func($db);
        }
    }



    //設定画面に移行
    header('Location: ./?c=/setting?mode=initialize');
    exit;
}

function createDirectory($dir, $make_deny_htaccess = false, $make_deny_php_exec_htaccess = false)
{
    if (!file_exists($dir)) {
        mkdir($dir, 0755);
        $fp = fopen("{$dir}/index.html", 'w');
        fclose($fp);
    }

    //直接アクセスを拒否するhtaccessの設置
    if ($make_deny_htaccess) {
        if (!file_exists("{$dir}/.htaccess")) {
            $fp = fopen("{$dir}/.htaccess", 'w');
            fwrite($fp, "Require all denied\n");
            fclose($fp);
            chmod("{$dir}/.htaccess", 0604);
        }
    }
    if ($make_deny_php_exec_htaccess) {
        if (!file_exists("{$dir}/.htaccess")) {
            $fp = fopen("{$dir}/.htaccess", 'w');
            fwrite($fp, "<FilesMatch \"\.php|cgi|pl$\">\nRequire all denied\n</FilesMatch>");
            fclose($fp);
            chmod("{$dir}/.htaccess", 0604);
        }
    }
}

function copyFolderContents($source, $destination)
{
    // ディレクトリを作成（存在しない場合）
    if (!is_dir($destination)) {
        mkdir($destination, 0755, true);
    }

    // ファイルおよびディレクトリの一覧を取得
    $items = scandir($source);
    $items = array_diff($items, array('.', '..'));

    // 各アイテムをコピー
    foreach ($items as $item) {
        $source_path = $source . '/' . $item;
        $destination_path = $destination . '/' . $item;

        if (is_dir($source_path)) {
            // ディレクトリの場合、再帰的に中身をコピー
            copyFolderContents($source_path, $destination_path);
        } else {
            // ファイルの場合、コピー
            copy($source_path, $destination_path);
        }
    }
}
function validatePassword($username, $password, $repassword): string
{
    // エラーメッセージを格納する変数
    $error = '';

    // パスワードの長さを確認
    if (strlen($password) < 8) {
        $error = 'パスワードは8文字以上である必要があります。';
    }
    // パスワードに大文字、小文字、数字が含まれているか確認
    elseif (!preg_match('/[A-Z]/', $password)) {
        $error = 'パスワードには大文字を含めてください。';
    } elseif (!preg_match('/[a-z]/', $password)) {
        $error = 'パスワードには小文字を含めてください。';
    } elseif (!preg_match('/\d/', $password)) {
        $error = 'パスワードには数字を含めてください。';
    }
    // パスワードと再入力が一致しているか確認
    elseif ($password !== $repassword) {
        $error = 'パスワードと再入力の内容が異なります。';
    }
    // ユーザー名が空でないか確認
    elseif (empty($username)) {
        $error = 'ユーザーIDを入力してください。';
    }

    return $error;
}

?>

<!doctype html>
<html lang="ja">

<head>
    <meta charset="utf-8">
    <title>初期設定</title>
    <meta name="description" content="">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="theme-color" content="#fafafa">
    <link rel="stylesheet" href="./system_resource/css/recss.css">
    <link rel="stylesheet" href="./system_resource/css/public_base.css">
    <link rel="stylesheet" href="./system_resource/vender/fontawesome/css/all.min.css" rel="preload">

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>

    <script src="./system_resource/script/dialog2.js"></script>
    <script src="./system_resource/script/common2.js" defer></script>
    <link rel="stylesheet" href="./system_resource/css/dialog2.css">
    <style>
        #container {
            display: flex;
            justify-content: center;
            align-items: center;

            width: 100%;
            height: 100vh;
        }

        #login-button {
            display: block;
            margin: 3em auto 0 auto;
        }

        table {
            margin: 0 auto 0 auto;
        }

        tr {
            height: 2.5em;
        }

        td {
            width: 15em;
        }

        #message {
            width: 100%;
            display: block;
            color: #f00;
            font-size: 0.9em;
            text-align: center;
            margin: 2em auto 2em auto;
        }

        label {
            margin-right: 3em;
        }

        .wmessage {
            color: red;
        }
    </style>
    <script>
        $(async function() {
            let dialog = new PppDialog();
            $('#password').on('input', function() {
                passwordCheck();
            });

            $('#re-password').on('input', function() {
                passwordCheck();
            });

            $('form').on('submit', async function(e) {
                if (!passwordCheck()) {
                    e.preventDefault();
                    await dialog.openAlert({
                        title: "エラー",
                        message: "ID,パスワードを確認してください。"
                    });
                    return;
                }

                //処理中ダイアログを表示
                let waitDialog = dialog.openAlert({
                    message: `<div style="display: grid;place-content: center; place-items: center;"><img src=\"./system_resource/loading.gif\"  width=32 height=32><p>処理中…</p></div>`,
                    noButtons: true
                });
            });
        });

        function passwordCheck() {
            var err = false;
            var password = $("#password").val();
            var repassword = $("#re-password").val();
            var hasUpperCase = /[A-Z]/.test(password);
            var hasLowerCase = /[a-z]/.test(password);
            var hasNumbers = /\d/.test(password);
            if (password.length < 8) {
                $('#password-strength').html('パスワードは8文字以上である必要があります。');
                err = true;
            } else if (!hasUpperCase || !hasLowerCase || !hasNumbers) {
                $('#password-strength').html('パスワードには大文字・小文字・数字を含めてください。');
                err = true;
            } else if (password != repassword) {
                $('#password-strength').html("パスワードと再入力の内容が異なります");
                err = true;
            } else if ($("#username").val() == "") {
                $('#password-strength').html("ユーザーIDを入力してください");
            } else {
                $('#password-strength').html("");
            }

            if (err ||
                $("#username").val() == "" ||
                password == "" ||
                password != repassword) {
                return false;
            }
            return true;
        }
    </script>

</head>

<body>
    <div id="container">

        <div class="login-area">
            <?php echo $message ?>
            <br>
            <form action="./index.php" method="POST">
                <table>
                    <tr>
                        <td><label for="username">ユーザーID</label></td>
                        <td><input type="text" id="username" name="username" class="flat_input p-input" value="<?= $DEMO_USER ?>"></td>
                    </tr>
                    <tr>
                        <td><label for="password">新しいパスワード</label></td>
                        <td><input type="password" id="password" name="password" class="flat_input p-input" value="<?= $DEMO_PASSWORD ?>"></td>
                    </tr>
                    <tr>
                        <td><label for="password">新しいパスワード(再入力)</label></td>
                        <td><input type="password" id="re-password" name="re_password" class="flat_input p-input" value="<?= $DEMO_PASSWORD ?>"></td>
                    </tr>
                </table>
                <span id="password-strength" class="wmessage"></span><br>
                ※パスワードは8文字以上・大文字・小文字・数字を含めてください。<br><br>
                <span style="font-size:0.9em; color:#449944;cursor:pointer" onClick="$('#options').toggle()">オプション設定▼</span>
                <div class="hide" id="options">
                    <table>
                        <tr>
                            <td>DBファイルパス</td>
                            <td><input type="text" id="dbfilepath" name="dbfilepath" class="flat_input p-input" placeholder="通常は空で問題ありません"></td>
                        </tr>
                    </table>
                </div>
                <input type="hidden" name="step" value="<?php echo $next_step; ?>">
                <button name="submit" value="決定" class="p-button" id="login-button">決定</button>
            </form>
        </div>

</body>

</html>