ポケモンGo!のアンテナサイトを作った。技術仕様やアプリケーション仕様などなど
酔った勢いで、ポケモンGo!のアンテナサイトを作ってみました。
こういうのって、スピードが大事ですよね。検索ボリュームが多い時にリリースできたのでよかったです。 1時間ぐらいでさくっと。
使用した技術
- CentOS7
- CakePHP 2.8.5
- PHP 7.0.8
- Redis 2
- MariaDB 10
- Capistrano 3
- Bitbucket
- Vagrant
- Nginx 1.8
- Gulp
- Sass
- Google Analytics
- Bootstrap3
- New Relic
サーバーはGMOクラウドのVPSのメモリ2GB、月額1,280円のプラン。
composer.json
"require": { "cakephp/cakephp": "2.*", "cakephp/debug_kit": "*", "intervention/image": "dev-master", "intervention/imagecache" : "*", "cakedc/migrations": "*", "nanapi/cakephp-redis": "*" },
アプリケーションの仕様
- hourlyで指定したRSSをクロール。
- サムネイルの取得は対象サイトのog:image、なかったら、RSSのdescriptionに含まれている、imgタグから取得。
- PVのカウントはRedisで貯めてって、デイリーバッチで、MariaDBに貯めこむ。
悲しかった事。
CakeDCのマイグレーションプラグインを使ったのですが、マイグレーションプラグインがStringクラスを使っていて、PHP7から「型と同じクラス名」を作れないという制約があるため、exception error が発生するという悲しみ。
なので手動でDB作りました。
今後やりたいこと
広告周りは適当にimobileのクリック広告しか貼ってないですが、ユーザの志向にあったものを採用していきたいです。
ポケモンGo!をやってみて。
FXシステムトレードフレームワーク Jiji をCentOS7にセットアップ
FXシステムトレードフレームワーク「Jiji」のセットアップメモです。
「Jiji」のドキュメントにはHeroku、AWS、Dockerの3つの方法が載っており、前者2つは詳細に説明が書かれていますが、3つ目の「Dockerにインストール」はパッケージインストールが省略されています。
この記事はCentOS7での1からのセットアップ記事です。誰かの参考になれば。
Docker、Git、docker-composeのインストール
# システムをアップデート $ sudo yum update -y # Gitのインストール $ sudo yum install -y git # Dockerの最新版をインストール $ curl -sSL https://get.docker.com/ | sh $ docker -v Docker version 1.10.2, build c3959b1 $ sudo systemctl start docker $ sudo systemctl enable docker $ sudo usermod -a -G docker YOURUSERNAME # docker-composeをインストール $ curl -L https://github.com/docker/compose/releases/download/1.6.0/docker-compose-`uname -s`-`uname -m` > /tmp/docker-compose $ sudo mv /tmp/docker-compose /usr/local/bin/ $ sudo chmod +x /usr/local/bin/docker-compose
docker-compose設定ファイルのひな形をチェックアウト
$ git clone https://github.com/unageanu/docker-jiji2
オレオレ証明書の作成
# スーパーユーザにスイッチ $ sudo su # jiji用のディレクトリ作成、移動 $ mkdir -p /etc/ssl/certs/jiji $ cd /etc/ssl/certs/jiji # 秘密鍵を生成 $ openssl genrsa 2048 > server.key # CSRを作成 $ openssl req -new -key server.key > server.csr # サーバー証明書を作成 $ openssl x509 -sha256 -days 365 -req -signkey server.key < server.csr > server.crt # アクセス権を制限 $ sudo chown root.root server.key $ sudo chmod 600 server.key # スーパーユーザから抜ける $ exit
docker-compose.yml の編集
vim ~/docker-jiji2
jiji: container_name: jiji_jiji image: unageanu/jiji:latest environment: # サーバー内部で秘匿データの暗号化に使うキー # 必ず変更して使用してください。 USER_SECRET: 20e43fa41e75c9fe958f5f11bc9e79d2174b50b links: - mongodb mongodb: container_name: jiji_mongodb image: mongo:3.0.7 ports: # MongoDBのポート番号 # 必要に応じて変更してください。 - "27018:27017" volumes: # MongoDBのデータを保存するディレクトリ # デフォルトでは、コンテナ内に作成します。(この場合、コンテナを再作成すると、データが初期化されます) # コメントアウトしてパスを設定することで、ホストマシンの任意のディレクトリに変更することができます。 # './' で始めることで、docker-compose.ymlからの相対パスで指定可能です。 # - ./path/to/data/dir:/data/db nginx: container_name: jiji_nginx image: unageanu/jiji-nginx:latest links: - jiji ports: # Jijiのポート番号 # 443に変更します - "443:443" volumes: # SSL証明書のパス # './path/to/server.crt' にサーバー証明書、 # './path/to/server.key' に秘密鍵を指定します。 # './' で始めることで、docker-compose.ymlからの相対パスで指定可能です。 - /etc/ssl/certs/jiji/server.crt:/etc/nginx/cert/ssl.crt:ro - /etc/ssl/certs/jiji/server.key:/etc/nginx/cert/ssl.key:ro
Dockerコンテナ起動
$ sudo /usr/local/bin/docker-compose up -d Creating jiji_mongodb Creating jiji_jiji Creating jiji_nginx
アクセス
https://<インストール先ホスト>:<docker-compose.ymlで設定したJijiのポート/デフォルトは8443>
【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をCentOSにインストール
マルコフ連鎖の実験をしたいがために、 京都大学情報学研究科と日本電信電話株式会社コミュニケーション科学基礎研究所が開発しているオープンソースの形態素解析エンジン「MeCab」 (和布蕪 めかぶ)をインストールするためのメモです。
本体をインストール
$ cd /tmp $ wget https://drive.google.com/uc?export=download&id=0B4y35FiV1wh7cENtOXlicTFaRUE $ tar zxfv mecab-X.X.tar.gz $ cd mecab-X.X $ ./configure --enable-utf8-only $ make $ make check # make install
辞書ファイルをインストール
$ cd /tmp $ wget https://drive.google.com/uc?export=download&id=0B4y35FiV1wh7MWVlSDBCSXZMTXM $ tar zxfv mecab-ipadic-2.7.0-XXXX.tar.gz $ cd mecab-ipadic-2.7.0-XXXX $ ./configure --with-charset=utf8 $ make # make install
試してみる
$ mecab すもももももももものうち すもも 名詞,一般,*,*,*,*,すもも,スモモ,スモモ も 助詞,係助詞,*,*,*,*,も,モ,モ もも 名詞,一般,*,*,*,*,もも,モモ,モモ も 助詞,係助詞,*,*,*,*,も,モ,モ もも 名詞,一般,*,*,*,*,もも,モモ,モモ の 助詞,連体化,*,*,*,*,の,ノ,ノ うち 名詞,非自立,副詞可能,*,*,*,うち,ウチ,ウチ EOS
うまくいってるっぽい。 このライブラリを使って今後マルコフ連鎖の実験をしていく。
- 作者: Steven Bird,Ewan Klein,Edward Loper,萩原正人,中山敬広,水野貴明
- 出版社/メーカー: オライリージャパン
- 発売日: 2010/11/11
- メディア: 大型本
- 購入: 20人 クリック: 639回
- この商品を含むブログ (44件) を見る
Apacheのmod_expiresというキャッシュモジュールを使ってWEBサイトを高速化しよう
Apacheにはmod_expiresというキャッシュモジュールがあります。 クライアント側で画像やCSSなどファイルをキャッシュさせるモジュールです。 これを利用し、転送量を減少させてWEBサイトの負荷対策します。 キャッシュを利用すると負荷対策ばかりか、表示速度も向上します。
mod_expiresが組み込まれているか確認
通常の方法でApacheをインストールしていた場合、mod_expiresはデフォルトで組み込まれています。 CentOSの場合/etc/httpd/conf/httpd.confに以下の行があることを確認してください。
LoadModule expires_module modules/mod_expires.so
mod_expiresの設定方法
httpd.confの377行目付近に以下を追加してください。
<IfModule mod_expires.c> ExpiresActive on ExpiresByType image/png "access plus 12 hours" ExpiresByType image/jpeg "access plus 12 hours" ExpiresByType image/gif "access plus 12 hours" ExpiresByType text/css "access plus 12 hours" ExpiresByType text/javascript "access plus 12 hours" </IfModule>
これはpng,jpg,gif,css,javascriptを12時間という期限でキャッシュさせるという宣言です。 Apacheを再起動されば反映されます。
mod_expiresの設定が反映されているか確認
Chromeのdev toolで画像のレスポンスヘッダを確認してみましょう。
max-age=43200なので43200秒、つまり12時間にちゃんと設定されていることが確認できました。
mod_expiresの設定するにあたっての注意
もしjavascriptなどに変更があり、更新した場合、クライアント側にキャッシュが残っており表示が意図しなくなる場合があります。
その場合はhoge-v1.jsなどファイル名でバージョン管理するか、hoge.js?123456などパラメータにタイムスタンプなどを付与すれば解決します。(モダンなWEBアプリケーションフレームワークにはこのような機能が含まれていると思います。)
ハイパフォーマンスWebサイト ―高速サイトを実現する14のルール
- 作者: Steve Souders,スティーブサウダーズ,武舎広幸,福地太郎,武舎るみ
- 出版社/メーカー: オライリージャパン
- 発売日: 2008/04/11
- メディア: 大型本
- 購入: 32人 クリック: 676回
- この商品を含むブログ (126件) を見る