Vagrant で作った仮想マシンから Box ファイルを作る方法
Vagrantで作った仮想環境を他人の環境でもまるまる使えるようにする方法です。
そんなのDocker使えばいいじゃんって言われそうですが、Vagrant使っているけどDockerは習得していないという人のために。
$ vagrant --version Vagrant 1.7.2
NIC のマッピングを削除
# ホスト $ vagrant ssh # 仮想 $ sudo ln -s -f /dev/null /etc/udev/rules.d/70-persistent-net.rules $ exit # ホスト $ vagrant halt
boxファイル作成
$ vagrant package $ ls package.box
boxファイルができました。
作成したboxファイルをインポート
作成したboxファイルを渡してあげて以下のコマンドを実行してください。
$ vagrant box add hogeos package.box $ vagrant init hogeos $ vagrant up
これで環境をまるっと移すことができます。
- 作者: Mitchell Hashimoto,Sky株式会社玉川竜司
- 出版社/メーカー: オライリージャパン
- 発売日: 2014/02/21
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (10件) を見る
【池上彰】世界で起きている大問題を包括的に知ることが出来るオススメ本
ニュース解説番組にひっぱりだこな池上彰さん。
そんな池上彰さんの新作、「知らないと恥をかく世界の大問題6 〜21世紀の曲がり角。世界はどこへ向かうのか?〜」を読みました。
知らないと恥をかく世界の大問題6 21世紀の曲がり角。世界はどこへ向かうのか?<知らないと恥をかく世界の大問題> (角川SSC新書)
- 作者: 池上彰
- 出版社/メーカー: KADOKAWA / 角川マガジンズ
- 発売日: 2015/05/10
- メディア: Kindle版
- この商品を含むブログ (1件) を見る
池上彰さんの世界情勢の分析を分かりやすく教えてくれる「知らないと恥をかく世界の大問題」シリーズは全部で6作目になりました。
内容は上記になっています。
特に、
の二点が非常にわかりやすく解説されており、勉強になりました。
イスラム国やオバマ大統領後のアメリカ、アベノミクス、集団的自衛権、沖縄の基地問題、憲法改正、等、知識としては決して先鋭的なものではありませんが、このぐらい知っておけば「世界情勢に疎い人」とは思われないでしょう。
過去の失敗を二度と繰り返さないこと。そのために歴史を学ぶ必要があるのだと思います。『知らないと恥をかく世界の大問題』という題名のシリーズは、多くの読者の支持を得て、ついに6冊目となりました。空港の書店に並べられ、国際線の機内で海外に出かける予習として読んでいる人をよく見かけます。ありがたいことです。5冊目から6冊目までの間に、世界は大きく変わりました。そんな変化の確認のためにも、この本がお役に立つことを願っています。
と本書にかかれている通り、国際線の機内で読む分量としては非常に調度良いです。
是非海外へ向かう前に空港でこの本を手にとってみてください。
【CentOS】迷惑メール(スパム)扱いされない為の最低限設定しておきたい3つの設定【Postfix】
さくらVPSでCentOSの環境を構築し、localhost(ローカルホスト)からPostfixでメールを送信しても、なにも設定していないと高確率で迷惑メール(スパム)扱いされてしまいます。
Yahoo!メールは幾分か緩いですが、Gmailはほぼ100%迷惑メール(スパム)扱いされます。
最近は無料でSMTPサーバを貸してくれるサービスもあり、そちらを使う場合もあるかもしれませんが、localhost(ローカルホスト)から送信する場合もあると思うので、そちらで最低限しておきたい3つの設定を記します。
当方の環境は下記の通りです。
サーバー: さくらVPS(CentOS)
ドメイン: お名前.comで契約したhoge.com
メールソフト: Postfix
1. DNS逆引きレコード変更
さくらVPSの場合、契約したタイミングで、さくらのドメインが割り振られますが、WEBサービスを運営する場合は独自ドメインを取得し、そちらで運用してると思います。
何も設定せずにサーバーのIPを逆引きした場合、さくらのドメインが表示されるため、運用しているWEBサービスのドメインと異なり、迷惑メール(スパム)扱いされます。
ですので、まずはDNS逆引きレコードを運営しているWEBサービスと同じドメインに変更しましょう。
さくらVPSの場合、コントロールパネルから逆引き設定できます。
確認は以下のコマンドを叩いて、ドメインが変わっていればOK
$ nslookup IPアドレス
2. SPFレコードの設定
Sender Policy Framework(センダー・ポリシー・フレームワーク)とは、電子メールにおける送信ドメイン認証のひとつ。差出人のメールアドレスが他のドメインになりすましていないかどうかを検出することができる。 SPF もしくは SPF認証 とも呼ばれる。
端的に言えば設定しておけば成りすましじゃないよ、ということを伝えることができるので、SPFレコードを設定してください。
お名前.comの場合は下記の画像のようにしてください。
ホスト名: 空
TYPE: TXT
TTL: 3600(お好みで)
VALUE: v=spf1 +a:hoge.com ~all
DKIMの設定
Domainkeys Identified Mail(DKIM)は、電子署名方式の送信ドメイン認証である。 DKIMでは送信側で電子メールに電子署名を付加し、受信側でその電子署名を照合するという方法で送信者のドメイン認証を行う。
DKIMの設定はOpenDKIMを使います。
sudo yum install opendkim
OpenDKIMを使って鍵を作成します。
sudo opendkim-genkey -D /etc/opendkim/keys/ -s hoge_com_selector -d hoge.com
作成された/etc/opendkim/keys/hoge_com_selector.txt の内容をDNSに登録してください。
ホスト名: hoge_com_selector._domainkey
TYPE: TXT
TTL: 3600(お好みで)
VALUE: v=DKIM1; k=rsa; p=MIGfMA0GCSq…
/etc/opendkim.confの設定
# 送信と受信 Mode sv # comment out # KeyFile /etc/opendkim/keys/default.private # uncomment KeyTable refile:/etc/opendkim/KeyTable # uncomment SigningTable refile:/etc/opendkim/SigningTable # uncomment ExternalIgnoreList refile:/etc/opendkim/TrustedHosts # uncomment InternalHosts refile:/etc/opendkim/TrustedHosts
/etc/opendkim/KeyTableの設定
hoge_com_selector._domainkey.hoge.com hoge.com:hoge_com_selector:/etc/opendkim/keys/hoge_com_selector.private
/etc/opendkim/SigningTableの設定
*@hoge.com hoge_com_selector._domainkey.hoge.com
Postfixの設定
/etc/postfix/main.cfの末尾に下記を追記
smtpd_milters = inet:127.0.0.1:8891
OpenDKIMとPostfixのrestart
sudo service opendkim restart sudo service postfix restart
OpenDKIMの設定が正しいか確認
メールを送信して署名が追加されているか確認する。
# mail example@gmail.com Subject: Test Test .
メールログ(/var/log/maillog)を確認し、
DKIM-Signature header added (s=hoge_com_selector, d=hoge.com)
という文字があれば設定完了。
【チュートリアル】最新フレームワークCakePHP3でブックマーカーを作ってみる その2
前回の続きになります。
ログイン機能の実装
ログイン機能はCakePHP2同様AuthComponentを利用します。
AppContorollerに追加しましょう
// In src/Controller/AppController.php namespace App\Controller; use Cake\Controller\Controller; class AppController extends Controller { public function initialize() { $this->loadComponent('Flash'); $this->loadComponent('Auth', [ 'authenticate' => [ 'Form' => [ 'fields' => [ 'username' => 'email', 'password' => 'password' ] ] ], 'loginAction' => [ 'controller' => 'Users', 'action' => 'login' ] ]); // Allow the display action so our pages controller // continues to work. $this->Auth->allow(['display']); } }
ここではflashとauthコンポーネントをロードしています。
usernameにemail,passwordにpasswordを使用します。このへんはCakePHP2と同様ですね。
現在ログインしていないので、どのページにアクセスしても/users/loginにリダイレクトされます。
では/users/loginページを実装しましょう。
// In src/Controller/UsersController.php public function login() { if ($this->request->is('post')) { $user = $this->Auth->identify(); if ($user) { $this->Auth->setUser($user); return $this->redirect($this->Auth->redirectUrl()); } $this->Flash->error('Your username or password is incorrect.'); } }
// src/Template/Users/login.ctp <h1>Login</h1> <?= $this->Form->create() ?> <?= $this->Form->input('email') ?> <?= $this->Form->input('password') ?> <?= $this->Form->button('Login') ?> <?= $this->Form->end() ?>
これでログイン機能ができました。
ログアウト機能の実装
UsersController.phpにlogoutメソッドを追加します。
public function logout() { $this->Flash->success('You are now logged out.'); return $this->redirect($this->Auth->logout()); }
ここもCakePHP2と同様ですね。
ユーザ登録の有効化
現在ユーザ登録しようとしてもログイン画面へリダイレクトされるので、それをさせないようにします。
// In src/Controller/UsersController.php public function beforeFilter(\Cake\Event\Event $event) { $this->Auth->allow(['add']); }
addメソッドが認証を必要としないことを示します。
ブックマークへのアクセス制限
現在ログインしさえすればすべてのユーザのブックマークにアクセスできてしまします。
ですので、その人が登録したブックマークのみアクセス出来るようにしましょう。
authorizationアダプターを使用します。
// In src/Controller/AppController.php public function initialize() { $this->loadComponent('Flash'); $this->loadComponent('Auth', [ 'authorize'=> 'Controller',//added this line 'authenticate' => [ 'Form' => [ 'fields' => [ 'username' => 'email', 'password' => 'password' ] ] ], 'loginAction' => [ 'controller' => 'Users', 'action' => 'login' ], 'unauthorizedRedirect' => $this->referer() ]); // Allow the display action so our pages controller // continues to work. $this->Auth->allow(['display']); } // add public function isAuthorized($user) { return false; }
基本はアクセス禁止で、ホワイトリスト方式が良いでしょう。
// In src/Controller/BookmarksController.php public function isAuthorized($user) { $action = $this->request->params['action']; // The add and index actions are always allowed. if (in_array($action, ['index', 'add', 'tags'])) { return true; } // All other actions require an id. if (empty($this->request->params['pass'][0])) { return false; } // Check that the bookmark belongs to the current user. $id = $this->request->params['pass'][0]; $bookmark = $this->Bookmarks->get($id); if ($bookmark->user_id == $user['id']) { return true; } return parent::isAuthorized($user); }
これで表示、編集、削除しても元のページに戻ります。 エラーページも用意しましょう
// In src/Template/Layout/default.ctp // Under the existing flash message. <?= $this->Flash->render('auth') ?>
一覧ページとフォームの修正
追加機能と一覧ページには以下の問題があります。 1. ブックマークを追加や編集する場合、ユーザを選択出来てしまう 2. 一覧ページでは他のユーザのブックマークまで閲覧できてしまう
これらを修正していきます。
フォームの修正
Bookmarks/add.ctpから input('user_id') を削除してユーザIDを編集できないようにしましょう。
またBookmarksController.phpをaddメソッドとeditメソッドを以下のように修正しましょう。
public function add() { $bookmark = $this->Bookmarks->newEntity(); if ($this->request->is('post')) { $bookmark = $this->Bookmarks->patchEntity($bookmark, $this->request->data); $bookmark->user_id = $this->Auth->user('id'); if ($this->Bookmarks->save($bookmark)) { $this->Flash->success('The bookmark has been saved.'); return $this->redirect(['action' => 'index']); } $this->Flash->error('The bookmark could not be saved. Please, try again.'); } $tags = $this->Bookmarks->Tags->find('list'); $this->set(compact('bookmark', 'tags')); }
public function edit($id = null) { $bookmark = $this->Bookmarks->get($id, [ 'contain' => ['Tags'] ]); if ($this->request->is(['patch', 'post', 'put'])) { $bookmark = $this->Bookmarks->patchEntity($bookmark, $this->request->data); $bookmark->user_id = $this->Auth->user('id'); if ($this->Bookmarks->save($bookmark)) { $this->Flash->success('The bookmark has been saved.'); return $this->redirect(['action' => 'index']); } $this->Flash->error('The bookmark could not be saved. Please, try again.'); } $tags = $this->Bookmarks->Tags->find('list'); $this->set(compact('bookmark', 'tags')); }
一覧画面の修正
続いて一覧画面でログインしているユーザーのブックマークだけを表示するようにします。 pagenate()に条件を加えて以下の様に修正してください。
public function index() { $this->paginate = [ 'conditions' => [ 'Bookmarks.user_id' => $this->Auth->user('id'), ] ]; $this->set('bookmarks', $this->paginate($this->Bookmarks)); }
タグ機能の修正
現状ではTagsControllerがすべてのアクセスを拒否するため、新しいタグの登録ができません。 アクセスを許可する代わりに、区切りのテキストで入力するUIを開発しましょう。 これにより良いユーザユーザーエクスペリエンスを手に入れられるだけでなく、ORMのさらなる機能を使ってみることができます。
処理済フィールドの追加
エンティティへのアクセスをシンプルな方法にするために、エンティティに仮想的で処理済なフィールドを追加しましょう。src/Model/Entity/Bookmark.phpに以下を追加してください。
use Cake\Collection\Collection; protected function _getTagString() { if (isset($this->_properties['tag_string'])) { return $this->_properties['tag_string']; } if (empty($this->tags)) { return ''; } $tags = new Collection($this->tags); $str = $tags->reduce(function ($string, $tag) { return $string . $tag->title . ', '; }, ''); return trim($str, ', '); }
これは私たちが$bookmark->tag_stringとすれば処理済のプロパティにアクセスすることを可能にします。 後で、このプロパティをフォームのinputで使います。 また保存に必要なのでtag_stringプロパティをエンティティの_accessibleリストに追加してください。
protected $_accessible = [ 'user_id' => true, 'title' => true, 'description' => true, 'url' => true, 'user' => true, 'tags' => true, 'tag_string' => true, ];
ビューの更新
エンティティが更新されたので、新しいinput要素を追加することができます。add、editの、既存のtags._idsinputを以下のように変更してください。
<?= $this->Form->input('tag_string', ['type' => 'text']) ?>
タグ文字列の永続化
既存のタグを文字列として表示できるようになりました。同様にタグ文字列を保存できるようにしてみましょう。
tag_stringを$_accessibleに追加したので、ORMはこのデータをリクエストからエンティティにコピーします。
beforeSave()フックメソッドを使用して、エンティティに対してタグ文字列のパースとタグリストの検索/追加ができます。以下のコードをBookmarksTable.phpに追加してください。
public function beforeSave($event, $entity, $options) { if ($entity->tag_string) { $entity->tags = $this->_buildTags($entity->tag_string); } } protected function _buildTags($tagString) { $new = array_unique(array_map('trim', explode(',', $tagString))); $out = []; $query = $this->Tags->find() ->where(['Tags.title IN' => $new]); // Remove existing tags from the list of new tags. foreach ($query->extract('title') as $existing) { $index = array_search($existing, $new); if ($index !== false) { unset($new[$index]); } } // Add existing tags. foreach ($query as $tag) { $out[] = $tag; } // Add new tags. foreach ($new as $tag) { $out[] = $this->Tags->newEntity(['title' => $tag]); } return $out; }
まとめ
ブックマークアプリケーションにおいて、簡単なログイン認証、アクセスコントロールなどを実装できました。 これを機会にCakePHP3に触れる人が増えてくればなによりです。
【チュートリアル】最新フレームワークCakePHP3でブックマーカーを作ってみる その1
そろそろちゃんと最新フレームワークCakePHP3を触らないといけない気がしてきたので、チュートリアルとしてCakePHP3を使ってブックマーカーを作ってみます。
環境はMacOSXにVirtualbox+VagrantでCentOS乗っけてます。
インストール
PHPのインストール
PHP5.6系をインストールします。
リポジトリはremiで。
% rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm % yum install --enablerepo=remi --enablerepo=remi-php56 php php-intl php-mbstring php-mysqlnd
$ php -v PHP 5.6.9 (cli) (built: May 15 2015 09:40:22) Copyright (c) 1997-2015 The PHP Group Zend Engine v2.6.0, Copyright (c) 1998-2015 Zend Technologies with Xdebug v2.3.2, Copyright (c) 2002-2015, by Derick Rethans
Composerのインストール
よもやぺちぱーでComposerを使っていない人はいないと思いますが、一応インストール方法を。
グローバルにインストールしちゃいます。
$ curl -sS https://getcomposer.org/installer | php % mv composer.phar /usr/local/bin/composer
Mysqlのインストール
とりあえず5.1以上をインストールしてください。
インストール方法は面倒なので飛ばします。
今回は5.6.24を使います。
CakePHP3のインストール
さていよいよCakePHP3のインストールです。
ワンライナーでインストールできてしまいます。良い時代ですね。
今回はプロジェクト名をbookmarkerで。
composer create-project --prefer-dist cakephp/app bookmarker Installing cakephp/app (3.0.3) - Installing cakephp/app (3.0.3) Downloading: 100% Created project in bookmarker Loading composer repositories with package information Installing dependencies (including require-dev) 省略 - Installing cakephp/cakephp (3.0.6) Loading from cache - Installing cakephp/migrations (1.1.1) Downloading: 100% - Installing cakephp/debug_kit (3.1.5) Loading from cache - Installing cakephp/bake (1.0.9) Downloading: 100% 省略 Created `config/app.php` file Set Folder Permissions ? (Default to Y) [Y,n]? Y 省略 Updated Security.salt value in config/app.php
MigrationsがCakeDCじゃなくなったのですね。
パーミッション云々聞かれるのでYとしましょう。
Saltも勝手にランダム値に設定してくれるみたいです。
2系でもインストールは楽だったのですが更に楽になりましたね。
ディレクトリ構成を見てみましょう。
$ tree -L 2 . |-- README.md |-- bin | |-- cake | |-- cake.bat | `-- cake.php |-- composer.json |-- composer.lock |-- config | |-- app.default.php | |-- app.php | |-- bootstrap.php | |-- bootstrap_cli.php | |-- paths.php | |-- routes.php | `-- schema |-- index.php |-- logs | |-- cli-error.log | `-- empty |-- phpunit.xml.dist |-- plugins | `-- empty |-- src | |-- Console | |-- Controller | |-- Model | |-- Shell | |-- Template | `-- View |-- tests | |-- Fixture | |-- TestCase | `-- bootstrap.php |-- tmp | |-- Bake-Controller-controller-ctp.php | |-- Bake-Element-Controller-add-ctp.php | |-- Bake-Element-Controller-delete-ctp.php | |-- Bake-Element-Controller-edit-ctp.php | |-- Bake-Element-Controller-index-ctp.php | |-- Bake-Element-Controller-view-ctp.php | |-- Bake-Element-form-ctp.php | |-- Bake-Layout-default-ctp.php | |-- Bake-Model-entity-ctp.php | |-- Bake-Model-table-ctp.php | |-- Bake-tests-fixture-ctp.php | |-- Bake-tests-test-case-ctp.php | |-- add-ctp.php | |-- cache | |-- debug_kit.sqlite | |-- edit-ctp.php | |-- index-ctp.php | |-- sessions | |-- tests | `-- view-ctp.php |-- vendor | |-- aura | |-- autoload.php | |-- bin | |-- cakephp | |-- cakephp-plugins.php | |-- composer | |-- dnoegel | |-- empty | |-- ircmaxell | |-- jakub-onderka | |-- mobiledetect | |-- nesbot | |-- nikic | |-- psr | |-- psy | |-- robmorgan | `-- symfony `-- webroot |-- css |-- favicon.ico |-- img |-- index.php `-- js 38 directories, 40 files
srcディレクトリにMVCが入るようになったのですね。
起動してみる
ビルドインサーバがあるので試してみます。
ローカルホスト上で動いている場合は
$ bin/cake server Welcome to CakePHP v3.0.6 Console --------------------------------------------------------------- App : src Path: /vagrant/blog/bookmarker/src/ DocumentRoot: /vagrant/blog/bookmarker/webroot --------------------------------------------------------------- built-in server is running in http://localhost:8765/ You can exit with `CTRL-C`
http://localhost:8765/ でアクセスできます。
仮想マシン上で動いている場合はホストを指定しなければなりません。
bin/cake server -H 0.0.0.0 Welcome to CakePHP v3.0.6 Console --------------------------------------------------------------- App : src Path: /vagrant/blog/bookmarker/src/ DocumentRoot: /vagrant/blog/bookmarker/webroot --------------------------------------------------------------- built-in server is running in http://0.0.0.0:8765/ You can exit with `CTRL-C`
vagrantでIPを192.168.33.50と指定しているので
http://192.168.33.50:8765/ でアクセスできます。
起動できました。
データベース(MySQL)の設定
CakePHPからMySQLへアクセスできるように設定をします。
Config/app.phpを自分の環境に合わせて設定してください。
'Datasources' => [ 'default' => [ 'className' => 'Cake\Database\Connection', 'driver' => 'Cake\Database\Driver\Mysql', 'persistent' => false, 'host' => 'localhost', /** * CakePHP will use the default DB port based on the driver selected * MySQL on MAMP uses port 8889, MAMP users will want to uncomment * the following line and set the port accordingly */ //'port' => 'nonstandard_port_number', 'username' => 'root', 'password' => '', 'database' => 'cake_bookmarks', 'encoding' => 'utf8', 'timezone' => 'Asia/Tokyo', 'cacheMetadata' => true, /** * Set identifier quoting to true if you are using reserved words or * special characters in your table or column names. Enabling this * setting will result in queries built using the Query Builder having * identifiers quoted when creating SQL. It should be noted that this * decreases performance because each query needs to be traversed and * manipulated before being executed. */ 'quoteIdentifiers' => false, /** * During development, if using MySQL < 5.6, uncommenting the * following line could boost the speed at which schema metadata is * fetched from the database. It can also be set directly with the * mysql configuration directive 'innodb_stats_on_metadata = 0' * which is the recommended value in production environments */ //'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'], ],
timezoneをAsia/Tokyoにした場合以下のようなエラーが出るかもしれません。
Exception: SQLSTATE[HY000]: General error: 1298 Unknown or incorrect time zone: 'Asia/Tokyo' in [/vagrant/bookmarker/vendor/cakephp/cakephp/src/Database/Driver/Mysql.php, line 94] php-intl
MySQLのタイムゾーンの設定に不備があるので下記のコマンドを実行してください
$ mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql -p
bakeを使ってコードを生成する
CakePHPチュートリアルでお馴染みのbakeでコードを生成していきます。
$ bin/cake bake all users $ bin/cake bake all bookmarks $ bin/cake bake all tags
コントローラ、モデル、ビュー、テストケースが生成されます。
テスト大事ですね!
では http://192.168.33.50:8765/bookmarks にアクセスしてみましょう。
ユーザを登録したりブックマークを登録したりタグを登録してみましょう。
パスワードのハッシュ化
ユーザ登録するとパスワードがプレーンテキストで保存されています。
例えばこの状態でサービスリリースをしてSQLインジェクションなどでユーザ情報が流出すると、このIDとパスワードを使って他のサービスのログインを試み、2次被害してしまいます。そういうことを防ぐためにパスワードは必ず暗号化して保存しなければなりません。
CakePHP2ではModelはModelクラスひとつでしたが、CakePHP3ではTableとEntityに分かれています。 TableはDBのテーブルにアクセスするクラスで、Entityは単一のレコードを扱うクラスです。
パスワードのハッシュ化ロジックはUserのEntityクラスのpasswordセッターに追加します。
_set{カラム名}とすると、カラムの保存前にメソッドが呼び出されるようです。
<?php namespace App\Model\Entity; use Cake\Auth\DefaultPasswordHasher; use Cake\ORM\Entity; /** * User Entity. */ class User extends Entity { /** * Fields that can be mass assigned using newEntity() or patchEntity(). * * @var array */ protected $_accessible = [ 'email' => true, 'password' => true, 'bookmarks' => true, ]; // Code from bake. protected function _setPassword($value) { $hasher = new DefaultPasswordHasher(); return $hasher->hash($value); } }
DefaultPasswordHasherはBCrypt(Blowfish暗号)になります。
これで、パスワードはハッシュ化されて保存されるようになります。
CakePHP2系ではSecurityコンポーネントで指定できるソルトは$2a$のみでしたが、DefaultPasswordHasherではデフォルトで$2y$なのですね。
特定タグのブックマークを取得する
http://192.168.33.50:8765/bookmarks/tagged/funny/cat/gifs でアクセスした時にfunny, cat, gifsのタグが付いたブックマークをを表示する、という機能をつけてみます。
routeの実装
config/routes.phpに以下を追加
Router::scope( '/bookmarks', ['controller' => 'Bookmarks'], function ($routes) { $routes->connect('/tagged/*', ['action' => 'tags']); } );
CakePHP2を経験してる人であれば意味はわかりますね。
では対応するメソッドを実装します。
tagsメソッドの実装
public function tags() { $tags = $this->request->params['pass']; $bookmarks = $this->Bookmarks->find('tagged', [ 'tags' => $tags ]); $this->set(compact('bookmarks', 'tags')); }
次に
$this->Bookmarks->find('tagged', [ 'tags' => $tags ]);
に当たる部分を実装します。
finder メソッドの実装
BookmarksTable.phpに以下を実装します。
public function findTagged(Query $query, array $options) { $fields = [ 'Bookmarks.id', 'Bookmarks.title', 'Bookmarks.url', ]; return $this->find() ->distinct($fields) ->matching('Tags', function ($q) use ($options) { return $q->where(['Tags.title IN' => $options['tags']]); }); }
これがカスタムファインダーメソッドです。これはCakePHP3の目玉機能の一つでクエリを再利用可能にします。
Viewの実装
ロジックができたので次はそれを表示するViewを実装します。
Bookmarks/tags.ctpに実装します。
<h1> Bookmarks tagged with <?= $this->Text->toList($tags) ?> </h1> <section> <?php foreach ($bookmarks as $bookmark): ?> <article> <h4><?= $this->Html->link($bookmark->title, $bookmark->url) ?></h4> <small><?= h($bookmark->url) ?></small> <?= $this->Text->autoParagraph($bookmark->description) ?> </article> <?php endforeach; ?> </section>
これで表示できるようになります。 「探偵物」というタグに「金田一少年の事件簿」というブックマークを紐付けたので以下のような表示になります。
http://192.168.33.50:8765/bookmarks/tagged/探偵物
とりあえず今日はここまで。 次回はログイン、ログアウト、アクセス制限などの機能を追加していきます。
【チュートリアル】最新フレームワークCakePHP3でブックマーカーを作ってみる その2
参考 http://book.cakephp.org/3.0/en/tutorials-and-examples/bookmarks/intro.html
CakePHPで学ぶ継続的インテグレーション (impress top gear)
- 作者: 渡辺一宏,吉羽龍太郎,岸田健一郎,穴澤康裕,丸山弘詩
- 出版社/メーカー: インプレス
- 発売日: 2014/09/19
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る
【MeCab】マルコフ連鎖テキストを吐き出すPHPライブラリを作った。
前回MeCabのインストール方法をご紹介しました。 そのMeCabを使ったマルコフ連鎖テキストを吐き出すPHPライブラリを作成しました。 Packagistにも公開したので簡単にインストール出来るようになっています。
インストール
- MeCabのインストール
- ComposerをインストールしていなかったらComposerをインストール
$ composer require 'yuzuru-s/markovchain:dev-master'
これで準備は完了です。
使い方
require_once 'vendor/autoload.php'; $mc = new YuzuruS\Markovchain\Markovchain(); $text = '繁栄を築き上げた人類は、突如出現した“天敵”「巨人」により滅亡の淵に立たされた。生き残った人類は、「ウォール・マリア」、「ウォール・ローゼ」、「ウォール・シーナ」という巨大な三重の城壁の内側に生活圏を確保することで、辛うじてその命脈を保っていた。城壁による平和を得てから約100年後。いつしか人類は巨人の脅威を忘れ、平和な日々の生活に埋没していた。'; $markovText = $mc->makeMarkovText($text); echo $text."\n"; echo '↓'."\n"; echo $markovText."\n";
結果
繁栄を築き上げた人類は、突如出現した“天敵”「巨人」により滅亡の淵に立たされた。生き残った人類は、「ウォール・マリア」、「ウォール・ローゼ」、「ウォール・シーナ」という巨大な三重の城壁の内側に生活圏を確保することで、辛うじてその命脈を保っていた。城壁による平和を得てから約100年後。いつしか人類は巨人の脅威を忘れ、平和な日々の生活に埋没していた。
↓
繁栄を築き上げた。いつしか人類は、突如出現した。生き残った人類は、辛うじてその命脈を得ていた“天敵”「ウォール・シーナ」、平和な日々の城壁による平和を忘れ、「ウォール・マリア」、「ウォール・シーナ」、辛うじてその命脈を確保することで、突如出現した“天敵”「ウォール・シーナ」、「巨人の脅威を保ってから約100年後。城壁による平和な三重の城壁による平和を忘れ、辛うじてその命脈を保ってから約100年後。
まとめ
とりあえず自分で使うために適当に作ったのでまだ汎用的に作ってないです。 時間があったらもう少し汎用的になるように修正します。
格安SIM(MVNO)とRaspberry Pi(ラズベリーパイ)でモバイルルータを作った 〜初期設定から完成まで〜
最近ジワジワ人気になってきた格安SIM(MVNO)とRaspberry Pi(ラズベリーパイ)。
今回はこの2つを使ってモバイルルータを作ってみたいと思います。
格安SIM(MVNO)とは?
格安SIM(MVNO)は非常に低価格でモバイル通信できます。 安いものだと月額500円以下のプランもあります。 非常に低価格なのですが、格安SIM(MVNO)を使うためには殆どの場合ドコモ端末かSIMフリー端末が必要となります。
Raspberry Pi(ラズベリーパイ)とは?
Raspberry Pi(ラズベリーパイ)とは手のひらサイズの超小型コンピュータで電子工作やプログラミング等に使えます。 価格も非常に安く、5000円ほどで手に入ります。
用意するもの
・Raspberry Pi Model B+(4266円)
- 出版社/メーカー: raspberrypi.org
- メディア: エレクトロニクス
- この商品を含むブログ (2件) を見る
・L-02C (4500円)
【白ロム】ドコモ L-02C Xi対応USBデータカード レッド
- 出版社/メーカー: LG電子
- メディア: エレクトロニクス
- クリック: 2回
- この商品を含むブログ (1件) を見る
・DMM mobile (最安プラン 660円)
今回は手持ちの格安SIM(MVNO)のDMM mobileを使用しました。
・無線LANアダプタ (713円)
BUFFALO 無線LAN子機 コンパクトモデル 11n技術・11g/b対応 WLI-UC-GNM
- 出版社/メーカー: バッファロー
- 発売日: 2010/06/25
- メディア: Personal Computers
- 購入: 44人 クリック: 226回
- この商品を含むブログ (29件) を見る
・8GB microSDカード (824円)
【Amazon.co.jp限定】Transcend microSDHCカード 8GB Class10 (無期限保証) TS8GUSDHC10E (FFP)
- 出版社/メーカー: トランセンド・ジャパン
- メディア: Personal Computers
- この商品を含むブログを見る
以前のRaspberry Pi(ラズベリーパイ)はSDカードでしたが最新のモデルはmicroSDカードなのでご注意を。
・軽いモバイルバッテリー
cheero Power Plus DANBOARD version -plate- 4200mAh 超薄型 モバイルバッテリー
- 出版社/メーカー: cheero
- メディア: エレクトロニクス
- この商品を含むブログ (2件) を見る
・有線LANケーブル (583円)
ELECOM LANケーブル CAT6 Gigabit やわらか 爪折れ防止 0.5m ブラック 【PlayStation 4 対応】 LD-GPYT/BK05
- 出版社/メーカー: エレコム
- 発売日: 2013/01/18
- メディア: Personal Computers
- この商品を含むブログを見る
RaspberryPi(ラズベリーパイ)の初期設定
作業PCはMacを使用します。
まずmicroSDカードにOSイメージを焼きます。OSはせっかくなのでRaspbian(ラズビアン)を使います。
公式サイトからRASPBIANを選択しダウンロード、解凍します。今回は2015-05-05リリースのものを使用します。ダウンロードが終わったらSDカードをMacに接続します。
df -hでSDカードのディスク名をチェック
$ df -h Filesystem Size Used Avail Capacity iused ifree %iused Mounted on /dev/disk2s1 29Gi 2.3Mi 29Gi 1% 0 0 100% /Volumes/NO NAME
ディスク名は/dev/disk2s1でした。
diskutilでアンマウント
# diskutil unmountDisk /dev/disk2s1 Password: Unmount of all volumes on disk2 was successful
成功です。
ddコマンドでSDカードにOSイメージを書き込み
# dd if=2015-05-05-raspbian-wheezy.img of=/dev/disk2s1 bs=4m 781+1 records in 781+1 records out 3276800000 bytes transferred in 290.594687 secs (11276187 bytes/sec)
30分ほど時間がかかりました。これでSDカードにOSイメージが書き込まれました。
RaspberryPi(ラズベリーパイ)へ接続
SDカード、有線LANをRaspberryPi(ラズベリーパイ)へ接続したあと、microUSBポートに電源を差し込みます。
赤と緑のLEDが点灯し緑が点滅すれば成功です。
私は初めて接続した時、赤と緑のLEDが点灯したまま点滅しませんでした。焼きがうまく行っていなかったようで、再度焼き直したら起動できました。
使用しているルータにアクセスしてRaspberryPi(ラズベリーパイ)に割り振られているIPアドレスを確認。今回は192.168.11.13でした。
MacからSSHを使って接続してみます。usernameはpi, passwordはraspberryです。
$ ssh pi@192.168.11.13 The authenticity of host '192.168.11.13 (192.168.11.13)' can't be established. RSA key fingerprint is 0d:6e:e9:9d:25:28:2b:51:59:c0:34:0e:6b:78:01:82. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '192.168.11.13' (RSA) to the list of known hosts. pi@192.168.11.13's password: Linux raspberrypi 3.18.11+ #781 PREEMPT Tue Apr 21 18:02:18 BST 2015 armv6l The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. Last login: Fri May 22 05:04:12 2015
無事接続できました。
初期設定
今後はRaspberry Pi(ラズベリーパイ)上での作業となります。
# raspi-config
上記のコマンドを実行すると下記のような画面が表示されます。
ここで日本locale設定だけにします。
- Expand Filesystemを選択します。
- Internationalisation Options > Change Locale > ja_JP.UTF-8で日本語環境にします。
- Internationalisation Options > Change Timezone > Asia > Tokyoで日本時間にします。
パッケージ更新
パッケージ更新 # apt-get update # apt-get upgrade
Vimをインストール
ついでにみんな大好きVimをインストールしておきましょう。
# apt-get install vim # update-alternatives --set editor /usr/bin/vim.tiny
これでRaspberry Pi(ラズベリーパイ)の初期設定はひとまず完了です。
WiFiアクセスポイント機能有効化
Raspberry Pi(ラズベリーパイ)に無線LANアクセスポイントであるWLI-UC-GNMを差し込んでください。
Wi-Fiアクセスポイント機能を有効にするためにhostapdを導入します。
有線LANのeth0にDHCPでIPアドレスを割り当て、無線LANのwlan0に固定IPアドレスを割り当てます。
# vim /etc/network/interfaces auto lo iface lo inet loopback iface eth0 inet dhcp allow-hotplug wlan0 auto wlan0 iface wlan0 inet static address 192.168.100.1 network 192.168.100.0 netmask 255.255.255.0 gateway 192.168.11.1
次にhostapdをインストールします。
# apt-get install hostapd
ここでhostapdの設定を行いますが、使用するアダプタ(ドライバ)によって手順が変わってきます。
今回は「用意するもの」で挙げたWLI-UC-GNMを使った設定を行います。
lsmodして、ドライバを確認します。
# /sbin/lsmod
ドライバがmac80211ベースでした。 こちらは本家のhostapdがサポートしているのですが、apt-getでインストールされるものはバージョンが古いためhostapdを入れ替える必要があります。 公式サイトから最新のソースをダウンロード、コンパイルします。
$ cd /tmp $ wget http://w1.fi/releases/hostapd-2.0.tar.gz $ tar xvf hostapd-2.0.tar.gz
コンパイルに必要なライブラリをインストールします。
# apt-get install libnl-genl-3-dev libssl-dev
必要な設定を加えてコンパイルします。
$ cd hostapd-2.0/hostapd $ cp defconfig .config $ echo "CONFIG_LIBNL32=y" >> .config $ make # make install
hostapdの設定ファイルを修正。 ssid, channel, wpa_passphraseは適宜変更してください。
interface=wlan0 driver=nl80211 ssid=korokkeyasan hw_mode=g channel=6 macaddr_acl=0 auth_algs=1 ignore_broadcast_ssid=0 wpa=2 wpa_passphrase=korokkeyasan wpa_key_mgmt=WPA-PSK wpa_pairwise=TKIP rsn_pairwise=CCMP
hostapd起動のための設定をします。
DAEMON_CONFがコメントアウトされているので下記のように修正してください。
# vim /etc/default/hostapd DAEMON_CONF="/etc/hostapd/hostapd.conf"
WPASupplicantを無効にしておきます。一応適当なところにバックアップしておきます。
# mv /usr/share/dbus-1/system-services/fi.epitest.hostap.WPASupplicant.service /tmp
DHCPサーバの導入
IPアドレスを自動で割り振るDHCPサーバを導入していきます。
# apt-get install isc-dhcp-server
設定ファイルを編集します。(設定した部分だけ抜粋)
# vim /etc/dhcp/dhcpd.conf #コメントアウト #option domain-name "example.org"; #option domain-name-servers ns1.example.org, ns2.example.org; #アンコメント # 正当な DHCP サーバーであることの宣言 authoritative; # ネットワークアドレスとサブネットマスク指定 subnet 192.168.100.0 netmask 255.255.255.0 { # 貸し出すIPアドレスの範囲指定 range 192.168.100.10 192.168.100.50; # ブロードキャストアドレス指定 option broadcast-address 192.168.100.255; # デフォルト貸出期間 default-lease-time 600; # 最大貸出期間 max-lease-time 7200; # ゲートウェイアドレス指定 option routers 192.168.100.1; # ドメイン名指定 option domain-name "local"; # ネームサーバーのホスト名 (Google) option domain-name-servers 8.8.8.8, 8.8.4.4; }
DHCPサーバの起動設定をします。
# vim /etc/default/isc-dhcp-server INTERFACES="wlan0"
先ほど設定したhostapdをデーモンとして起動するようにしたいので下記のように設定します。
# service hostapd start
また起動時にhostapdを起動させたいので下記のように設定します。
# update-rc.d hostapd enable
DHCPサーバを起動します。
# service isc-dhcp-server start
また起動時にDHCPサーバを起動させたいので下記のように設定します。
# update-rc.d isc-dhcp-server enable
これで自動でIPアドレスが割り振られるようになりました。
IPマスカレードの設定
カーネルの機能なので、ここでは特に何かインストールする必要はありません。
# vim /etc/sysctl.conf # アンコメント net.ipv4.ip_forward=1
一度再起動してこの設定を有効にします。
# reboot
再起動が終わったら再度SSH接続してください。 IPテーブルの設定でIPマスカレードを有効にします。
# iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
これで有線LAN接続状態でクライアントが無線でインターネットに接続出来るようになりました!
LTEネットワーク接続
いよいよ有線LANで接続ではなくLTEネットワークでの接続設定をしていきます。 予めL-02CをRaspberry Pi(ラズベリーパイ)に挿入しておいてください。
# apt-get install wvdial # apt-get install eject
wvdialはダイアルアップ接続用ソフトなのですがejectはCD/DVD-ROMドライブをEjectするためのコマンド。 なぜか今回使用するL-02CはRaspberry Pi(ラズベリーパイ)につなぐとCD-ROMドライブとして認識され、Ejectしないと使えないという謎仕様。だから安いんですけどね。。
# eject sr0
確認します。
$ lsusb
L-02Cが一覧に出てくればOKです。
次に使用するSIMの設定を行っていきます。今回はDMM mobile(IIJmio系)を想定しています。
# vim /etc/wvdial.conf [Dialer Defaults] Init1 = ATZ Init2 = AT+CGDCONT=1,"IP","iijmio.jp" Init3 = ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0 Dial Attempts = 3 Stupid Mode = 1 Modem Type = Analog Modem Dial Command = ATD Stupid Mode = yes Baud = 460800 New PPPD = yes APN = iijmio.jp Modem = /dev/ttyUSB2 ISDN = 0 Phone = *99***1# Password = iij Username = mio@iij Carrier Check = no
Phoneは"99*1#"でも"99#"でも可能です。 いよいよ接続です。
# wvdial
PPP接続できました!! IPマスカレードの設定をします。
# iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
起動時にPPP接続できるようにします。
# vim /etc/init.d/wvdialloop.sh #!/bin/bash LOG='/var/log/wvdial' eject /dev/sr0 ( while : ; do wvdial 2>&1 sleep 15 done ) 2>&1 > ${LOG} < /dev/null &
# chmod +x /etc/init.d/wvdialloop.sh # update-rc.d wvdialloop.sh defaults
rc.localにIPマスカレードの設定を追加します。
# vim /etc/rc.local # exit 0 の前に追加 iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
これで電源を入れたらLTEネットワークに接続されモバイルルータとして機能するようになりました!!
その他
初期設定のままSSH接続していましたが、ちゃんと運用するのであればパスワードを変更するなり鍵を設定するなりしてセキュリティを高めてください。
また結構熱を持つのでRaspberry Pi(ラズベリーパイ)のケースを買ったほうが良いかもしれません。
Raspberry Pi ラズベリー・パイ 超小型パソコン Pi Model B+ / Pi 2 Model B 専用ケ-ス(Clear)
- 出版社/メーカー: Raspberry Pi
- メディア: エレクトロニクス
- この商品を含むブログを見る
まとめ
モバイルネットワークにつながると夢が広がりますね。とはいっても実はドコモ系MVNOはグローバルIPアドレスが割り振られないようで、遠隔操作やWEBサーバとして使うのは難しいようです。。ngrokを使うといけそうな気もするので次回挑戦してみたいと思います。
参考にしたサイト
・http://qiita.com/makoto_kw/items/393e098f214f81449c9f
・http://sideb.hatenablog.com/entry/mvno_kakuyasu_sim_raspberry_pi_lte_3g_mobile_router