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.2k
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
FigmaとPHPで作る1ミリたりとも表示崩れしない最強の帳票印刷ソリューション
ttskch
47
28k
データベース/SQL超入門!完全初心者向けに世界一分かりやすく解説します
ttskch
1
4.4k
Symfony UX Autocompleteとかいう 顧客が本当に必要だったもの
ttskch
0
1.7k
就活生あるいは新人エンジニアさんへのお節介なアドバイス
ttskch
0
1.5k
symfony/pantherでWordleを解いてみた
ttskch
0
260
ついに、Webアプリでの帳票印刷のベストプラクティスを編み出しました💡
ttskch
16
19k
phpenvやめました🤦♂️
ttskch
0
1.2k
phpenv on Mac 難しすぎワロタ
ttskch
0
550
1.5流エンジニアの生存戦略
ttskch
12
10k
Other Decks in Programming
See All in Programming
EventSourcingの理想と現実
wenas
5
2k
qmuntal/stateless のススメ
sgash708
0
110
『ドメイン駆動設計をはじめよう』のモデリングアプローチ
masuda220
PRO
4
150
色々なIaCツールを実際に触って比較してみる
iriikeita
0
130
2万ページのSSG運用における工夫と注意点 / Vue Fes Japan 2024
chinen
3
1.3k
Golang と Erlang
taiyow
8
1.8k
RailsのPull requestsのレビューの時に私が考えていること
yahonda
4
1.5k
Vue.js学習の振り返り
hiro_xre
2
130
讓數據說話:用 Python、Prometheus 和 Grafana 講故事
eddie
0
320
Piniaの現状と今後
waka292
5
1.4k
プロジェクト新規参入者のリードタイム短縮の観点から見る、品質の高いコードとアーキテクチャを保つメリット
d_endo
1
950
Vertical Architectures for Scalable Angular Applications
manfredsteyer
PRO
0
290
Featured
See All Featured
Designing the Hi-DPI Web
ddemaree
280
34k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
131
33k
Designing Experiences People Love
moore
138
23k
How GitHub (no longer) Works
holman
311
140k
Put a Button on it: Removing Barriers to Going Fast.
kastner
59
3.5k
Visualization
eitanlees
143
15k
VelocityConf: Rendering Performance Case Studies
addyosmani
325
24k
How STYLIGHT went responsive
nonsquared
95
5.1k
Principles of Awesome APIs and How to Build Them.
keavy
126
17k
How to train your dragon (web standard)
notwaldorf
88
5.6k
GraphQLの誤解/rethinking-graphql
sonatard
66
9.9k
Documentation Writing (for coders)
carmenintech
65
4.4k
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!ʗ