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
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
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
180
デシリアライゼーションを理解する / 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
Claude Code本って、 読む必要あるの?
oikon48
2
420
なぜSRE・セキュリティは評価されないのか?守りの組織を事業成長エンジンに変えた実践
cscengineer
PRO
3
2.5k
TinyGo 開発サイクルを高速化する:Go で作るエミュレータ入門
zozotech
PRO
1
650
全員がプロダクトへ向き合う組織を持続成長させるために——組織づくりのフライホイールと4象限 / The Flywheel Model and Four Quadrants for Organizational Design
hiro_torii
4
980
enechainの内製セルフサービスプラットフォーム
hiyosi
0
160
『止めない』を設計する — 制約の中で、事業の根幹を支える判断
hiroyaterui
0
270
AIオーケストレーションを活用した 開発ワークフローの設計と実践
bqnq
0
140
日経電子版を支えていく Kasane Design System/fec_fukuoka
nikkei_engineer_recruiting
0
960
Redmine 7.0で私が開発した新機能の狙いと背景
vividtone
1
160
AI時代に顧客へ最速で価値を 届けるための試行錯誤 〜「AI × マネジメント」領域におけるmentoのケース〜
posterkeisuke
0
110
アプリをもっと"iOSアプリっぽく"する小さな工夫 / Small Touches That Make Your App Feel More Like an iOS App
matsuji
1
630
Screen Lens - 今見てる画面を翻訳する
komagata
0
250
Featured
See All Featured
A better future with KSS
kneath
240
18k
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
720
Bash Introduction
62gerente
615
220k
Primal Persuasion: How to Engage the Brain for Learning That Lasts
tmiket
0
450
[SF Ruby Conf 2025] Rails X
palkan
2
1.4k
Navigating Algorithm Shifts & AI Overviews - #SMXNext
aleyda
1
1.6k
B2B Lead Gen: Tactics, Traps & Triumph
marketingsoph
0
240
Designing for Timeless Needs
cassininazir
1
470
Practical Orchestrator
shlominoach
191
12k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.5k
Rails Girls Zürich Keynote
gr2m
96
14k
The World Runs on Bad Software
bkeepers
PRO
72
12k
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