2014/06/19 shin1x1
第16回関西PHP勉強会
Heroku で作る

スケーラブルな 

PHP アプリケーション
Agenda
(c) 2014 Masashi Shinbara @shin1x1
• Heroku とは
• PHPアプリケーションのデプロイ
• スケーラブルな構成を作る
• 大事なこと
• まとめ
Herokuとは
(c) 2014 Masashi Shinbara @shin1x1
• Salesforce 社が運営する PaaS
• 2007年サービスイン
• 3,000,000以上のアプリケーションが稼働
• Ruby をはじめとして、複数言語の実行環境
• PHPが 2014/04 に正式対応
(c) 2014 Masashi Shinbara @shin1x1
Herokuとは
• git push だけで、デプロイ完了
• ミドルウェアのインストールや設定などが不要
• 無料枠があり、かなり試すことができる
• 豊富な動作実績があり、ノウハウも多数ある
(c) 2014 Masashi Shinbara @shin1x1
Herokuのうれしいところ
• PHP 5.5.12 / 5.5.13
• HHVM 3.1.0
• 拡張も追加可能(mbstring, memcached等)
• Composer が使える
(c) 2014 Masashi Shinbara @shin1x1
HerokuでのPHP
• PostgreSQL / MySQL / KVS
• メール送受信
• ログ転送
• 監視
• キュー
• etc
(c) 2014 Masashi Shinbara @shin1x1
豊富なアドオン
PHPアプリケーションの
デプロイ
(c) 2014 Masashi Shinbara @shin1x1
(c) 2014 Masashi Shinbara @shin1x1
PHPアプリケーション
$ ls!
index.php!
!
$ cat index.php!
<?php phpinfo();!
!
$ git init!
$ git add .; git commit -m “init”
1. heroku.com でサインアップ(サインアップ)
2. Heroku Toolbelt インストール
3. Heroku でアプリケーションを作成
4. PHPアプリケーションをデプロイ
(c) 2014 Masashi Shinbara @shin1x1
Quick Start
(c) 2014 Masashi Shinbara @shin1x1
サインアップ
https://id.heroku.com/signup
(c) 2014 Masashi Shinbara @shin1x1
Heroku Toolbelt
• Heroku クライアントツールセット
• OSX, Windows, Debian / Ubuntsu
• Heroku の操作を CLI で行う
• Web 画面でも可能だが、あると便利
(c) 2014 Masashi Shinbara @shin1x1
Heroku Toolbelt
https://devcenter.heroku.com/articles/quickstart
(c) 2014 Masashi Shinbara @shin1x1
Heroku Toolbelt
$ heroku login!
Enter your Heroku credentials.!
Email: shin1x1@gmail.com!
Password (typing will be hidden):!
Two-factor code: xxxxx!
Authentication successful.!
• ログイン
2要素認証も可能
(c) 2014 Masashi Shinbara @shin1x1
アプリケーション作成
!
$ heroku create -r heroku!
Creating xxx-xxxx-xxxx... done, stack is cedar!
http://xxx-xxxx-xxxx.herokuapp.com/ |
git@heroku.com:xxx-xxxx-xxxx.git!
•アプリ名は、ランダムで自動生成
•̶app NAME で、アプリ名を指定することも可能
•-r heroku で、「git remote add heroku URL」を実行
(c) 2014 Masashi Shinbara @shin1x1
デプロイ
!
$ git push heroku master!
Initializing repository, done.!
Counting objects: 3, done.!
Writing objects: 100% (3/3), 218 bytes | 0 bytes/s, done.!
Total 3 (delta 0), reused 0 (delta 0)

!
(snip)!


-----> Setting up runtime environment...!
- PHP 5.5.12!
- Apache 2.4.9!
- Nginx 1.4.6!
(c) 2014 Masashi Shinbara @shin1x1
完了!
!
$ heroku open!
(c) 2014 Masashi Shinbara @shin1x1
管理画面
スケーラブルな構成を作る
(c) 2014 Masashi Shinbara @shin1x1
(c) 2014 Masashi Shinbara @shin1x1
アプリケーション
• 画像アップロードサイト
• ログイン認証
• 画像アップロード
• Laravel 4.2
https://github.com/shin1x1/laravel-on-heroku
(c) 2014 Masashi Shinbara @shin1x1
アプリケーション
https://github.com/shin1x1/laravel-on-heroku
(c) 2014 Masashi Shinbara @shin1x1
シンプルな構成
Apache / PHP
Log DB
Session File
(c) 2014 Masashi Shinbara @shin1x1
シンプルな構成
• 全てが 1 台のサーバにある
• Apache(nginx) / PHP / DB etc
• スケールアップしかできない
(c) 2014 Masashi Shinbara @shin1x1
Apache / PHP
Log DB
Session File
スケーラブルな構成
(c) 2014 Masashi Shinbara @shin1x1
スケーラブルな構成
DB
FileSession
Log Apache / PHP
(c) 2014 Masashi Shinbara @shin1x1
スケーラブルな構成
Apache / PHP
DB
FileSession
Log Apache / PHP
(c) 2014 Masashi Shinbara @shin1x1
スケーラブルな構成
Apache / PHP
DB
FileSession
Log Apache / PHP
Apache / PHP
(c) 2014 Masashi Shinbara @shin1x1
Herokuでの構成
Apache / PHP
DB
FileSession
Log Apache / PHP
Apache / PHP
Dyno
(c) 2014 Masashi Shinbara @shin1x1
Herokuでの構成
Apache / PHP
DB
FileSession
Log Apache / PHP
Apache / PHP
Dyno
Dyno
Dyno
(c) 2014 Masashi Shinbara @shin1x1
Herokuでの構成
Apache / PHP
DB
FileSession
Log Apache / PHP
Apache / PHP
Dyno
Dyno
Dyno
3 Dynos
(c) 2014 Masashi Shinbara @shin1x1
Herokuでの構成
Apache / PHP
DB
FileSession
Log Apache / PHP
Apache / PHP
Add-ons Add-ons
(c) 2014 Masashi Shinbara @shin1x1
Herokuでの構成
Apache / PHP
DB
FileSession
Log Apache / PHP
Apache / PHP
(c) 2014 Masashi Shinbara @shin1x1
スケーラブルな構成
• Dyno(PHPサーバ)は、ステートレスにする
• Dyno を増やしてスケールさせる
• アプリケーションデータは、アドオンに置く
(c) 2014 Masashi Shinbara @shin1x1
データベース
• Heroku Postgres(無料枠あり)
• 接続情報を環境変数から取得
DATABASE_URL=postgres://xxxxx:yyyyyy@ec2-nnn-nnn-
nnn-nnn.compute-1.amazonaws.com:5432/XXXXXXX
• parse_url() でパース
• アドオンは、ほぼこのパターン
(c) 2014 Masashi Shinbara @shin1x1
データベース
<?php!
$url = parse_url(getenv('DATABASE_URL'));
array(6) {!
'scheme' =>!
string(8) "postgres"!
'host' =>!
string(43) "ec2-nnn-nnn-nnn-nnn.compute-1.amazonaws.com"!
'port' =>!
int(5432)!
'user' =>!
string(4) "user"!
'pass' =>!
string(4) "pass"!
'path' =>!
string(7) "/dbname"!
}
(c) 2014 Masashi Shinbara @shin1x1
データベース
<?php!
$url = parse_url(getenv('DATABASE_URL'));!
!
$dsn = sprintf(‘pgsql:host=%s;dbname=%s',!
$url['host'], substr($url['path'], 1));!
!
$pdo = new PDO($dsn, $url['user'], $url['pass']);
• PDO の例
(c) 2014 Masashi Shinbara @shin1x1
データベース
<?php!
$postgresqlUrl = parse_url(getenv('DATABASE_URL'));!
!
return [!
'default' => 'pgsql',!
'connections' => [!
'pgsql' => [!
'driver' => 'pgsql',!
'host' => $postgresqlUrl['host'],!
'database' => substr($postgresqlUrl['path'], 1),!
'username' => $postgresqlUrl['user'],!
'password' => $postgresqlUrl['pass'],!
'charset' => 'utf8',!
'prefix' => '',!
'schema' => 'public',!
],!
],!
];
• Laravel の例
(c) 2014 Masashi Shinbara @shin1x1
データベース
http://qiita.com/shin1x1/items/68732dcf02a93c0a0fbb
(c) 2014 Masashi Shinbara @shin1x1
ログイン認証(セッション)
• Redis でセッション情報を共有
• Redis To Go(無料枠あり)
• 接続情報を環境変数から取得
• composer.json で redis を有効に
REDISTOGO_URL=redis://
redistogo:xxxxxxxxxxxxxxx@xxxxx.redistogo.com:PORT/
(c) 2014 Masashi Shinbara @shin1x1
ログイン認証(セッション)
<?php!
$url = parse_url(getenv('REDISTOGO_URL'));!
!
$redisServer = sprintf(‘tcp://%s:%d?auth=%s',!
$url['host'], $url['port'], $url['pass']);!
!
ini_set('session.save_handler', 'redis');!
ini_set('session.save_path', $redisServer);!
• redis セッションハンドラの例
(c) 2014 Masashi Shinbara @shin1x1
ログイン認証(セッション)
http://qiita.com/shin1x1/items/43181cd0487c72cb87a3
(c) 2014 Masashi Shinbara @shin1x1
画像ファイル
• S3 に保存(アドオンではない)
• AWS SDK for PHP で実装
• 接続情報は、環境変数にセットしておくと良い
• heroku config:set で環境変数をセット
$ heroku config:set AWS_ACCESS_ID=xxxx!
$ heroku config:set AWS_ACCESS_SECRET_KEY=xxxx
(c) 2014 Masashi Shinbara @shin1x1
ログ
• ログは、stdout or stderr に出力
• PaperTail などのアドオンで保存
• 複数 Dyno のログをアドオンに集約
• monolog / file_put_contents()
(c) 2014 Masashi Shinbara @shin1x1
ログ
(c) 2014 Masashi Shinbara @shin1x1
デモ
アクセスする Dyno が違う
(c) 2014 Masashi Shinbara @shin1x1
デモ
アクセスする Dyno が違う
(c) 2014 Masashi Shinbara @shin1x1
デモ
アクセスする Dyno が違う
(c) 2014 Masashi Shinbara @shin1x1
デモ
アクセスする Dyno が違う
大事なこと
(c) 2014 Masashi Shinbara @shin1x1
(c) 2014 Masashi Shinbara @shin1x1
大事なこと
• ファイルに保存したデータは消える!!
• デプロイ、環境変数変更等の操作
• 1日1回の再起動時
• アクセスが無い場合、自動停止

(Dyno が 1 台構成だとアクセスが無い時間は、

自動でスリープする)
(c) 2014 Masashi Shinbara @shin1x1
ファイルが消える
<?php!
const FILE_PATH = '/tmp/file';!
!
file_put_contents(FILE_PATH, !
date('Y/m/d H:i:s') . '<br>', FILE_APPEND);!
!
echo file_get_contents(FILE_PATH);
• file.php として、デプロイ
(c) 2014 Masashi Shinbara @shin1x1
ファイルが消える
• ブラウザでアクセス
(c) 2014 Masashi Shinbara @shin1x1
ファイルが消える
• 何度かリロード
(c) 2014 Masashi Shinbara @shin1x1
ファイルが消える
$ echo “//foo” >> file.php!
$ git add file.php; git commit -m “add comment”!
$ git push heroku master
• 変更して、再デプロイ
• ブラウザでアクセスすると、消えている
(c) 2014 Masashi Shinbara @shin1x1
Herokuとは
Heroku では、データファイルは消える
(c) 2014 Masashi Shinbara @shin1x1
Herokuとは
Heroku では、データファイルは消える
データは全て外部に逃す
(c) 2014 Masashi Shinbara @shin1x1
Herokuとは
Heroku では、データファイルは消える
データは全て外部に逃す
スケーラブルなアプリケーションに!!
(c) 2014 Masashi Shinbara @shin1x1
Heroku では、データファイルは消える
データは全て外部に逃す
スケーラブルなアプリケーションに!!
Herokuは
スケーラブルな
アプリケーション
矯正ギプス
Herokuとは
まとめ
(c) 2014 Masashi Shinbara @shin1x1
(c) 2014 Masashi Shinbara @shin1x1
まとめ
• Heroku は、無料から使える
• アドオンの活用が肝
• スケーラブルアプリケーション矯正ギプス
(c) 2014 Masashi Shinbara @shin1x1
参考
https://devcenter.heroku.com/categories/php
(c) 2014 Masashi Shinbara @shin1x1
参考
http://tatsu-zine.com/books/heropro
@shin1x1
(c) 2014 Masashi Shinbara @shin1x1

Heroku で作る
スケーラブルな 
PHP アプリケーション

  • 1.
  • 2.
    Agenda (c) 2014 MasashiShinbara @shin1x1 • Heroku とは • PHPアプリケーションのデプロイ • スケーラブルな構成を作る • 大事なこと • まとめ
  • 3.
  • 4.
    • Salesforce 社が運営するPaaS • 2007年サービスイン • 3,000,000以上のアプリケーションが稼働 • Ruby をはじめとして、複数言語の実行環境 • PHPが 2014/04 に正式対応 (c) 2014 Masashi Shinbara @shin1x1 Herokuとは
  • 5.
    • git pushだけで、デプロイ完了 • ミドルウェアのインストールや設定などが不要 • 無料枠があり、かなり試すことができる • 豊富な動作実績があり、ノウハウも多数ある (c) 2014 Masashi Shinbara @shin1x1 Herokuのうれしいところ
  • 6.
    • PHP 5.5.12/ 5.5.13 • HHVM 3.1.0 • 拡張も追加可能(mbstring, memcached等) • Composer が使える (c) 2014 Masashi Shinbara @shin1x1 HerokuでのPHP
  • 7.
    • PostgreSQL /MySQL / KVS • メール送受信 • ログ転送 • 監視 • キュー • etc (c) 2014 Masashi Shinbara @shin1x1 豊富なアドオン
  • 8.
  • 9.
    (c) 2014 MasashiShinbara @shin1x1 PHPアプリケーション $ ls! index.php! ! $ cat index.php! <?php phpinfo();! ! $ git init! $ git add .; git commit -m “init”
  • 10.
    1. heroku.com でサインアップ(サインアップ) 2.Heroku Toolbelt インストール 3. Heroku でアプリケーションを作成 4. PHPアプリケーションをデプロイ (c) 2014 Masashi Shinbara @shin1x1 Quick Start
  • 11.
    (c) 2014 MasashiShinbara @shin1x1 サインアップ https://id.heroku.com/signup
  • 12.
    (c) 2014 MasashiShinbara @shin1x1 Heroku Toolbelt • Heroku クライアントツールセット • OSX, Windows, Debian / Ubuntsu • Heroku の操作を CLI で行う • Web 画面でも可能だが、あると便利
  • 13.
    (c) 2014 MasashiShinbara @shin1x1 Heroku Toolbelt https://devcenter.heroku.com/articles/quickstart
  • 14.
    (c) 2014 MasashiShinbara @shin1x1 Heroku Toolbelt $ heroku login! Enter your Heroku credentials.! Email: shin1x1@gmail.com! Password (typing will be hidden):! Two-factor code: xxxxx! Authentication successful.! • ログイン 2要素認証も可能
  • 15.
    (c) 2014 MasashiShinbara @shin1x1 アプリケーション作成 ! $ heroku create -r heroku! Creating xxx-xxxx-xxxx... done, stack is cedar! http://xxx-xxxx-xxxx.herokuapp.com/ | git@heroku.com:xxx-xxxx-xxxx.git! •アプリ名は、ランダムで自動生成 •̶app NAME で、アプリ名を指定することも可能 •-r heroku で、「git remote add heroku URL」を実行
  • 16.
    (c) 2014 MasashiShinbara @shin1x1 デプロイ ! $ git push heroku master! Initializing repository, done.! Counting objects: 3, done.! Writing objects: 100% (3/3), 218 bytes | 0 bytes/s, done.! Total 3 (delta 0), reused 0 (delta 0)
 ! (snip)! 
 -----> Setting up runtime environment...! - PHP 5.5.12! - Apache 2.4.9! - Nginx 1.4.6!
  • 17.
    (c) 2014 MasashiShinbara @shin1x1 完了! ! $ heroku open!
  • 18.
    (c) 2014 MasashiShinbara @shin1x1 管理画面
  • 19.
  • 20.
    (c) 2014 MasashiShinbara @shin1x1 アプリケーション • 画像アップロードサイト • ログイン認証 • 画像アップロード • Laravel 4.2 https://github.com/shin1x1/laravel-on-heroku
  • 21.
    (c) 2014 MasashiShinbara @shin1x1 アプリケーション https://github.com/shin1x1/laravel-on-heroku
  • 22.
    (c) 2014 MasashiShinbara @shin1x1 シンプルな構成 Apache / PHP Log DB Session File
  • 23.
    (c) 2014 MasashiShinbara @shin1x1 シンプルな構成 • 全てが 1 台のサーバにある • Apache(nginx) / PHP / DB etc • スケールアップしかできない
  • 24.
    (c) 2014 MasashiShinbara @shin1x1 Apache / PHP Log DB Session File スケーラブルな構成
  • 25.
    (c) 2014 MasashiShinbara @shin1x1 スケーラブルな構成 DB FileSession Log Apache / PHP
  • 26.
    (c) 2014 MasashiShinbara @shin1x1 スケーラブルな構成 Apache / PHP DB FileSession Log Apache / PHP
  • 27.
    (c) 2014 MasashiShinbara @shin1x1 スケーラブルな構成 Apache / PHP DB FileSession Log Apache / PHP Apache / PHP
  • 28.
    (c) 2014 MasashiShinbara @shin1x1 Herokuでの構成 Apache / PHP DB FileSession Log Apache / PHP Apache / PHP Dyno
  • 29.
    (c) 2014 MasashiShinbara @shin1x1 Herokuでの構成 Apache / PHP DB FileSession Log Apache / PHP Apache / PHP Dyno Dyno Dyno
  • 30.
    (c) 2014 MasashiShinbara @shin1x1 Herokuでの構成 Apache / PHP DB FileSession Log Apache / PHP Apache / PHP Dyno Dyno Dyno 3 Dynos
  • 31.
    (c) 2014 MasashiShinbara @shin1x1 Herokuでの構成 Apache / PHP DB FileSession Log Apache / PHP Apache / PHP Add-ons Add-ons
  • 32.
    (c) 2014 MasashiShinbara @shin1x1 Herokuでの構成 Apache / PHP DB FileSession Log Apache / PHP Apache / PHP
  • 33.
    (c) 2014 MasashiShinbara @shin1x1 スケーラブルな構成 • Dyno(PHPサーバ)は、ステートレスにする • Dyno を増やしてスケールさせる • アプリケーションデータは、アドオンに置く
  • 34.
    (c) 2014 MasashiShinbara @shin1x1 データベース • Heroku Postgres(無料枠あり) • 接続情報を環境変数から取得 DATABASE_URL=postgres://xxxxx:yyyyyy@ec2-nnn-nnn- nnn-nnn.compute-1.amazonaws.com:5432/XXXXXXX • parse_url() でパース • アドオンは、ほぼこのパターン
  • 35.
    (c) 2014 MasashiShinbara @shin1x1 データベース <?php! $url = parse_url(getenv('DATABASE_URL')); array(6) {! 'scheme' =>! string(8) "postgres"! 'host' =>! string(43) "ec2-nnn-nnn-nnn-nnn.compute-1.amazonaws.com"! 'port' =>! int(5432)! 'user' =>! string(4) "user"! 'pass' =>! string(4) "pass"! 'path' =>! string(7) "/dbname"! }
  • 36.
    (c) 2014 MasashiShinbara @shin1x1 データベース <?php! $url = parse_url(getenv('DATABASE_URL'));! ! $dsn = sprintf(‘pgsql:host=%s;dbname=%s',! $url['host'], substr($url['path'], 1));! ! $pdo = new PDO($dsn, $url['user'], $url['pass']); • PDO の例
  • 37.
    (c) 2014 MasashiShinbara @shin1x1 データベース <?php! $postgresqlUrl = parse_url(getenv('DATABASE_URL'));! ! return [! 'default' => 'pgsql',! 'connections' => [! 'pgsql' => [! 'driver' => 'pgsql',! 'host' => $postgresqlUrl['host'],! 'database' => substr($postgresqlUrl['path'], 1),! 'username' => $postgresqlUrl['user'],! 'password' => $postgresqlUrl['pass'],! 'charset' => 'utf8',! 'prefix' => '',! 'schema' => 'public',! ],! ],! ]; • Laravel の例
  • 38.
    (c) 2014 MasashiShinbara @shin1x1 データベース http://qiita.com/shin1x1/items/68732dcf02a93c0a0fbb
  • 39.
    (c) 2014 MasashiShinbara @shin1x1 ログイン認証(セッション) • Redis でセッション情報を共有 • Redis To Go(無料枠あり) • 接続情報を環境変数から取得 • composer.json で redis を有効に REDISTOGO_URL=redis:// redistogo:xxxxxxxxxxxxxxx@xxxxx.redistogo.com:PORT/
  • 40.
    (c) 2014 MasashiShinbara @shin1x1 ログイン認証(セッション) <?php! $url = parse_url(getenv('REDISTOGO_URL'));! ! $redisServer = sprintf(‘tcp://%s:%d?auth=%s',! $url['host'], $url['port'], $url['pass']);! ! ini_set('session.save_handler', 'redis');! ini_set('session.save_path', $redisServer);! • redis セッションハンドラの例
  • 41.
    (c) 2014 MasashiShinbara @shin1x1 ログイン認証(セッション) http://qiita.com/shin1x1/items/43181cd0487c72cb87a3
  • 42.
    (c) 2014 MasashiShinbara @shin1x1 画像ファイル • S3 に保存(アドオンではない) • AWS SDK for PHP で実装 • 接続情報は、環境変数にセットしておくと良い • heroku config:set で環境変数をセット $ heroku config:set AWS_ACCESS_ID=xxxx! $ heroku config:set AWS_ACCESS_SECRET_KEY=xxxx
  • 43.
    (c) 2014 MasashiShinbara @shin1x1 ログ • ログは、stdout or stderr に出力 • PaperTail などのアドオンで保存 • 複数 Dyno のログをアドオンに集約 • monolog / file_put_contents()
  • 44.
    (c) 2014 MasashiShinbara @shin1x1 ログ
  • 45.
    (c) 2014 MasashiShinbara @shin1x1 デモ アクセスする Dyno が違う
  • 46.
    (c) 2014 MasashiShinbara @shin1x1 デモ アクセスする Dyno が違う
  • 47.
    (c) 2014 MasashiShinbara @shin1x1 デモ アクセスする Dyno が違う
  • 48.
    (c) 2014 MasashiShinbara @shin1x1 デモ アクセスする Dyno が違う
  • 49.
  • 50.
    (c) 2014 MasashiShinbara @shin1x1 大事なこと • ファイルに保存したデータは消える!! • デプロイ、環境変数変更等の操作 • 1日1回の再起動時 • アクセスが無い場合、自動停止
 (Dyno が 1 台構成だとアクセスが無い時間は、
 自動でスリープする)
  • 51.
    (c) 2014 MasashiShinbara @shin1x1 ファイルが消える <?php! const FILE_PATH = '/tmp/file';! ! file_put_contents(FILE_PATH, ! date('Y/m/d H:i:s') . '<br>', FILE_APPEND);! ! echo file_get_contents(FILE_PATH); • file.php として、デプロイ
  • 52.
    (c) 2014 MasashiShinbara @shin1x1 ファイルが消える • ブラウザでアクセス
  • 53.
    (c) 2014 MasashiShinbara @shin1x1 ファイルが消える • 何度かリロード
  • 54.
    (c) 2014 MasashiShinbara @shin1x1 ファイルが消える $ echo “//foo” >> file.php! $ git add file.php; git commit -m “add comment”! $ git push heroku master • 変更して、再デプロイ • ブラウザでアクセスすると、消えている
  • 55.
    (c) 2014 MasashiShinbara @shin1x1 Herokuとは Heroku では、データファイルは消える
  • 56.
    (c) 2014 MasashiShinbara @shin1x1 Herokuとは Heroku では、データファイルは消える データは全て外部に逃す
  • 57.
    (c) 2014 MasashiShinbara @shin1x1 Herokuとは Heroku では、データファイルは消える データは全て外部に逃す スケーラブルなアプリケーションに!!
  • 58.
    (c) 2014 MasashiShinbara @shin1x1 Heroku では、データファイルは消える データは全て外部に逃す スケーラブルなアプリケーションに!! Herokuは スケーラブルな アプリケーション 矯正ギプス Herokuとは
  • 59.
    まとめ (c) 2014 MasashiShinbara @shin1x1
  • 60.
    (c) 2014 MasashiShinbara @shin1x1 まとめ • Heroku は、無料から使える • アドオンの活用が肝 • スケーラブルアプリケーション矯正ギプス
  • 61.
    (c) 2014 MasashiShinbara @shin1x1 参考 https://devcenter.heroku.com/categories/php
  • 62.
    (c) 2014 MasashiShinbara @shin1x1 参考 http://tatsu-zine.com/books/heropro
  • 63.
    @shin1x1 (c) 2014 MasashiShinbara @shin1x1