Tạo chức năng CRUD (Thêm, Sửa, Xóa, Xem) upload hình Sản phẩm (upload đơn, mỗi lần 1 file)

  • Để upload file lên Server thì chúng ta phải sử dụng form có thuộc tính enctype="multipart/form-data" và phương thức POST, thẻ input sẽ có type="file".
  • Khi chúng ta upload một file lên thì trên Server sẽ nhận được 5 thông số cho một file, và PHP sẽ dựa vào các thông số đó để tiến hành upload, các thông số đó là:
    • name: Tên của file chúng ta upload
    • type: Kiểu file mà chúng ta upload (hình ảnh, word, …)
    • tmp_name: Đường dẫn đến file tạm trên web server
    • error: Trạng thái của file chúng ta upload, 0 => không có lỗi
    • size: Kích thước của file chúng ta upload

Lưu đồ hoạt động của quá trình Upload file từ Client lên Server

Step 1: tạo cấu trúc thư mục cho chức năng CRUD Hình Sản phẩm

  • Để tiện cho việc quản lý, ta sẽ tạo cấu trúc thư mục tương ứng với tên của từng chức năng
  • Tạo thư mục /backend/functions/hinhsanpham dùng để quản lý các chức năng CRUD của danh mục Hình sản phẩm

Step 2: tạo chức năng create dùng để hiển thị FORM thêm mới Hình Sản phẩm

  • Tạo file /backend/functions/hinhsanpham/create.php để xử lý logic/nghiệp vụ
  • Nội dung file:
<!-- Nhúng file cấu hình để xác định được Tên và Tiêu đề của trang hiện tại người dùng đang truy cập -->
<?php include_once(__DIR__ . '/../../layouts/config.php'); ?>

<!DOCTYPE html>
<html>

<head>
  <!-- Nhúng file quản lý phần HEAD -->
  <?php include_once(__DIR__ . '/../../layouts/head.php'); ?>
</head>

<body class="d-flex flex-column h-100">
  <!-- header -->
  <?php include_once(__DIR__ . '/../../layouts/partials/header.php'); ?>
  <!-- end header -->

  <div class="container-fluid">
    <div class="row">
      <!-- sidebar -->
      <?php include_once(__DIR__ . '/../../layouts/partials/sidebar.php'); ?>
      <!-- end sidebar -->

      <main role="main" class="col-md-10 ml-sm-auto px-4 mb-2">
        <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
          <h1 class="h2">Thêm mới</h1>
        </div>

        <!-- Block content -->
        <?php
        // Hiển thị tất cả lỗi trong PHP
        // Chỉ nên hiển thị lỗi khi đang trong môi trường Phát triển (Development)
        // Không nên hiển thị lỗi trên môi trường Triển khai (Production)
        ini_set('display_errors', 1);
        ini_set('display_startup_errors', 1);
        error_reporting(E_ALL);

        // Truy vấn database
        // 1. Include file cấu hình kết nối đến database, khởi tạo kết nối $conn
        include_once(__DIR__ . '/../../../dbconnect.php');

        /*  --- 
        --- 2.Truy vấn dữ liệu sản phẩm 
        --- 
        */
        // Chuẩn bị câu truy vấn sản phẩm
        $sqlSanPham = "select * from `sanpham`";

        // Thực thi câu truy vấn SQL để lấy về dữ liệu
        $resultSanPham = mysqli_query($conn, $sqlSanPham);

        // Khi thực thi các truy vấn dạng SELECT, dữ liệu lấy về cần phải phân tích để sử dụng
        // Thông thường, chúng ta sẽ sử dụng vòng lặp while để duyệt danh sách các dòng dữ liệu được SELECT
        // Ta sẽ tạo 1 mảng array để chứa các dữ liệu được trả về
        $dataSanPham = [];
        while ($rowSanPham = mysqli_fetch_array($resultSanPham, MYSQLI_ASSOC)) {
          // Sử dụng hàm sprintf() để chuẩn bị mẫu câu với các giá trị truyền vào tương ứng từng vị trí placeholder
          $sp_tomtat = sprintf(
            "Sản phẩm %s, giá: %s",
            $rowSanPham['sp_ten'],
            number_format($rowSanPham['sp_gia'], 2, ".", ",") . ' vnđ'
          );

          $dataSanPham[] = array(
            'sp_ma' => $rowSanPham['sp_ma'],
            'sp_tomtat' => $sp_tomtat,
          );
        }
        // var_dump($dataSanPham);die;
        /* --- End Truy vấn dữ liệu sản phẩm --- */
        ?>

        <!-- Form cho phép người dùng upload file lên Server bắt buộc phải có thuộc tính enctype="multipart/form-data" -->
        <form name="frmhinhsanpham" id="frmhinhanpham" method="post" action="" enctype="multipart/form-data">
          <div class="form-group">
            <label for="sp_ma">Sản phẩm</label>
            <select class="form-control" id="sp_ma" name="sp_ma">
              <?php foreach ($dataSanPham as $sanpham) : ?>
                <option value="<?= $sanpham['sp_ma'] ?>"><?= $sanpham['sp_tomtat'] ?></option>
              <?php endforeach; ?>
            </select>
          </div>
          <div class="form-group">
            <label for="hsp_tentaptin">Tập tin ảnh</label>

            <!-- Tạo khung div hiển thị ảnh cho người dùng Xem trước khi upload file lên Server -->
            <div class="preview-img-container">
              <img src="/php/myhand/assets/shared/img/default-image_600.png" id="preview-img" width="200px" />
            </div>

            <!-- Input cho phép người dùng chọn FILE -->
            <input type="file" class="form-control" id="hsp_tentaptin" name="hsp_tentaptin">
          </div>
          <button class="btn btn-primary" name="btnSave">Lưu</button>
          <a href="index.php" class="btn btn-outline-secondary" name="btnBack" id="btnBack">Quay về</a>
        </form>

        <?php
        // 3. Nếu người dùng có bấm nút Đăng ký thì thực thi câu lệnh UPDATE
        if (isset($_POST['btnSave'])) {
          // Lấy dữ liệu người dùng hiệu chỉnh gởi từ REQUEST POST
          $sp_ma = $_POST['sp_ma'];

          // Nếu người dùng có chọn file để upload
          if (isset($_FILES['hsp_tentaptin'])) {
            // Đường dẫn để chứa thư mục upload trên ứng dụng web của chúng ta. Các bạn có thể tùy chỉnh theo ý các bạn.
            // Ví dụ: các file upload sẽ được lưu vào thư mục ../../../assets/uploads
            $upload_dir = __DIR__ . "/../../../assets/uploads/";
            // Các hình ảnh sẽ được lưu trong thư mục con `products` để tiện quản lý
            $subdir = 'products/';

            // Đối với mỗi file, sẽ có các thuộc tính như sau:
            // $_FILES['hsp_tentaptin']['name']     : Tên của file chúng ta upload
            // $_FILES['hsp_tentaptin']['type']     : Kiểu file mà chúng ta upload (hình ảnh, word, excel, pdf, txt, ...)
            // $_FILES['hsp_tentaptin']['tmp_name'] : Đường dẫn đến file tạm trên web server
            // $_FILES['hsp_tentaptin']['error']    : Trạng thái của file chúng ta upload, 0 => không có lỗi
            // $_FILES['hsp_tentaptin']['size']     : Kích thước của file chúng ta upload

            // 3.1. Chuyển file từ thư mục tạm vào thư mục Uploads
            // Nếu file upload bị lỗi, tức là thuộc tính error > 0
            if ($_FILES['hsp_tentaptin']['error'] > 0) {
              echo 'File Upload Bị Lỗi'; die;
            } else {
              // Để tránh trường hợp có 2 người dùng cùng lúc upload tập tin trùng tên nhau
              // Ví dụ:
              // - Người 1: upload tập tin hình ảnh tên `hoahong.jpg`
              // - Người 2: cũng upload tập tin hình ảnh tên `hoahong.jpg`
              // => dẫn đến tên tin trong thư mục chỉ còn lại tập tin người dùng upload cuối cùng
              // Cách giải quyết đơn giản là chúng ta sẽ ghép thêm ngày giờ vào tên file
              $hsp_tentaptin = $_FILES['hsp_tentaptin']['name'];
              $tentaptin = date('YmdHis') . '_' . $hsp_tentaptin; //20200530154922_hoahong.jpg

              // Tiến hành di chuyển file từ thư mục tạm trên server vào thư mục chúng ta muốn chứa các file uploads
              // Ví dụ: move file từ C:\xampp\tmp\php6091.tmp -> C:/xampp/htdocs/learning.nentang.vn/php/twig/assets/uploads/hoahong.jpg
              // var_dump($_FILES['hsp_tentaptin']['tmp_name']);
              // var_dump($upload_dir . $subdir . $tentaptin);

              move_uploaded_file($_FILES['hsp_tentaptin']['tmp_name'], $upload_dir . $subdir . $tentaptin);
            }

            // 3.2. Lưu thông tin file upload vào database
            // Câu lệnh INSERT
            $sql = "INSERT INTO `hinhsanpham` (hsp_tentaptin, sp_ma) VALUES ('$tentaptin', $sp_ma);";
            // print_r($sql); die;

            // Thực thi INSERT
            mysqli_query($conn, $sql);

            // Đóng kết nối
            mysqli_close($conn);

            // Sau khi cập nhật dữ liệu, tự động điều hướng về trang Danh sách
            echo '<script>location.href = "index.php";</script>';
          }
        }
        ?>
        <!-- End block content -->
      </main>
    </div>
  </div>

  <!-- footer -->
  <?php include_once(__DIR__ . '/../../layouts/partials/footer.php'); ?>
  <!-- end footer -->

  <!-- Nhúng file quản lý phần SCRIPT JAVASCRIPT -->
  <?php include_once(__DIR__ . '/../../layouts/scripts.php'); ?>

  <!-- Các file Javascript sử dụng riêng cho trang này, liên kết tại đây -->
  <script>
    // Hiển thị ảnh preview (xem trước) khi người dùng chọn Ảnh
    const reader = new FileReader();
    const fileInput = document.getElementById("hsp_tentaptin");
    const img = document.getElementById("preview-img");
    reader.onload = e => {
      img.src = e.target.result;
    }
    fileInput.addEventListener('change', e => {
      const f = e.target.files[0];
      reader.readAsDataURL(f);
    })
  </script>
</body>

</html>

Step 3: tạo chức năng index dùng để hiển thị màn hình danh sách các Hình Sản phẩm có trong database

  • Tạo file /backend/functions/hinhsanpham/index.php để xử lý logic/nghiệp vụ
  • Nội dung file:
<!-- Nhúng file cấu hình để xác định được Tên và Tiêu đề của trang hiện tại người dùng đang truy cập -->
<?php include_once(__DIR__ . '/../../layouts/config.php'); ?>

<!DOCTYPE html>
<html>

<head>
  <!-- Nhúng file quản lý phần HEAD -->
  <?php include_once(__DIR__ . '/../../layouts/head.php'); ?>
</head>

<body class="d-flex flex-column h-100">
  <!-- header -->
  <?php include_once(__DIR__ . '/../../layouts/partials/header.php'); ?>
  <!-- end header -->

  <div class="container-fluid">
    <div class="row">
      <!-- sidebar -->
      <?php include_once(__DIR__ . '/../../layouts/partials/sidebar.php'); ?>
      <!-- end sidebar -->

      <main role="main" class="col-md-10 ml-sm-auto px-4 mb-2">
        <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
          <h1 class="h2">Danh sách</h1>
        </div>

        <!-- Block content -->
        <?php
        // Hiển thị tất cả lỗi trong PHP
        // Chỉ nên hiển thị lỗi khi đang trong môi trường Phát triển (Development)
        // Không nên hiển thị lỗi trên môi trường Triển khai (Production)
        ini_set('display_errors', 1);
        ini_set('display_startup_errors', 1);
        error_reporting(E_ALL);

        // Truy vấn database
        // 1. Include file cấu hình kết nối đến database, khởi tạo kết nối $conn
        include_once(__DIR__ . '/../../../dbconnect.php');

        // 2. Chuẩn bị câu truy vấn $sql
        // Sử dụng HEREDOC của PHP để tạo câu truy vấn SQL với dạng dễ đọc, thân thiện với việc bảo trì code
        $sql = <<<EOT
        SELECT *
        FROM `hinhsanpham` hsp
        JOIN `sanpham` sp on hsp.sp_ma = sp.sp_ma
EOT;

        // 3. Thực thi câu truy vấn SQL để lấy về dữ liệu
        $result = mysqli_query($conn, $sql);
        // 4. Khi thực thi các truy vấn dạng SELECT, dữ liệu lấy về cần phải phân tích để sử dụng
        // Thông thường, chúng ta sẽ sử dụng vòng lặp while để duyệt danh sách các dòng dữ liệu được SELECT
        // Ta sẽ tạo 1 mảng array để chứa các dữ liệu được trả về
        $data = [];
        while ($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
          // Sử dụng hàm sprintf() để chuẩn bị mẫu câu với các giá trị truyền vào tương ứng từng vị trí placeholder
          $sp_tomtat = sprintf(
            "Sản phẩm %s, giá: %d",
            $row['sp_ten'],
            number_format($row['sp_gia'], 2, ".", ",") . ' vnđ'
          );

          $data[] = array(
            'hsp_ma' => $row['hsp_ma'],
            'hsp_tentaptin' => $row['hsp_tentaptin'],
            'sp_tomtat' => $sp_tomtat,
          );
        }
        /* --- End Truy vấn dữ liệu sản phẩm --- */
        ?>

        <!-- Nút thêm mới, bấm vào sẽ hiển thị form nhập thông tin Thêm mới -->
        <a href="create.php" class="btn btn-primary">
          Thêm mới
        </a>
        <table class="table table-bordered table-hover mt-2">
          <thead class="thead-dark">
            <tr>
              <th>Mã Hình Sản phẩm</th>
              <th>Hình ảnh</th>
              <th>Sản phẩm</th>
              <th>Hành động</th>
            </tr>
          </thead>
          <tbody>
            <?php foreach($data as $hinhsanpham): ?>
            <tr>
              <td><?= $hinhsanpham['hsp_ma'] ?></td>
              <td>
                <img src="/php/myhand/assets/uploads/products/<?= $hinhsanpham['hsp_tentaptin'] ?>" class="img-fluid" width="100px" />
              </td>
              <td><?= $hinhsanpham['sp_tomtat'] ?></td>
              <td>
                <!-- Nút sửa, bấm vào sẽ hiển thị form hiệu chỉnh thông tin dựa vào khóa chính `hsp_ma` -->
                <a href="edit.php?hsp_ma=<?= $hinhsanpham['hsp_ma'] ?>" class="btn btn-warning">
                  Sửa
                </a>

                <!-- Nút xóa, bấm vào sẽ xóa thông tin dựa vào khóa chính `sp_ma` -->
                <a href="delete.php?hsp_ma=<?= $hinhsanpham['hsp_ma'] ?>" class="btn btn-danger">
                  Xóa
                </a>
              </td>
            </tr>
            <?php endforeach; ?>
          </tbody>
        </table>
        <!-- End block content -->
      </main>
    </div>
  </div>

  <!-- footer -->
  <?php include_once(__DIR__ . '/../../layouts/partials/footer.php'); ?>
  <!-- end footer -->

  <!-- Nhúng file quản lý phần SCRIPT JAVASCRIPT -->
  <?php include_once(__DIR__ . '/../../layouts/scripts.php'); ?>

  <!-- Các file Javascript sử dụng riêng cho trang này, liên kết tại đây -->
  <!-- <script src="..."></script> -->
</body>

</html>

Step 4: tạo chức năng delete dùng để xóa Hình Sản phẩm

  • Tạo file /backend/functions/hinhsanpham/delete.php để xử lý logic/nghiệp vụ
  • Nội dung file:
<?php
// Hiển thị tất cả lỗi trong PHP
// Chỉ nên hiển thị lỗi khi đang trong môi trường Phát triển (Development)
// Không nên hiển thị lỗi trên môi trường Triển khai (Production)
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

// Truy vấn database
// 1. Include file cấu hình kết nối đến database, khởi tạo kết nối $conn
include_once(__DIR__ . '/../../../dbconnect.php');

/* --- 
   --- 2. Truy vấn dữ liệu Hình ảnh Sản phẩm theo khóa chính
   --- 
*/
// Chuẩn bị câu truy vấn $sqlSelect, lấy dữ liệu ban đầu của record cần update
// Lấy giá trị khóa chính được truyền theo dạng QueryString Parameter key1=value1&key2=value2...
$hsp_ma = $_GET['hsp_ma'];
$sqlSelect = "SELECT * FROM `hinhsanpham` WHERE hsp_ma=$hsp_ma;";
// var_dump($sqlSelect);die;

// Thực thi câu truy vấn SQL để lấy về dữ liệu ban đầu của record cần update
$resultSelect = mysqli_query($conn, $sqlSelect);
$hinhsanphamRow = mysqli_fetch_array($resultSelect, MYSQLI_ASSOC); // 1 record

/* --- End Truy vấn dữ liệu Sản phẩm theo khóa chính --- */

// 3. Xóa file cũ để tránh rác trong thư mục UPLOADS
// Đường dẫn để chứa thư mục upload trên ứng dụng web của chúng ta. Các bạn có thể tùy chỉnh theo ý các bạn.
// Ví dụ: các file upload sẽ được lưu vào thư mục ../../../assets/uploads
$upload_dir = __DIR__ . "/../../../assets/uploads/";
// Các hình ảnh sẽ được lưu trong thư mục con `products` để tiện quản lý
$subdir = 'products/';

// Kiểm tra nếu file có tổn tại thì xóa file đi
$old_file = $upload_dir . $subdir . $hinhsanphamRow['hsp_tentaptin'];
if (file_exists($old_file)) {
    // Hàm unlink(filepath) dùng để xóa file trong PHP
    unlink($old_file);
}

// 4. Chuẩn bị câu truy vấn $sql
// Lấy giá trị khóa chính được truyền theo dạng QueryString Parameter key1=value1&key2=value2...
$hsp_ma = $_GET['hsp_ma'];
$sql = "DELETE FROM `hinhsanpham` WHERE hsp_ma=" . $hsp_ma;

// 5. Thực thi câu lệnh DELETE
$result = mysqli_query($conn, $sql);

// 6. Đóng kết nối
mysqli_close($conn);

// Sau khi cập nhật dữ liệu, tự động điều hướng về trang Danh sách
header('location:index.php');

Step 5: tạo chức năng edit dùng để hiệu chỉnh Hình Sản phẩm

  • Tạo file /backend/functions/hinhsanpham/edit.php để xử lý logic/nghiệp vụ
  • Nội dung file:
<!-- Nhúng file cấu hình để xác định được Tên và Tiêu đề của trang hiện tại người dùng đang truy cập -->
<?php include_once(__DIR__ . '/../../layouts/config.php'); ?>

<!DOCTYPE html>
<html>

<head>
  <!-- Nhúng file quản lý phần HEAD -->
  <?php include_once(__DIR__ . '/../../layouts/head.php'); ?>
</head>

<body class="d-flex flex-column h-100">
  <!-- header -->
  <?php include_once(__DIR__ . '/../../layouts/partials/header.php'); ?>
  <!-- end header -->

  <div class="container-fluid">
    <div class="row">
      <!-- sidebar -->
      <?php include_once(__DIR__ . '/../../layouts/partials/sidebar.php'); ?>
      <!-- end sidebar -->

      <main role="main" class="col-md-10 ml-sm-auto px-4 mb-2">
        <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
          <h1 class="h2">Hiệu chỉnh</h1>
        </div>

        <!-- Block content -->
        <?php
        // Hiển thị tất cả lỗi trong PHP
        // Chỉ nên hiển thị lỗi khi đang trong môi trường Phát triển (Development)
        // Không nên hiển thị lỗi trên môi trường Triển khai (Production)
        ini_set('display_errors', 1);
        ini_set('display_startup_errors', 1);
        error_reporting(E_ALL);

        // Truy vấn database
        // 1. Include file cấu hình kết nối đến database, khởi tạo kết nối $conn
        include_once(__DIR__ . '/../../../dbconnect.php');

        /*  --- 
        --- 2.Truy vấn dữ liệu sản phẩm 
        --- 
        */
        // Chuẩn bị câu truy vấn sản phẩm
        $sqlSanPham = "select * from `sanpham`";

        // Thực thi câu truy vấn SQL để lấy về dữ liệu
        $resultSanPham = mysqli_query($conn, $sqlSanPham);

        // Khi thực thi các truy vấn dạng SELECT, dữ liệu lấy về cần phải phân tích để sử dụng
        // Thông thường, chúng ta sẽ sử dụng vòng lặp while để duyệt danh sách các dòng dữ liệu được SELECT
        // Ta sẽ tạo 1 mảng array để chứa các dữ liệu được trả về
        $dataSanPham = [];
        while ($rowSanPham = mysqli_fetch_array($resultSanPham, MYSQLI_ASSOC)) {
          // Sử dụng hàm sprintf() để chuẩn bị mẫu câu với các giá trị truyền vào tương ứng từng vị trí placeholder
          $sp_tomtat = sprintf(
            "Sản phẩm %s, giá: %d",
            $rowSanPham['sp_ten'],
            number_format($rowSanPham['sp_gia'], 2, ".", ",") . ' vnđ'
          );

          $dataSanPham[] = array(
            'sp_ma' => $rowSanPham['sp_ma'],
            'sp_tomtat' => $sp_tomtat
          );
        }
        /* --- End Truy vấn dữ liệu sản phẩm --- */

        /* --- 
          --- 3. Truy vấn dữ liệu Sản phẩm theo khóa chính
          --- 
        */
        // Chuẩn bị câu truy vấn $sqlSelect, lấy dữ liệu ban đầu của record cần update
        // Lấy giá trị khóa chính được truyền theo dạng QueryString Parameter key1=value1&key2=value2...
        $hsp_ma = $_GET['hsp_ma'];
        $sqlSelect = "SELECT * FROM `hinhsanpham` WHERE hsp_ma=$hsp_ma;";

        // Thực thi câu truy vấn SQL để lấy về dữ liệu ban đầu của record cần update
        $resultSelect = mysqli_query($conn, $sqlSelect);
        $hinhsanphamRow = mysqli_fetch_array($resultSelect, MYSQLI_ASSOC); // 1 record
        /* --- End Truy vấn dữ liệu Sản phẩm theo khóa chính --- */
        ?>

        <!-- Form cho phép người dùng upload file lên Server bắt buộc phải có thuộc tính enctype="multipart/form-data" -->
        <form name="frmhinhsanpham" id="frmhinhanpham" method="post" action="" enctype="multipart/form-data">
          <div class="form-group">
            <label for="">Hình ảnh hiện tại</label>
            <br />
            <img src="/php/myhand/assets/uploads/products/<?= $hinhsanphamRow['hsp_tentaptin'] ?>" class="img-fluid" width="300px" />
          </div>
          <div class="form-group">
            <label for="sp_ma">Sản phẩm</label>
            <select class="form-control" id="sp_ma" name="sp_ma" disabled="disabled">
              <?php foreach ($dataSanPham as $sanpham) : ?>
                <?php if ($sanpham['sp_ma'] == $hinhsanphamRow['sp_ma']) : ?>
                  <option value="<?= $sanpham['sp_ma'] ?>" selected><?= $sanpham['sp_tomtat'] ?></option>
                <?php else : ?>
                  <option value="<?= $sanpham['sp_ma'] ?>"><?= $sanpham['sp_tomtat'] ?></option>
                <?php endif; ?>
              <?php endforeach; ?>
            </select>
          </div>
          <div class="form-group">
            <label for="hsp_tentaptin">Tập tin ảnh</label>

            <!-- Tạo khung div hiển thị ảnh cho người dùng Xem trước khi upload file lên Server -->
            <div class="preview-img-container">
              <img src="/php/myhand/assets/shared/img/default-image_600.png" id="preview-img" width="200px" />
            </div>

            <!-- Input cho phép người dùng chọn FILE -->
            <input type="file" class="form-control" id="hsp_tentaptin" name="hsp_tentaptin">
          </div>
          <button class="btn btn-primary" name="btnSave">Lưu</button>
          <a href="index.php" class="btn btn-outline-secondary" name="btnBack" id="btnBack">Quay về</a>
        </form>

        <?php
        // 3. Nếu người dùng có bấm nút Đăng ký thì thực thi câu lệnh UPDATE
        if (isset($_POST['btnSave'])) {
          // Lấy dữ liệu người dùng hiệu chỉnh gởi từ REQUEST POST
          $hsp_ma = $_GET['hsp_ma'];

          // Nếu người dùng có chọn file để upload
          if (isset($_FILES['hsp_tentaptin'])) {
            // Đường dẫn để chứa thư mục upload trên ứng dụng web của chúng ta. Các bạn có thể tùy chỉnh theo ý các bạn.
            // Ví dụ: các file upload sẽ được lưu vào thư mục ../../../assets/uploads
            $upload_dir = __DIR__ . "/../../../assets/uploads/";
            // Các hình ảnh sẽ được lưu trong thư mục con `products` để tiện quản lý
            $subdir = 'products/';

            // Đối với mỗi file, sẽ có các thuộc tính như sau:
            // $_FILES['hsp_tentaptin']['name']     : Tên của file chúng ta upload
            // $_FILES['hsp_tentaptin']['type']     : Kiểu file mà chúng ta upload (hình ảnh, word, excel, pdf, txt, ...)
            // $_FILES['hsp_tentaptin']['tmp_name'] : Đường dẫn đến file tạm trên web server
            // $_FILES['hsp_tentaptin']['error']    : Trạng thái của file chúng ta upload, 0 => không có lỗi
            // $_FILES['hsp_tentaptin']['size']     : Kích thước của file chúng ta upload

            // 3.1. Chuyển file từ thư mục tạm vào thư mục Uploads
            // Nếu file upload bị lỗi, tức là thuộc tính error > 0
            if ($_FILES['hsp_tentaptin']['error'] > 0) {
              echo 'File Upload Bị Lỗi';
              die;
            } else {
              // Xóa file cũ để tránh rác trong thư mục UPLOADS
              // Kiểm tra nếu file có tổn tại thì xóa file đi
              $old_file = $upload_dir . $subdir . $hinhsanphamRow['hsp_tentaptin'];
              if (file_exists($old_file)) {
                // Hàm unlink(filepath) dùng để xóa file trong PHP
                unlink($old_file);
              }

              // Để tránh trường hợp có 2 người dùng cùng lúc upload tập tin trùng tên nhau
              // Ví dụ:
              // - Người 1: upload tập tin hình ảnh tên `hoahong.jpg`
              // - Người 2: cũng upload tập tin hình ảnh tên `hoahong.jpg`
              // => dẫn đến tên tin trong thư mục chỉ còn lại tập tin người dùng upload cuối cùng
              // Cách giải quyết đơn giản là chúng ta sẽ ghép thêm ngày giờ vào tên file
              $hsp_tentaptin = $_FILES['hsp_tentaptin']['name'];
              $tentaptin = date('YmdHis') . '_' . $hsp_tentaptin; //20200530154922_hoahong.jpg

              // Tiến hành di chuyển file từ thư mục tạm trên server vào thư mục chúng ta muốn chứa các file uploads
              // Ví dụ: move file từ C:\xampp\tmp\php6091.tmp -> C:/xampp/htdocs/learning.nentang.vn/php/twig/assets/uploads/hoahong.jpg
              // var_dump($_FILES['hsp_tentaptin']['tmp_name']);
              // var_dump($upload_dir . $subdir . $tentaptin);

              move_uploaded_file($_FILES['hsp_tentaptin']['tmp_name'], $upload_dir . $subdir . $tentaptin);
            }

            // 3.2. Lưu thông tin file upload vào database
            // Câu lệnh UPDATE
            $sql = "UPDATE `hinhsanpham` SET hsp_tentaptin='$tentaptin' WHERE hsp_ma=$hsp_ma;";
            // print_r($sql); die;

            // Thực thi
            mysqli_query($conn, $sql);

            // Đóng kết nối
            mysqli_close($conn);

            // Sau khi cập nhật dữ liệu, tự động điều hướng về trang Danh sách
            echo '<script>location.href = "index.php";</script>';
          }
        }
        ?>
        <!-- End block content -->
      </main>
    </div>
  </div>

  <!-- footer -->
  <?php include_once(__DIR__ . '/../../layouts/partials/footer.php'); ?>
  <!-- end footer -->

  <!-- Nhúng file quản lý phần SCRIPT JAVASCRIPT -->
  <?php include_once(__DIR__ . '/../../layouts/scripts.php'); ?>

  <!-- Các file Javascript sử dụng riêng cho trang này, liên kết tại đây -->
  <script>
    // Hiển thị ảnh preview (xem trước) khi người dùng chọn Ảnh
    const reader = new FileReader();
    const fileInput = document.getElementById("hsp_tentaptin");
    const img = document.getElementById("preview-img");
    reader.onload = e => {
      img.src = e.target.result;
    }
    fileInput.addEventListener('change', e => {
      const f = e.target.files[0];
      reader.readAsDataURL(f);
    })
  </script>
</body>

</html>

Step 6: bổ sung menu chức năng Quản lý Hình Sản phẩm bên sidebar

  • Hiệu chỉnh file /backend/layouts/partials/sidebar.php
  • Nội dung file:
<nav class="col-md-2 d-none d-md-block sidebar">
  <div class="sidebar-sticky">
    <ul class="nav flex-column">
      ...

      <!-- Menu Hình Sản phẩm -->
      <li class="nav-item">
        <a href="#hinhsanphamSubMenu" data-toggle="collapse" aria-expanded="false" class="dropdown-toggle">
          Hình Sản phẩm
        </a>
        <ul class="collapse" id="hinhsanphamSubMenu">
          <li class="nav-item">
            <a href="/php/myhand/backend/functions/hinhsanpham/index.php">Danh sách</a>
          </li>
          <li class="nav-item">
            <a href="/php/myhand/backend/functions/hinhsanpham/create.php">Thêm mới</a>
          </li>
        </ul>
      </li>
      <!-- End Sản phẩm -->

      ...
    </ul>
  </div>
</nav>

Demo