หลายครั้งเวลาที่เราสร้างเว็บไซต์ขึ้นมาก็มักจะต้องมีระบบอัปโหลดภาพเช่นการอัปโหลดภาพโปรไฟล์ แล้วระบบอัปโหลดภาพเนี่ยมันทำยังไงกันนะ แล้วภาพจะถูกเก็บไว้ระบบเราเองก็จะหนัก แล้วเราจะไปเก็บไว้ที่ไหน ในบทความนี้มีคำตอบครับ
เขียนโดย
Thanawat Udchachon
Internship @ borntoDev
Cloudinary คืออะไร
ก่อนอื่นก่อนใดเลยเรามารู้จักกับ Cloudinary กันก่อนดีกว่า Cloudinary เนี่ยเป็นแพลตฟอร์มสำหรับเก็บไฟล์ประเภทสื่อ เช่น ภาพ วิดีโอ ซึ่งก็เจ้านี่แหละ ที่เราจะใช้ในการฝากไฟล์ภาพของเรากัน ว่าแล้วเราก็มาดูบนหน้า dashboard กันเลยก่อนดีกว่า
จะเห็นได้ว่าจะมีข้อมูลต่าง ๆ อย่าง Cloud Name, API Key, API Secret, API Environment variable ซึ่งข้อมูลเหล่านี้แหละ ที่เราจะนำไปใช้ในโปรเจกต์ของเรา แต่ก่อนเราจะไปเริ่มเขียนโค้ดกัน เรามาสร้าง preset กันก่อนดีกว่า โดยเจ้า preset เนี่ย มันเป็นเหมือนการตั้งค่าสำหรับการอัปโหลดภาพให้เหมาะกับงานของเราแต่ละงาน อ่ะ เราไปลองสร้างดูกันก่อนดีกว่า
สร้าง preset สำหรับการอัปโหลดภาพ
ให้เรากดที่ปุ่ม settings ด้านขวาบนแล้วก็ไปที่แถบ Upload แล้วเลื่อนลงมาก็จะเจอกับ Upload presets แล้วก็ให้เรากด Add upload preset
สำหรับ preset นี้เนี่ย ผมจะทำเป็น preset สำหรับ upload ภาพโปรไฟล์ละกัน
ส่วนหลัก ๆ ที่เราจะตั้งค่ากันเนี่ยก็คือชื่อของ preset ในที่นี้ก็จะเป็น profile_pic แล้วก็ชื่อ folder ซึ่งก็จะเป็น profile_pic เหมือนกัน ซึ่ง folder ที่ว่าเนี่ยมันคือที่เก็บไฟล์ ซึ่งก็อยู่บน Cloudinary นี่แหละ แล้วก็อีกส่วนก็คือ Overwrite ในที่นี้จะตั้งเป็น on ไว้เพราะภาพโปรไฟล์เก่าก็จะไม่ถูกใช้อยู่แล้ว เราก็เลยให้เวลาอัปภาพโปรไฟล์ใหม่ขึ้นมาจะให้ไปทับภาพเดิมเลย
มาเริ่มเขียนโค้ดกันเลยดีกว่า
สำหรับตัวอย่างโค้ดจะขอใช้เป็น React.js แล้วก็ Express.js สำหรับบันทึกที่อยู่ไฟล์ลง database นะครับ
เอาล่ะอันดับแรกเรามาดูโค้ดตั้งต้นกันก่อนดีกว่า
import React from 'react'; export default function Upload() { return ( <div> <form> <input type="file" /> <button type="submit"> submit </button> </form > </div > ) }
ซึ่งโค้ดนี้ก็เป็นการแสดงปุ่มเลือกไฟล์ที่เลือกไฟล์ไปแล้วก็ยังทำอะไรต่อไม่ได้กับปุ่ม submit เปล่า ๆ นะครับ
ต่อมาเรามาเขียนฟังก์ชันรับไฟล์ภาพกัน
โดยฟังก์ชันเราก็จะไม่ได้มีอะไรซับซ้อนโดยเราจะให้เมื่อเลือกไฟล์แล้วจะให้ไฟล์ภาพนั้นไปเก็บไว้ใน state แล้วเมื่อกดปุ่ม submit ก็จะส่งไฟล์ที่อยู่ใน state ไปที่ back-end ผ่าน axios นั้นเอง
import React, { useState } from 'react'; import Axios from 'axios'; export default function Upload() { Axios.defaults.withCredentials = true; const [imageFile, setImageFile] = useState(''); const handleFileInputChange = (e) => { const file = e.target.files[0]; const reader = new FileReader(); reader.readAsDataURL(file); reader.onloadend = () => { setImageFile(reader.result); } } const handleSubmitFile = (e) => { e.preventDefault(); if (!imageFile) return; Axios.put(`api url`, { data: imageFile}); } return ( <div> <form onSubmit={handleSubmitFile}> <input type="file" onChange={handleFileInputChange} /> <button type="submit"> submit </button> </form > </div > ) }
โดยในส่วนของ api url นี้จะเป็น url ของ back-end ของเราหรือจะเป็น url ของ Cloudinary เลยก็ได้ ซึ่งจะเป็นลิงก์แบบนี้ httpsุ://api.cloudinary.com/v1_1/(Cloud Name ของ Cloudinary)/upload
แต่เราจะต้องใส่ข้อมูล key อื่น ๆ ของ Cloudinary ไปด้วย แต่ในที่นี้เราจะไปเขียนกันใน back-end แต่ก่อนอื่นเรามาติดตั้งเจ้า cloudinary กันก่อนดีกว่า ซึ่งก็สามารถเข้าไปในลิงก์ต่อไปนี้ได้เลยครับ https://www.npmjs.com/package/cloudinary
เอาล่ะแล้วเราก็มาโผล่บน express.js ของเรากัน
router.use(express.json({ limit: '50mb' })); router.use(express.urlencoded({ limit: '50mb', extended: true })); const { cloudinary } = require('../utils/cloudinary'); router.put('/upload', async (req, res) => { try { const user = req.session.user[0]; const fileStr = req.body.data; const uploadedResponse = await cloudinary.uploader.upload(fileStr, { upload_preset: 'profile_pic', public_id: `${user.userId}` }); console.log(uploadedResponse); const url = uploadedResponse.url; var sql = `UPDATE Users SET imgProfile="${url}" WHERE userId = ${user.userId}`; db.query(sql, (err, result) => { if (err) { console.log(err); } else { console.log(result); } }); res.json({ msg: 'Upload complete' }); } catch (error) { console.error(error); res.status(500).json({ err: 'Something went wrong' }) } });
อันนี้ก็จะเป็นตัวอย่างโค้ด back-end ของการอัปโหลดรูปภาพขึ้น Cloudinary โค้ดอาจจะดูเยอะไปสักหน่อย ซึ่งจริง ๆ ตัวสำคัญมันก็ไม่ได้มีเยอะอะไร ว่าแล้วก็มาอธิบายโค้ดกันสักหน่อยดีกว่า
ส่วนแรกเลยคือเจ้า {cloudinary} จะเป็นตัวที่เก็บข้อมูลต่าง ๆ สำหรับ cloudinary ไว้เช่น key ต่าง ๆ
โดยเราจะตั้งชื่อเจ้าไฟล์นี้กันว่า cloudinary.js ซึ่งมีหน้าตาโค้ดดังนี้
require('dotenv').config(); const cloudinary = require('cloudinary').v2; cloudinary.config({ cloud_name: process.env.CLOUDINARY_NAME, api_key: process.env.CLOUDINARY_API_KEY, api_secret: process.env.CLOUDINARY_API_SECRET, }); module.exports = { cloudinary };
ซึ่งที่จริงแล้วเราสามารถนำ key ต่าง ๆ ของ cloudinary มาพิมพ์ใส่ตรง ๆ เลยก็ได้ แต่เพื่อความปลอดภัย แนะนำว่าเก็บไว้ใน .env จะดีกว่า โดยการจะใช้ .env ขอแนะนำเจ้า dotenv ซึ่งก็สามารถไปติดตั้งกันได้ตามลิงก์นี้เลยครับ https://www.npmjs.com/package/dotenv
ต่อมานะครับ อย่างที่บอกไปก่อนหน้านี้ว่าเราจะทำระบบอัปโหลดรูปโปรไฟล์กัน ดังนั้น method ที่เราจะใช้จะเป็น PUT เพื่อไปแก้ลิงก์รูปโปรไฟล์ใน database นะครับ แต่ถ้าหากเพื่อนอยากจะทำระบบอัปโหลดภาพโดยไม่ต้องไปแก้ข้อมูลที่มีอยู่แล้วใน database ก็สามารถใช้เป็น method POST ได้เลยครับผม โดยการทำงานของมันหลัก ๆ นะครับมันก็จะส่งข้อมูลไปตามข้อมูลที่เราใส่ไว้ใน cloudinary.js โดยเป็น preset profile_pic ตามที่เราได้ตั้งค่าไว้ก่อนหน้านี้ และตั้งชื่อไฟล์ตาม userId ของระบบเรา เพื่อที่ว่าถ้า user ของเว็บไซต์เราได้ทำการอัปโหลดภาพโปรไฟล์ใหม่จะได้ไปทับโปรไฟล์เดิมของเขาบน cloudinary เลย
และหลังจากที่อัปโหลดไปแล้วเราจะได้ response กลับมา โดยเราสามารถดูได้จาก console.log(uploadedResponse) ซึ่งในนั้นก็จะมี url ซึ่งเป็นลิงก์ของภาพที่เราได้ทำการอัปโหลดขึ้นไป แล้วเราก็ทำการบันทึกลิงก์ดังกล่าวลงไปใน database ของเราสำหรับการเรียกแสดง
โดยภาพที่เราทำการอัปโหลดก็จะมาโผล่เป็นเว็บไซต์ Cloudinary ในส่วนของ Media Library ตามนี้เลย
สรุปสุดท้ายสิ่งที่ผู้อ่านจะได้รับ
เป็นยังไงกันบ้างครับสำหรับระบบอัปโหลดรูปภาพและเก็บไฟล์ด้วย Cloudinary อยากจะลองให้ลองไปเล่น preset กันดู โดยนอกจากการรับอัปโหลดที่ละไฟล์แล้วมันยังสามารถอัปทีละหลายไฟล์หรือตั้งไม่ให้ทับไฟล์เก่าและอีกมากมายครับ และก็เพิ่มเติมสำหรับเพื่อน ๆ ที่ไม่อยากให้เป็นปุ่มอัปโหลดแต่อยากให้สามารถลากวางไฟล์ได้เลยก็ขอแนะนำเจ้า Dropzone ซึ่งสามารถติดตั้งได้ที่ลิงก์นี้ได้เลยครับ https://www.npmjs.com/package/dropzone
อ้างอิงจาก
- Cloudinary Image Upload with Nodejs and React, สืบค้นเมื่อ 27 มกราคม 2565 จาก: https://www.youtube.com/watch?v=Rw_QeJLnCK4&t=849s
- Image Uploads to Cloudinary in React with Drag & Drop, สืบค้นเมื่อ 27 มกราคม 2565 จาก: https://www.youtube.com/watch?v=V8w7K1HdrFo&t=404s