1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

PHP入門 PHP,JavaScript,HTML,CSSで作るwebサイト(じゃんけんゲーム) ②サイト作成1

1
Last updated at Posted at 2025-06-25

①を読んでない人はこちら

1 DB関連

db_connect.phpを使用して、DBとの接続を管理

db_connect.php
<?php
// .env読み込み関数
function loadEnv($path) {
    if (!file_exists($path)) {
        throw new Exception('.env file not found');
    }

    $lines = file($path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
    foreach ($lines as $line) {
        if (strpos($line, '=') !== false && strpos($line, '#') !== 0) {
            list($key, $value) = explode('=', $line, 2);
            $_ENV[trim($key)] = trim($value);
        }
    }
}

// .envファイルを読み込み
loadEnv('sec.env');

// 変数で定義(定数の代わり)
$PDO_DSN = "mysql:host={$_ENV['DB_HOST']};dbname={$_ENV['DB_NAME']};charset={$_ENV['DB_CHARSET']}";
$USERNAME = $_ENV['DB_USER'];
$PASSWORD = $_ENV['DB_PASS'];

// データベース接続
function connectDB() {
    global $PDO_DSN, $USERNAME, $PASSWORD;
    
    try {
        $pdo = new PDO($PDO_DSN, $USERNAME, $PASSWORD);
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        return $pdo;
    } catch (PDOException $e) {
        die("データベース接続エラー: " . $e->getMessage());
    }
}

$pdo = connectDB();
?>
sec.env
DB_HOST=localhost
DB_NAME=
DB_USER=
DB_PASS=
DB_CHARSET=utf8mb4

2.1 ログイン画面

スクリーンショット 2025-06-25 203543.png

login.php
<?php
session_start();


// データベース接続ファイルを読み込み
require_once 'db_connect.php';

$error_message = '';
$success_message='';


// フォームが送信された場合の処理
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $name = trim($_POST['name']);
    //パスワード
    $pin = $_POST['pin'];
    //アクション(ログインor登録)
    $action = $_POST['action'];

    
    // バリデーション
    if (empty($name) || empty($pin)) {
        $error_message = '名前とパスワードを入力してください。';
    } elseif (!preg_match('/^\d{4}$/', $pin)) {
        $error_message = 'パスワードは4桁の数字で入力してください。';
    } else {
        if ($action === 'login') {
            // ログイン処理
            try {
                $stmt = $pdo->prepare("SELECT * FROM status WHERE name = ? AND pin = ?");
                $stmt->execute([$name, $pin]);
                $user = $stmt->fetch();
            } catch (PDOException $e) {
                $error_message = 'データベースエラーが発生しました。';
                // ログに記録(本番環境では)
                error_log($e->getMessage());
            }
            
            if ($user) {
                $_SESSION['id'] = $user['id'];
                $_SESSION['name'] = $user['name'];
                $_SESSION['winRate'] = $user['winRate'];
                $_SESSION['drawRate'] = $user['drawRate'];
                $_SESSION['loseRate'] = $user['loseRate'];
                $_SESSION['handCount'] = $user['handCount'];
                $_SESSION['guuRatio'] = $user['guuRatio'];
                $_SESSION['chokiRatio'] = $user['chokiRatio'];
                $_SESSION['paaRatio'] = $user['paaRatio'];
                $_SESSION['point'] = $user['point'];
    
                header('Location: index.php');
                exit;
            } else {
                $error_message = 'ユーザー名またはパスワードが間違っています。';
            }
        } elseif ($action === 'register') {
            // 登録処理
            // まず同じ名前のユーザーが存在するかチェック
            $stmt = $pdo->prepare("SELECT COUNT(*) FROM status WHERE name = ?");
            $stmt->execute([$name]);
            $count = $stmt->fetchColumn();


            
            if ($count > 0) {
                $error_message = 'この名前は既に使用されています。';
            } else {
                // 新規ユーザー登録(全カラムに初期値を設定)
                $stmt = $pdo->prepare("INSERT INTO status (name, pin, winRate, drawRate, loseRate, handCount, guuRatio, chokiRatio, paaRatio, point) VALUES (?, ?, 0, 0, 0, 0, 0, 0, 0, 0)");
                if ($stmt->execute([$name, $pin])) {
                    $user_id = $pdo->lastInsertId();
                    $_SESSION['id'] = $user_id;
                    $_SESSION['name'] = $name;
                    $_SESSION['winRate'] = 0;
                    $_SESSION['drawRate'] = 0;
                    $_SESSION['loseRate'] = 0;
                    $_SESSION['handCount'] = 0;
                    $_SESSION['guuRatio'] = 0;
                    $_SESSION['chokiRatio'] = 0;
                    $_SESSION['paaRatio'] = 0;
                    $_SESSION['point'] = 1000;
    
                    header('Location: index.php');
                    exit;
                } else {
                    $error_message = '登録に失敗しました。';
                }
            }
        }
    }
}
?>

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>じゃんけんギャンブル - ログイン</title>
	<link rel="stylesheet" href="style_login.css">
</head>
<body>
    <div class="login-container">
        <h1 class="game-title">🎲 じゃんけんギャンブル 🎲</h1>
        <p class="subtitle">運試しの時間だ!</p>
        
        <?php if ($error_message): ?>
            <div class="error-message"><?php echo htmlspecialchars($error_message); ?></div>
        <?php endif; ?>
        
        <?php if ($success_message): ?>
            <div class="success-message"><?php echo htmlspecialchars($success_message); ?></div>
        <?php endif; ?>
        
        <form method="POST" action="">
            <div class="form-group">
                <label for="name">プレイヤー名</label>
                <input type="text" id="name" name="name" placeholder="あなたの名前を入力" 
                       value="<?php echo isset($_POST['name']) ? htmlspecialchars($_POST['name']) : ''; ?>" required>
            </div>
            
            <div class="form-group">
                <label for="pin">パスワード(4桁の数字)</label>
                <input type="password" id="pin" name="pin" placeholder="1234" 
                       pattern="\d{4}" maxlength="4" required>
            </div>
            
            <div class="button-group">
                <button type="submit" name="action" value="login" class="login-btn">
                    ログイン
                </button>
                <button type="submit" name="action" value="register" class="register-btn">
                    新規登録
                </button>
            </div>
        </form>
        
        <div class="game-info">
            <p><strong>ゲーム概要</strong></p>
            <p><span class="emoji"></span><span class="emoji"></span><span class="emoji">✌️</span></p>
            <p>じゃんけんでコインを賭けて勝負!<br>
            </p>
        </div>
    </div>

    <script>
        // 数字のみ入力を許可
        document.getElementById('pin').addEventListener('input', function(e) {
            this.value = this.value.replace(/[^0-9]/g, '');
        });
        
        // フォーム送信時の確認
        document.querySelector('form').addEventListener('submit', function(e) {
            const name = document.getElementById('name').value.trim();
            const pin = document.getElementById('pin').value;
            const action = e.submitter.value;
            
            if (!name || !pin) {
                alert('名前とパスワードを入力してください。');
                e.preventDefault();
                return;
            }
            
            if (!/^\d{4}$/.test(pin)) {
                alert('パスワードは4桁の数字で入力してください。');
                e.preventDefault();
                return;
            }
            
            if (action === 'register') {
                if (!confirm('新しいアカウントを作成しますか?')) {
                    e.preventDefault();
                }
            }
        });
    </script>
</body>
</html>
style_login.css
body {
    font-family: 'Arial', sans-serif;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    margin: 0;
    padding: 0;
    min-height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
}

.login-container {
    background: white;
    padding: 40px;
    border-radius: 15px;
    box-shadow: 0 15px 35px rgba(0, 0, 0, 0.2);
    width: 100%;
    max-width: 400px;
    text-align: center;
}

.game-title {
    color: #333;
    font-size: 28px;
    margin-bottom: 10px;
    font-weight: bold;
}

.subtitle {
    color: #666;
    font-size: 16px;
    margin-bottom: 30px;
}

.form-group {
    margin-bottom: 20px;
    text-align: left;
}

label {
    display: block;
    margin-bottom: 8px;
    color: #333;
    font-weight: bold;
}

input[type="text"], input[type="password"] {
    width: 100%;
    padding: 12px;
    border: 2px solid #ddd;
    border-radius: 8px;
    font-size: 16px;
    box-sizing: border-box;
    transition: border-color 0.3s;
}

input[type="text"]:focus, input[type="password"]:focus {
    outline: none;
    border-color: #667eea;
}

.button-group {
    display: flex;
    gap: 15px;
    margin-top: 30px;
}

button {
    flex: 1;
    padding: 12px 20px;
    border: none;
    border-radius: 8px;
    font-size: 16px;
    font-weight: bold;
    cursor: pointer;
    transition: all 0.3s;
}

.login-btn {
    background: #667eea;
    color: white;
}

.login-btn:hover {
    background: #5a6fd8;
    transform: translateY(-2px);
}

.register-btn {
    background: #48bb78;
    color: white;
}

.register-btn:hover {
    background: #38a169;
    transform: translateY(-2px);
}

.error-message {
    background: #fed7d7;
    color: #c53030;
    padding: 12px;
    border-radius: 8px;
    margin-bottom: 20px;
    border-left: 4px solid #c53030;
}

.success-message {
    background: #c6f6d5;
    color: #2f855a;
    padding: 12px;
    border-radius: 8px;
    margin-bottom: 20px;
    border-left: 4px solid #2f855a;
}

.game-info {
    background: #f7fafc;
    padding: 20px;
    border-radius: 8px;
    margin-top: 30px;
    color: #666;
    font-size: 14px;
}

.emoji {
    font-size: 24px;
    margin: 0 5px;
}

2.2 メイン画面

スクリーンショット 2025-06-26 082838.png

index.php
<?php
// セッションの開始
session_start();

// データベース接続ファイルを読み込み
require_once 'db_connect.php';

// ユーザーをデータベースに保存する関数
function saveUserToDB($username) {
    // $pdo = connectDB();
    
    // 既に同じ名前のユーザーが存在するかチェック
    $stmt = $pdo->prepare("SELECT id FROM status WHERE name = ?");
    $stmt->execute([$username]);
    
    if ($stmt->rowCount() == 0) {
        // 新規ユーザーの場合、データベースに保存(全フィールドに初期値を設定)
        $stmt = $pdo->prepare("
            INSERT INTO status (
                name, winRate, drawRate, loseRate, handCount, 
                guuRatio, chokiRatio, paaRatio, point
            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
        ");
        $stmt->execute([
            $username,  // name
            0,          // winRate (初期勝率0%)
            0,          // drawRate (初期引き分け率0%)
            0,          // loseRate (初期負け率0%)
            0,          // handCount (初期手数0)
            0,          // gu-Ratio (初期グー比率0%)
            0,          // chokiRatio (初期チョキ比率0%)
            0,          // pa-Ratio (初期パー比率0%)
            1000        // point (初期ポイント1000)
        ]);
        return $pdo->lastInsertId(); // 新しく作成されたIDを返す
    } else {
        // 既存ユーザーの場合、IDを取得
        $user = $stmt->fetch(PDO::FETCH_ASSOC);
        return $user['id'];
    }
}


// ページ遷移の処理
if (isset($_POST['action'])) {
    switch ($_POST['action']) {
        case 'game':
            if (!isset($_SESSION['name'])) {
                header('Location: login.php');
                exit();
            } else {
                header('Location: game.php');
                exit();
            }
            break;
        case 'ranking':
            header('Location: ranking.php');
            exit();
            break;
        case 'status':
            if (!isset($_SESSION['name'])) {
                header('Location: login.php');
                exit();
            } else {
                header('Location: status.php');
                exit();
            }
            break;
        case 'logout':
            // セッションの完全削除
            $_SESSION = [];
            setcookie(session_name(), '', time() - 1, '/');
            session_destroy();
            header('Location: login.php');
            exit();
            break;
    }
}

// IDチェックとプレイヤー情報の取得
if (!isset($_SESSION['id'])) {
    header('Location: login.php');
    exit();
}

?>
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>じゃんけんギャンブル</title>
	<link rel="stylesheet" href="style_index.css">
</head>
<body>
    <div class="container">
        <h1>🎲 じゃんけんギャンブル 🎲</h1>
        
        <div class="odds-info">
            <h3>📊 オッズ情報</h3>
            <div class="odds-table">
                <div class="odds-item">
                    <strong>✂️ チョキ</strong><br>
                    勝利: 2倍<br>
                    敗北: 2倍
                </div>
                <div class="odds-item">
                    <strong>👊 グー</strong><br>
                    勝利: 1.5倍<br>
                    敗北: 1.5倍
                </div>
                <div class="odds-item">
                    <strong>✋ パー</strong><br>
                    勝利: 5倍<br>
                    敗北: 5倍
                </div>
            </div>
        </div>

        <?php if (isset($_SESSION['name'])): ?>
        <div class="user-info">
            <h3>👤 ユーザー情報</h3>
            <p><strong>ID:</strong> <?= htmlspecialchars($_SESSION['id'] ?? 'N/A') ?></p>
            <p><strong>名前:</strong> <?= htmlspecialchars($_SESSION['name']) ?></p>
            <p><strong>所持ポイント:</strong> <?= number_format($_SESSION['point'] ?? 1000) ?> pt</p>
        </div>
        <?php endif; ?>

        <?php if (isset($error_msg)): ?>
        <div class="error">
            ⚠️ <?= htmlspecialchars($error_msg) ?>
        </div>
        <?php endif; ?>



        <div class="navigation">
            <form method="POST" style="margin: 0;">
                <input type="hidden" name="action" value="game">
                <button type="submit">🎮 ゲーム画面</button>
            </form>
            
            <form method="POST" style="margin: 0;">
                <input type="hidden" name="action" value="status">
                <button type="submit">📊 ステータス</button>
            </form>
            
            <form method="POST" style="margin: 0;">
                <input type="hidden" name="action" value="ranking">
                <button type="submit">🏆 ランキング</button>
            </form>
            
            <?php if (isset($_SESSION['name'])): ?>
            <form method="POST" style="margin: 0;">
                <input type="hidden" name="action" value="logout">
                <button type="submit" class="reset-btn" onclick="return confirm('本当にログアウトしますか?')">👋 ログアウト</button>
            </form>
            <?php endif; ?>
        </div>

        <div style="margin-top: 30px; padding: 20px; background-color: #f0f0f0; border-radius: 5px;">
            <h3>📝 ゲームルール</h3>
            <ul>
                <li>初期ポイント: 1000pt</li>
                <li>じゃんけんで勝負し、賭けたポイントがオッズに応じて増減します</li>
                <li>勝てば賭けたポイント × オッズ分のポイントを獲得します</li>
                <li>負ければ賭けたポイント × オッズ分のポイントを失います</li>
                <li>あいこの場合は賭けたポイントはそのまま返却</li>
            </ul>
        </div>
    </div>
</body>
</html>
style_index.css

body {
    font-family: Arial, sans-serif;
    max-width: 800px;
    margin: 0 auto;
    padding: 20px;
    background-color: #f5f5f5;
}
.container {
    background-color: white;
    padding: 30px;
    border-radius: 10px;
    box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
h1 {
    color: #333;
    text-align: center;
    border-bottom: 3px solid #4CAF50;
    padding-bottom: 10px;
}
.odds-info {
    background-color: #e8f5e8;
    padding: 15px;
    border-radius: 5px;
    margin: 20px 0;
}
.odds-info h3 {
    margin-top: 0;
    color: #2e7d32;
}
.odds-table {
    display: flex;
    justify-content: space-around;
    text-align: center;
}
.odds-item {
    flex: 1;
    padding: 10px;
}
.form-section {
    background-color: #f9f9f9;
    padding: 20px;
    border-radius: 5px;
    margin: 20px 0;
}
.user-info {
    background-color: #e3f2fd;
    padding: 15px;
    border-radius: 5px;
    margin: 20px 0;
}
.error {
    background-color: #ffebee;
    color: #c62828;
    padding: 10px;
    border-radius: 5px;
    margin: 10px 0;
    border-left: 4px solid #c62828;
}
.navigation {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 10px;
    margin: 20px 0;
}
button, input[type="submit"] {
    background-color: #4CAF50;
    color: white;
    padding: 12px 20px;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    font-size: 16px;
    transition: background-color 0.3s;
}
button:hover, input[type="submit"]:hover {
    background-color: #45a049;
}
.reset-btn {
    background-color: #f44336;
}
.reset-btn:hover {
    background-color: #da190b;
}
input[type="text"] {
    width: 100%;
    padding: 10px;
    border: 2px solid #ddd;
    border-radius: 5px;
    font-size: 16px;
    margin-top: 5px;
}
input[type="text"]:focus {
    border-color: #4CAF50;
    outline: none;
}
label {
    font-weight: bold;
    color: #333;
}
small {
    color: #666;
}


1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?