เขียนโปรแกรมด้วย CodeIgniter การป้องกัน CSRF แล้วเกิดปัญหากับ AJAX เมื่อเปิด csrf_regenerate

โดย SONGCHAI SAETERN


PHP CodeIgniter Security Class

https://www.codeigniter.com/user_guide/libraries/security.html

การเขียนโปรแกรมเพื่อความปลอดภัยในการรับข้อมูลจากแบบฟอร์ม ใน CodeIgniter จะต้องเปิด $config['csrf_protection'] = TRUE; ถือว่าเป็นสิ่งจำเป็นที่จะต้องเปิดใช้งาน แต่ถ้าหากต้องการให้โปรแกรมเรา Submit ได้ครั้งเดียว ให้เปิดการป้องกันการรีเฟรช ด้วยการเพิ่ม  $config['csrf_regenerate'] = TRUE; เข้าไปอีกอัน

$config['csrf_protection'] = TRUE;
$config['csrf_token_name'] = 'csrf_token_name';
$config['csrf_cookie_name'] = 'csrf_cookie_name';
$config['csrf_expire'] = 7200;
$config['csrf_regenerate'] = TRUE;

แต่ปัญหาคือ เมื่อเปิด $config['csrf_regenerate'] = TRUE; การทำงานของโปรแกรมจะมีปัญหากับการส่งค่าแบบ AJAX ทำให้หน้า Controller ไม่สามารถรับค่าจากแบบฟอร์มได้





สำหรับวิธีการแก้ไขปัญหาคือ จะต้องเขียนโปรแกรมอ่านค่าจาก Cookie มาอีกครั้งเพื่อส่งข้อมูลการเข้ารหัสความปลอดภัยของแบบฟอร์มไปด้วย

ตัวอย่าง

csrf_token_name = '<?php echo $this->security->get_csrf_token_name(); ?>';
csrf_cookie_name = '<?php echo $this->config->item('csrf_cookie_name'); ?>';
$(function ($) {
    // this bit needs to be loaded on every page where an ajax POST 
    var object = {};
    object[csrf_token_name] = $.cookie(csrf_cookie_name);
    $.ajaxSetup({
        data: object
    });
    $(document).ajaxComplete(function () {
        object[csrf_token_name] = $.cookie(csrf_cookie_name);
        $.ajaxSetup({
            data: object
        });
    });
});

โค้ดด้านบนนี้ จะมีการอ่านคุกกี้ มาเก็บไว้อีกครั้งก่อนส่งข้อมูลออกไป

object[csrf_token_name] = $.cookie(csrf_cookie_name);

ซึ่ง csrf_token_name และ csrf_cookie_name ด้านบนนี้ก็จะต้องตรงกับที่เราคอนฟิกไว้

หากท่านใดเขียนโปรแกรมด้วย PHP CodeIgniter เมื่อใช้ AJAX ในแบบฟอร์มแล้วมีปัญหากับ  csrf_regenerate ก็ลองใช้วิธีนี้ดูนะครับ


:: อ้างอิง ::

How to make Ajax work when csrf_regeneration is true in CodeIgniter3?
https://stackoverflow.com/questions/29903517/how-to-make-ajax-work-when-csrf-regeneration-is-true-in-codeigniter3


เขียนโปรแกรม PHP เชื่อมข้อมูลหลายตารางแบบไม่ใช้ INNER/LEFT JOIN

โดย SONGCHAI SAETERN

PHP กับการเชื่อมตารางหลายตารางโดยไม่ใช้ JOIN

ในการเขียนโปรแกรม PHP กับ MySQL บางครั้งการ JOIN แม้จะทำ INDEX ไปแล้วแต่ก็ยังมีโอกาสทำงานช้าได้ ซึ่งจากบทความก่อนหน้านั้น ผมได้สาธิตวิธีการเขียนโปรแกรมเชื่อมต่อฐานข้อมูล MySQL หลายตารางด้วยคำสั่ง JOIN ไว้ในบทความ "การทำ Index ให้ MySQL Database เพื่อเพิ่มความเร็ว" จะเห็นว่าเราสามารถเพิ่มความเร็วให้ได้อย่างดีทีเดียว



แต่การเขียนโปรแกรมดังในวิดีโอนี้ จะเป็นการใช้ Array เก็บข้อมูลจากฐานข้อมูลไว้เปรียบเทียบรหัสที่ตรงกัน เพื่อดึงชื่อจากตารางอื่นมาแสดง ซึ่งก็มีข้อจำกัดเรื่องจำนวนเรคอร์ดหรือแถวของตารางที่จะดึงข้อมูลมาใส่ใน Array เพราะถ้าข้อมูลเยอะและมีการเปลี่ยนแปลงตลอดเวลา การเขียนโปรแกรม PHP โดยเก็บไว้ในอาร์เรย์ทั้งหมด ก็คงเป็นเรื่องยาก

$allProduct = array();
$allCategoryId = array();

ดังนั้นตัวแปรทั้งสองตัวด้านบนนี้ จึงต้องเก็บเฉพาะข้อมูลของรายการที่เกี่ยวข้องเท่านั้นด้วยการค้นหาตาราง product โดยคัดเอาเฉพาะที่มีอยู่ในรายการเท่านั้น IN()

$allCategory = array();
แต่การใช้กับตาราง category จะต่างกัน เพราะในตารางนี้เป็นข้อมูลหลัก ที่นานๆจะเปลี่ยนแปลงที หรือต่อให้เปลี่ยนแปลงยังไงก็ไม่เกินร้อยเรคอร์ด หรือไม่เกินพัน ก็เป็นเรื่องง่ายที่จะจับข้อมูลทั้งหมดใส่ใน Array ไปเลย


สำหรับ Code PHP ในตัวอย่างมีดังต่อไปนี้





[ PHP Code ]

<?php
$page_title = 'เชื่อมข้อมูลหลายตารางแบบไม่ใช้  INNERT/LEFT JOIN';
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>PHP สำหรับผู้เริ่มต้น : <?php echo $page_title;?></title>
<link rel="stylesheet" href="bootstrap/css/bootstrap.min.css">
<style>
body{
font-family : 'TH sarabunPSK';
padding : 10px;
font-size : 18pt;
}
</style>
</head>
<body>
<?php
$db_config=array(
    "host"=>"localhost",  // กำหนด host
    "user"=>"tobedev", // กำหนดชื่อ user
    "pass"=>"abcd.1234",    // กำหนดรหัสผ่าน
    "dbname"=>"tobedev_product_cost",  // กำหนดชื่อฐานข้อมูล
    "charset"=>"utf8"  // กำหนด charset
);
$mysqli = @new mysqli($db_config["host"], $db_config["user"], $db_config["pass"], $db_config["dbname"]);
if(mysqli_connect_error()) {
    die('Connect Error (' . mysqli_connect_errno() . ') '. mysqli_connect_error());
    exit;
}
if(!$mysqli->set_charset($db_config["charset"])) { // เปลี่ยน charset เป้น utf8 พร้อมตรวจสอบการเปลี่ยน
    printf("Error loading character set utf8: %sn", $mysqli->error);  // ถ้าเปลี่ยนไม่ได้
}

//ดึงข้อมูลการขาย ซึ่งเป็นข้อมูลหลักที่ต้องการ แต่จะได้แค่ไอดี product ยังขาดชื่อและหมวดหมู่
$sql = "SELECT * FROM `product_sales`
WHERE sale_date BETWEEN '2017-08-01' AND '2017-08-31'
GROUP BY product_id
ORDER BY `product_id` ";
$result = $mysqli->query($sql); // ทำการ query คำสั่ง sql
$data_list = array();
while($rs = $result->fetch_assoc()){ // วนลูปแสดงข้อมูล
$data_list[] = $rs;
}
//เริ่มสร้าง Array เก็บชื่อหมวดหมู่และสินค้า
// เก็บรายชื่อ Category ทั้งหมด
$sql = "SELECT * FROM `category`";
$result = $mysqli->query($sql);
$allCategory = array();
while($rs = $result->fetch_assoc()){
$allCategory[$rs['id']] = $rs['name'];
}
//ดึงข้อมูลรหัสสินค้า จาก Array ทั้งหมด
$productAllId = array_column($data_list, 'product_id');
//สร้างรหัสต่อเนื่องเพื่อนำไปใช้กับฟังก์ชั่น IN() ใน MySQL
// ที่ต้องใช้ IN() เพื่อกรองแค่ข้อมูลที่ต้องการเท่านั้น
// หากข้อมูลใน product นานๆเพิ่มที่ หรือจำกัดไม่มาก จะดึงทั้งหมดก็ได้
//แล้วแต่ว่าแบบไหนจะทำงานเร็วกว่ากัน
$in_id = implode($productAllId, ',');
$sql = "SELECT id, name, category_id
FROM `product`
WHERE id IN ($in_id)";
$result = $mysqli->query($sql);
$allProduct = array();
$allCategoryId = array();
//วนลูปเก็บชื่อ และหมวดหมู่สินค้า
while($rs = $result->fetch_assoc()){
$allProduct[$rs['id']] = $rs['name'];
$allCategoryId[$rs['id']] = $rs['category_id'];
}
//echo '<pre>',print_r($allProduct, true),'</pre>';
//ปิดการเชื่อมต่อฐานข้อมูล
$mysqli->close();
?>
<h1><?php echo $page_title;?></h1>
<div>
ตารางที่ 1 <b>category</b>, ตารางที่ 2 <b>product</b>, ตารางที่ 3 <b>product_sales</b>  (ตารางที่ต้องการผลลัพธ์)
</div>
<table class="table table-bordered">
    <thead>
      <tr>
    <th>Product ID</th>
        <th>Product Name</th>
        <th>Category</th>
      </tr>
    </thead>
    <tbody>
<?php
if(!empty($data_list)){
foreach($data_list as $row){
$product_id = $row['product_id'];
//ตรวจสอบว่า product_id ตรงกับค่าใน Array หรือไม่ ถ้าตรงให้ดึงออกมาใช้
$cate_id = isset($allCategoryId[$product_id]) ? $allCategoryId[$product_id] : '';
$category_name = isset($allCategory[$cate_id]) ? $allCategory[$cate_id] : '';
$product_name = isset($allProduct[$product_id]) ? $allProduct[$product_id] : '';
?>
      <tr>
        <td><?php echo $product_id;?></td>
        <td><?php echo $product_name;?></td>
        <td><?php echo $category_name;?></td>
      </tr>
    <?php
}
}
?>
    </tbody>
  </table>
<script src="jquery/jquery.min.js"></script>
<script src="jquery-ui/jquery-ui.min.js"></script>
<script src="bootstrap/js/bootstrap.min.js"></script>
</body>
</html>


[ SQL สร้างฐานข้อมูล ]



บทความที่คล้ายกัน
PHP กับจัดการฐานข้อมูลหมวดหมู่สินค้า MySQL แบบใช้ตารางเพียงตารางเดียวเท่านั้น


PHP CI MANIA PHP Code Generator 
โปรแกรมช่วยสร้างโค้ด ลดเวลาการเขียนโปรแกรม เขียนโปรแกรมง่ายและสะดวกขึ้น
สนใจสั่งซื้อราคาสุดคุ้ม >> http://fastcoding.phpcodemania.com/


อ้างอิง

array_columnReturn the values from a single column in the input array
http://php.net/manual/en/function.array-column.php

implodeJoin array elements with a string
http://php.net/manual/en/function.implode.php

MySQL WHERE IN ()
https://stackoverflow.com/questions/9736284/mysql-where-in

มาใช้ mysqli แทน mysql แบบเดิม ใน php กันอย่างง่าย
https://www.ninenik.com/มาใช้_mysqli_แทน_mysql_แบบเดิม_ใน_php_กันอย่างง่าย-527.html

เขียนโปรแกรม JavaScript เปรียบเทียบเวลา หาความต่างของเวลา Day, Hours, Minute, Seconds

โดย CyberMAN

"Get time difference between two dates"

ถ้าค้นหาด้วยคีย์เวิร์ดนี้ เราจะเจอวิธีการเขียนโปรแกรมเปรียบเทียบวันเวลาที่หลากหลาย ให้เลือกใช้กันตามที่ถนัดได้เลยครับ




จากบทความที่แล้วผมได้แนะนำเกี่ยวกับการเขียนโปรแกรม "PHP กับการเลื่อนกำหนดเวลาครั้งถัดไป เมื่อบันทึกเลยกำหนดในครั้งก่อน" ซึ่งเป็นการทำงานในเวอร์ชั่นภาษา PHP จากนั้นก็มีแฟนเพจ "PHP สำหรับผู้เริ่มต้น" ได้สอบถามเข้ามาอีกว่าถ้าต้องการเขียนโปรแกรมเปรียบเทียบเวลาโดยใช้ JavaScript ล่ะ จะต้องเขียนแบบไหน จึงเป็นที่มาของบทความแนะนำการ "เขียนโปรแกรม JavaScript เปรียบเทียบเวลา หาความต่างของเวลา Day, Hours, Minute, Seconds" นี้ครับ

สำหรับซอร์สโค้ดที่ใช้ มีดังต่อไปนี้ครับ




[ JavaScript Code ]

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>การหาผลต่างของเวลาด้วย JavaScript</title>
</head>
<body>

<h1>การหาผลต่างของเวลาด้วย JavaScript</h1>
<div><input id="text1" /></div>
<div><input id="text2" /></div>
<div><input id="total" /></div>
<div><input type="button" value="Process" onclick="CheckTime()" /></div>

<script>

    function CheckTime(){
        //Get datetime from input
        datetime1 = document.getElementById('text1').value;
        datetime2 = document.getElementById('text2').value;
      
        //Set date time format
        var startDate = new Date(datetime1);
        var endDate   = new Date(datetime2);
        var seconds = (endDate.getTime() - startDate.getTime()) / 1000;
      
        //Calculate time
        var days = Math.floor(seconds / (3600*24));
        var hrs_d   = Math.floor((seconds - (days * (3600*24))) / 3600);
        var hrs   = Math.floor(seconds / 3600);
        var mnts = Math.floor((seconds - (hrs * 3600)) / 60);
        var secs = seconds - (hrs * 3600) - (mnts * 60);
      
        //Add 0 if one digit
        if(hrs_d<10) hrs_d = "0" + hrs_d;
        if(mnts<10) mnts = "0" + mnts;
        if(secs<10) secs = "0" + secs;
      
        document.getElementById('total').value = days + ' ' + hrs_d + ':' + mnts + ':' + secs;
    }

</script>
</body>
</html>


 ถ้านับโค้ดด้านบนนี้ไปลองรันดู เมื่อเราป้อนวันเวลาในช่องที่ 1 และ ช่องที่ 2 จากนั้นกดปุ่ม "Process" ก็จะปรากฏผลลัพธ์ค่าวันเวลาที่ต่างกันในช่องที่ 3


ซึ่งจากโค้ดนี้เราสามารถนำค่าเวลาที่หน่วยเป็นวินาทีในตัวแปร seconds ไปเพิ่มลดเวลา หรือชดเชยเวลาให้กับกำหนดการครั้งต่อไปได้ ซึ่งผู้เขียนจะแนะนำวิธีการในโอกาสต่อไป


สนับสนุนค่ากาแฟผู้เขียนได้ที่

( Mobile Banking / Application )

สนับสนุนค่ากาแฟผู้เขียนได้ที่

PHP CI MANIA PHP Code Generator 
โปรแกรมช่วยสร้างโค้ด ลดเวลาการเขียนโปรแกรม เขียนโปรแกรมง่ายและสะดวกขึ้น
สนใจสั่งซื้อราคาสุดคุ้ม >> http://fastcoding.phpcodemania.com/

:: อ้างอิง :: 

Get time difference between two dates in seconds
https://stackoverflow.com/questions/13894632/get-time-difference-between-two-dates-in-seconds
 
Convert to days,hours,minutes,seconds
https://stackoverflow.com/questions/36098913/convert-to-days-hours-minutes-seconds 

change time format to 24 hours in javascript
https://stackoverflow.com/questions/22347521/change-time-format-to-24-hours-in-javascript