เรื่องของเรื่อง คือ กำลังเขียน script pirate อยู่
ซึ่งพยายามจะเป็น full UTF-8 ทั้งเวป (เค้าบอกกันว่า ดีก็ เลยอยากใช้ของดี อะไรประมาณนั้น)
แต่แล้วไปเจอปัญหา กับ download.php ซึ่ง … มันทำงานไม่ได้ !?
เพราะ มัน ดัน ยัด BOM ใส่มาให้ใน 3 byte แรกของ file … ซึ่งทำให้ file เสีย !!
BOM 3 byte แรก ที่ยัดมาก็คือ --> 0xef,0xbb,0xbf
ทีนี้ ผมก็คิดว่า .. เอ๊ะ หรือเพราะเซ็ตเป็น UTF-8 … Server มันเลยอวดฉลาดใส่ BOM มาให้ ?
แต่ ท่า server ค๊าบ .. นู๋ไม่อยากได้ BOM อ่ะค๊าบบบบบบ
ท่าน server ช่วยแกล้งโง่ เอาออกให้ได้ม๊ายยยยยย
ซึ่ง การวิเคราะห์แรก .. ผม โทษ sv ก่อนเลย .. (สันนิฐานแรก แมร่งประมาณว่า กรูถูกเสมอ .. คนอื่นแม่งผิดหมด … ว๊ะ ฮ่า ฮ่า ฮ่า)
ก็ไปบ่นใน iRC ว่า cloudflare ที่ใช้ แม่ง กวนตีน … ยัด BOM มาให้เฉยเลย
ไฟล์ตูที่โหลดจาก code เทพ เสียหายโม๊ดดดด (แล้วก็ บ่น cloudflare ไปชุดใหญ่)
แล้วผม ก็ post code download.php ไป
ซึ่ง หลักการ เขียน download.php มัน ไม่มีอะไรมาก แค่ ส่ง header เป็น attachment
ประมาณ
include('function.php'); $content = 'เนื้อหาในfile'; header('Content-Disposition: attachment; filename="file.torrent"'); header('Content-Type: application/zip; ');#ตรงนี้ จริงๆ แล้ว จะใส่อะไรก็ได้ ด้วยซ้ำ .. ขอแค่ ให้ ถูกประเภทของ file ก็พอ #แต่ ถ้าใส่ bittorrent .. มันจะ ไม่รอด พวก หอพัก จะ block header ของ bit หมด #ทำให้ user โหลด ไม่ได้ .. ก็เลย ต้อง ปลอมเป็น zip ไป (แต่ มันก็ block ได้หลายวิธีอยุ่ดี) echo $content; die();
ซึ่งเวลาเปิดหน้า download.php แล้ว ก็น่าจะได้ file.torrent วึ่ง เนื้อหาข้างใน ควรจะมีแค่ ใน $content เท่านั้น
แต่ !! …. บอกแล้ว มัน ยัด BOM มาด้วย
แทนที่จะได้ “เนื้อหาในfile”
แต่มันกลับเป็น “0xef0bbbfเนื้อหาในfile” <--- 0xef0bbbf คือ 3byte แรกที่เป็น BOM ตัวทำให้ file เสีย T_____T
ทีนี้ .. ถ้า user ธรรมดาสามัญชนโหลดไป .. ก็จะ เปิดกะ utorrent ไม่ได้ .. ปัญหา ก็มาลงที่คนทำ (แค่คิด ก็เหนื่อยแล้ว)
แต่ประเด็นมันคือ .. ทำไม ชาวบ้าน ที่ ใช้ cloudflare เค้าถึงไม่มีปัญหาล่ะ
(ก็เลย ลองไป sniff header ของ เวปในตำนานมา เค้าใช้ TIS-620 .. เลย ยิ่ง หาข้อเปรียบเทียบไม่ได้)
ก็เลย เอาวะ BOM มันอาจจะมาจาก ใน function.php
ก็เลยลองใหม่ โดยไม่ include ('function.php')
ผลคือ ... ไม่มี BOM !!!
ชิบห่าน แล้ว ... BOM มาจากไหน ?
function.php เรียก SSI.php ของ board SMF ด้วย
โอ้ว . . . คิดแล้ว อยากจะกรี๊ด เป็นพาส MySQL
ผมก็เลย นั่งอ่าน google อยุ่ 2 วัน ... พร้อมทั้ง ตามหา BOM ... จนเจอ ^^"
สรุป ... ไปเจออยู่ ที่
/Themes/default/languages/Faq.thai.php
/Themes/default/languages/Faq.thai-utf8.php
ซึ่งเป็น ตัวเสริม ของ SMF เอามา mod ลงไว้ใน board นั่นเอง
ต้องขอ ขอบคุณ สคิปชาวบ้านในการหา BOM (ทำให้ไม่ต้องเขียนเอง *0*)
<?php // http://www.simplemachines.org/community/index.php?topic=300626.msg1989826#msg1989826 class FileChecker { /** * @var string */ var $_file = ''; /** * @var boolean */ var $_recursive = false; /** * @var string */ var $_include = false; /** * @var string */ var $_exclude = false; /** * @var array */ var $_errors = array(); /** * @param string $file - File or Directory to check * @param boolean $recursive - Use recursive checking on directories */ function FileChecker($file = '') { $this->_file = $file; } function run() { set_time_limit(300); $this->_run($this->_file, $this->_recursive); } /** * Return the count and filesize for files in a directory * * @param string $dir * @param boolean $recursive * @param string $ext * */ function _run($file, $recursive) { if (substr($file,-1) == '.') $file = substr($file,0,-1); if (is_file($file) && is_readable($file)) return $this->_checkFile($file); elseif (!is_dir($file) || !$dir_handle = opendir($file)) { trigger_error('Unable to open directory: ' . $file); return; } while(($filename = readdir($dir_handle)) !== false) { if (($filename == '.') || ($filename == '..')) continue; $extension = array_pop(explode('.', $filename)); $real_path = $file . DIRECTORY_SEPARATOR . $filename; // Are we going to skip this file? $skip_file = (($this->_include !== false) && !in_array($extension, $this->_include)) ? true : (($this->_exclude !== false) && in_array($extension, $this->_exclude)) ? true : false; if(is_file($real_path) && is_readable($real_path) && !$skip_file) $this->_checkFile($real_path); elseif(is_dir($real_path) && $recursive && !(($this->_exclude !== false) && in_array($extension, $this->_exclude))) $this->_run($real_path, $recursive); } closedir($dir_handle); } /** * @desc This function can be overloaded to provide custom functionality * @param $filepath * @return Nothing, fills _error array with array(string filename, array errors) */ function _checkFile($filepath) { $handle = fopen($filepath, 'r'); $errors = array(); // Let's go to the front of the file fseek($handle, 0); // BOM Check fseek($handle, 0); $opening = fgets($handle, 6); // And now the end of the file fseek($handle, -2, SEEK_END); $closing = fgets($handle, 3); if (strcasecmp(substr($opening, 0, 3), pack("CCC",0xef,0xbb,0xbf)) == 0) { $errors[] = 'UTF-8 BOM found'; if (strcasecmp(substr($opening, 3), '<?') != 0) $errors[] = 'File does not begin with <?php'; } elseif (strcasecmp($opening, '<?php') != 0) $errors[] = 'File does not begin with <?php'; if (strcasecmp($closing, '?>') != 0) $errors[] = 'File does not end with ?>'; if (!empty($errors)) { $this->_errors[] = array( 'file' => $filepath, 'errors' => $errors, ); } } /** * @return false on no errors, or error array if not empty */ function errors() { if (empty($this->_errors)) return false; else return $this->_errors; } /** * @param $file */ function setFile($file = '') { $this->_file = $file; } /** * @param false | string $extension | array $extension */ function setInclude($extension) { $this->_include = ($extension !== false && !is_array($extension)) ? array($extension) : $extension; } /** * @param false | string $extension | array $extension */ function setExclude($extension) { $this->_exclude = ($extension !== false && !is_array($extension)) ? array($extension) : $extension; } /** * @desc This will only set recursive to true if the file is a directory * @param boolean $recursive */ function setRecursive($recursive = true) { $this->_recursive = is_dir($this->_file) && $recursive; } /** * @return string file */ function getFile() { return $this->_file; } } $file_test = new FileChecker(dirname(__FILE__)); $file_test->setRecursive(); $file_test->setInclude('php'); $file_test->setExclude('store'); $file_test->run(); $file_errors = $file_test->errors(); /**/ echo ' <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title>SMF File Checker Utility</title> <style type="text/css"> body { background-color: #E5E5E8; margin: 0px; padding: 0px; } body, td { color: #000000; font-size: small; font-family: verdana, sans-serif; } div#header { background-image: url(Themes/default/images/catbg.jpg); background-repeat: repeat-x; background-color: #88A6C0; padding: 22px 4% 12px 4%; color: white; font-family: Georgia, serif; font-size: xx-large; border-bottom: 1px solid black; height: 40px; } div#content { padding: 20px 30px; } div.panel { border: 1px solid gray; background-color: #F6F6F6; margin: 1ex 0 3ex 0; padding: 1.2ex; } div.panel h2 { margin: 0; margin-bottom: 2ex; padding-bottom: 3px; border-bottom: 1px dashed black; font-size: 14pt; font-weight: normal; } dl { margin-left: 3ex; } dt { font-style: italic; } dd { margin-bottom: 1ex; } div .code { color: #000000; background-color: #dddddd; font-family: "courier new", "times new roman", monospace; font-size: small; line-height: 1.3em; /* Put a nice border around it. */ border: 1px solid #000000; margin: 1px auto 1px auto; padding: 5px; width: 95%; /* Dont wrap its contents, and show scrollbars. */ white-space: nowrap; overflow: auto; /* Stop after about 24 lines, and just show a scrollbar. */ max-height: 24em; } /* The "Quote:" and "Code:" header parts... */ div .codeheader { color: #000000; text-decoration: none; font-style: normal; font-weight: bold; font-size: x-small; line-height: 1.2em; } div.code span.comment { font-style: italic; color: #000066; } </style> </head> <body> <div id="header"> <div title="Millenia">SMF File Checker Utility</div> </div> <div id="content"> <div class="panel"> <h2 id="contents">Below are the results of the scan</h2>'; if (empty($file_errors)) echo ' <p>Congratulations, no errors have been found in any of your files.</p>'; else foreach($file_errors as $file) { echo ' <ul> <li>', $file['file'], ' <ul>'; foreach ($file['errors'] as $error) echo ' <li>', $error, '</li>'; echo ' </ul> </li> </ul>'; } echo ' </div> </div> </body> </html>'; ?>









