Kotchasan Framework Documentation
คู่มือการพัฒนาเว็บเพจพื้นฐานด้วย Kotchasan
คู่มือการพัฒนาเว็บเพจพื้นฐานด้วย Kotchasan
บทนำ
คู่มือนี้จะแนะนำการพัฒนาเว็บเพจพื้นฐานด้วย Kotchasan Framework ตั้งแต่การสร้าง CRUD operations, การจัดการผู้ใช้, การทำ authentication, การจัดการฟอร์ม, การตรวจสอบข้อมูล, และการอัปโหลดไฟล์
สารบัญ
- การเตรียมโปรเจกต์
- การสร้าง CRUD Operations
- ระบบ Authentication
- การจัดการฟอร์ม
- การตรวจสอบข้อมูล
- การอัปโหลดไฟล์
- ตัวอย่างเว็บเพจสมบูรณ์
- Best Practices
การเตรียมโปรเจกต์
1. โครงสร้างโปรเจกต์
myproject/
├── modules/
│ └── blog/
│ ├── controllers/
│ ├── models/
│ ├── views/
│ └── template/
├── settings/
│ ├── config.php
│ └── database.php
├── datas/
│ ├── cache/
│ ├── logs/
│ └── uploads/
└── index.php2. การกำหนดค่าฐานข้อมูล
// settings/database.php
return [
'default' => [
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'myblog',
'username' => 'root',
'password' => '',
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => 'blog_'
]
];3. การสร้างตาราง
-- ตารางผู้ใช้
CREATE TABLE blog_users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
role ENUM('admin', 'user') DEFAULT 'user',
status ENUM('active', 'inactive') DEFAULT 'active',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
-- ตารางโพสต์
CREATE TABLE blog_posts (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
title VARCHAR(200) NOT NULL,
content TEXT NOT NULL,
status ENUM('draft', 'published') DEFAULT 'draft',
views INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES blog_users(id) ON DELETE CASCADE
);
-- ตารางหมวดหมู่
CREATE TABLE blog_categories (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
slug VARCHAR(100) UNIQUE NOT NULL,
description TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- ตารางความสัมพันธ์โพสต์-หมวดหมู่
CREATE TABLE blog_post_categories (
post_id INT NOT NULL,
category_id INT NOT NULL,
PRIMARY KEY (post_id, category_id),
FOREIGN KEY (post_id) REFERENCES blog_posts(id) ON DELETE CASCADE,
FOREIGN KEY (category_id) REFERENCES blog_categories(id) ON DELETE CASCADE
);การสร้าง CRUD Operations
1. Model สำหรับ CRUD
// modules/blog/models/post.php
namespace Blog\Post;
use Kotchasan\Model;
class Model extends \Kotchasan\Model
{
protected $table = 'posts';
/**
* ดึงโพสต์ทั้งหมด (Read)
*/
public function getAllPosts($limit = 10, $offset = 0)
{
return $this->db->select('p.*', 'u.name as author_name')
->from($this->table . ' p')
->leftJoin('users u', 'u.id', 'p.user_id')
->where('p.status', '=', 'published')
->orderBy('p.created_at', 'DESC')
->limit($limit, $offset)
->fetchAll();
}
/**
* ดึงโพสต์ตาม ID (Read)
*/
public function getPostById($id)
{
$post = $this->db->select('p.**', 'u.name as author_name')
->from($this->table . ' p')
->leftJoin('users u', 'u.id', 'p.user_id')
->where('p.id', '=', $id)
->first();
if ($post) {
// เพิ่มจำนวนการดู
$this->db->update($this->table)
->set(['views' => 'views + 1'])
->where('id', '=', $id)
->execute();
}
return $post;
}
/**
* สร้างโพสต์ใหม่ (Create)
*/
public function createPost($data)
{
// ตรวจสอบข้อมูล
$this->validatePostData($data);
$data['created_at'] = date('Y-m-d H:i:s');
$data['status'] = $data['status'] ?? 'draft';
$this->db->insert($this->table)
->values($data)
->execute();
return $this->db->lastInsertId();
}
/**
* อัปเดตโพสต์ (Update)
*/
public function updatePost($id, $data)
{
$this->validatePostData($data);
$data['updated_at'] = date('Y-m-d H:i:s');
return $this->db->update($this->table)
->set($data)
->where('id', '=', $id)
->execute();
}
/**
* ลบโพสต์ (Delete)
*/
public function deletePost($id)
{
return $this->db->delete($this->table)
->where('id', '=', $id)
->execute();
}
/**
* ตรวจสอบข้อมูลโพสต์
*/
private function validatePostData($data)
{
if (empty($data['title'])) {
throw new \Exception('กรุณากรอกหัวข้อ');
}
if (empty($data['content'])) {
throw new \Exception('กรุณากรอกเนื้อหา');
}
if (empty($data['user_id'])) {
throw new \Exception('ไม่พบข้อมูลผู้เขียน');
}
}
/**
* ค้นหาโพสต์
*/
public function searchPosts($keyword)
{
return $this->db->select('p.*', 'u.name as author_name')
->from($this->table . ' p')
->leftJoin('users u', 'u.id', 'p.user_id')
->where('p.status', '=', 'published')
->where('p.title', 'LIKE', "%{$keyword}%")
->orWhere('p.content', 'LIKE', "%{$keyword}%")
->orderBy('p.created_at', 'DESC')
->fetchAll();
}
}2. Controller สำหรับ CRUD
// modules/blog/controllers/post.php
namespace Blog\Post;
use Gcms\Login;
use Kotchasan\Http\Request;
class Controller extends \Kotchasan\Controller
{
/**
* แสดงรายการโพสต์
*/
public function render(Request $request)
{
$model = new Model();
$page = $request->request('page')->toInt() ?: 1;
$limit = 10;
$offset = ($page - 1) $limit;
$posts = $model->getAllPosts($limit, $offset);
$view = new View();
return $view->render($posts, $page);
}
/**
* แสดงโพสต์เดียว
*/
public function view(Request $request)
{
$id = $request->request('id')->toInt();
if ($id <= 0) {
return new \Kotchasan\Http\NotFound();
}
$model = new Model();
$post = $model->getPostById($id);
if (!$post) {
return new \Kotchasan\Http\NotFound();
}
$view = new View();
return $view->viewPost($post);
}
/**
* แสดงฟอร์มสร้าง/แก้ไขโพสต์
*/
public function form(Request $request)
{
// ตรวจสอบการ login
$login = Login::isMember();
if (!$login) {
return new \Kotchasan\Http\NotFound();
}
$id = $request->request('id')->toInt();
$post = [];
if ($id > 0) {
$model = new Model();
$post = $model->getPostById($id);
// ตรวจสอบสิทธิ์แก้ไข
if (!$post || ($post['user_id'] != $login['id'] && $login['role'] != 'admin')) {
return new \Kotchasan\Http\NotFound();
}
}
$view = new View();
return $view->form($post, $login);
}
}3. View สำหรับ CRUD
// modules/blog/views/post.php
namespace Blog\Post;
use Kotchasan\Html;
use Kotchasan\Http\Request;
class View extends \Gcms\View
{
/**
* แสดงรายการโพสต์
*/
public function render($posts, $currentPage)
{
$container = Html::create('div', ['class' => 'blog-container']);
// หัวข้อ
$container->add('h1', [], 'บล็อกของเรา');
// ฟอร์มค้นหา
$searchForm = $container->add('form', [
'method' => 'GET',
'class' => 'search-form'
]);
$searchForm->add('input', [
'type' => 'text',
'name' => 'search',
'placeholder' => 'ค้นหาโพสต์...',
'value' => $_GET['search'] ?? ''
]);
$searchForm->add('button', ['type' => 'submit'], 'ค้นหา');
// รายการโพสต์
if (empty($posts)) {
$container->add('p', [], 'ไม่พบโพสต์');
} else {
foreach ($posts as $post) {
$article = $container->add('article', ['class' => 'post-item']);
$article->add('h2')->add('a', [
'href' => 'index.php?module=blog&page=post&action=view&id=' . $post['id']
], $post['title']);
$meta = $article->add('div', ['class' => 'post-meta']);
$meta->add('span', [], 'โดย ' . $post['author_name']);
$meta->add('span', [], ' | ' . date('d/m/Y H:i', strtotime($post['created_at'])));
$meta->add('span', [], ' | ดู ' . number_format($post['views']) . ' ครั้ง');
$content = substr(strip_tags($post['content']), 0, 200);
$article->add('p', [], $content . '...');
$article->add('a', [
'href' => 'index.php?module=blog&page=post&action=view&id=' . $post['id'],
'class' => 'read-more'
], 'อ่านต่อ');
}
}
// Pagination
$this->renderPagination($container, $currentPage);
return $container->render();
}
/**
* แสดงโพสต์เดียว
*/
public function viewPost($post)
{
$container = Html::create('div', ['class' => 'post-container']);
$container->add('h1', [], $post['title']);
$meta = $container->add('div', ['class' => 'post-meta']);
$meta->add('span', [], 'โดย ' . $post['author_name']);
$meta->add('span', [], ' | ' . date('d/m/Y H:i', strtotime($post['created_at'])));
$meta->add('span', [], ' | ดู ' . number_format($post['views']) . ' ครั้ง');
$container->add('div', ['class' => 'post-content'], $post['content']);
// ปุ่มกลับ
$container->add('a', [
'href' => 'index.php?module=blog&page=post',
'class' => 'back-button'
], '← กลับไปรายการโพสต์');
return $container->render();
}
}ระบบ Authentication
1. User Model
// modules/blog/models/user.php
namespace Blog\User;
use Kotchasan\Model;
use Kotchasan\Password;
class Model extends \Kotchasan\Model
{
protected $table = 'users';
/**
* ตรวจสอบการ login
*/
public function authenticate($email, $password)
{
$user = $this->db->select('*')
->from($this->table)
->where('email', '=', $email)
->where('status', '=', 'active')
->first();
if ($user && password_verify($password, $user['password'])) {
// อัปเดตเวลา login ล่าสุด
$this->db->update($this->table)
->set(['last_login' => date('Y-m-d H:i:s')])
->where('id', '=', $user['id'])
->execute();
return $user;
}
return false;
}
/**
* สร้างผู้ใช้ใหม่
*/
public function register($data)
{
// ตรวจสอบอีเมลซ้ำ
$existing = $this->db->select('id')
->from($this->table)
->where('email', '=', $data['email'])
->first();
if ($existing) {
throw new \Exception('อีเมลนี้มีผู้ใช้แล้ว');
}
// เข้ารหัสรหัสผ่าน
$data['password'] = password_hash($data['password'], PASSWORD_DEFAULT);
$data['created_at'] = date('Y-m-d H:i:s');
$data['role'] = 'user';
$data['status'] = 'active';
$this->db->insert($this->table)
->values($data)
->execute();
return $this->db->lastInsertId();
}
/**
* ดึงข้อมูลผู้ใช้ตาม ID
*/
public function getUserById($id)
{
return $this->db->select('*')
->from($this->table)
->where('id', '=', $id)
->where('status', '=', 'active')
->first();
}
/**
* อัปเดตโปรไฟล์
*/
public function updateProfile($id, $data)
{
// ไม่อนุญาตให้แก้ไขอีเมลและรหัสผ่านที่นี่
unset($data['email'], $data['password'], $data['role']);
$data['updated_at'] = date('Y-m-d H:i:s');
return $this->db->update($this->table)
->set($data)
->where('id', '=', $id)
->execute();
}
}2. Login Controller
// modules/blog/controllers/login.php
namespace Blog\Login;
use Kotchasan\Http\Request;
use Kotchasan\Session;
class Controller extends \Kotchasan\Controller
{
/**
* แสดงฟอร์ม login
*/
public function render(Request $request)
{
// ถ้า login แล้วให้ redirect
if (Session::get('user_id')) {
header('Location: index.php?module=blog&page=dashboard');
exit;
}
$view = new View();
return $view->loginForm();
}
/**
* ประมวลผล login
*/
public function authenticate(Request $request)
{
if ($request->initSession() && $request->isSafe()) {
try {
$email = $request->post('email')->toString();
$password = $request->post('password')->toString();
if (empty($email) || empty($password)) {
throw new \Exception('กรุณากรอกอีเมลและรหัสผ่าน');
}
$model = new \Blog\User\Model();
$user = $model->authenticate($email, $password);
if ($user) {
// บันทึก session
Session::set('user_id', $user['id']);
Session::set('user_name', $user['name']);
Session::set('user_role', $user['role']);
return [
'alert' => 'เข้าสู่ระบบสำเร็จ',
'location' => 'index.php?module=blog&page=dashboard'
];
} else {
throw new \Exception('อีเมลหรือรหัสผ่านไม่ถูกต้อง');
}
} catch (\Exception $e) {
return [
'alert' => $e->getMessage(),
'input' => 'email'
];
}
}
return [
'alert' => 'การเข้าสู่ระบบไม่ถูกต้อง'
];
}
/**
* ออกจากระบบ
*/
public function logout(Request $request)
{
Session::destroy();
header('Location: index.php?module=blog&page=login');
exit;
}
}3. Register Controller
// modules/blog/controllers/register.php
namespace Blog\Register;
use Kotchasan\Http\Request;
class Controller extends \Kotchasan\Controller
{
/**
* แสดงฟอร์มสมัครสมาชิก
*/
public function render(Request $request)
{
$view = new View();
return $view->registerForm();
}
/**
* ประมวลผลการสมัครสมาชิก
*/
public function submit(Request $request)
{
if ($request->initSession() && $request->isSafe()) {
try {
$data = [
'name' => $request->post('name')->toString(),
'email' => $request->post('email')->toString(),
'password' => $request->post('password')->toString(),
];
$confirmPassword = $request->post('confirm_password')->toString();
// ตรวจสอบข้อมูล
if (empty($data['name'])) {
throw new \Exception('กรุณากรอกชื่อ');
}
if (empty($data['email']) || !filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
throw new \Exception('กรุณากรอกอีเมลที่ถูกต้อง');
}
if (strlen($data['password']) < 6) {
throw new \Exception('รหัสผ่านต้องมีอย่างน้อย 6 ตัวอักษร');
}
if ($data['password'] !== $confirmPassword) {
throw new \Exception('รหัสผ่านไม่ตรงกัน');
}
$model = new \Blog\User\Model();
$userId = $model->register($data);
return [
'alert' => 'สมัครสมาชิกสำเร็จ กรุณาเข้าสู่ระบบ',
'location' => 'index.php?module=blog&page=login'
];
} catch (\Exception $e) {
return [
'alert' => $e->getMessage(),
'input' => 'name'
];
}
}
return [
'alert' => 'การสมัครสมาชิกไม่ถูกต้อง'
];
}
}การจัดการฟอร์ม
1. ฟอร์ม Login
// modules/blog/views/login.php
namespace Blog\Login;
use Kotchasan\Html;
class View extends \Gcms\View
{
public function loginForm()
{
$container = Html::create('div', ['class' => 'login-container']);
$container->add('h2', [], 'เข้าสู่ระบบ');
$form = $container->add('form', [
'id' => 'login_form',
'class' => 'login-form',
'action' => 'index.php/blog/login/authenticate',
'onsubmit' => 'doFormSubmit',
'ajax' => true,
'token' => true
]);
// อีเมล
$group = $form->add('div', ['class' => 'form-group']);
$group->add('label', [], 'อีเมล');
$group->add('input', [
'type' => 'email',
'name' => 'email',
'required' => true,
'placeholder' => 'กรอกอีเมล'
]);
// รหัสผ่าน
$group = $form->add('div', ['class' => 'form-group']);
$group->add('label', [], 'รหัสผ่าน');
$group->add('input', [
'type' => 'password',
'name' => 'password',
'required' => true,
'placeholder' => 'กรอกรหัสผ่าน'
]);
// ปุ่ม submit
$form->add('button', [
'type' => 'submit',
'class' => 'btn btn-primary'
], 'เข้าสู่ระบบ');
// ลิงก์สมัครสมาชิก
$container->add('p')->add('a', [
'href' => 'index.php?module=blog&page=register'
], 'ยังไม่มีบัญชี? สมัครสมาชิก');
return $container->render();
}
}2. ฟอร์มสร้าง/แก้ไขโพสต์
// modules/blog/views/post.php (เพิ่มเมธอด)
public function form($post, $user)
{
$isEdit = !empty($post);
$container = Html::create('div', ['class' => 'post-form-container']);
$container->add('h2', [], $isEdit ? 'แก้ไขโพสต์' : 'สร้างโพสต์ใหม่');
$form = $container->add('form', [
'id' => 'post_form',
'class' => 'post-form',
'action' => 'index.php/blog/post/save',
'onsubmit' => 'doFormSubmit',
'ajax' => true,
'token' => true
]);
// ID (สำหรับแก้ไข)
if ($isEdit) {
$form->add('input', [
'type' => 'hidden',
'name' => 'id',
'value' => $post['id']
]);
}
// หัวข้อ
$group = $form->add('div', ['class' => 'form-group']);
$group->add('label', [], 'หัวข้อ ');
$group->add('input', [
'type' => 'text',
'name' => 'title',
'value' => $post['title'] ?? '',
'required' => true,
'placeholder' => 'กรอกหัวข้อโพสต์'
]);
// เนื้อหา
$group = $form->add('div', ['class' => 'form-group']);
$group->add('label', [], 'เนื้อหา ');
$group->add('textarea', [
'name' => 'content',
'required' => true,
'rows' => 10,
'placeholder' => 'กรอกเนื้อหาโพสต์'
], $post['content'] ?? '');
// สถานะ
$group = $form->add('div', ['class' => 'form-group']);
$group->add('label', [], 'สถานะ');
$select = $group->add('select', ['name' => 'status']);
$select->add('option', [
'value' => 'draft',
'selected' => ($post['status'] ?? 'draft') === 'draft'
], 'แบบร่าง');
$select->add('option', [
'value' => 'published',
'selected' => ($post['status'] ?? '') === 'published'
], 'เผยแพร่');
// ปุ่ม submit
$buttonGroup = $form->add('div', ['class' => 'button-group']);
$buttonGroup->add('button', [
'type' => 'submit',
'class' => 'btn btn-primary'
], $isEdit ? 'อัปเดต' : 'บันทึก');
$buttonGroup->add('a', [
'href' => 'index.php?module=blog&page=dashboard',
'class' => 'btn btn-secondary'
], 'ยกเลิก');
return $container->render();
}
}การตรวจสอบข้อมูล
1. Validation Helper
// modules/blog/models/validator.php
namespace Blog\Validator;
class Model
{
/**
* ตรวจสอบอีเมล
*/
public static function validateEmail($email)
{
if (empty($email)) {
throw new \Exception('กรุณากรอกอีเมล');
}
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new \Exception('รูปแบบอีเมลไม่ถูกต้อง');
}
return true;
}
/**
* ตรวจสอบรหัสผ่าน
*/
public static function validatePassword($password, $confirmPassword = null)
{
if (empty($password)) {
throw new \Exception('กรุณากรอกรหัสผ่าน');
}
if (strlen($password) < 6) {
throw new \Exception('รหัสผ่านต้องมีอย่างน้อย 6 ตัวอักษร');
}
if ($confirmPassword !== null && $password !== $confirmPassword) {
throw new \Exception('รหัสผ่านไม่ตรงกัน');
}
return true;
}
/**
* ตรวจสอบข้อความ
*/
public static function validateText($text, $fieldName, $minLength = 1, $maxLength = null)
{
if (empty($text)) {
throw new \Exception("กรุณากรอก{$fieldName}");
}
$length = mb_strlen($text, 'UTF-8');
if ($length < $minLength) {
throw new \Exception("{$fieldName}ต้องมีอย่างน้อย {$minLength} ตัวอักษร");
}
if ($maxLength && $length > $maxLength) {
throw new \Exception("{$fieldName}ต้องไม่เกิน {$maxLength} ตัวอักษร");
}
return true;
}
/**
* ตรวจสอบไฟล์อัปโหลด
*/
public static function validateUploadFile($file, $allowedTypes = [], $maxSize = 2097152)
{
if (!isset($file['tmp_name']) || empty($file['tmp_name'])) {
throw new \Exception('กรุณาเลือกไฟล์');
}
if ($file['error'] !== UPLOAD_ERR_OK) {
throw new \Exception('เกิดข้อผิดพลาดในการอัปโหลดไฟล์');
}
if ($file['size'] > $maxSize) {
$maxSizeMB = $maxSize / 1024 / 1024;
throw new \Exception("ไฟล์มีขนาดใหญ่เกิน {$maxSizeMB} MB");
}
if (!empty($allowedTypes)) {
$fileType = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if (!in_array($fileType, $allowedTypes)) {
throw new \Exception('ประเภทไฟล์ไม่ถูกต้อง อนุญาตเฉพาะ: ' . implode(', ', $allowedTypes));
}
}
return true;
}
}การอัปโหลดไฟล์
1. Upload Controller
// modules/blog/controllers/upload.php
namespace Blog\Upload;
use Kotchasan\Http\Request;
use Kotchasan\File;
class Controller extends \Kotchasan\Controller
{
/**
* อัปโหลดรูปภาพ
*/
public function image(Request $request)
{
if ($request->initSession() && $request->isSafe()) {
try {
$file = $request->getUploadedFiles()['image'] ?? null;
if (!$file) {
throw new \Exception('ไม่พบไฟล์ที่อัปโหลด');
}
// ตรวจสอบไฟล์
\Blog\Validator\Model::validateUploadFile([
'tmp_name' => $file->getStream()->getMetadata('uri'),
'name' => $file->getClientFilename(),
'size' => $file->getSize(),
'error' => $file->getError()
], ['jpg', 'jpeg', 'png', 'gif'], 5242880); // 5MB
// สร้างชื่อไฟล์ใหม่
$extension = strtolower(pathinfo($file->getClientFilename(), PATHINFO_EXTENSION));
$filename = uniqid() . '.' . $extension;
$uploadPath = ROOT_PATH . '/datas/uploads/images/';
// สร้างโฟลเดอร์ถ้าไม่มี
if (!is_dir($uploadPath)) {
mkdir($uploadPath, 0755, true);
}
// ย้ายไฟล์
$file->moveTo($uploadPath . $filename);
// ปรับขนาดรูปภาพ (ถ้าต้องการ)
$this->resizeImage($uploadPath . $filename, 800, 600);
return [
'alert' => 'อัปโหลดสำเร็จ',
'filename' => $filename,
'url' => 'datas/uploads/images/' . $filename
];
} catch (\Exception $e) {
return [
'alert' => $e->getMessage()
];
}
}
return [
'alert' => 'การอัปโหลดไม่ถูกต้อง'
];
}
/**
* ปรับขนาดรูปภาพ
*/
private function resizeImage($imagePath, $maxWidth, $maxHeight)
{
$imageInfo = getimagesize($imagePath);
if (!$imageInfo) {
return false;
}
$originalWidth = $imageInfo[0];
$originalHeight = $imageInfo[1];
$imageType = $imageInfo[2];
// คำนวณขนาดใหม่
$ratio = min($maxWidth / $originalWidth, $maxHeight / $originalHeight);
if ($ratio >= 1) {
return true; // ไม่ต้องปรับขนาด
}
$newWidth = intval($originalWidth $ratio);
$newHeight = intval($originalHeight $ratio);
// สร้างรูปภาพใหม่
$newImage = imagecreatetruecolor($newWidth, $newHeight);
switch ($imageType) {
case IMAGETYPE_JPEG:
$sourceImage = imagecreatefromjpeg($imagePath);
break;
case IMAGETYPE_PNG:
$sourceImage = imagecreatefrompng($imagePath);
imagealphablending($newImage, false);
imagesavealpha($newImage, true);
break;
case IMAGETYPE_GIF:
$sourceImage = imagecreatefromgif($imagePath);
break;
default:
return false;
}
// ปรับขนาด
imagecopyresampled($newImage, $sourceImage, 0, 0, 0, 0, $newWidth, $newHeight, $originalWidth, $originalHeight);
// บันทึกรูปภาพ
switch ($imageType) {
case IMAGETYPE_JPEG:
imagejpeg($newImage, $imagePath, 85);
break;
case IMAGETYPE_PNG:
imagepng($newImage, $imagePath);
break;
case IMAGETYPE_GIF:
imagegif($newImage, $imagePath);
break;
}
// ล้างหน่วยความจำ
imagedestroy($sourceImage);
imagedestroy($newImage);
return true;
}
}2. ฟอร์มอัปโหลดไฟล์
// modules/blog/views/upload.php
namespace Blog\Upload;
use Kotchasan\Html;
class View extends \Gcms\View
{
public function imageUploadForm()
{
$container = Html::create('div', ['class' => 'upload-container']);
$container->add('h3', [], 'อัปโหลดรูปภาพ');
$form = $container->add('form', [
'id' => 'upload_form',
'class' => 'upload-form',
'action' => 'index.php/blog/upload/image',
'method' => 'POST',
'enctype' => 'multipart/form-data',
'onsubmit' => 'doFormSubmit',
'ajax' => true,
'token' => true
]);
// ไฟล์อัปโหลด
$group = $form->add('div', ['class' => 'form-group']);
$group->add('label', [], 'เลือกรูปภาพ');
$group->add('input', [
'type' => 'file',
'name' => 'image',
'accept' => 'image/*',
'required' => true
]);
// คำแนะนำ
$group->add('small', ['class' => 'help-text'],
'รองรับไฟล์ JPG, PNG, GIF ขนาดไม่เกิน 5MB');
// ปุ่มอัปโหลด
$form->add('button', [
'type' => 'submit',
'class' => 'btn btn-primary'
], 'อัปโหลด');
// พื้นที่แสดงผลลัพธ์
$container->add('div', [
'id' => 'upload_result',
'class' => 'upload-result'
]);
return $container->render();
}
}ตัวอย่างเว็บเพจสมบูรณ์
1. Dashboard
// modules/blog/controllers/dashboard.php
namespace Blog\Dashboard;
use Gcms\Login;
use Kotchasan\Http\Request;
class Controller extends \Kotchasan\Controller
{
public function render(Request $request)
{
// ตรวจสอบการ login
$login = Login::isMember();
if (!$login) {
header('Location: index.php?module=blog&page=login');
exit;
}
// ดึงสถิติ
$postModel = new \Blog\Post\Model();
$userPosts = $postModel->getUserPosts($login['id']);
$stats = $postModel->getUserStats($login['id']);
$view = new View();
return $view->render($login, $userPosts, $stats);
}
}2. Dashboard View
// modules/blog/views/dashboard.php
namespace Blog\Dashboard;
use Kotchasan\Html;
class View extends \Gcms\View
{
public function render($user, $posts, $stats)
{
$container = Html::create('div', ['class' => 'dashboard-container']);
// Header
$header = $container->add('div', ['class' => 'dashboard-header']);
$header->add('h1', [], 'แดชบอร์ด');
$header->add('p', [], 'ยินดีต้อนรับ, ' . $user['name']);
// สถิติ
$statsRow = $container->add('div', ['class' => 'stats-row']);
$statCard = $statsRow->add('div', ['class' => 'stat-card']);
$statCard->add('h3', [], $stats['total_posts']);
$statCard->add('p', [], 'โพสต์ทั้งหมด');
$statCard = $statsRow->add('div', ['class' => 'stat-card']);
$statCard->add('h3', [], $stats['published_posts']);
$statCard->add('p', [], 'โพสต์ที่เผยแพร่');
$statCard = $statsRow->add('div', ['class' => 'stat-card']);
$statCard->add('h3', [], number_format($stats['total_views']));
$statCard->add('p', [], 'การดูทั้งหมด');
// เมนูด่วน
$quickMenu = $container->add('div', ['class' => 'quick-menu']);
$quickMenu->add('h2', [], 'เมนูด่วน');
$menuRow = $quickMenu->add('div', ['class' => 'menu-row']);
$menuRow->add('a', [
'href' => 'index.php?module=blog&page=post&action=form',
'class' => 'menu-item'
], '+ สร้างโพสต์ใหม่');
$menuRow->add('a', [
'href' => 'index.php?module=blog&page=post',
'class' => 'menu-item'
], 'ดูโพสต์ทั้งหมด');
$menuRow->add('a', [
'href' => 'index.php?module=blog&page=profile',
'class' => 'menu-item'
], 'แก้ไขโปรไฟล์');
// โพสต์ล่าสุด
$recentPosts = $container->add('div', ['class' => 'recent-posts']);
$recentPosts->add('h2', [], 'โพสต์ล่าสุดของคุณ');
if (empty($posts)) {
$recentPosts->add('p', [], 'ยังไม่มีโพสต์');
} else {
$table = $recentPosts->add('table', ['class' => 'data-table']);
// Header
$thead = $table->add('thead');
$tr = $thead->add('tr');
$tr->add('th', [], 'หัวข้อ');
$tr->add('th', [], 'สถานะ');
$tr->add('th', [], 'การดู');
$tr->add('th', [], 'วันที่สร้าง');
$tr->add('th', [], 'จัดการ');
// Body
$tbody = $table->add('tbody');
foreach ($posts as $post) {
$tr = $tbody->add('tr');
$tr->add('td', [], $post['title']);
$tr->add('td', [], $post['status'] === 'published' ? 'เผยแพร่' : 'แบบร่าง');
$tr->add('td', [], number_format($post['views']));
$tr->add('td', [], date('d/m/Y', strtotime($post['created_at'])));
$actions = $tr->add('td');
$actions->add('a', [
'href' => 'index.php?module=blog&page=post&action=form&id=' . $post['id'],
'class' => 'btn btn-sm btn-primary'
], 'แก้ไข');
$actions->add('a', [
'href' => 'index.php?module=blog&page=post&action=view&id=' . $post['id'],
'class' => 'btn btn-sm btn-secondary'
], 'ดู');
}
}
return $container->render();
}
}Best Practices
1. ความปลอดภัย
// ใช้ CSRF Token เสมอ
$form = Html::create('form', [
'token' => true, // เปิดใช้งาน CSRF protection
'ajax' => true
]);
// ตรวจสอบ session และ token
if ($request->initSession() && $request->isSafe()) {
// ประมวลผลข้อมูล
}
// Escape ข้อมูลก่อนแสดงผล
echo htmlspecialchars($userInput, ENT_QUOTES, 'UTF-8');
// ใช้ Prepared Statements
$users = $db->select('*')
->from('users')
->where('email', '=', $email) // ปลอดภัยจาก SQL Injection
->execute();2. การจัดการ Error
try {
// โค้ดที่อาจเกิด error
$result = $model->createPost($data);
return [
'alert' => 'บันทึกสำเร็จ',
'location' => 'index.php?module=blog&page=dashboard'
];
} catch (\Exception $e) {
// Log error สำหรับ developer
error_log('Post creation error: ' . $e->getMessage());
// แสดงข้อความที่เหมาะสมกับผู้ใช้
return [
'alert' => 'เกิดข้อผิดพลาด: ' . $e->getMessage(),
'input' => 'title' // focus ไปที่ field ที่มีปัญหา
];
}3. การ Validate ข้อมูล
class ExampleClass {
<?php
// Validate ทั้งฝั่ง Client และ Server
// Client-side (JavaScript)
document.getElementById('email').addEventListener('blur', function() {
const email = this.value;
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
this.setCustomValidity('รูปแบบอีเมลไม่ถูกต้อง');
} else {
this.setCustomValidity('');
}
});
// Server-side (PHP)
public function validateEmail($email)
{
if (empty($email)) {
throw new \Exception('กรุณากรอกอีเมล');
}
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new \Exception('รูปแบบอีเมลไม่ถูกต้อง');
}
return true;
}
}4. การจัดการ Session
// ตรวจสอบ login
function requireLogin()
{
if (!Session::get('user_id')) {
header('Location: index.php?module=blog&page=login');
exit;
}
return [
'id' => Session::get('user_id'),
'name' => Session::get('user_name'),
'role' => Session::get('user_role')
];
}
// ใช้งาน
$user = requireLogin();5. การ Optimize Performance
// ใช้ Pagination
public function getAllPosts($page = 1, $limit = 10)
{
$offset = ($page - 1) $limit;
return $this->db->select()
->from('posts')
->where('status', '=', 'published')
->orderBy('created_at', 'DESC')
->limit($limit, $offset)
->fetchAll();
}
// ใช้ Cache สำหรับข้อมูลที่ไม่เปลี่ยนบ่อย
public function getCategories()
{
$cacheKey = 'blog_categories';
$categories = Cache::get($cacheKey);
if ($categories === null) {
$categories = $this->db->select('*')
->from('categories')
->orderBy('name')
->fetchAll();
Cache::set($cacheKey, $categories, 3600); // cache 1 ชั่วโมง
}
return $categories;
}
// Lazy Loading สำหรับรูปภาพ
<img src="placeholder.jpg" data-src="actual-image.jpg" class="lazy-load" alt="...">
}6. การจัดระเบียบโค้ด
// แยก Business Logic ออกจาก Controller
class PostController extends \Kotchasan\Controller
{
private $postService;
public function __construct()
{
$this->postService = new PostService();
}
public function create(Request $request)
{
try {
$data = $request->getParsedBody();
$post = $this->postService->createPost($data);
return $this->successResponse($post);
} catch (\Exception $e) {
return $this->errorResponse($e->getMessage());
}
}
}
// Service Class
class PostService
{
private $postModel;
private $validator;
public function __construct()
{
$this->postModel = new PostModel();
$this->validator = new PostValidator();
}
public function createPost($data)
{
$this->validator->validate($data);
return $this->postModel->create($data);
}
}สรุป
การพัฒนาเว็บเพจด้วย Kotchasan Framework ให้ความสำคัญกับ:
- ความปลอดภัย - ใช้ CSRF Token, Prepared Statements, Input Validation
- การจัดระเบียบ - ใช้ MVC Pattern, แยก Business Logic
- ประสิทธิภาพ - ใช้ Cache, Pagination, Optimization
- ความสะดวก - Form Helper, Validation Helper, Upload Helper
- การบำรุงรักษา - Error Handling, Logging, Testing
การปฏิบัติตาม Best Practices เหล่านี้จะช่วยให้เว็บเพจมีคุณภาพสูง ปลอดภัย และใช้งานได้อย่างมีประสิทธิภาพ