| Current Path : /var/www/html/ains/frontend/controllers/ |
| Current File : /var/www/html/ains/frontend/controllers/ReadingRecordController.php |
<?php
namespace frontend\controllers;
use yii;
use yii\web\Controller;
use frontend\models\ReadingRecord;
use frontend\models\FrontendUser;
use yii\web\UploadedFile;
use frontend\models\Book;
class ReadingRecordController extends Controller {
public function behaviors() {
$this->enableCsrfValidation = true;
}
public function actionSaverecord() {
$status = 'failed';
// Audit fields
$userId = Yii::$app->user->identity->id;
$now = date("Y-m-d H:i:s");
// Use Yii's request component instead of raw $_POST for better security
$post = Yii::$app->request->post();
$allowedFields = [
'jenis_rekod' => 'record_type',
'kategori' => 'record_cat',
'jenis' => 'record_type2',
'bahasa' => 'record_language',
'tajuk' => 'record_title',
'tahun' => 'record_year_publish',
'penulis' => 'record_author',
'isbn' => 'record_isbn',
'mukasurat' => 'record_total_page',
'penerbit' => 'record_publisher',
'pautan' => 'record_url',
'penilaian' => 'record_rating',
'rumusan' => 'record_summary',
'pengajaran' => 'record_lesson',
'record_book_id' => 'record_book_id',
'record_book_thumbnail' => 'record_book_thumbnail',
'record_update_id' => 'record_update_id'
];
if (isset($post['record_update_id']) && !empty($post['record_update_id'])) {
$model = ReadingRecord::findOne($post['record_update_id']);
$model->record_approval_status = 'pending';
$model->updated_at = $now;
$model->updated_by = $userId;
$model->updated_user_type = 'frontend_user';
} else {
$model = new ReadingRecord();
// Generate UUID
$model->record_code = (new \yii\db\Query)->select(new \yii\db\Expression('UUID()'))->scalar();
$model->record_student_id = $userId;
$model->record_approval_status = 'pending';
$model->created_at = $now;
$model->created_by = $userId;
$model->created_user_type = 'frontend_user';
$model->updated_at = $now;
$model->updated_by = $userId;
$model->updated_user_type = 'frontend_user';
}
foreach ($allowedFields as $postKey => $modelAttr) {
if (!empty($post[$postKey])) {
$model->$modelAttr = $post[$postKey];
}
}
// --- SECURE IMAGE UPLOAD ---
$coverImg = UploadedFile::getInstanceByName('kulit');
if ($coverImg !== null) {
// 1. Validate Extension
$allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
$extension = strtolower($coverImg->extension);
if (!in_array($extension, $allowedExtensions)) {
return 'failed:invalid_image_extension';
}
// 2. Validate MIME Type (prevents extension spoofing)
$finfo = new \finfo(FILEINFO_MIME_TYPE);
$mimeType = $finfo->file($coverImg->tempName);
$allowedMimeTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
if (!in_array($mimeType, $allowedMimeTypes)) {
return 'failed:invalid_image_mime';
}
// 3. Validate File Size (e.g., max 5MB)
if ($coverImg->size > 5 * 1024 * 1024) {
return 'failed:image_too_large';
}
// 4. Generate a safe, unique filename (never trust user filenames)
$safeFileName = Yii::$app->security->generateRandomString(32) . '.' . $extension;
$relativePath = 'uploads/record/' . $safeFileName;
// 5. Upload to Google Cloud Storage
if (\common\components\GcsHelper::save($coverImg->tempName, $relativePath)) {
$model->record_cover_img = $relativePath;
} else {
return 'failed:upload_error';
}
} else {
if (!empty($model->record_book_thumbnail)) {
$model->record_cover_img = $model->record_book_thumbnail;
}
}
if (empty($model->record_total_page))
$model->record_total_page = 1;
if ($model->save()) {
ReadingRecord::updatepoints($model->record_id);
FrontendUser::updatetotal($model->record_student_id);
$status = 'success';
} else {
$status = 'failed:' . json_encode($model->errors);
}
return $status;
}
public function actionTeachersaverecord() {
$status = 'success';
// Use Yii's request component instead of raw $_POST for better security
$post = Yii::$app->request->post();
$allowedFields = [
'jenis_rekod' => 'record_type',
'kategori' => 'record_cat',
'jenis' => 'record_type2',
'bahasa' => 'record_language',
'tajuk' => 'record_title',
'tahun' => 'record_year_publish',
'penulis' => 'record_author',
'isbn' => 'record_isbn',
'mukasurat' => 'record_total_page',
'penerbit' => 'record_publisher',
'pautan' => 'record_url',
'penilaian' => 'record_rating',
'rumusan' => 'record_summary',
'pengajaran' => 'record_lesson',
'record_book_id' => 'record_book_id',
'record_book_thumbnail' => 'record_book_thumbnail',
'student_list' => 'student_list'
];
// Audit fields
$userId = Yii::$app->user->identity->id;
$now = date("Y-m-d H:i:s");
$record_cover_img = '';
// --- SECURE IMAGE UPLOAD ---
$coverImg = UploadedFile::getInstanceByName('kulit');
if ($coverImg !== null) {
// 1. Validate Extension
$allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
$extension = strtolower($coverImg->extension);
if (!in_array($extension, $allowedExtensions)) {
return 'failed:invalid_image_extension';
}
// 2. Validate MIME Type (prevents extension spoofing)
$finfo = new \finfo(FILEINFO_MIME_TYPE);
$mimeType = $finfo->file($coverImg->tempName);
$allowedMimeTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
if (!in_array($mimeType, $allowedMimeTypes)) {
return 'failed:invalid_image_mime';
}
// 3. Validate File Size (e.g., max 5MB)
if ($coverImg->size > 5 * 1024 * 1024) {
return 'failed:image_too_large';
}
// 4. Generate a safe, unique filename (never trust user filenames)
$safeFileName = Yii::$app->security->generateRandomString(32) . '.' . $extension;
$relativePath = 'uploads/record/' . $safeFileName;
// 5. Upload to Google Cloud Storage
if (\common\components\GcsHelper::save($coverImg->tempName, $relativePath)) {
$record_cover_img = $relativePath;
} else {
return 'failed:upload_error';
}
}
if (isset($_POST['student_list'])) {
foreach ($_POST['student_list'] as $student_id) {
$model = new ReadingRecord();
$model->record_code = (new \yii\db\Query)->select(new \yii\db\Expression('UUID()'))->scalar();
$model->record_approval_status = 'approved';
$model->record_approval_at = $now;
$model->record_approval_by = $userId;
$model->record_approval_user_type = 'frontend_user';
$model->created_at = $now;
$model->created_by = $userId;
$model->created_user_type = 'frontend_user';
$model->updated_at = $now;
$model->updated_by = $userId;
$model->updated_user_type = 'frontend_user';
$model->record_cover_img = $record_cover_img;
$model->record_student_id = $student_id;
foreach ($allowedFields as $postKey => $modelAttr) {
if (!empty($post[$postKey])) {
$model->$modelAttr = $post[$postKey];
}
}
if ($model->save()) {
ReadingRecord::updatepoints($model->record_id);
FrontendUser::updatetotal($model->record_student_id);
} else {
$status = 'failed:' . json_encode($model->errors);
}
}
}
return $status;
}
public function actionUpdatestatus() {
$id = $_GET['id'];
$status = $_GET['status'];
$output = 'failed';
$model = ReadingRecord::findOne($id);
if (!empty($model)) {
$model->record_approval_status = $status;
$model->record_approval_at = date("Y-m-d H:i:s");
$model->record_approval_by = Yii::$app->user->identity->id;
$model->record_approval_user_type = 'frontend_user';
if (!empty($_GET['comment'])) {
$model->record_approval_comments = $_GET['comment'];
}
if ($status == 'rejected') {
$model->record_points = 0;
}
if ($model->save()) {
FrontendUser::updatetotal($model->record_student_id);
$output = 'success';
}
}
return $output;
}
}