เมื่อผมวางยาตัวเอง

วันนี้มีเรื่องเล่าสุดพิสดารมาฝาก ลองดูตัวอย่างโค้ดนี้
// login
$login= (int)$_SESSION['login']['id'];
// query
$sql = "SELECT L.`id`,L.`module_id`,L.`period`,L.`point`,L.`like`,L.`published`,G.`id` AS `cat_id`,G.`topic`,G.`c2`,U.`id` AS `member_id`,U.`point` AS `u_point`";
$sql .= ",COALESCE((SELECT `id` FROM `".DB_LOTTO_CUSTOMER."` WHERE `member_id`='$login' AND `lotto_id`=L.`id` LIMIT 1),0) AS `customer`";
$sql .= " FROM `".DB_LOTTO."` AS L";
$sql .= " INNER JOIN `".DB_MODULES."` AS M ON M.`id`=L.`module_id` AND M.`owner`='lottoresult'";
$sql .= " INNER JOIN `".DB_CATEGORY."` AS G ON G.`category_id`=L.`category_id` AND G.`module_id`=L.`module_id`";
$sql .= " INNER JOIN `".DB_USER."` AS U ON U.`id`='$login'";
$sql .= " WHERE L.`id`='$match[2]' LIMIT 1";
$lotto = $db->customQuery($sql);

จากโค้ดด้านบน ดูยังไงก็ไม่ผิดปกติใช่มั้ยครับ จริงๆแล้วมันก็ทำงานได้สมบูรณ์แบบบน Server ของผมละครับ แต่พอนำสคริปต์ไปติดตั้งให้กับลูกค้ากลับพบว่า มันจะมีการ logout ออกเองอัตโนมัติทุกครั้งโดยไม่ทราบสาเหตุ

จากการตรวจสอบ (แบบสุ่มๆไปเรื่อยๆ) ก็พบว่าการ login หายไปเมื่อมีการทำรายการที่หน้านี้ (ความยากมันอยู่ที่หน้านี้เป็นการทำงานด้วย Ajax อีตอนที่มันหายไปเราจะไม่รู้หรอกครับ เพราะผลตอบกลับในครั้งแรกก่อนหายมันจะยังปกติ ซึ่งจะรู้ตัวว่าหายอีกทีก็ตอนที่ทำอะไรต่อไม่ได้นั้่นแหละ เนื่องจากการ login มันหายไปแล้ว) ซึ่งโค้ดในหน้าที่มีปัญหา (ที่เกี่ยวข้องกับปัญหา) ก็มีดังด้านบนแค่นั้นครับ แค่นั้นจริงๆ.....

เรารู้ว่าปัญหาคือการ login มันหายไป ซึ่งเมื่อ login หายไป ปัญหาก็น่าจะอยู่ที่ SESSION หาย และโค้ดที่เกี่ยวข้องกับ SESSION ก็มีเพียงบรรทัดเดียวคือ $login= (int)$_SESSION['login']['id']

ทีแรกก็กังวลว่า SESSION มันไปถูกทำลายที่ไหนว่า แต่บรรทัดที่เกี่ยวข้องกับ ตัวแปร login ก็มีเพียง  WHERE `member_id`='$login' และ ON U.`id`='$login'" ซึ่งไม่มีอะไรบ่งบอกว่ามันจะไปทำลาย SESSION ได้

จากการทดสอบสารพัดวิธีเท่าที่จะนึกได้พบว่ามันเป็นปัญหาเส้นผมบังภูเขาแค่นั้นเอง สิ่งที่ผมทำคือ เปลี่ยนชื่อตัวแปรจาก $login เป็น $login_id แค่นั้น...แค่นั้นจริงๆ

ทำไมจึงเป็นเช่นนั้น จากการวิเคราะห์หาสาเหตุที่อาจเป็นไปได้ ผมเดาว่า อาจเป็นไปได้ว่าชื่อของตัวแปรที่ใช้งานไปซ้ำกับ ชื่อของ SESSION นั่นคือ ตัวแปร $login และ $_SESSION['login'] (ผมจึงทำแค่เปลี่ยนชื่อตัวแปรให้ไม่ตรงกันกับชื่อ SESSION เท่านั้น)

สาเหตุ ถ้ามีใครเคยเขียน PHP มาตั้งแต่สมัย PHP4 เขาจะมีกฏการใช้ SESSION ว่า ให้เรารับค่าของ SESSION ได้จากตัวแปรที่มีชื่อเดียวกันกับ SESSION ซึ่งในปัจจุบันกฏนี้ไม่เป็นที่นิยมใช้แล้วเพราะมันมีความปลอดภัยต่ำ ซึ่งกฏที่ว่าเกี่ยวข้องกับการตั้งค่า register_globals = On ครับ (ใน PHP4 ค่านี้จะเป็น On) ซึ่งจากการตรวจสอบก็เป็นจริงดังคาดครับ เมื่อทำการแก้ไข register_globals ให้เป็น Off แล้ว ผมก็สามารถใช้ตัวแปร $login ได้
 
สรุป เพื่อป้องกันปัญหาที่อาจเกิดขึ้น ผมแนะนำให้เลี่ยงการใช้ตัวแปรที่มีชื่อตรงกับชื่อ SESSION ครับ

ปล.มีเพื่อนสมาชิกถามว่าทำไมไม่สรุปว่าให้แก้ไข register_globals = Off แทน ... จริงๆ ถ้าทำได้ผมก็แนะนำให้ใช้วิธีนั้นครับ แต่เนื่องจากในปัจจุบันยังมีเว็บไซต์จำนวนมากซึ่งเปิดใช้งานตัวนี้อยู่ และโดยทั่วไปเราจะไม่สามารถแก้ไขค่านี้ได้ด้วยตัวเอง (ถ้าไม่ใช่ผู้ดูแลระบบ) ทำให้การหลีกเลี่ยงปัญหาดูจะเป็นวิธีการที่เหมาะสมที่สุด
ผู้เขียน goragod โพสต์เมื่อ 24 มี.ค. 2557 เปิดดู 10,409 ป้ายกำกับ SQL
^