การใส่ข้อมูลลงในไฟล์ word (.docx) ด้วย PHP กันเถอะ

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

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

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

รูปแบบระบบส่งข่าวของช่องเก้า (MCOT/อสมท.) มีความไม่เหมือนใครตรงที่ ทางสถานีจะให้ส่งเป็นไฟล์บทข่าวเป็นไฟล์ word (.docx) เพื่อเข้านำเข้าสู่ระบบและนำไฟล์วีดีโอส่งเป็น FTP เข้าสถานี โดยส่วนตัวชอบ FTP นะครับเพราะว่ามันส่งไฟล์ใหญ่ๆได้ดี แต่ก็มีเหมือนกันในบางสำนักข่าวจะให้ upload ทั้งบทข่าวและไฟล์วีดีโอทางเว็บบาร์วเซอร์ ซึ่งทั้งสองระบบมีข้อดีข้อเสียต่างกันออกไป

จริงๆที่ผ่านมาก็จะใช้ Teamviewer ไป remote กลับไปที่เครื่องที่บ้านเพื่อตัดต่อและพิมพ์ไฟล์เอกสาร เอาจริงๆแค่ตัดตัดเครื่องก็จะระเบิดแล้ว แถมเวลาเปลี่ยน layout keyboard สลับไปมาระหว่างไทยอังกฤษนี่บอกเลยถึงตายอ่ะครับ

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

ไปอ่านครั้งแรกก็เจอใน Stackoverflow ว่าไฟล์ docx เนี่ยมันเป็น xml contrainer นะเราสามารถเปลี่ยนเป็น zip แล้วแตกไฟล์ออกมาแล้วแก้ไฟล์ชื่อ content.xml ได้เลย

เดียวก่อน! ถ้าใครจะทำตามข้างบนนั้นผม บอกเลยว่า มันไม่ด้ายยยยยยย

ซึ่งก็ลองอยู่หลายทีจนหมดกำลังใจ 555 สงสัยกลับไปเขียน word เหมือนเดิมก็ได้ จนมาเจอ library ตัวนึงชื่อ PHPWord ซึ่งทำให้ PHP สามารถสร้างไฟล์ word ได้ด้วย

ซึ่งวิธีการลงคงไม่ต้องอธิบายอะไร (ใช้ composer หรือไม่ก็ลากๆวางๆเอา) หลักแล้วการทำงานไม่ยากเลยคือ

1.ให้สร้างไฟล์ word ที่มีข้อความพร้อมแทนที่วางไฟล์โดยตั้ง ${value1} โดยใช้ value1 เป็นชื่อตัวแปร


ในรูปตั้งผิดนะต้องเป็น ${value1} อะไรงี้ไม่ใช่แค่ {value1} เฉยๆ

2.ให้ PHPWord โหลดไฟล์ข้อ 1.

$templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor("ch9.docx");

3.สั่งให้ PHPWord แทนที่ข้อความ

$templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor("ch9.docx");
	$templateProcessor->setValue('value1', $v1); //news title
	//...
	$templateProcessor->setValue('value8', $v8); //NEWS CONTENT

4.สั่งให้เซฟ

$templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor("ch9.docx");
	$templateProcessor->setValue('value1', $v1); //news title
	$templateProcessor->setValue('value2', $v2); //DATE OF NEWS 01 ม.ค. 61
	$templateProcessor->setValue('value3', $v3); //NEWS CITY
	$templateProcessor->setValue('value4', $v4); //NEWS PLACE
	$templateProcessor->setValue('value5', $v5); //REPORTER NAME
	$templateProcessor->setValue('value6', $v6); //NEWS NOTE
	$templateProcessor->setValue('value7', $v7); //NEWS HEADLINE
	$templateProcessor->setValue('value8', $v8); //NEWS CONTENT
 
	$templateProcessor->saveAs("news_fn.docx");

แค่นี้ก็สามารถแทนที่ได้แล้ว!แล้วครับ โดยส่วนตัวคิดว่าหลังจากนี้น่าจะทำงานง่ายขึ้นเยอะเลยล่ะ

วันพระ 2561 – 2562 สำหรับโปรแกรมมิ่ง

คือจริงๆก็ไม่ได้มีอะไรซับซ้อนเรื่องมันมีอยู่ว่า ทุกๆก่อนวันพระเราจะมีวันนึงที่เรียกว่าวันโกน เราจะไม่เราว่ามันมีที่มายังไง หรือมีความสำคัญทางศาสนาอย่างไร

แต่ที่สำคัญที่สุดคือ มันเป็นวันก่อนหยุดของร้านหมูครับ … ซึ่งลูกค้าทุกคนจะรุมเข้ามาสั่งของเพื่อตุนของเอาไว้ก่อนที่ร้านจะปิด

ความจำเป็นในครั้งนี้คือ เราต้องทำระบบที่ใช้แจ้งเตือนลูกค้าประจำว่าพรุ่งนี้เป็นวันโกนแล้วให้ประเมิน (self-assign) ว่าจะสั่งหมูเพิ่มขึ้นไหม หรือจะวางแผนเกี่ยวกับสต๊อกอย่างไร

 

ผลคือผมก็นั่งทำข้อมูลเกี่ยวกับวันพระล่วงหน้าไว้ตั้งแต่ปี 61-62 เอาไว้ เป็น timestamp เอาไว้

1533920400
1534611600
1535216400
1535907600
1536426000
1537117200
1537722000
1538413200
1539018000
1539709200
1540314000
1541005200
1541523600
1542214800
1542819600
1543510800
1544115600
1544806800
1545411600
1546102800
1546621200
1547312400
1547917200
1548608400
1549213200
1549904400
1550509200
1551200400
1551718800
1552410000
1553014800
1553706000
1554310800
1555002000
1555606800
1556298000
1556816400
1557507600
1558112400
1558803600
1559408400
1560099600
1560704400
1561395600
1561914000
1562605200
1563210000
1563296400
1563901200
1564506000
1565197200
1565802000
1566493200
1567011600
1567702800
1568307600
1568998800
1569603600
1570294800
1570899600
1571590800
1572109200
1572800400
1573405200
1574096400
1574701200
1575392400
1575997200
1576688400
1577206800

ใครสนใจก็ก๊อปเอาไปใช้ได้ตามอัธยาศัยครับ

เปิดเก๊ะคิดเงิน (Cash Drawer) ผ่านแลนด้วย PHP

จริงๆก่อนที่จะมาเขียนโปรแกรมหน้าร้าน (POS: Point-of-sale) เองก็มพยายามที่จะไปซื้อโปรแกรมคนอื่นเหมือนกันแต่หลายๆเจ้าที่ติดต่อไปก็ไม่ติดต่อกลับมาอาจด้วยเหตุผลที่ว่าร้านเราเล็กเกินไป (ที่คิดแบบนั้นเพราะมีบริษัทนึงแจ้งเรามาแบบนั้น เขาแจ้งว่าไม่คุ้มที่จะให้เซลล์เดินทางไป​) งั้นเอาว่ะ เขียนเองก็ได้

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

จริงๆได้เขียน POS ด้วยตัวเองก็สนุกไปอีกแบบเหมือนกันได้ลองอะไรใหม่ๆบ้าง

เรื่องที่ใหม่มากตอนนั้นคือเรื่องการเปิดเก๊ะคิดเงิน (Cash Drawer) หรือเก๊ะเก็บเงิน คือเราไม่เข้าใจการทำงานมันจริงๆ เพราะเป็นเรื่องที่ใหม่มากๆของเรา

ตอนนั้นการแก้ปัญหาตอนนั้นคือ “สั่งให้เครื่องพิมพ์เป็นผู้เปิดเก๊ะคิดเงินหลังจากที่พิมพ์เสร็จ” (ในตอนนั้นใช้เครื่องพิมพ์ของ XPrinter N200N มั้ง เป็น USB)

ความวิกฤติก็คือ ไม่ว่าจะพิมพ์น้อยหรือเยอะแค่ไหนเครื่องพิมพ์ก็จะสั่งให้เปิดเก๊ะเสมอ (เอ้าก็เป็นคนสั่งเอง)

เราสามารถสั่งให้เรื่องพิมพ์ทำเช่นนั้นได้โดยการ คลิกขวาที่เครื่องพิมพ์เลือก properties แล้วเลือก Dervice Settings แล้วส่วนของ Cash Select ก็เลือกเอาว่าจะให้ทำยังไง (เปิดเก๊ะก่อนพิมพ์ หรือ พิมพ์ให้เสร็จก่อนค่อยเปิดเก๊ะ) อันนี้แล้วแต่ความสะดวกของแต่ละการใช้งาน

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

จนไปเจอคนแนะนำให้ทำ fwrite ส่งค่าเข้าไปที่เครื่องพิมพ์เป็นค่าสำหรับการ kick cash drawer ออกมาซึ่งก็ได้เป็นโค้ตข้างล่างนี้

$fpo = fsockopen("192.168.1.155", 9100, $er, $es, 10); 
if (!$fp) { 
    die('ERROR'); 
}else{ 
  $opencode = Chr(27) . Chr(112) . Chr(0). Chr(148) . Chr(49);
  fwrite($fp, $opencode);
  fclose($fp); 
} 
//192.168.1.155 เป็นเลข IP ของเครื่องพิมพ์ดู IP เครื่องพิมพ์และตั้งค่าได้โดยก่อนเปิดเครื่อง กดปุ่มพ่นกระดาษออกมาค้างไว้แล้วเปิดเครื่อง ปล่อยมือจากปุ่มพ่นกระดาษแล้วจะมีตั้งค่าออกมาครับ

แต่… อย่างที่บอกไปแล้วข้างบนครับคือโค้ตมันออกแบบมาเอาไว้ใช้สำหรับเครื่องพิมพ์ในระบบ Network ซึ่งหมายความว่าจะใช้โค้ตนี้ได้เครื่องพิมพ์ปัจจุบันของผม (แบบ USB) ใช้ไม่ได้ เลยตัดสินใจเปลี่ยนซะเลยเป็น Xprinter เหมือนเดิม แต่เปลี่ยนเป็นรุ่น 80C ซึ่งรองรับ Network

พอเราเสียบสายทุกอย่างเรียบร้อยแล้ว

ไม่ได้ใช้ได้เฉพาะ XPrinter อย่างเดียวนะ ใช้ได้เกือบทุกรุ่นเลยยังไงลองหาข้อมูลเกี่ยวกับ Kick Code กับยี่ห่อ + รุ่นในอินเทอร์เนตดูครับ อย่างของผมคือ 27 112 0 148 49 ดังนั้นก็เอาไปแก้ในโค้ตได้เลยครับ

ร้านหมูเรารองรับ Line Pay Barcode แล้วนะ

ช่วงหลังๆพวก E-Wallet กำลังมาแรง รู้สึกถ้าตามไม่ทันก็จะตกยุค หลังจากเอาพร้อมเพย์มาใส่ชีวิตก็ดีมีคนใช้บ้าง แต่ก็ไม่เยอะเท่าไร

เมื่อสักเดือนสองเดือนก่อนอยู่ๆก็มีคนมาขอจ่ายค่าหมู ด้วย True Wallet

เราก็โชคดีที่มีแอพในเครื่องพอดีก็โชคดีไป เลยรับจ่ายได้ เลยมานั่งนึกดูว่า เราใช้ True Wallet กับอะไรบ้างนึงขึ้นได้ก็เป็น 7-11 แค่โชว์บาร์โค้ตก็จ่ายเงินได้เลย ggez

ก็เลยนึกสนุกอยากเอาไปติดตั้งในระบบ POS ที่ร้านบ้าง เลยไปพบความจริงว่าของทรูไม่ให้ต่อ API ต้องใช้เครื่องตัดเงินของทรูอย่างเดียว… (เห็นได้ตามแม็คโครครับ) เป้าหมายของเราคือการผสานร่างระบบตัดเงินเข้ากับ POS เพราะฉะนั้นถ้าต้องใช้อุปกรณ์ภายนอก มันเสียเวลาพอๆกับเครื่องรูดบัตรเลยป่ะ? ตัดไปก่อนแล้วกัน ไว้อารมณ์ดีแล้วจะกลับมาดูใหม่อีกที

เลยไปสนใจ Blue Wallet กับ Line Pay มาเจอว่า Blue Wallet ยังไม่เปิดให้นักพัฒนาภายนอกเข้ามาใช้งาน โอเคตัดไปอีกหนึ่ง

แต่ Line Pay นี่เปิดให้ลงทะเบียนมานานแล้ว คนใช้ก็มีจำนวนนึง (เราเองก็หนึ่งในนั้น) ก็เลยลองยื่นสมัครไปได้ก็ดีไม่ได้ก็ไม่ได้ซีเรียสอะไร ก็ส่งเอกสารไปๆมาๆ รอบแรกเหมือนเขาไม่มั่นใจว่าทำธุระกิจเกี่ยวกับอะไรเลยขอให้ถ่ายรูปร้านไปให้ ก็ถ่ายไป รอรวมๆ (นับตั้งแต่เริ่มส่งเอกสาร) อยู่ร่วมประมาณ 3 อาทิตย์มั้งถึงจะได้

เรื่องเอกสารไม่มีข้อติ เขียนเอกสาร API ได้ดีมาก อ่านแล้วเข้าใจเลย

ส่วนของการติดต่อฝั่งเซิฟเวอร์แค่ GET/POST ง่ายๆไม่มีอะไรซับซ้อนแค่นี้ก็หักเงินได้เลยง่ายจัง จะติดอยู่นิดหน่อยคือเรื่องของ IP ของเครื่องที่ทำหน้าที่ยิงค่าเข้า API ของไลน์ต้องมี IP ที่คงที่ไม่งั้นจะลงทะเบียน white list IP ในไลน์ไม่ได้ สุดท้ายเลยต้องเอา VPS วาง script ตัดเงินไว้แล้วเรียกผ่าน POS อีกทีนึง

แต่เรื่องค่าธรรมเนียม ขอบอกเลยว่าค่าธรรมเนียมของ Line Pay แพง กว่าค่าธรรมเนียมของเครื่องรูดบัตรที่ขอกับธนาคาร (บัตร top-tier พวกแพตตินั่ม,วิสด้อม ฯลฯ) อีกครับ (อันนี้ไม่ทราบว่าคนอื่นเป็นอย่างไรนะครับ เอาเฉพาะร้านผมนะ)

ถ้าลูกค้ามีเงินในบัญชี Line Pay เหลือแล้วอยากเอามาซื้อของเล็กๆน้อยๆ (กากหมู,น้ำมันหมู) Line Pay มันเร็วกว่าจริงๆแหละครับยิงปุ๊บได้ปั๊บเร็วเวอร์

 

แต่จะให้ลูกค้าชำระเงินเป็นหลักนั้น ทางไลน์คงต้องพิจารณาเรื่องค่าธรรมเนียมหน่อย มันน่ากลัวมาเลย