บทเรียนการสร้างเว็บไซต์พื้นฐาน

การทำงานกับเซิร์ฟเวอร์และฐานข้อมูล (PHP & MySQL)

บทเรียนนี้จะพาเข้าสู่โลกของ Backend ด้วย PHP (Hypertext Preprocessor) ซึ่งเป็นภาษา Scripting ที่ทำงานบนเซิร์ฟเวอร์ และ MySQL ซึ่งเป็นระบบจัดการฐานข้อมูลเชิงสัมพันธ์

4.1 ทำความรู้จักกับ Backend และ PHP

Backend คืออะไร?

Backend คือส่วนที่ทำงานอยู่เบื้องหลังเว็บไซต์บนเซิร์ฟเวอร์ มีหน้าที่จัดการตรรกะทางธุรกิจ, การเชื่อมต่อฐานข้อมูล, การประมวลผลข้อมูลที่ส่งมาจากผู้ใช้, และการรักษาความปลอดภัย

PHP คืออะไร?

PHP เป็นภาษา Scripting ที่ทำงานบนฝั่งเซิร์ฟเวอร์ (Server-Side Scripting) มีความสามารถในการสร้างเนื้อหา HTML แบบไดนามิก (Dynamic HTML)

การติดตั้งสภาพแวดล้อม

ในการรันโค้ด PHP และ MySQL บนเครื่องของคุณ คุณต้องติดตั้งชุดซอฟต์แวร์ที่จำลองสภาพแวดล้อมเซิร์ฟเวอร์ เช่น:

  • XAMPP: (X-platform, Apache, MySQL, PHP, Perl)
  • WAMP: (Windows, Apache, MySQL, PHP)
  • MAMP: (Mac, Apache, MySQL, PHP)

4.2 พื้นฐานภาษา PHP

โค้ด PHP จะถูกเขียนอยู่ภายในแท็ก <?php และ ?>

Syntax และการแสดงผล

<?php
    // นี่คือคอมเมนต์ใน PHP
    echo "สวัสดี, โลก!"; // คำสั่ง echo ใช้ในการแสดงผลออกไปยังเบราว์เซอร์
    $name = "Manus"; // การประกาศตัวแปรขึ้นต้นด้วยเครื่องหมาย $
    echo "<h1>ยินดีต้อนรับ, " . $name . "</h1>"; // การเชื่อมข้อความ (Concatenation) ใช้เครื่องหมายจุด (.)
?>

<!-- โค้ด HTML สามารถอยู่ร่วมกับ PHP ได้ -->
<p>ข้อความนี้มาจาก HTML</p>

ตัวแปร, ชนิดข้อมูล และ Array

แนวคิด คำอธิบาย ตัวอย่างโค้ด
ตัวแปร ขึ้นต้นด้วย $ ไม่ต้องประกาศชนิดข้อมูล $age = 30; (Integer)
$price = 199.99; (Float)
$is_active = true; (Boolean)
Array ใช้เก็บชุดข้อมูลที่มีความสัมพันธ์กัน $colors = array("Red", "Green", "Blue");
echo $colors[0]; // Output: Red
Associative Array Array ที่ใช้ Key เป็นข้อความ $user = ["name" => "Alice", "age" => 25];
echo $user["name"]; // Output: Alice

โครงสร้างควบคุม

คล้ายกับ JavaScript แต่ใช้ if, else, while, for

<?php
    $score = 75;

    if ($score >= 80) {
        echo "A";
    } elseif ($score >= 70) {
        echo "B";
    } else {
        echo "C";
    }

    // Loop
    for ($i = 1; $i <= 5; $i++) {
        echo "<p>รอบที่ $i</p>";
    }
?>

4.3 การทำงานกับฟอร์มด้วย PHP

PHP ใช้ Superglobal Variables ในการรับข้อมูลที่ส่งมาจากฟอร์ม HTML

การรับข้อมูลจากฟอร์ม

Superglobal วิธีการส่งข้อมูล คำอธิบาย
$_POST method="POST" ใช้สำหรับข้อมูลที่ละเอียดอ่อน (เช่น รหัสผ่าน) ข้อมูลไม่แสดงใน URL
$_GET method="GET" ใช้สำหรับข้อมูลที่ไม่ละเอียดอ่อน ข้อมูลแสดงใน URL (เหมาะสำหรับ Search/Filter)

ตัวอย่าง: ไฟล์ process_data.php

<?php
    // ตรวจสอบว่ามีการส่งข้อมูลแบบ POST มาหรือไม่
    if ($_SERVER["REQUEST_METHOD"] == "POST") {
        // รับค่าจากฟอร์ม โดยใช้ name attribute ของ input
        $username = $_POST['username'] ?? '';
        $password = $_POST['password'] ?? '';

        // ป้องกัน XSS ด้วย htmlspecialchars
        echo "<h2>ข้อมูลที่ได้รับ:</h2>";
        echo "<p>ชื่อผู้ใช้: " . htmlspecialchars($username, ENT_QUOTES, 'UTF-8') . "</p>";
        // ไม่ควรแสดงรหัสผ่านจริง
        echo "<p>รหัสผ่านได้รับแล้ว</p>";
    } else {
        // ถ้าเข้าถึงโดยตรง
        header("Location: index.html");
        exit();
    }
?>

ใช้สำหรับเก็บสถานะของผู้ใช้ระหว่างการเข้าชมหน้าต่างๆ (เช่น ระบบ Login)

ฟังก์ชัน หน้าที่
session_start() ต้องเรียกใช้ก่อนโค้ด HTML เพื่อเริ่ม Session
$_SESSION['key'] = value; เก็บข้อมูลใน Session
setcookie('key', 'value', time() + 3600); ตั้งค่า Cookie (เก็บข้อมูลบนเครื่อง Client)

4.4 พื้นฐานฐานข้อมูล MySQL

MySQL เป็นระบบจัดการฐานข้อมูลเชิงสัมพันธ์ (Relational Database Management System - RDBMS) ที่ได้รับความนิยม

แนวคิดฐานข้อมูลเชิงสัมพันธ์

  • Database: ฐานข้อมูลหลัก (เช่น my_website_db)
  • Table: ตารางที่ใช้เก็บข้อมูลที่มีโครงสร้าง (เช่น users, products)
  • Column: คอลัมน์หรือฟิลด์ที่กำหนดชนิดของข้อมูล (เช่น id, name, email)
  • Row/Record: แถวที่เก็บข้อมูลจริงแต่ละรายการ

SQL เบื้องต้น (Structured Query Language)

SQL คือภาษาที่ใช้ในการจัดการฐานข้อมูล

คำสั่ง หน้าที่ ตัวอย่าง
SELECT ดึงข้อมูล SELECT name, email FROM users WHERE age > 18;
INSERT เพิ่มข้อมูล INSERT INTO users (name, email) VALUES ('Alice', 'a@mail.com');
UPDATE แก้ไขข้อมูล UPDATE users SET email = 'new@mail.com' WHERE id = 1;
DELETE ลบข้อมูล DELETE FROM users WHERE id = 5;

4.5 การเชื่อมต่อ PHP กับ MySQL ด้วย PDO

เราจะใช้ PDO (PHP Data Objects) ซึ่งเป็นวิธีที่ทันสมัยและปลอดภัยกว่าในการเชื่อมต่อฐานข้อมูล

ทำไมต้องใช้ PDO?

ข้อดีของ PDO คำอธิบาย
รองรับหลายฐานข้อมูล สามารถใช้กับ MySQL, PostgreSQL, SQLite ฯลฯ
Prepared Statements ป้องกัน SQL Injection ได้ดีกว่า
Object-Oriented เขียนโค้ดได้สะอาดและจัดการ Error ได้ดีกว่า
Named Parameters ใช้ชื่อแทนเครื่องหมาย ? ทำให้อ่านง่าย

ขั้นตอนการเชื่อมต่อ

<?php
    $host = "localhost";
    $dbname = "my_website_db";
    $username = "root";
    $password = "";

    try {
        // สร้าง PDO Connection
        $pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $username, $password);

        // ตั้งค่า Error Mode เป็น Exception
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

        // ตั้งค่าให้ fetch ข้อมูลเป็น Associative Array
        $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);

        echo "Connected successfully";
    } catch(PDOException $e) {
        // ในโปรเจกต์จริง ไม่ควรแสดง error message โดยตรง
        die("Connection failed: " . $e->getMessage());
    }
?>

4.6 การสร้างระบบ CRUD (Create, Read, Update, Delete) ด้วย PDO

นี่คือหัวใจของการพัฒนาเว็บแบบมีฐานข้อมูล โดยใช้ Prepared Statements เพื่อความปลอดภัย

1. Read (การดึงข้อมูล)

<?php
    try {
        // ดึงข้อมูลทั้งหมด
        $stmt = $pdo->query("SELECT id, name, email FROM users");
        $users = $stmt->fetchAll();

        foreach ($users as $user) {
            echo "ID: " . htmlspecialchars($user['id']) . " - ";
            echo "Name: " . htmlspecialchars($user['name']) . " - ";
            echo "Email: " . htmlspecialchars($user['email']) . "<br>";
        }

        // ดึงข้อมูลตามเงื่อนไข (ใช้ Prepared Statement)
        $stmt = $pdo->prepare("SELECT * FROM users WHERE age > :age");
        $stmt->execute(['age' => 18]);
        $adults = $stmt->fetchAll();

    } catch(PDOException $e) {
        echo "Error: " . $e->getMessage();
    }
?>

2. Create (การเพิ่มข้อมูล)

<?php
    try {
        // ใช้ Named Parameters (:name, :email)
        $stmt = $pdo->prepare("INSERT INTO users (name, email, age) VALUES (:name, :email, :age)");

        $stmt->execute([
            'name' => 'Alice',
            'email' => 'alice@example.com',
            'age' => 25
        ]);

        echo "New record created successfully. ID: " . $pdo->lastInsertId();

    } catch(PDOException $e) {
        echo "Error: " . $e->getMessage();
    }
?>

3. Update (การแก้ไขข้อมูล)

<?php
    try {
        $stmt = $pdo->prepare("UPDATE users SET email = :email WHERE id = :id");

        $stmt->execute([
            'email' => 'newemail@example.com',
            'id' => 1
        ]);

        echo "Record updated successfully. Rows affected: " . $stmt->rowCount();

    } catch(PDOException $e) {
        echo "Error: " . $e->getMessage();
    }
?>

4. Delete (การลบข้อมูล)

<?php
    try {
        $stmt = $pdo->prepare("DELETE FROM users WHERE id = :id");
        $stmt->execute(['id' => 5]);

        echo "Record deleted successfully";

    } catch(PDOException $e) {
        echo "Error: " . $e->getMessage();
    }
?>

4.7 การรักษาความปลอดภัยฐานข้อมูล

ความปลอดภัยเป็นสิ่งสำคัญที่สุดในการพัฒนา Backend

1. การป้องกัน SQL Injection

SQL Injection คือการที่ผู้โจมตีใส่โค้ด SQL เข้าไปในช่องกรอกข้อมูล เพื่อให้เซิร์ฟเวอร์รันคำสั่งที่เป็นอันตราย

❌ วิธีที่ไม่ปลอดภัย:

// อันตราย! ไม่ควรทำแบบนี้
$username = $_POST['username'];
$sql = "SELECT * FROM users WHERE username = '$username'";
$result = $pdo->query($sql);

✅ วิธีที่ปลอดภัย - ใช้ Prepared Statements:

// ปลอดภัย
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username");
$stmt->execute(['username' => $_POST['username']]);
$user = $stmt->fetch();

2. การเข้ารหัสรหัสผ่าน (Password Hashing)

ห้ามเก็บรหัสผ่านเป็นข้อความธรรมดา ในฐานข้อมูล ต้องใช้ฟังก์ชัน Hashing

<?php
// การสมัครสมาชิก - เข้ารหัสรหัสผ่าน
$password = $_POST['password'];
$hashed_password = password_hash($password, PASSWORD_DEFAULT);

// บันทึกลงฐานข้อมูล
$stmt = $pdo->prepare("INSERT INTO users (username, password) VALUES (:username, :password)");
$stmt->execute([
    'username' => $_POST['username'],
    'password' => $hashed_password
]);

// การเข้าสู่ระบบ - ตรวจสอบรหัสผ่าน
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username");
$stmt->execute(['username' => $_POST['username']]);
$user = $stmt->fetch();

if ($user && password_verify($_POST['password'], $user['password'])) {
    echo "เข้าสู่ระบบสำเร็จ";
    $_SESSION['user_id'] = $user['id'];
} else {
    echo "ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง";
}
?>

3. การป้องกัน XSS (Cross-Site Scripting)

ใช้ htmlspecialchars() เมื่อแสดงข้อมูลที่มาจากผู้ใช้

<?php
// ป้องกัน XSS
$user_input = $_POST['comment'];
echo htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8');
?>

4. การจำกัดสิทธิ์ฐานข้อมูล

  • สร้าง User ฐานข้อมูลแยกสำหรับแต่ละแอปพลิเคชัน
  • ให้สิทธิ์เฉพาะที่จำเป็น (ไม่ใช้ root)
  • ใช้รหัสผ่านที่แข็งแรง
-- สร้าง User ใหม่
CREATE USER 'webapp_user'@'localhost' IDENTIFIED BY 'strong_password';

-- ให้สิทธิ์เฉพาะที่จำเป็น
GRANT SELECT, INSERT, UPDATE, DELETE ON my_website_db.* TO 'webapp_user'@'localhost';

FLUSH PRIVILEGES;

5. การใช้ Environment Variables

ไม่ควรเขียนข้อมูลการเชื่อมต่อฐานข้อมูลในโค้ดโดยตรง

<?php
// ไฟล์ config.php
$host = getenv('DB_HOST') ?: 'localhost';
$dbname = getenv('DB_NAME') ?: 'my_website_db';
$username = getenv('DB_USER') ?: 'root';
$password = getenv('DB_PASS') ?: '';

try {
    $pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $username, $password);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
} catch(PDOException $e) {
    // Log error แทนการแสดงผล
    error_log("Database connection failed: " . $e->getMessage());
    die("เกิดข้อผิดพลาดในการเชื่อมต่อฐานข้อมูล");
}
?>

แบบฝึกหัดท้ายบท

  1. ติดตั้ง XAMPP/WAMP/MAMP และสร้างฐานข้อมูล MySQL ชื่อ my_project
  2. สร้างไฟล์ PHP ที่ใช้ PDO เชื่อมต่อกับฐานข้อมูล
  3. สร้างตาราง products ด้วย SQL และเพิ่มข้อมูลตัวอย่าง
  4. เขียนโค้ด PHP เพื่อดึงข้อมูลจากตาราง products ด้วย PDO
  5. สร้างระบบ CRUD สำหรับจัดการสินค้า โดยใช้ Prepared Statements
  6. เพิ่มระบบ Login ที่มีการเข้ารหัสรหัสผ่านด้วย password_hash()

ในบทถัดไป เราจะเรียนรู้เกี่ยวกับ Responsive Web Design และการรักษาความปลอดภัยเว็บไซต์เพิ่มเติม