Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
iOSDCを支えるDrupal8 / Drupal 8 - backend of iOSDC
Search
HASEGAWA Tomoki
July 25, 2016
Technology
110
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
iOSDCを支えるDrupal8 / Drupal 8 - backend of iOSDC
Drupal Meetup #1のスライドです。
HASEGAWA Tomoki
July 25, 2016
More Decks by HASEGAWA Tomoki
See All by HASEGAWA Tomoki
ファミコンでPHPを動かす / PHP on the Famicom
tomzoh
2
1.7k
3Dプリンタでコレはこう作る! - マルチディスプレイ用モニタアームマウンタの作り方 / Made with a 3D Printer: DIY Multi-Display Monitor Arm Mount
tomzoh
0
190
デシリアライゼーションを理解する / Inside Deserialization
tomzoh
0
1.2k
PHPer Book Revue: CPUの創りかた / How to Build a CPU
tomzoh
0
140
超入門3Dプリンタ: 生活を便利にするモノを作ろう / Getting Started with 3D Printing: Making small things that quietly improve your daily life.
tomzoh
0
110
最新ハードウェアの中の8ビットCPU / The Hidden Power of 8-Bit CPUs in Modern Hardware
tomzoh
0
390
PHPからはじめるコンピュータアーキテクチャ / From Scripts to Silicon: A Journey Through the Layers of Computing Hiroshima 2025 Edition
tomzoh
0
480
PHPからはじめるコンピュータアーキテクチャ / From Scripts to Silicon: A Journey Through the Layers of Computing
tomzoh
5
1k
低レイヤを知りたいPHPerのためのCコンパイラ作成入門 完全版 / Building a C Compiler for PHPers Who Want to Dive into Low-Level Programming - Expanded
tomzoh
6
5k
Other Decks in Technology
See All in Technology
「図書館」という名前のままでいいのか -Code4Lib JAPANカンファレンス2026 アンカンファレンス報告- / Code4Lib JAPAN Conference 2026: Unconference Report
ykiyota
0
170
GoCon2026 - Open Source, Open World
sanposhiho
4
3.4k
作品が生態系になった ─ Mini Tokyo 3D から世界へ
nagix
0
170
幾何アルゴリズムで なめらかなピン操作を / iOSDC Japan 2026 / smoothpin
kazumanagano
0
290
module Synths; end
asonas
1
130
2026-09-09 【sigma_ucj#1】Sigma を IaC 管理したい! / IaC for Sigma
civitaspo
0
120
Sigmaユーザーのための有用リソース一挙公開 & Sigmaで使えるMCP #sigma_ucj /useful-resources-for-sigma-computing-users-and-mcps-with-sigma
shinyaa31
0
200
#jawssonic2026 あの時代が悪かった ~動かなかったSageMakerと共に迎えたイベント当日~
ktkn1129
0
150
AIエージェントの自己改善をどう設計するか / How to Design Self-Improvement for AI Agents
22mi
14
7.8k
20260906 「AWS運用入門」著者が教える、運用業務への生成AI活用入門
masaruogura
0
260
AIで仕事のやり方を変える
matsu7874
3
1.1k
家のリアーキテクト・リファクタリング
suguruooki
0
130
Featured
See All Featured
Scaling GitHub
holman
464
140k
Imperfection Machines: The Place of Print at Facebook
scottboms
270
14k
The agentic SEO stack - context over prompts
schlessera
0
930
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
[SF Ruby Conf 2025] Rails X
palkan
2
1.4k
How STYLIGHT went responsive
nonsquared
100
6.3k
Navigating Team Friction
lara
192
16k
Thoughts on Productivity
jonyablonski
76
5.4k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
1.3k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
38
3k
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
980
Why Your Marketing Sucks and What You Can Do About It - Sophie Logan
marketingsoph
0
410
Transcript
iOSDCを支えるDrupal8 Drupal 8 - backend of iOSDC 長谷川智希 HASEGAWA Tomoki
この資料は後ほど公開します This slide will be published later.
ライフワーク: Web / iOSアプリ開発, ビール, 電子工作, サッカー観戦, レンタルカートレース, … 長谷川
智希 Web / iOS App Development, Beer, IoT, Watch soccer match, Rental Kart Racing, … デジタルサーカス株式会社 副団長CTO Digital Circus, Inc. Vice-master CTO Tokyo, Japan Hobby: @tomzoh
None
None
WE ARE HIRING!! Web Development Mobile App Development ( )
(iOS, Android) http://www.dgcircus.com Omotesando, Tokyo
今日のテーマ Drupal 8 - backend of iOSDC iOSDCを支えるDrupal8 Today’s theme
iOSDC https://iosdc.jp
技術カンファレンス • スピーカーを募集して技術トークをする。 • チケットを販売。 • スポンサーを募集して快適度アップ。 • 運営は公募したボランティアスタッフ。 •
開催情報は公式サイトにて告知。
技術カンファレンス • スピーカーを募集して技術トークをする。 • チケットを販売。 • スポンサーを募集して快適度アップ。 • 運営は公募したボランティアスタッフ。 •
開催情報は公式サイトにて告知。
技術カンファレンス • スピーカーを募集して技術トークをする。 • チケットを販売。 • スポンサーを募集して快適度アップ。 • 運営は公募したボランティアスタッフ。 •
開催情報は公式サイトにて告知。
技術カンファレンス • スピーカーを募集して技術トークをする。 • チケットを販売。 • スポンサーを募集して快適度アップ。 • 運営は公募したボランティアスタッフ。 •
開催情報は公式サイトにて告知。
技術カンファレンス • スピーカーを募集して技術トークをする。 • チケットを販売。 • スポンサーを募集して快適度アップ。 • 運営は公募したボランティアスタッフ。 •
開催情報は公式サイトにて告知。
募集
数多くのフォーム
トーク応募フォーム
スポンサー申込フォーム
当日スタッフ募集フォーム
スピーカーディナー参加フォーム
フォームが増えるたびに いちいちプログラムを作るのか…
否
ではどうするか
None
None
iOSDCを支える技術
iOSDCを支える技術
今日のテーマ Drupal 8 - backend of iOSDC iOSDCを支えるDrupal8 Today’s theme
Googleフォーム & スプレッドシート
Google フォーム • フォームを作るサービス。 • いくつかの入力形式。 • テキスト入力 • チェックボックス
• ラジオボタン • 複数ページ対応なども可能。 • アンケート的な集計も可。
Google スプレッドシート • Excel • 複数人での同時編集可。 • Googleフォームの入力内容を 流し込める •
APIからアクセスできる。
• 開催が決まる • 各種募集を行う • コアスタッフ • トーク • スポンサー
• デザインができる • Webサイトができる カンファレンス × CMS
• 開催が決まる • 各種募集を行う • コアスタッフ • トーク • スポンサー
• デザインができる • Webサイトができる カンファレンス × CMS
• 開催が決まる • 各種募集を行う • コアスタッフ • トーク • スポンサー
• デザインができる • Webサイトができる カンファレンス × CMS オンラインコラボレーション
• 開催が決まる • 各種募集を行う • コアスタッフ • トーク • スポンサー
• デザインができる • Webサイトができる カンファレンス × CMS オンラインコラボレーション 情報公開
None
iOSDCサイト •応募されたトーク •採用されたトーク •チケットを購入したユーザ •写真登録
iOSDCサイト •応募されたトーク •採用されたトーク •チケットを購入したユーザ •写真登録 トーク応募
iOSDCサイト •応募されたトーク •採用されたトーク •チケットを購入したユーザ •写真登録 トーク応募 購入者データ
iOSDCサイト •応募されたトーク •採用されたトーク •チケットを購入したユーザ •写真登録 トーク応募 購入者データ 参加者 アイコン
Case 1: Googleフォーム → Drupal
iOSDCサイト •応募されたトーク •採用されたトーク •チケットを購入したユーザ •写真登録 トーク応募 購入者データ 参加者 アイコン
iOSDCサイト •応募されたトーク •採用されたトーク •チケットを購入したユーザ •写真登録 トーク応募 購入者データ 参加者 アイコン Google
API + CRON
Googleスプレッドシートアクセス • 2通りの方法: • Google Developers Consoleで認証情報を設定して、OSSの PHP用モジュールをインストール • データ取得用のURLからデータ取得
• iOSDCでは後者を使用。 • データが読めれば良かった。(書き込みは不要) • 後者は認証が不要でラク。 • どちらにしても値のアクセスはやや面倒。
function get_cfps(){ $url = 'https://spreadsheets.google.com/feeds/cells/xxx/yyy/public/values?alt=json'; $json = file_get_contents($url); $data =
json_decode($json, true); // CfP parser used as generator function sheet_parser($data){ $row_cursor = 1; $cols = []; foreach ($data['feed']['entry'] as $cell){ $c = $cell['gs$cell']; $row = intval($c['row']); if ($row !== $row_cursor){ yield $cols; $cols = []; $row_cursor = $row; } $cols[] = trim($c['$t']); } } $rows = sheet_parser($data); $cfps = []; foreach ($rows as $row){ if (! trim(implode('', $row))){ break; } $cfps[] = $row; } array_shift($cfps); return $cfps; }
function get_cfps(){ $url = 'https://spreadsheets.google.com/feeds/cells/xxx/yyy/public/values?alt=json'; $json = file_get_contents($url); $data =
json_decode($json, true); // CfP parser used as generator function sheet_parser($data){ $row_cursor = 1; $cols = []; foreach ($data['feed']['entry'] as $cell){ $c = $cell['gs$cell']; $row = intval($c['row']); if ($row !== $row_cursor){ yield $cols; $cols = []; $row_cursor = $row; } $cols[] = trim($c['$t']); } } $rows = sheet_parser($data); $cfps = []; foreach ($rows as $row){ if (! trim(implode('', $row))){ break; } $cfps[] = $row; } array_shift($cfps); return $cfps; } JSONでデータ取得
function get_cfps(){ $url = 'https://spreadsheets.google.com/feeds/cells/xxx/yyy/public/values?alt=json'; $json = file_get_contents($url); $data =
json_decode($json, true); // CfP parser used as generator function sheet_parser($data){ $row_cursor = 1; $cols = []; foreach ($data['feed']['entry'] as $cell){ $c = $cell['gs$cell']; $row = intval($c['row']); if ($row !== $row_cursor){ yield $cols; $cols = []; $row_cursor = $row; } $cols[] = trim($c['$t']); } } $rows = sheet_parser($data); $cfps = []; foreach ($rows as $row){ if (! trim(implode('', $row))){ break; } $cfps[] = $row; } array_shift($cfps); return $cfps; } JSONでデータ取得 セルが1つずつJSONデータに 入っているのですべてループし て取り出す。
None
列: 1, 行: 1, データ形式: テキ スト, データ: “タイムスタンプ”
列: 2, 行: 1, データ形式: テキ スト, データ: “トーク時間”
列: 3, 行: 1, データ形式: テキ スト, データ: “トークタイトル”
列: 3, 行: 1, データ形式: テキ スト, データ: “トークタイトル” TSURAI
Drupalのcronタスク <?php function cfp_importer_cron() { // Calculate latest hour. $the_hour
= intval(REQUEST_TIME / 3600) * 3600; $last_run = Drupal::state()->get('cfp_importer.cron_last_run'); Drupal::logger('cfp_importer')->debug( 'Now: '.date('Y/m/d H:i:s', REQUEST_TIME)."\n". 'Last run : '.date('Y/m/d H:i:s', $last_run)."\n". 'Latest hour: '.date('Y/m/d H:i:s', $the_hour)); // Skip this cron if cron run after latest hour. if (($last_run) and ($last_run > $the_hour)){ //Drupal::logger('cfp_importer')->debug('Skip cron'); //return; } (略) // Update cron_last_run to next time. Drupal::state()->set('cfp_importer.cron_last_run', REQUEST_TIME); }
Case 2: PassMarket (CSV) → Drupal
iOSDCサイト •応募されたトーク •採用されたトーク •チケットを購入したユーザ •写真登録 トーク応募 購入者データ 参加者 アイコン
iOSDCサイト •応募されたトーク •採用されたトーク •チケットを購入したユーザ •写真登録 トーク応募 購入者データ 参加者 アイコン +
モジュール
None
None
None
PassMarket(CSV) → Drupal • 参加者データ(CSV)ダウンロードにパスワード を要求される。 • TSURAI • Guzzleとかcurlとかで頑張ってやれば出来なくは
ない。 • 時限でしか使わないモノで「頑張る」のも TSURAI。
頑張らない
こうした • 手動でCSVダウンロード • 諸般の事情で複数のイベントがあるので6回ほど同じ手順を繰 り返してダウンロード • Dropboxで本番サーバに同期 • Dropbox
for Linuxを使う。 • ローカルPCに置いたデータが本番サーバに同期される • 自作モジュールでインポート • Drupalユーザを作成する • 特定のディレクトリのCSVを全部開いてインポート
こうした • 手動でCSVダウンロード • 諸般の事情で複数のイベントがあるので6回ほど同じ手順を繰 り返してダウンロード • Dropboxで本番サーバに同期 • Dropbox
for Linuxを使う。 • ローカルPCに置いたデータが本番サーバに同期される • 自作モジュールでインポート • Drupalユーザを作成する • 特定のディレクトリのCSVを全部開いてインポート 職人の手による暖かみのある手作業
: foreach ($lines as $line){ if (! $line){ continue; }
$cols = explode(",", $line); $email = substr($cols[6], 1, -1); $order_no = substr($cols[0], 1, -1); $nids_order_no = \Drupal::entityQuery('user') ->condition('field_ticket_order_no', $order_no) ->execute(); $nids_email = \Drupal::entityQuery('user') ->condition('mail', $email) ->execute(); if ((count($nids_order_no) > 0) or (count($nids_email) > 0)){ // Existing user : } else { // New user. : } } :
: foreach ($lines as $line){ if (! $line){ continue; }
$cols = explode(",", $line); $email = substr($cols[6], 1, -1); $order_no = substr($cols[0], 1, -1); $nids_order_no = \Drupal::entityQuery('user') ->condition('field_ticket_order_no', $order_no) ->execute(); $nids_email = \Drupal::entityQuery('user') ->condition('mail', $email) ->execute(); if ((count($nids_order_no) > 0) or (count($nids_email) > 0)){ // Existing user : } else { // New user. : } } : ファイルを開いて 行でループ
: foreach ($lines as $line){ if (! $line){ continue; }
$cols = explode(",", $line); $email = substr($cols[6], 1, -1); $order_no = substr($cols[0], 1, -1); $nids_order_no = \Drupal::entityQuery('user') ->condition('field_ticket_order_no', $order_no) ->execute(); $nids_email = \Drupal::entityQuery('user') ->condition('mail', $email) ->execute(); if ((count($nids_order_no) > 0) or (count($nids_email) > 0)){ // Existing user : } else { // New user. : } } : 繰り返し実行するので 存在チェックが必要。 ファイルを開いて 行でループ
Case 3: Drupal → Local PC
iOSDCサイト •応募されたトーク •採用されたトーク •チケットを購入したユーザ •写真登録 トーク応募 購入者データ 参加者 アイコン API
+ CRON + モジュール
Drupal → Local PC • ユーザにフィールドタイプ「画像」のフィールドを 追加。 • 画像ファイルのアップロード先からDropbox対象の ディレクトリにシンボリックリンク。
• アップロードされた画像が何もしなくてもローカルPCに! • 何も考えずに作るとファイル名=アップロードされ たファイル名。これでは誰だかわからない
アップロードファイル名を変更する • ユーザが画像ファイルをアップロードした時に ユーザにユニークなファイル名にリネームする。 function user_image_rename_file_insert($file){ $parts = pathinfo($file->getFilename()); $order_no
= get_order_no_by_user_id($file->getOwnerId()); $filename = $order_no.".".$parts['extension']; $uri = 'public://avatars/' . $filename; $file = file_move($file, $uri); }
アップロードファイル名を変更する • ユーザが画像ファイルをアップロードした時に ユーザにユニークなファイル名にリネームする。 function user_image_rename_file_insert($file){ $parts = pathinfo($file->getFilename()); $order_no
= get_order_no_by_user_id($file->getOwnerId()); $filename = $order_no.".".$parts['extension']; $uri = 'public://avatars/' . $filename; $file = file_move($file, $uri); } フック
まとめ • iOSDCはDrupalが支えている • サイトが無い状態でデータが発生する場合: • Googleフォーム & スプレッドシートを使うと、 後が(比較的)ラク。
• モジュールを少し作るのがお勧め。難易度低め。 • Drupal 8はもう使えるか。 • ふつうに使える。 • Drupal 7の知識は半分使える感じでは。
Thanks WE ARE HIRING @tomzoh
…
おや…?
Drupalの様子が…?
!!
None
SA-CONTRIB-2016-039 • バリデーションが不十分でPHPコードが実行され る可能性がある。 • モジュールが有効化されていなくても影響を受け る。
SA-CONTRIB-2016-039 • バリデーションが不十分でPHPコードが実行され る可能性がある。 • モジュールが有効化されていなくても影響を受け る。
どういう修正が当たっているか • coder_upgrade/scripts/coder_upgrade.run.php にこの対策としてパッチが当たっている。 • 実行環境がCLI(Command Line Interface) でなければ終了する。 •
つまりApacheから実行されると都合が悪い。
パッチが当たっていないとどうなるか
パッチが当たっていないとどうなるか ここに http://example.com/poison.txt とかを突っ込める
どこだ!? $parameters = unserialize(file_get_contents($path)); : // Extract individual array items
by key. foreach ($parameters as $key => $variable) { $$key = $variable; } : // Load coder_upgrade bootstrap code. $path = $_coder_upgrade_modules_base . '/coder/coder_upgrade'; $files = array( 'coder_upgrade.inc', 'includes/main.inc', 'includes/utility.inc', ); : foreach ($files as $file) { require_once DRUPAL_ROOT . '/' . $path . "/$file"; }
どこだ!? $parameters = unserialize(file_get_contents($path)); : // Extract individual array items
by key. foreach ($parameters as $key => $variable) { $$key = $variable; } : // Load coder_upgrade bootstrap code. $path = $_coder_upgrade_modules_base . '/coder/coder_upgrade'; $files = array( 'coder_upgrade.inc', 'includes/main.inc', 'includes/utility.inc', ); : foreach ($files as $file) { require_once DRUPAL_ROOT . '/' . $path . "/$file"; } 既存のクラスのデストラクタが動く
どこだ!? $parameters = unserialize(file_get_contents($path)); : // Extract individual array items
by key. foreach ($parameters as $key => $variable) { $$key = $variable; } : // Load coder_upgrade bootstrap code. $path = $_coder_upgrade_modules_base . '/coder/coder_upgrade'; $files = array( 'coder_upgrade.inc', 'includes/main.inc', 'includes/utility.inc', ); : foreach ($files as $file) { require_once DRUPAL_ROOT . '/' . $path . "/$file"; } 既存のクラスのデストラクタが動く うまく文字列を作ればローカルファイルを実行できる
デモ IUUQESVQBMTJUFTBMMNPEVMFTDPEFSDPEFS@VQHSBEF TDSJQUTDPEFS@VQHSBEFSVOQIQ pMFIUUQ"' 'ESVQBM'QPJTPOUYU IUUQESVQBMTJUFTBMMNPEVMFTDPEFSDPEFS@VQHSBEF TDSJQUTDPEFS@VQHSBEFSVOQIQ
もう1つありましたね。
None
まくらばなし • 太古の昔から、UNIXでは環境変数にシステムの設 定を入れるという習慣があった。 • システムのプロキシ設定は環境変数 HTTP_PROXY に入れることになっていた。 • UNIXにCGIの仕組みが出来たときに、HTTPリクエ
ストの各種パラメタを環境変数としてプログラム に受け渡すことになった。
httpoxyは なぜヤバい? • 外部から、HTTPリクエストヘッダに Proxy ヘッダ を付けてリクエストすると、Apacheは環境変数 HTTP_PROXY にその中身を展開してプログラムを 実行する。
• 攻撃者が指定したプロキシを使わせることができ る。
攻撃対象 決済サービス
攻撃対象 攻撃者 決済サービス
攻撃対象 攻撃者 Proxy: x.x.x.x 決済サービス
攻撃対象 攻撃者 Proxy: x.x.x.x 決済サービス
攻撃対象 攻撃者 Proxy: x.x.x.x 決済サービス 攻撃者の設置した プロキシ x.x.x.x
Thanks WE ARE HIRING @tomzoh