Tag Archive เฮดเดอร์

PHP: no-cache css javascript

ตามคำแนะนำในการทำเว็บให้เร็วคือให้แยกไฟล์ภาพ, css และ javascript ออกมาเพราะว่าไฟล์พวกนี้แทบจะเหมือนๆ กันทุกๆหน้า และเปลี่ยนไม่บ่อยนัก การ set server จึงกำหนดให้ทางฝั่ง browser จดจำ static content (css, images,js files) พวกนี้เอาไว้ จะได้ไม่ต้องโหลดไฟล์พวกนี้ใหม่ ทำให้สิ้นเปลือง (สิ้นเปลือง bandwide แบนด์วิธอันล้ำค่าและมีราคาที่เช่ามาจาก isp และ cpu, ram ที่ใช่จัดการจ่ายไฟล์จาก server ไปให้บราวน์เซอร์ของยูเซอร์)

ปัญหาก็คือ เมื่อเราแก้ไฟล์ image, css หรือ javascript อัพโหลดขึ้นไปบน server แล้วแต่ user ยังได้รับไฟล์ version เดิมๆ อยู่ ที่นิยมกันก็คือ ใส่ตัวแปรแบบสุ่มหรือเวลาตามหลังชื่อไฟล์ เช่น

<link href="styles.css?ts=150151" rel="stylesheet" type="text/css">
...
<script src="scripts.js?ts=150151">
...
<img src="logo.png?ts=150151">

เมื่อต้องการให้ใช้ไฟล์ version ใหม่ก็เปลี่ยนค่าของ ts เป็นค่าอื่น ตัว browser จะถือว่าเป็นคนละไฟล์กับไฟล์เดิมที่เก็บไว้ใน cache ของมันเอง ปัญหาก็คือถ้ามีไฟล์พวกนี้ 100 จุด หรือ 1000 จุดก็ต้องไล่แก้ทั้งหมดให้เหมือนๆกันถึงจะเปลี่ยนไฟล์ทุกตัวให้เป็นตัวใหม่พร้อมๆกัน อาจจะทำเป็น global variable หรือใช้ function จัดการให้แต่มันซับซ้อนเกินไป

อีกวิธีที่ทำได้ง่ายแต่ได้ผลกับทุกๆ ไฟล์คือใช้

header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');

เมื่อต้องการให้ browser โหลดไฟล์ใหม่อีกครั้ง โดยใส่ใน header ของเว็บ

อ่านเพิ่มเติม HTTP Caching

สร้างไฟล์ csv จาก phpexcel

phpexcel สร้างไฟล์ excel ได้สะดวกมาก แต่ไม่ใช่ทุกระบบจะสามารถ import ข้อมูลจากไฟล์แบบเอ็กเซลได้ การส่งออกไฟล์แบบตัวอักษรล้วนๆ และใช้เครื่องหมายคั่นแบบไฟล์ csv จึงยังจำเป็นอยู่

ที่สำคัญคือสามารถแก้หรือเพิ่มเงื่อนไขจาก code ส่งออกข้อมูลเป็น excel โดย phpexcel ที่มีอยู่เดิม โดยดัดแปลงเล็กน้อยในส่วน header และการ write data

<?php

/* PHPExcel_IOFactory - Reader */
include 'PHPOffice/PHPExcel/Classes/PHPExcel.php';

$objPHPExcel = new PHPExcel();

/* Set default style */
$defaultStyle = $objPHPExcel->getDefaultStyle();

$defaultStyle->getFont()
    ->setName('Arial')
    ->setSize(11);

$defaultStyle->getNumberFormat()
    ->setFormatCode('yyyy-mm-dd');

/* Set document properties */
$title = 'Exports_Datas_' . date('Y-m-d_H:i');
$objPHPExcel->getProperties()->setCreator('Pitt Phunsanit')
    ->setCategory('Exports Datas')
    ->setDescription($title)
    ->setKeywords('Exports Datas ' . date('Y-m-d'))
    ->setSubject($title)
    ->setTitle($title);

/* rename sheet */
$objWorkSheet = $objPHPExcel->getActiveSheet();
$objWorkSheet->setTitle('Exports Datas');

for ($rowNo = 1; $rowNo < 10; $rowNo++) {
    for ($colNo = 0; $colNo < 5; $colNo++) {

        $insert = rand(0, 1);
        if($insert == 1) {

            $colString = PHPExcel_Cell::stringFromColumnIndex($colNo);

            $coordinate = $colString . $rowNo;

            $objWorkSheet->setCellValue($coordinate, 'ส่งออกข้อมูล -> '.$coordinate);
        }
    }
}

header('Cache-Control: max-age=0');
header('Content-Encoding: UTF-8');
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-type: text/csv; charset=UTF-8');
header('Content-Disposition: attachment;filename="'.$title.'.csv"');
echo "\xEF\xBB\xBF"; /* UTF-8 BOM */

$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'CSV');

/* set Delimiter, (defaults ,) */
//$objWriter->setDelimiter('|');
//$objWriter->setEnclosure('');
/* Set line ending (defaults PHP_EOL) */
//$objWriter->setLineEnding('0x0d0a');

$objWriter->save('php://output');

ถ้าสังเกตุจะมี $insert = rand(0, 1); และ if($insert == 1) { ทำให้บาง cell ไม่มีข้อมูล เพื่อที่จะแสดงให้เห็นว่าการใช้ phpexcel จะดีกว่าการใช้ echo ส่งออกข้อมูลแบบที่ง่ายที่สุด (CSV) ในกรณีที่บางคอลัมข้อมูลไม่มี เราไม่จำเป็นต้อง echo ค่าว่าง หรือมานับ , ว่าครบมั๋ย phpexcel จะจัดการให้เอง

ถ้าเปลี่ยนรูปแบบอื่นเช่น

  • ต้องการใช้เครื่องหมายอื่นเช่น pipe | ก็สามารถกำหนดโดยใช่ setDelimiter
  • ต้องการ wrap ข้อมูลก็ใช้ setEnclosure จะปิดหัว ปิดท้ายข้อมูลแต่ละ cell ให้
  • ต้องการใช้เครื่องมายอื่นในการแบ่งข้อมูลออกเป็นชุดๆ ก็ setLineEnding

เขียนครั้งเดียวส่งออกข้อมูลได้ 2 รูปแบบ ส่วนคำสั่งที่ไม่ได้ใช้ในรูปแบบ csv เช่น setTitle ก็ไม่ทำให้มี error ดีจริงๆ phpexcel

ส่งออกข้อมูลแบบที่ง่ายที่สุด (CSV)

วิธีที่ส่งออกข้อมูลที่ง่ายที่สุด และอิมพอร์ตเข้าโปรแกรมต่างๆได้มากที่สุดคือ comma-separated values (CSV) แปลง่ายๆว่า ไฟล์ตารางที่คั่นด้วยคอมม่า แปลบ้านๆไปอีกคือ text file ที่ข้อมูลถูกแบ่งโดย , หรือเครื่องหมายอื่นเช่น pipe | โดยข้อมูลต่ละ record จะแบ่งโดยการขึ้นบรรทัดใหม่ (ใน php คือ \n)

เขียนง่ายๆ แค่มีการเพิ่ม header เข้าไปว่ามันเป็น csv นะและ echo ธรรมดาๆ

<?php

$filename = 'Exports_Datas_' . date('Y-m-d_H:i');

header('Cache-Control: max-age=0');
header('Content-Encoding: UTF-8');
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-type: text/csv; charset=UTF-8');
header('Content-Disposition: attachment;filename="'.$filename.'.csv"');
echo "\xEF\xBB\xBF"; /* UTF-8 BOM */

/* random add datas */
for($a = 0; $a < 10; $a++) {
	$datas = [];
	for($b = 0; $b < 5; $b++) {
		$datas[$b] = 'ส่งออกข้อมูล '.rand(1, 100);
	}
	echo implode(',', $datas)."\n";
}

หลังจากเรียกไฟล์ php ก็จะเห็นว่ามีการให้ download ขึ้นมาให้ save ลองคลิกเปิดดูถ้าเครื่องมี excel อยู่ก็จะเปิดอ่านข้อมูลได้ทันที หรือจะใช้ text editor เปิดขึ้นมาดูก็ได้ ทดลองเปลี่ยนเป็นให้ดึงข้อมูลจาก database ดูครับ