[แจกฟรี] โปรแกรม Vote, PHP Vote script

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

เมื่อพิจารณาจากกรณีของผู้ใช้ทั่วๆไปส่วนใหญ่แล้ว การเลือกการออกแบบโปรแกรมให้มีประสิทธิภาพที่สุดภายใต้ทรัพยากรอันจำกัด ดูจะมีเหตุผลที่สุด
  • ข้อจำกัดด้านภาษา ผู้ใช้งานมี Server PHP จะบอกให้ผู้ใช้เปลี่ยนเป็น Node หรือ GO ก็คงจะใช่ที่ ถึงแม้มันจะมีประสิทธิภาพดีกว่า
  • เลือก Framework ผมเลือกใช้ Somtum Framework เพราะมันมีประสิทธิภาพสูงกว่า Kotchasan และถ้าจะเอาจริงๆ เขียน PHP ธรรมดา ยังจะเร็วกว่าได้อีก (ตัวอย่างนี้ ต้องการให้เห็นถึงคุณประโยชน์ด้านความเร็วของ Framework)
  • ใช้เทคนิคบ้านๆ ที่ใครๆก็คิดได้ในการออกแบบ ไม่ซับซ้อน แต่มีประสิทธิภาพ
  • ถ้าทำเต็มที่แล้วยังไม่พอ ถึงเวลาอัปเกรด Server แล้วแหละ (ต่อให้สคริปต์มีประสิทธิภาพแค่ไหน สุดท้ายมันก็ถูกจำกัดด้วย ประสิทธิภาพของ Server อยู่ดี)

แนวคิด
  • ผมออกแบบ Script แยกออกเป็นส่วนๆ โดยหน้าเว็บสำหรับการโหวต ผมเลือกใช้ HTML + Javascript + JSON ในการทำงาน ที่ไฟล์ index.html โดยไม่ใช้ PHP เลย ข้อดีคือ เราสามารถนำสคริปต์นี้ไปไว้ที่ไหนก็ได้ เช่น เอาไปฝากไว้บน Firebase หรือ บน Github หรือ Server ฟรีไหนๆก็ได้ แถมพ่วงด้วย Cloudflare เพื่อทำให้หน้าเว็บไม่ล่ม หากมีคนเข้ามากๆ
  • Data ของผู้รับการโหวต ผมเลือกใช้ข้อมูล JSON โดยใช้ Ajax โหลดจาก Server เมื่อมีการเรียกหน้า index.html ข้อดีของข้อมูลแบบนี้คือ ไม่ต้องพึ่งพา PHP อีกเช่นกัน สามารถย้ายข้อมูลไปไว้ที่ไหนก็ได้ อาจเป็นบน Server เดียวกันกับที่ติดตั้ง index.html หรือ บน Server ของเราก็ได้
  • ข้อดีอีกอย่างของการใช้เทคโนโลยีพื้นฐานพวกนี้ คือ สามารถแคชได้ ทำให้โอกาสที่เว็บจะล่ม น้อยลงได้อีก
  • เมื่อมีการโหวตเกิดขึ้น ก็จะใช้ Ajax ส่งข้อมูลกลับมายัง PHP Server ของเราเพื่อบันทึกข้อมูลการโหวตลงฐานข้อมูล ตรงนี้ผมยังคงใช้ PHP ร่วมกับ MySQL เพื่อเก็บข้อมูล เนื่องจากเป็นจุดประสงค์แต่แรกว่าจะใช้ทรัพยากรเท่าที่มีอยู่ ซึ่งหากต้องการประสิทธิภาพที่สูงขึ้น สามารถเปลี่ยนไปใช้ Server หรือ ฐานข้อมูลประเภทอื่นได้ เช่น เปลี่ยนไปใช้ GO ร่วมกับ MongoDB เนื่องจากการโหวตด้วย Ajax อาศัยการส่งข้อมูลในรูปแบบ API ซึ่งไม่มีความเกี่ยวข้องกันโดยตรงสามารถใช้เทคโนโลยีอะไรก็ได้
  • ถ้าถามว่า แล้วทำไม ไม่ใช้ NodeJS หรือ Go ทั้งระบบไปเลย คำตอบง่ายๆคือ ในฝั่ง Front End คงไม่มีเทคโนโลยีอะไร มีประสิทธิภาพมากไปกว่า HTML ธรรมดาแล้วครับ

ความปลอดภัยในการโหวต
ข้อนี้ดูจะเป็นจุดสำคัญ และมีปัญหามากที่สุด แต่ผมสรุปแบบเข้าใจง่ายๆได้เลยว่า ไม่มีระบบโหวตใดๆในโลกนี้ ที่สมบูรณ์ปลอดภัย 100% หากต้องการความปลอดภัยสูงสุด ก็ต้องแลกกับประสิทธิภาพที่ลดลง หรือข้อจำกัด และความยุ่งยากในการใช้งาน
  • ในโปรเจ็คนี้ผมเลือกความปลอดภัยในระดับพื้นฐาน โดยจะมีการตรวจสอบการโหวตซ้ำจากข้อมูลเบอร์โทรที่กรอกเท่านั้น ซึ่งข้อเสียของวิธีนี้คือ เราไม่สามารถป้องกันการโหวตแบบใช้เครื่องมือได้ แต่ถ้าจะพิจารณากันจริงๆ ในกรณีที่คนทั่วๆไปใช้ เราคงไม่สามารถตรวจสอบได้อยู่แล้วว่าการโหวตเกิดจากคนหรือเครื่องมือ เพราะแค่เปลี่ยนเบอร์โทร ก็ควรจะโหวตได้
  • หากต้องการป้องกันการฟลัดโหวต ผมแนะนำให้ทำการลงทะเบียนผู้ใช้ก่อน ซึ่งหากเป็นหน่วยงาน เช่นโรงเรียน เราจะมีฐานข้อมูลนักเรียนอยู่แล้ว เราก็เอามาใช้เป็นข้อมูลตั้งต้นในการโหวต เวลาโหวตก็ตรวจสอบกับฐานข้อมูลถ้าเลขประจำตัวตรงกันก็สามารถโหวตได้ ก็จะเป็นการป้องกันการฟลัดไปในตัว
  • การป้องกันการปั่นโหวตด้วยสคริปต์ จุดนี้ระบบไม่ได้ตรวจสอบอะไรมาก ยังคงมีช่องทางให้สามารถทำได้ เนื่องจากระบบเน้นประสิทธิภาพเป็นหลัก แต่หากจะเสริมความปลอดภัยด้านนี้ก็จะต้องเป็นการลดประสิทธิภาพโดยรวมของระบบลง ยกตัวอย่างเทคนิคที่สามารถทำได้ เช่น
    • เปลี่ยนการร้องขอข้อมูล Data จาก JSON เป็นเรียกผ่าน API แทน โดยเมื่อมีการเรียก API เพื่อขอข้อมูลผู้รับการโหวต ให้ส่งค่า token กลับมาด้วย โดยเป็น token แบบใช้ครั้งเดียว และจำกัดอายุการใช้งานสั้นๆ เช่น มีการสร้าง token แบบสุ่ม เก็บไว้ในฐานข้อมูล พร้อมกับกำหนดอายุ เช่น 5 นาที (ปกติในการโหวตเมื่อเข้ามาแล้วคนจะต้องรีบโหวต ดังนั้นอายุของ token ไมจำเป็นต้องนาน) แล้วส่งกลับไปที่ Front End ร่วมกับข้อมูลอื่นๆ เมื่อมีการโหวตเกิดขึ้น ให้ส่ง token กลับมาด้วย เพื่อยืนยันว่ามาจากการกดโหวตจริง โดยตรวจสอบกับฐานข้อมูล ถ้ามี token อยู่และยังไม่หมดเวลา ก็สามารถโหวตได้ ซึ่งเมื่อโหวตแล้ว ก็ให้ลบ token ออกจากฐานข้อมูล ก็จะไม่สามารถใช้ token นั้นในการโหวตได้อีก ซึ่งหากมีการโหวตโดยโปรแกรม ก็จะสามารถโหวตได้แค่ครั้งเดียวเท่านั้น แต่เทคนิคนี้ จะไม่สามารถป้องกันการโหวต โดยการใช้เครื่องมือจำลองการกรอกฟอร์มอัตโนมัติได้ เนื่องจากการทำงานจะถูกมองว่าเป็นเหมือนขั้นตอนปกติ
    • ผมแน่ใจว่า คงมีคนคิดว่าทำไมไม่ตรวจสอบจาก IP หรือ SESSION ร่วมด้วย คำตอบง่ายๆคือ เราไม่รู้ว่าผู้ใช้จะโหวตผ่านช่องทางไหน ยกตัวอย่างเช่น ผู้ใช้โหวตผ่าน Browser ตัวเดียวกัน (ยืมกันโหวต) หรือ โหวตจากระบบภายใน ซึ่งเป็นไปได้ว่า อาจจะได้ SESSION หรือ  IP เดิมทุครั้ง ทำให้การใช้ IP หรือ SESSION ดูจะมีข้อจำกัดมากเกินไป
    • ลงทะเบียนก่อนโหวต แน่นอนว่า ความยุ่งยากที่ต้องลงทะเบียนก่อน จะทำให้การฟลัดโหวตลดลงได้ แต่หน้าลงทะเบียนก็เป็นจุดใหญ่อีกจุดที่ทำให้เกิดคอขวดได้ แถมการลงทะเบียน ก็ยังสามารถใช้ระบบอัตโนมัติช่วยได้อยู่ดี (ทางแก้อาจใช้ร่วมกับ captcha หรือ token ได้) ซึ่งถ้าจุดประสงค์เพื่อป้องกันการฟลัดโหวตเท่านั้นผมว่าการใช้ token อย่างเดียว จะมีประโยชน์กว่า
    • สุดท้าย ใช้ captcha ร่วมกับการกดโหวต เช่น reCAPTCHA ก็ดูจะเป็นทางออกที่ง่ายและสะดวกที่สุดในการป้องกันการฟลัดโหวต โดยมีการแก้ไขสคริปต์น้อยที่สุด

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

สคริปต์นี้ไม่เหมาะสม สำหรับ
  • ผู้ที่มีทางเลือกที่ดีกว่า เช่น องค์กรใหญ่ๆ ที่มีทรัพยากรเหลือเฟือ พร้อมจะเปลี่ยนแปลงเพื่อรับเทคโนโลยีใหม่ๆ แนะนำให้ใช้ภาษาอื่นที่มีประสิทธิภาพมากกว่า PHP

แนวทางการปรับปรุงเพิ่มเติม
  • การรายงานผลการโหวตแบบตามเวลาจริง ปัจจุบันใช้วิธีการทาง Ajax ในการเรียกดูข้อมูล ถ้าจะให้ดีกว่านี้ เปลี่ยนไปใช้ Websocket จะช่วยให้การแสดงผลตามเวลาจริงราบรื่นกว่านี้ (ในสคริปต์ กำหนดช่วงเวลา Refresh ไว้ที่ 10 วินาที ต่อรอบ)
  • การเก็บข้อมูล สามารถเปลี่ยนไปใช้ฐานข้อมูลแบบอื่นได้ เช่น MongoDB เนื่องจากระบบข้อมูลไม่ได้ซับซ้อน สามารถปรับเปลี่ยนได้เอง
  • การใช้งานภายในองค์กร สามารถนำเข้าข้อมูลผู้โหวตเข้าไปยังฐานข้อมูลล่วงหน้าก่อนได้ เพื่อป้องกันการฟลัดโหวต ตามที่ได้อธิบายไป ซึ่งระบบไมได้รองรับการทำงานแบบนี้โดยตรง แต่สามารถแก้ไขการทำงานในส่วนของการโหวตให้เข้ากับกฏนี้ได้ไม่ยาก
  • หน้าเว็บ (Front End) สามารถลดขนาดได้อีก เนื่องจากเว็บไม่ได้มีองค์ประกอบมากนัก สามารถตกแต่ง CSS ได้ด้วยตัวเอง

การติดตั้ง 
  1. อัปโหลดไฟล์ทั้งหมดขึ้นไปยัง Server ยกเว้น vote.sql
  2. แก้ไขไฟล์ settings/config.php ให้ถูกต้อง
  3. ปรับ chmod ให้ settings/config.php และ ไดเร็คทอรี่ datas/ รวมทั้งไฟล์ทั้งหมดในนั้น ให้สามารถเขียนได้
  4. สร้างฐานข้อมูลจากไฟล์ vote.sql
  5. เข้าระบบผู้ดูแลที่ http://domain.tld/admin.php  โดยใช้ username: admin@localhost และ password: admin

เว็บตัวอย่าง https://vote.kotchasan.com/index.html
ระบบผู้ดูแล https://vote.kotchasan.com/admin.php

ดาวน์โหลดโค้ดได้จาก Github

หากต้องการสนับสนุนผู้เขียน สามารถบริจาคช่วยเหลือค่า Server ได้ที่
ธนาคาร กสิกรไทย สาขากาญจนบุรี
เลขที่บัญชี 221-2-78341-5
ชื่อบัญชี กรกฎ วิริยะ
^