Cách sử dụng câu lệnh include, require trong PHP
Trong bài này, chúng ta sẽ tìm hiểu cách sử dụng câu lệnh include, require trong...
Kết quả sẽ mở trong tab mới, giới hạn trong website này.
Truy cập nhanh
Tìm kiếm gần đây
Đồ án web PHP chạy được vẫn có thể bị trừ điểm. Bài viết tổng hợp 7 lỗi sinh viên hay mắc khi làm web với PHP và MySQL, kèm code sửa và checklist trước khi nộp.
Đồ án web PHP của sinh viên thường chạy được, nhưng vẫn bị trừ điểm vì những lỗi lặp lại năm này qua năm khác. Bài này tổng hợp 7 lỗi hay gặp nhất khi làm web với PHP và MySQL, kèm cách sửa bằng code cụ thể.
Các ví dụ dùng PDO. Nếu chưa từng dùng PDO, các bạn xem lại bài kết nối MySQL với PHP sử dụng PDO trước nhé.
Mục tiêu bài học:
Nhóm lỗi này nguy hiểm nhất. Web vẫn chạy bình thường, nên sinh viên thường không biết mình đang mắc lỗi.
Đây là code đăng nhập rất hay gặp trong đồ án:
// SAI: ghép thẳng dữ liệu từ form vào câu SQL
$username = $_POST['username'];
$password = $_POST['password'];
$sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
$result = $conn->query($sql);Giả sử người dùng nhập tên đăng nhập là admin' -- (có dấu cách sau hai dấu gạch). Câu SQL sẽ thành:
SELECT * FROM users WHERE username = 'admin' -- ' AND password = '...'Phần sau -- bị MySQL coi là chú thích. Điều kiện mật khẩu biến mất, và người lạ vào được tài khoản admin. Kiểu tấn công này gọi là SQL injection (chèn mã SQL).
Cách sửa là dùng prepared statement. Câu SQL chỉ chứa dấu ?, dữ liệu được truyền riêng qua execute():
// ĐÚNG: dùng prepared statement
$sql = "SELECT * FROM users WHERE username = ?";
$stmt = $conn->prepare($sql);
$stmt->execute([$username]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);Mẹo: Câu SQL nào có biến lấy từ $_GET, $_POST, $_COOKIE thì phải dùng prepared statement. Không có ngoại lệ, kể cả khi đã validate form.
Mở phpMyAdmin mà thấy cột password ghi rõ “123456” là toang. Ai xem được database cũng biết mật khẩu của mọi người.
Dùng md5() cũng không an toàn hơn bao nhiêu. Hàm này quá nhanh, và các mật khẩu phổ biến đã có sẵn bảng tra ngược trên mạng.
PHP có sẵn hàm password_hash() để băm mật khẩu. Khi đăng ký:
// Đăng ký: băm mật khẩu trước khi lưu
$hash = password_hash($_POST['password'], PASSWORD_DEFAULT);
$stmt = $conn->prepare("INSERT INTO users (username, password) VALUES (?, ?)");
$stmt->execute([$_POST['username'], $hash]);Khi đăng nhập, lấy user theo tên rồi so khớp bằng password_verify():
// Đăng nhập: kiểm tra mật khẩu với chuỗi đã băm
session_start(); // đặt ở đầu file
if ($user && password_verify($_POST['password'], $user['password'])) {
session_regenerate_id(true); // cấp session ID mới sau khi đăng nhập
$_SESSION['user_id'] = $user['id'];
$_SESSION['role'] = $user['role'];
header('Location: index.php');
exit;
}
echo 'Sai tên đăng nhập hoặc mật khẩu';Không so sánh kiểu WHERE password = ... nữa. Mỗi lần băm, password_hash() cho ra một chuỗi khác nhau, nên chỉ password_verify() mới kiểm tra được.
Lưu ý: Đặt cột password là VARCHAR(255). Chuỗi băm hiện dài 60 ký tự, nhưng có thể dài hơn khi PHP đổi thuật toán mặc định.
Trang bình luận, trang tìm kiếm thường in thẳng dữ liệu người dùng nhập. Nếu ai đó gửi nội dung <script>...</script>, đoạn script sẽ chạy trên máy mọi người xem trang. Lỗi này gọi là XSS (Cross-Site Scripting).
// SAI
echo "<p>" . $row['content'] . "</p>";
// ĐÚNG: chuyển ký tự đặc biệt thành dạng an toàn
echo "<p>" . htmlspecialchars($row['content'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8') . "</p>";Sau khi escape, trình duyệt chỉ hiển thị chữ <script> chứ không chạy nó.
ENT_SUBSTITUTE giữ lại dữ liệu khi gặp ký tự UTF-8 hỏng, thay vì trả về chuỗi rỗng. Nếu cột trong database có thể NULL, viết $row['content'] ?? '' để tránh thông báo Deprecated (PHP 8.1 trở lên). Lưu ý: htmlspecialchars() chỉ an toàn khi in vào nội dung HTML hoặc thuộc tính có dấu nháy, không dùng để in dữ liệu vào bên trong thẻ <script>.
Nhiều nhóm chỉ ẩn nút “Quản trị” trên menu khi chưa đăng nhập. Nhưng ai gõ thẳng địa chỉ admin/xoa_sach.php?id=5 vẫn vào được.
Hãy tạo file admin/check_login.php và require nó ở dòng đầu mọi trang admin:
<?php
// admin/check_login.php
session_start();
if (!isset($_SESSION['user_id']) || ($_SESSION['role'] ?? '') !== 'admin') {
header('Location: ../login.php');
exit; // Bắt buộc: không có exit thì code bên dưới vẫn chạy
}Chú ý dòng exit. Hàm header() chỉ gửi lệnh chuyển trang cho trình duyệt. Thiếu exit, phần xóa dữ liệu phía dưới vẫn được thực thi. Ngoài ra, thao tác xóa, sửa nên gửi bằng form POST thay vì link GET như xoa_sach.php?id=5, để không ai lừa admin bấm vào một đường link xóa dữ liệu.
Cảnh báo: Chức năng upload ảnh cũng là lỗ hổng hay gặp. Nếu không giới hạn đuôi file, người khác có thể upload file .php rồi chạy nó trên server. Chỉ cho phép một danh sách đuôi cố định như jpg, png, webp. Xem thêm bài xử lý upload file với PHP.
Dữ liệu nhập vào hiện thành “Láºp trình” hoặc dấu hỏi chấm. Nguyên nhân là bảng mã không thống nhất giữa database, kết nối PHP và trang HTML.
Cần dùng UTF-8 ở cả ba chỗ. Với MySQL, nên chọn utf8mb4 ngay khi tạo database:
CREATE DATABASE quanlysach CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;Trong chuỗi kết nối PDO, thêm charset=utf8mb4 (xem code ở lỗi 6). Trang HTML thì có thẻ <meta charset="UTF-8">, và file code được lưu với encoding UTF-8.
Đồ án có 20 trang thì có 20 đoạn new PDO(...) giống nhau. Đến lúc đổi tên database hay mật khẩu, sửa sót một file là trang đó lỗi ngay.
Gom phần kết nối vào một file config.php:
<?php
// config.php: khai báo kết nối một lần duy nhất
$dbHost = 'localhost';
$dbName = 'quanlysach';
$dbUser = 'root';
$dbPass = '';
try {
$conn = new PDO("mysql:host=$dbHost;dbname=$dbName;charset=utf8mb4", $dbUser, $dbPass);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die('Không kết nối được database');
}Các trang khác chỉ cần một dòng require_once 'config.php';. Cách dùng chi tiết có trong bài câu lệnh include, require trong PHP.
Code chạy ngon lành trên máy mình, nhưng mang sang máy giáo viên thì trắng trang. Có ba nguyên nhân thường gặp.
.sql và nộp kèm.http://localhost/doan_nhom3/sach.php hỏng ngay khi đổi tên thư mục. Hãy dùng đường dẫn tương đối như sach.php hoặc ../login.php.README.txt.Trước buổi demo, mở thử từng trang và xử lý hết các dòng Warning, Notice hiện lên. Đừng giấu lỗi bằng dấu @ trước hàm. Xem lại bài các loại lỗi trong PHP để đọc hiểu thông báo lỗi.
password_hash().htmlspecialchars().require file kiểm tra đăng nhập.config.php..sql và README.txt ghi tài khoản test.Đi hết 8 dòng trên là đồ án của các bạn đã tránh được phần lớn lỗi mà giáo viên hay bắt. Phần còn lại là giao diện và tính năng, chỗ để nhóm ghi điểm.
Tài liệu tham khảo: