Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
PHPでCSVのインポート/エクスポートに立ち向かう
Search
Takashi Kanemoto
May 29, 2021
Programming
1
2.4k
PHPでCSVのインポート/エクスポートに立ち向かう
PHPカンファレンス沖縄2021の発表資料です。
https://connpass.com/event/212058/
Takashi Kanemoto
May 29, 2021
Tweet
Share
More Decks by Takashi Kanemoto
See All by Takashi Kanemoto
いりゃあせ、PHPカンファレンス名古屋2025 / Welcome to PHP Conference Nagoya 2025
ttskch
1
350
PHPとAPI Platformで作る本格的なWeb APIアプリケーション(入門編) / phpcon 2024 Intro to API Platform
ttskch
0
740
今年書いた技術記事で伸びたやつの自慢と自分の中では力作なのにさっぱり伸びなかったやつの供養 / My Tech Articles 2024
ttskch
2
120
FigmaとPHPで作る1ミリたりとも表示崩れしない最強の帳票印刷ソリューション
ttskch
47
37k
データベース/SQL超入門!完全初心者向けに世界一分かりやすく解説します
ttskch
1
6k
Symfony UX Autocompleteとかいう 顧客が本当に必要だったもの
ttskch
0
2k
就活生あるいは新人エンジニアさんへのお節介なアドバイス
ttskch
0
1.6k
symfony/pantherでWordleを解いてみた
ttskch
0
340
ついに、Webアプリでの帳票印刷のベストプラクティスを編み出しました💡
ttskch
16
19k
Other Decks in Programming
See All in Programming
Composerが「依存解決」のためにどんな工夫をしているか #phpcon
o0h
PRO
1
230
[初登壇@jAZUG]アプリ開発者が気になるGoogleCloud/Azure+wasm/wasi
asaringo
0
130
なぜ「共通化」を考え、失敗を繰り返すのか
rinchoku
1
530
Haskell でアルゴリズムを抽象化する / 関数型言語で競技プログラミング
naoya
17
4.9k
アンドパッドの Go 勉強会「 gopher 会」とその内容の紹介
andpad
0
270
なぜ適用するか、移行して理解するClean Architecture 〜構造を超えて設計を継承する〜 / Why Apply, Migrate and Understand Clean Architecture - Inherit Design Beyond Structure
seike460
PRO
1
690
既存デザインを変更せずにタップ領域を広げる方法
tahia910
1
240
プロダクト志向ってなんなんだろうね
righttouch
PRO
0
160
WindowInsetsだってテストしたい
ryunen344
1
200
CursorはMCPを使った方が良いぞ
taigakono
1
180
今ならAmazon ECSのサービス間通信をどう選ぶか / Selection of ECS Interservice Communication 2025
tkikuc
20
3.6k
XP, Testing and ninja testing
m_seki
3
200
Featured
See All Featured
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
20
1.3k
Designing Experiences People Love
moore
142
24k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
248
1.3M
Build your cross-platform service in a week with App Engine
jlugia
231
18k
Code Reviewing Like a Champion
maltzj
524
40k
Six Lessons from altMBA
skipperchong
28
3.8k
Keith and Marios Guide to Fast Websites
keithpitt
411
22k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
357
30k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
181
53k
Writing Fast Ruby
sferik
628
61k
Fireside Chat
paigeccino
37
3.5k
The Language of Interfaces
destraynor
158
25k
Transcript
/32 2021/05/29 #phpcon_okinawa @ttskch 1 PHPͰCSVͷΠϯϙʔτ/ ΤΫεϙʔτʹཱ͔ͪ͏
/32 • ϦεςΟϯάࠂͷձࣾͰWebαʔϏεΛ࡞ͬͯ·ͨ͠ • CTOͱͯ͠ࡏ੶ͨ͠8ؒͰɺࣾһ2໊ˠ60໊ɺ ച্ن5000ສԁˠ27ԯԁʹ·Ͱ 💪 💪 💪
• ຊΛॻ͍ͨΓSchooͰߨٛͨ͠Γͱ͍ͬͨ׆ಈ 2 ͖ͨͭͪ ʙ2020/03 (ג)ΧϧςοτίϛϡχέʔγϣϯζCTO 📝 blog.ttskch.com/thank-you-quartet-communications @ttskch
/32 • डୗ։ൃͱࣾ֎CTO/ٕज़ސۀத৺Ͱ׆ಈͯ͠·͢ • Symfony͕େ͖Ͱ͢ ✨ • ڈΞυϕϯτΧϨϯμʔΛ1ਓͰ15ॻ͍ͨΓ 10ສจࣈͷిࢠॻ੶Λແྉެ։ͨ͠Γ͠·ͨ͠💪💪💪
3 ͖ͨͭͪ 2020/04ʙ ϑϦʔϥϯεWebΤϯδχΞ 👨💻 https://kannade.jp @ttskch
/32 2021/05/29 #phpcon_okinawa @ttskch 4 PHPͰCSVͷΠϯϙʔτ/ ΤΫεϙʔτʹཱ͔ͪ͏
/32 • ࣮ExcelBOM͖UTF-8ͷCSVΛ։͚ΔͷͰSJISͰग़ྗ͢Δඞཁͳ͍ • league/csvΛͬͨΠϯϙʔτ/ΤΫεϙʔτͷ࣮ྫΛհ • Πϯϙʔτ/ΤΫεϙʔτʹಛԽͨ͠ttskch/bulkonyΛ͑ ͬͱ؆୯/ॊೈʹ࣮Ͱ͖Δ 5
✅͜ͷτʔΫͷཁ 10͔͠ͳ͍ͷͰαϥοͱͰ͢🙏
/32 6 ExcelBOM͖UTF-8ͷ CSVΛ։͚Δ
/32 7 ҙ֎ͱΒΕ͍ͯͳ͍ࣄ࣮ https://ja.wikipedia.org/wiki/UTF-8#όΠτॱϚʔΫͷ༻ ExcelBOM͖UTF-8ͷCSVΛ։͚Δ ٯʹݴ͏ͱɺBOM͖Ͱ͋ΕUTF-8Ͱී௨ʹ։͚Δ😳
/32 $fp = fopen('/path/to/output.csv', 'w+');ʊ fwrite($fp, "\xEF\xBB\xBF"); // ϑΝΠϧͷઌ಄ʹBOMΛૠೖ foreach
($data as $row) {ʊ fputcsv($fp, $row);ʊ }ʊ fclose($fp); 8 PHPͰग़ྗ͢Δྫ https://ja.wikipedia.org/wiki/όΠτॱϚʔΫ ϑΝΠϧͷઌ಄ʹ ”EF BB BF” ͱ͍͏όΠφϦΛՃ͢Δ͚ͩ👌 ExcelBOM͖UTF-8ͷCSVΛ։͚Δ
/32 $fp = fopen('/path/to/output.csv', 'w+');ʊ fwrite($fp, "\xEF\xBB\xBF"); // ϑΝΠϧͷઌ಄ʹBOMΛૠೖ foreach
($data as $row) {ʊ fputcsv($fp, $row);ʊ }ʊ fclose($fp); 9 PHPͰग़ྗ͢Δྫ https://ja.wikipedia.org/wiki/όΠτॱϚʔΫ ϑΝΠϧͷઌ಄ʹ ”EF BB BF” ͱ͍͏όΠφϦΛՃ͢Δ͚ͩ👌 ExcelBOM͖UTF-8ͷCSVΛ։͚Δ
/32 $fp = fopen('/path/to/output.csv', 'w+');ʊ fwrite($fp, "\xEF\xBB\xBF"); // ϑΝΠϧͷઌ಄ʹBOMΛૠೖ foreach
($data as $row) {ʊ fputcsv($fp, $row);ʊ }ʊ fclose($fp); 10 PHPͰग़ྗ͢Δྫ https://ja.wikipedia.org/wiki/όΠτॱϚʔΫ ϑΝΠϧͷઌ಄ʹ ”EF BB BF” ͱ͍͏όΠφϦΛՃ͢Δ͚ͩ👌 ExcelBOM͖UTF-8ͷCSVΛ։͚Δ
/32 • ExcelͰ։͍ͯΒ͏ͨΊ͚ͩʹSJISͰग़ྗ͢Δඞཁͳ͍ • UTF-8͔ΒSJISʹม͢ΔͱSJISʹଘࡏ͠ͳ͍จࣈ͕ ? ʹͳΔ • SJIS͔ΒͷΠϯϙʔτͬͱհͳͷͰɺ
ΞϓϦ͕ు͍ͨCSVΛΠϯϙʔτʹ͏߹ಛʹBOM͖UTF-8Ұ 11 ✅ BOM͖UTF-8Λੵۃతʹ͓͏ ExcelBOM͖UTF-8ͷCSVΛ։͚Δ ※ SJISͷCSVΛ҆શʹѻ͓͏ͱ͢Δͱߟྀ͢Δ͜ͱ͕৭ʑ͋Γ·͢ʢεϥΠυͷ࠷ޙͰࢀߟURLΛ͝հ͠·͢ʣ
/32 12 league/csvΛͬͨ Πϯϙʔτ/ΤΫεϙʔτͷ࣮ྫ
/32 • ۙΑ͘ΘΕ͍ͯΔɺCSVΛ؆୯ʹѻ͏ͨΊͷPHPϥΠϒϥϦ • fgetcsvͱ͔ΛͬͯࣗྗͰϨΠϠʔͷίʔυΛॻ͔ͳͯ͘ɺ CSVΛ͍͍ײ͡ʹநԽͯ͘͠ΕΔ 13 league/csvͱ league/csvΛͬͨΠϯϙʔτ/ΤΫεϙʔτͷ࣮ྫ
/32 $csv = Reader::createFromPath('/path/to/input.csv');ʊ $csv->setHeaderOffset(0); // ϔομʔ͕0ߦͰ͋Δ͜ͱΛએݴ $rows = $csv->getRecords();ʊ
foreach ($rows as $row) {ʊ // ࣮ࡍͷΠϯϙʔτॲཧ } 14 Πϯϙʔτͷ࣮ྫ league/csvΛͬͨΠϯϙʔτ/ΤΫεϙʔτͷ࣮ྫ
/32 $csv = Reader::createFromPath('/path/to/input.csv');ʊ $csv->setHeaderOffset(0); // ϔομʔ͕0ߦͰ͋Δ͜ͱΛએݴ $rows = $csv->getRecords();ʊ
foreach ($rows as $row) {ʊ // ࣮ࡍͷΠϯϙʔτॲཧ } 15 Πϯϙʔτͷ࣮ྫ league/csvΛͬͨΠϯϙʔτ/ΤΫεϙʔτͷ࣮ྫ શσʔλͷྻͰͳ͘ 1ߦͣͭऔಘͰ͖ΔΠςϨʔλͳͷͰ লϝϞϦ
/32 $csv = Reader::createFromPath('/path/to/input.csv');ʊ $csv->setHeaderOffset(0); // ϔομʔ͕0ߦͰ͋Δ͜ͱΛએݴ $rows = $csv->getRecords();ʊ
foreach ($rows as $row) {ʊ // ࣮ࡍͷΠϯϙʔτॲཧ } 16 Πϯϙʔτͷ࣮ྫ league/csvΛͬͨΠϯϙʔτ/ΤΫεϙʔτͷ࣮ྫ ϔομʔߦͷҐஔΛએݴͨ͠ͷͰ [ 'ྻ໊' => '', 'ྻ໊' => '', : ] ͱ͍͏ܗࣜͷྻσʔλ͕ಘΒΕΔ ͜ΕΛͬͯΠϯϙʔτॲཧΛॻ͘
/32 $csv = Writer::createFromPath('php://temp');ʊ $csv->insertOne(['ྻ1', 'ྻ2', 'ྻ3']); // Ұߦૠೖ $csv->insertAll($data);
// ೋ࣍ݩྻͰෳߦ·ͱΊͯૠೖ // ग़ྗ࣌ʹBOMΛՃ͢ΔΑ͏ઃఆ $csv->setOutputBOM("\xEF\xBB\xBF");ʊ $csv->output('μϯϩʔυ.csv'); 17 ΤΫεϙʔτͷ࣮ྫ league/csvΛͬͨΠϯϙʔτ/ΤΫεϙʔτͷ࣮ྫ
/32 $csv = Writer::createFromPath('php://temp');ʊ $csv->insertOne(['ྻ1', 'ྻ2', 'ྻ3']); // Ұߦૠೖ $csv->insertAll($data);
// ೋ࣍ݩྻͰෳߦ·ͱΊͯૠೖ // ग़ྗ࣌ʹBOMΛՃ͢ΔΑ͏ઃఆ $csv->setOutputBOM("\xEF\xBB\xBF");ʊ $csv->output('μϯϩʔυ.csv'); 18 ΤΫεϙʔτͷ࣮ྫ league/csvΛͬͨΠϯϙʔτ/ΤΫεϙʔτͷ࣮ྫ ࢦఆͨ͠ϑΝΠϧ໊Ͱ_ μϯϩʔυͤ͞ΔͨΊͷ HTTPϨεϙϯεΛૹग़
/32 • ಛʹΠϯϙʔτɺ • ೖྗσʔλͷόϦσʔγϣϯ • Πϯϙʔτ࣮ߦલʹը໘ͰϓϨϏϡʔ ͳͲ͕ඞཁʹͳΔͱ్ʹΔ͜ͱ͕૿͑ͯͻͨ͢Βେม😓 19 Ͱɺ·ͩ·ͩࣗલͰ࣮͖͢͜ͱ͕ଟ͍…
league/csvΛͬͨΠϯϙʔτ/ΤΫεϙʔτͷ࣮ྫ
/32 20
/32 21 Ή͠Ζ͜͜Λָ͍ͨ͠…😓
/32 22 ttskch/bulkony
/32 • PHPΞϓϦʹΠϯϙʔτ/ΤΫεϙʔτػೳΛ࣮͢Δࡍʹ ͍ͭॻ͍͍ͯͨ͋Ε͜ΕΛϥΠϒϥϦʹΓग़͠·ͨ͠ • ⚡BOM͖UTF-8ͰͷΤΫεϙʔτ • ⚡ϝϞϦޮʹྀͨ͠Πϯϙʔτ/ΤΫεϙʔτͷΛఏڙ •
⚡Πϯϙʔτ༰ͷόϦσʔγϣϯͷΛఏڙ • ⚡Πϯϙʔτ༰ͷϓϨϏϡʔػೳͷΛఏڙ 23 ttskch/bulkonyͱ ttskch/bulkony
/32 use Ttskch\Bulkony\Export\Exporter;ʊ $exporter = new Exporter();ʊ $rowGenerator = new
App\RowGenerator(); // ࣗ࡞Ϋϥε // ϑΝΠϧγεςϜʹग़ྗ $exporter->export('/path/to/output.csv', $rowGenerator);ʊ // HTTPϨεϙϯεΛૹग़ $exporter->exportAndOutput('users.csv', $rowGenerator); 24 ར༻ΠϝʔδʢΤΫεϙʔτʣ ttskch/bulkony
/32 use Ttskch\Bulkony\Export\Exporter;ʊ $exporter = new Exporter();ʊ $rowGenerator = new
App\RowGenerator(); // ࣗ࡞Ϋϥε // ϑΝΠϧγεςϜʹग़ྗ $exporter->export('/path/to/output.csv', $rowGenerator);ʊ // HTTPϨεϙϯεΛૹग़ $exporter->exportAndOutput('users.csv', $rowGenerator); 25 ར༻ΠϝʔδʢΤΫεϙʔτʣ ttskch/bulkony ͜ͷΫϥεʹCSVߦͷੜखॱΛॻ͘👨💻 ※ ৄࡉREADMEΛ͝ࢀর͍ͩ͘͞🙏
/32 use Ttskch\Bulkony\Import\Importer;ʊ $importer = new Importer();ʊ $rowVisitor = new
App\RowVisitor(); // ࣗ࡞Ϋϥε // CSVͷͲͷηϧʹόϦσʔγϣϯΤϥʔ͕͋Δ͔ɺ // ΠϯϙʔτʹΑͬͯͲ͜ͷ͕ߋ৽͞ΕΔ͔ɺͷใ͕ಘΒΕΔ $preview = $importer->preview('/path/to/input.csv', $rowVisitor);ʊ // ͦΕΛը໘ʹදࣔ͢ΕϓϨϏϡʔػೳ render('some.template', ['preview' => $preview]); 26 ར༻ΠϝʔδʢΠϯϙʔτʣ ttskch/bulkony
/32 use Ttskch\Bulkony\Import\Importer;ʊ $importer = new Importer();ʊ $rowVisitor = new
App\RowVisitor(); // ࣗ࡞Ϋϥε // CSVͷͲͷηϧʹόϦσʔγϣϯΤϥʔ͕͋Δ͔ɺ // ΠϯϙʔτʹΑͬͯͲ͜ͷ͕ߋ৽͞ΕΔ͔ɺͷใ͕ಘΒΕΔ $preview = $importer->preview('/path/to/input.csv', $rowVisitor);ʊ // ͦΕΛը໘ʹදࣔ͢ΕϓϨϏϡʔػೳ render('some.template', ['preview' => $preview]); 27 ར༻ΠϝʔδʢΠϯϙʔτʣ ttskch/bulkony ͜ͷΫϥεʹߦ͝ͱͷΠϯϙʔτ όϦσʔγϣϯͷϩδοΫΛॻ͘👨💻 ※ ৄࡉREADMEΛ͝ࢀর͍ͩ͘͞🙏
/32 28 ΑΖ͚͠ΕͬͯΈ͍ͯͩ͘͞😇 https://github.com/ttskch/bulkony
/32 29 ·ͱΊ
/32 • ࣮ExcelBOM͖UTF-8ͷCSVΛ։͚ΔͷͰSJISͰग़ྗ͢Δඞཁͳ͍ • league/csvΛͬͨΠϯϙʔτ/ΤΫεϙʔτͷ࣮ྫΛհ • Πϯϙʔτ/ΤΫεϙʔτʹಛԽͨ͠ttskch/bulkonyΛ͑ ͬͱ؆୯/ॊೈʹ࣮Ͱ͖Δ 30
✅͜ͷτʔΫͷཁ
/32 • SJISͷCSVΛจࣈԽ͚ͤͣʹಡΈॻ͖͢Δํ๏ʹ͍ͭͯɺ PHPerKaigi 2021ͷए༿ষ͞Μͷηογϣϯ͕େมࢀߟʹͳΓ·͢ • https://youtu.be/pc6ov8HWt1A 31 📝ؔ࿈͢Δ͓͢͢Ίใ
/32 32 @ttskch ʘThanks!ʗ