Be an Engineer.

社会人からWEBエンジニアになった人間の備忘録的勉強記録

Heroku Add-onのProcess SchedulerでAPI Keyを変更する方法

久しぶりの更新ですが、ショートにメモ。

先日Herokuに作成しているアカウントのパスワードを変更したらHeroku API Key(以降、API Key)の値も変わる仕組みらしく、Heroku Add-onのProcess Scheduler から [<Project Name>] Failure to scale web process type という件名のメールが送られてきました。(Process Schedulerが何者なのかは今回は割愛します。)

メール本文には、さらに

Process Scheduler failed to scale the web process type for your application shirachan from to . The following error occurred : Invalid credentials provided.

This error means the API key you provided is no longer valid. This is the case when you change your Heroku's account password.
To resolve this error, you must connect on Process Scheduler web interface and change your API Token in the settings panel.

という内容が親切にも書いてくれていたので、不適切にAPI Keyが設定されてしまっているとのことでした。

ただ、このProcess Schedulerの画面からAPI Keyの設定を編集するリンクがとても気づきにくかったので、ご紹介。

Heroku Add-ons → Process Scheduler画面

Process Schedulerを使っているならば説明しなくてもいいとは思いますが、一応。
下の画像の赤く囲ったリンクから、Process Schedulerの設定画面にいけます。

f:id:shirakiya:20160322095833p:plain

Process Scheduler → API Keyの設定画面

今回めっちゃ苦労したのは、下の画像で歯車のアイコンが見つけられなかったことでした。(あまりコントラストがはっきりしているディスプレイを使っていなかったというのも相まって見つけづらかったです。)

f:id:shirakiya:20160322100532p:plain

この歯車をクリックすれば、以下に例示するAPI Keyを設定できる画面にいけます。

f:id:shirakiya:20160322101057p:plain

いやー見つけられなかった自分もアレかなとは思いますが、いいディスプレイを使っているユーザーばかりではないので、こういったUIは考えないといけないですね!
デザインは難しい…。

iOSアプリの実装 - オレオレ証明書と戦う(webview、Alamofire)

iOSアプリを作る過程で、webview や Alamofire などを使って、Webサイトを表示させたり、APIを叩いたりすることは当たり前のようにあると思います。
ただ実装過程では、サーバーを立てて仮想的にHTTPS通信にするためにオレオレ証明書を作ってテストすることがままあると思うのですが、アプリ側の実装をそのままにしていると基本以下のようなエラーが表示されたりします。

2016-01-16 21:36:19.940 Webview[8069:1398803] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)

調べた記事内容とその参考記事を簡単にまとめました。
(あまり深いことはわかっていません、すみません。)

オレオレ証明書なサイトをWebviewで閲覧する時

  1. 新しく.swiftのファイルを作る
  2. 以下のコードを書くだけ
import Foundation

// NSURLRequestの非公開APIをオーバーライド
extension NSURLRequest {
    static func allowsAnyHTTPSCertificateForHost(host: String) -> Bool {
        return true
    }
}

(参考)
SwiftでHTTPS通信時に自己認証証明書の警告によるエラーを無視させる - Steel Dragon 14106

オレオレ証明書なサーバーとAlamofireを使って通信する時

Aalamofireを使う画面のviewDidLoad() などで、実際にAlamofireで通信させる前に、以下のコードを実行させるだけで良い。

let manager = Alamofire.Manager.sharedInstance
        
manager.delegate.sessionDidReceiveChallenge = { session, challenge in
    var disposition: NSURLSessionAuthChallengeDisposition = .PerformDefaultHandling
    var credential: NSURLCredential?

    if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
        disposition = NSURLSessionAuthChallengeDisposition.UseCredential
        credential = NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!)
    } else {
        if challenge.previousFailureCount > 0 {
            disposition = .CancelAuthenticationChallenge
        } else {
            credential = manager.session.configuration.URLCredentialStorage?.defaultCredentialForProtectionSpace(challenge.protectionSpace)
            if credential != nil {
                disposition = .UseCredential
            }
        }
    }
    return (disposition, credential)
}

(参考)
[iOS]Alamofireでオレオレ証明書なSSLサーバへの接続を可能にする | 開発メモ

注意

非公開APIを書き換えているために、App Store提出時のReleaseビルドに含めてしまうとAppleの審査でリジェクトを食らう可能性が高いので、Releaseビルドには含めないように注意!

hubot-google-images を復活させた

先日、Hubotのhubot-google-imagesが急に使えなくなったので、その修復で行った作業内容を備忘録的に記事にします。

ちなみに使えなくなった理由ですが、これは2011年5月からdeprecatedになっていたGoogle Image Search APIが完全に利用不可になってしまったためでした。

また、hubot-google-imagesがv0.1.5以降のバージョンであれば下記の手順で使えるようになります。

1. Google Custom Search API Key を取得する

Google Developers Console
Google Custom Search API Key(CSE_KEY)はGoogle Developers Consoleから取得します。

プロジェクトを作成する

プロジェクトが1つもない状態ならば、プロジェクトを作成します。
Google APIを利用する」をクリックすると、プロジェクト作成モーダルが出てくるので、プロジェクト名を入力して作成します。

f:id:shirakiya:20151207011935p:plain

f:id:shirakiya:20151207011953p:plain

Custom Search APIを有効にする

Custom Search APIを選択して、有効にします。

f:id:shirakiya:20151207012011p:plain

f:id:shirakiya:20151207012042p:plain

APIキーを取得

「認証情報」タブに移動し、「認証情報を追加」します。
APIキーを選択すると、下の画像のモーダルが表示されるので、ここはサーバーキーを選択します。(Hubotはサーバーで動いていますので。)

f:id:shirakiya:20151207012055p:plain

f:id:shirakiya:20151207012115p:plain

APIキーの名前とリクエスト元のIPアドレスを入力します。
※リクエストを受け入れるサーバーIPアドレスには、セキュリティを鑑みて入力してください。

f:id:shirakiya:20151207012127p:plain

f:id:shirakiya:20151207012141p:plain

これで取得できました!

2. Google Custom Search Engine ID を取得する

Googleカスタム検索
Google Custom Search Engine ID(CSE_ID)はGoogleカスタム検索から取得します。

カスタム検索を作成する

「新しい検索エンジン」から作成画面にいきます。

f:id:shirakiya:20151207012300p:plain

などとして作成します。

CSE_IDを取得する

CSE_IDを取得していきます。
「コントロールパネル」をクリックすると詳細情報が見れます。
詳細ページで画像中央の「検索エンジンID」をクリックすると、モーダルが表示されるのでこの中に入っているのがCSE_IDです。

f:id:shirakiya:20151207012323p:plain

f:id:shirakiya:20151207012347p:plain

f:id:shirakiya:20151207012357p:plain

Tips

「検索するサイト」に先ほど入力したwww.google.co.jpが入っています。

これを設定したままだと、実際にHubotにimage機能で検索文字列を投げかけると、www.google.co.jpに含まれるコンテンツの中からその検索文字列を探してくるので、ある種googleに偏った検索結果になってしまいます。

そこで、 検索するサイト は全て削除して、「追加したサイトだけ検索する」と表示されているプルダウンから 「追加したサイトを重視して、ウェブ全体を検索する」に変更 します。

f:id:shirakiya:20151207012414p:plain

こうするとことでウェブ全体から重み付けなく検索してくれるようになります。

CSE_KEY/CSE_IDのチェック

CSE_KEYとCSE_IDが有効であるかどうかは実際にAPIにリクエストを送って確認します。

https://www.googleapis.com/customsearch/v1?key={CSE_KEY}&cx={CSE_ID}&searchType=image&fields=items(link)&q={何か検索したい文字列}

↑のURLのCSE_KEYとCSE_IDにこれまでで取得した実際のものを使って、ブラウザでリクエストします。
itemsというキーが存在するJSONが返ってきたら成功です。

3. HubotにCSE_KEYとCSE_IDを設定する

最後の仕上げに、以上の手順で取得したCSE_KEYとCSE_IDを環境変数に設定します。

変数名は、

  • CSE_KEY:HUBOT_GOOGLE_CSE_KEY
  • CSE_ID:HUBOT_GOOGLE_CSE_ID

とします。

herokuでHubotを動かしていたり、色々な環境で動かしているので設定方法は一概になんとも言えないので、具体的な方法は割愛します。
(起動スクリプトを用意している場合は、exportさせて環境変数を設定したりとかです。)

さいごに

ちなみにCustom Search APIは無料枠であれば1日100クエリまでとなっています。
なかなか少ないですね…。

リクエストがどんな場合でカウントされてしまうのかは下記の記事で軽く書かれていましたので、掲載しておきます。

Google Custom Search API を使ってみる

Enjoy Hubot Life !!

iOS9から導入されたATSとは?そして回避する方法は?

(2016/06/18 追記) 以下の記事によると、2017年1月1日から全てのiOSアプリにATSに対応しないといけなくなるそうです。
その場合はこの記事にあるような回避策は有効じゃない可能性があります。ご承知ください。 japan.cnet.com

(以下本編)

※ この記事は2015年10月3日の情報を元に公開しています。

概要

Xcode6を使ってた時代はWebViewがちゃんと動いていたのですが、最近Xcode7にアップデートして動かしてみると、ページが表示されなくなって焦ったわけで。。
そこで調べてみるとATSという機能によって動かないことがわかったので、その知見を共有しておきます。

ATSとは

ATSとは「App Transport Security」の略で、ざっくり言うと「接続先URLがHTTPSでかつセキュアでないサーバー証明書を使ってないなら接続しねーぞこら。」という機能です。

OSX, iOS アプリケーションが NSURLConnection, CFURL, NSURLSession を利用してサーバに接続する際 現時点で最善に近いセキュアな接続を達成するために導入されたものとのこと。

開発者はATS導入を受けて、サーバー証明書Appleが要求する暗号化スイートに変更するか、ATS機能側の例外設定を適切にする必要があります。
ATSはiOS9.0以降、MacOSX10.11以降で使用可能となります(というか勝手に機能しだします。)

ATSのデフォルト動作

NSURLConnection, CFURL, NSURLSessionを利用してサーバーと接続する場合はATSが動作し、下記要求を満たさない場合は接続できなくなります。(CFNetwork SSLHandshake failed (-9824)なんてエラーが表示される)

These are the App Transport Security requirements:

  • The server must support at least Transport Layer Security (TLS) protocol version 1.2.
  • Connection ciphers are limited to those that provide forward secrecy (see the list of ciphers below.)
  • Certificates must be signed using a SHA256 or greater signature hash algorithm, with either a 2048-bit or greater RSA key or a 256-bit or greater Elliptic-Curve (ECC) key.

Invalid certificates result in a hard failure and no connection.

日本語でおk

  • サーバは TLS 1.2 をサポートしていなければならない
  • 利用できる暗号化スイート(Cipher Suite)は、Forward Secrecy を提供できる(下記リスト)ものに限られる
  • 利用されるサーバ証明書はSHA256以上のハッシュアルゴリズムによって署名されており、2048ビット以上のRSA 鍵、もしくは256ビット以上のECC鍵が使われている必要がある
    検証できない証明書はエラーとなり接続ができない

なお利用できる暗号化スイート(Cipher Suite)のリストは以下の通り。

  • TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
  • TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
  • TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
  • TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
  • TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
  • TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
  • TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
  • TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
  • TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
  • TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
  • TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA

Cipher suiteを調べる

エラーCipher suiteを確認するために接続先のWebサーバーで

$ openssl ciphers -v

と叩いても確認はできるらしいですが、今回はQUALYS SSL LabsのSSL Testを使って確認してみました(使い方はドメイン貼り付けてスタートさせるだけなので割愛)。

実行させてみると以下の様なリストがあるので、AppleのデフォルトのCipher suiteと比較します。

f:id:shirakiya:20151004014455p:plain

結果を見てみると、僕の場合はどうも鍵交換アルゴリズム(kx)がDHEが使われていることが問題のようです(ATSのデフォルト設定ではECDHEのみ許可されている)。

回避方法

もちろん証明書は現時点で最もセキュリティが高い暗号化スイートを利用しているのにこしたことが無いが、どうしてもATSを有効にするのは厳しい状況もあるはず(例えば自社で証明書を管理していないとかの政治的な事情とか)。
公式ドキュメントにも書かれている通り、ATS機能についての例外設定が可能です。

例外設定はinfo.plistに書きます(Xcode使ってるならポチポチで可能)。
設定構造はこんな感じです。

  • NSAppTransportSecurity (Dictionary)
    • NSAllowsArbitraryLoads (Boolean)
    • NSExceptionDomains (Dictionary)
      • <domain-name-for-exception-as-string> (Dictionary)
        • NSExceptionMinimumTLSVersion (String)
        • NSExceptionRequiresForwardSecrecy (Boolc)
        • NSExceptionAllowsInsecureHTTPLoads (Boolean)
        • NSRequiresCertificateTransparency (Boolean)
        • NSIncludesSubdomains (Boolean)
        • NSThirdPartyExceptionMinimumTLSVersion (String)
        • NSThirdPartyExceptionRequiresForwardSecrecy (Boolean)
        • NSThirdPartyExceptionAllowsInsecureHTTPLoads (Boolean)

NSAppTransportSecurity

トップレベルのDictionary。この配下に設定を加えていく

NSAllowsArbitraryLoads

こいつをYESすると、ATS機能が無効となる。つまりデフォルトはNO

NSExceptionDomains

特定のドメインに対する個別の設定を行うDictionary

<domain-name-for-exception-as-string>

特定のドメインを記載するDictionaly。keyに「apple.com」のようにドメインを設定する

NSExceptionMinimumTLSVersion

接続を許可するTLSのミニマムのバージョンを記載する。使用できる文字列は

  • TLSv1.0
  • TLSv1.1
  • TLSv1.2(デフォルトはこれ)

NSExceptionRequiresForwardSecrecy

許可する鍵交換アルゴリズムの設定。デフォルトはYES。
YESの場合は上記のCipher Suiteのリストに限られるが、Noにすると以下のリストも許可するようになる。

NSExceptionAllowsInsecureHTTPLoads

セキュアでないHTTPS接続を許可するかどうか。
NOにすると許可せず、YESにすると許可する。(デフォルトはNO)

  • セキュアでないHTTPS接続
    • no certificate
    • with an error for a self-signed
    • expired
    • hostname mismatch certificate.

NSIncludesSubdomains

指定したトップレベルドメインに対する全てのサブドメインにおいて、設定を適用されるかどうか。
NOにすると設定を適用せず、YESにすると設定を適用させる。(デフォルトはNO)

NSThirdPartyExceptionMinimumTLSVersion

アプリ開発者が変更不可能なサービスに対するTLSのミニマムのバージョンを設定する。
Appleがどうやって変更不可能かどうかを判断しているのかは不明でした...)

NSThirdPartyExceptionRequiresForwardSecrecy

アプリ開発者が変更不可能なサービスに対する、許可する鍵交換アルゴリズムを設定する。
(これもNSThirdPartyExceptionMinimumTLSVersion同様不明...)

NSThirdPartyExceptionAllowsInsecureHTTPLoads

アプリ開発者が変更不可能なサービスに対する、セキュアでないHTTPS接続を許可するかどうかを設定する。
(これもNSThirdPartyExceptionMinimumTLSVersion同様不明...)

今回の場合は鍵交換アルゴリズムが許可されていないものだったので、NSExceptionRequiresForwardSecrecyをNOにすることに。
Xcode上では感じで設定。

f:id:shirakiya:20151003234647p:plain

内部ではこんな感じ。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads</key>
        <false/>
        <key>NSExceptionDomains</key>
        <dict>
            <key>example.com</key>
            <dict>
                <key>NSExceptionMinimumTLSVersion</key>
                <string>TLSv1.2</string>
                <key>NSExceptionRequiresForwardSecrecy</key>
                <false/>
                <key>NSExceptionAllowsInsecureHTTPLoads</key>
                <false/>
                <key>NSIncludesSubdomains</key>
                <false/>
            </dict>
        </dict>
    </dict>
    ...
</dict>
</plist>

そして再ビルドするとページが表示されました!!
ひとまず助かったという感じですが、理想はサーバー証明書Appleが要求する暗号化スイートを使ったものにすることなので油断はしてはいけないですねー。

参考資料

AWS SDK for PHP を使ってみる

環境要件

  • PHP5.3.3 以上のバージョンであること
  • cURLJSONXML・OpenSSL・zlib の拡張モジュールと入れてコンパイルしていること
    • $ php -mでどのモジュールが入っているか確認可能
  • cURLモジュールは 7.16.2 以上のバージョンであること

(参考)Requirements — AWS SDK for PHP 2.8.17 documentation

インストール方法

3種類の方法がある。

  1. Composer を利用してインストールする
  2. Pharをインストールする
  3. Zipファイルをダウンロードして使う

AWS SDK for PHPライブラリのバージョン管理ができて依存関係が簡単に解決できるComposerがAWS的にも推奨されているのでComposerを使った方法を紹介する。

(参考)Installation — AWS SDK for PHP 2.8.17 documentation

ComposerでAWS SDK for PHPを使う

公式ドキュメントと重複する部分もあるが、全体の流れを追うということで紹介。 ※ composerはcpanやBundlerなどと違ってバージョンが5.3.2以上のPHPが入っていれば使える。 (実際は細かい拡張モジュールが必要らしいが、公式ドキュメントにすら詳細が書かれていないので、エラーが表示されたら残念ぐらいの気持ちで良さそう)

1. composer.pharをダウンロードする

$ curl -sS https://getcomposer.org/installer | php

これでcomposer.pharがカレントディレクトリにダウンロードされる。

2. composer.jsonを作成する

composer.jsonは1のコマンドを実行させても作成されるわけではない。 新たに自分で作成し、インストールする AWS SDK for PHP の情報とそのバージョンを書く。

{
    "require": {
        "aws/aws-sdk-php": "2.*"
    }
}

3. インストール開始

$ php composer.phar install

これで AWS SDK for PHP のライブラリ本体がvender/以下にインストールされる。

4. 実際にSDKを利用するスクリプトでロードして利用する

<?php

require(dirname(__FILE__).'/../vendor/autoload.php');
// ↑公式とは書き方を変えている。requireはスクリプトを実行しているディレクトリが基準になるので、安易に相対パスを使うと痛い目に遭うことが多いため。

5. credential情報を取得するためにIAMユーザーを作成する

あんまりこの記事で伝えたいところでもないので、割愛。 参考となる公式記事はこちら

  • ここでアクセスキーとシークレットアクセスキーを取得しておく
  • 作成したユーザーの管理ポリシーは(状況のよりけりなので選定する必要があるが)以下のようなポリシーをアタッチしておく
    • AmazonRoute53DomainsFullAccess
    • AmazonRoute53FullAccess

6. credential情報を使う

SDKクライアントオブジェクトを生成するために、アクセスが許可されているユーザーなのか(credential情報)やどこリージョンにリクエストを送るのか等の情報を付与する必要がある。 その情報の与え方が複数あるようで。

1. ~/.aws/credentialsファイルに情報を記載するパターン

~/.aws/credentials

[project1]  // ①
aws_access_key_id = YOUR_AWS_ACCESS_KEY_ID
aws_secret_access_key = YOUR_AWS_SECRET_ACCESS_KEY

hogehoge.php

<?php

require(dirname(__FILE__).'/../vendor/autoload.php');

use Aws\Route53\Route53Client;

$client = Route53Client::factory(array(
    'profile' => 'project1',  // ①
));

2. 設定ファイルを作成して、コンストラクタに食わせるパターン

config.php

<?php

return array(
    'includes' => array('_aws'),
    'services' => array(
        'default_settings' => array(
            'params' => array(
                'credentials' => array(
                    'key'    => 'YOUR_AWS_ACCESS_KEY_ID',
                    'secret' => 'YOUR_AWS_SECRET_ACCESS_KEY',
                ),
                'region' => 'us-east-1'  // Route 53 の場合。他はこちら参照→http://docs.aws.amazon.com/ja_jp/general/latest/gr/rande.html
            )
        )
    )
);

hogehoge.php

<?php

require(dirname(__FILE__).'/../vendor/autoload.php');

use Aws\Route53\Route53Client;

$client = Route53Client::factory('path/to/config.php');

3. credentialオブジェクトを生成してコンストラクタに食わせるパターン

hogehoge.php

<?php

require(dirname(__FILE__).'/../vendor/autoload.php');

use use Aws\Route53\Route53Client;
use Aws\Common\Credentials\Credentials;

$credentials = new Credentials('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY');

$client = Route53Client::factory(array(
    'credentials' => $credentials
));

4. 生で書くパターン

hogehoge.php

<?php

require(dirname(__FILE__).'/../vendor/autoload.php');

use use Aws\Route53\Route53Client;

$client = Route53Client::factory(array(
    'credentials' => array(
        'key'    => 'YOUR_AWS_ACCESS_KEY_ID',
        'secret' => 'YOUR_AWS_SECRET_ACCESS_KEY',
    )
));

7. あとはAPIメソッドドキュメント眺めてAPI叩いて楽しむ

ドキュメントを読むと色々できて夢広がる感じの時が、一番楽しいポイントですよねー 色々できそうですが、ホストゾーン内のリソースレコードをCRUD操作するコードを書いたので参考までにベロっと貼っておきます。

(参考)Class Aws\Route53\Route53Client | AWS SDK for PHP

hogehoge.php

<?php

require(dirname(__FILE__).'/../vendor/autoload.php');

use Aws\Route53\Route53Client;

$client    = Route53Client::factory(array(
    'profile' => 'someproject',
));

/* レコード一覧取得 */
try {
    // http://docs.aws.amazon.com/aws-sdk-php/v2/api/class-Aws.Route53.Route53Client.html#_listResourceRecordSets
    $res = $client->listResourceRecordSets(array(
        'HostedZoneId' => 'Host Zone ID をコンソールから調べて記述',
    ));
    foreach ($res['ResourceRecordSets'] as $record) {
        echo $record['Name']."\n";
    }
} catch (Exception $e) {
    // 例外クラスは大量にあるので、エラー処理難しそう。。
    // http://docs.aws.amazon.com/aws-sdk-php/v2/api/namespace-Aws.Route53.Exception.html
    echo $e->getMessage();
}

/* レコード追加 */
try {
    // http://docs.aws.amazon.com/aws-sdk-php/v2/api/class-Aws.Route53.Route53Client.html#_changeResourceRecordSets
    $client->changeResourceRecordSets(array(
        'HostedZoneId' => 'Host Zone ID をコンソールから調べて記述',
        'ChangeBatch'  => array(
            'Comment' => 'from my PHP script',
            'Changes' => array(
                array(
                    'Action' => 'CREATE',  // string: CREATE | DELETE | UPSERT
                    'ResourceRecordSet' => array(
                        'Name' => 'www.hogehoge.com',
                        'Type' => 'A',
                        'TTL'  => 86400,
                        'ResourceRecords' => array(
                            array(
                                'Value' => 'some IP address',
                            ),
                        ),
                    ),
                ),
            ),
        ),
    ));
} catch (Exception $e) {
    echo $e->getMessage();
}

/* レコード変更 */
try {
    $client->changeResourceRecordSets(array(
        'HostedZoneId' => 'Host Zone ID をコンソールから調べて記述',
        'ChangeBatch'  => array(
            'Comment' => 'from my PHP script',
            'Changes' => array(
                array(
                    'Action' => 'UPSERT',  // string: CREATE | DELETE | UPSERT
                    'ResourceRecordSet' => array(
                        'Name' => 'www.shirakiya.com',
                        'Type' => 'A', // UPSERT の場合でも必要
                        'TTL'  => 7200,
                        'ResourceRecords' => array(
                            array(
                                'Value' => 'some IP address',  // UPSERT の場合でも必要
                            ),
                        ),
                    ),
                ),
            ),
        ),
    ));
} catch (Exception $e) {
    echo $e->getMessage();
}

/* レコード削除 */
try {
    $client->changeResourceRecordSets(array(
        'HostedZoneId' => 'Host Zone ID をコンソールから調べて記述',
        'ChangeBatch'  => array(
            'Comment' => 'from my PHP script',
            'Changes' => array(
                array(
                    'Action' => 'DELETE',  // string: CREATE | DELETE | UPSERT
                    'ResourceRecordSet' => array(
                        'Name' => 'www.shirakiya.com',
                        'Type' => 'A', // DELETE の場合でも必要
                        'TTL'  => 7200,
                        'ResourceRecords' => array(
                            array(
                                'Value' => 'some IP address',  // DELETE の場合でも必要
                            ),
                        ),
                    ),
                ),
            ),
        ),
    ));
} catch (Exception $e) {
    echo $e->getMessage();
}

これでいい感じにRoute 53のレコード管理ができると思います。 今回はRoute 53だけ紹介しましたが、もちろん他のAWSサービスでも使えますので!

(参考)Namespace Aws | AWS SDK for PHP

FuelPHPでCoffeeScriptのコンパイルにcoffeescript-phpを使う

はじめに

突然ですが、FuelPHPCoffeeScript使って実装したいと思ったことありませんか?
生のjavascriptよりも簡潔に書けて、javascript特有のバグも起きにくいということからCoffeeScriptで書きたいというケースは少なからずあると思います。
でもCoffeeScriptで実装する際にめんどくさいポイントが2つあると思っていて、

このポイントを解決できるのがcoffeescript-php(https://github.com/alxlit/coffeescript-php)です。
2012年に書かれたものなのですが、これは

という代物です。そこでcoffeescript-phpを使ってFuelPHPCoffeeScriptの自動コンパイル機能を簡単に実装してみます。

coffeescript-phpのインストール

FuelPHPcoffeescript-phpをインストールするにはComposerを使います。FuelPHPには初期からComposerがあるのでそれを利用します。

{
...
    "require": {
        ...
        "coffeescript/coffeescript": "1.3.1"
    },
...
}

と追加してからcomposer.pharがあるディレクトリで

$ php composer.phar update

とすればVENDERPATH配下にインストールされます。(FuelPHPVENDORPATH等についてはこちらを参照

使い方

coffeescript-phpがインストールができるともう使用することができます。
(Composer経由でインストールしたパッケージは、autoload.phpをrequireすれば使用可能になりますし、それがFuelPHPではCOREPATH/bootstrap.phpで記述されているのでほぼ全てのファイルで使用可能になります。)
ここいらがFuelPHPの楽ちんなところですね!

coffeescript-phpCoffeeScriptファイルからjavascriptファイルを生成するには以下のようにします。

<?php
...

// コンパイルを実行したいCoffeeScriptファイルへのフルパス
$coffeescript_path = "/path/to/coffeescript_file";

// ファイルの中身を取得
$coffeescript = File::read($coffeescript_path, true);
 
$javascript = CoffeeScript\Compiler::compile($coffeescript);
// $javascript にはコンパイル実行結果のjavascriptのコードが文字列で格納されている

あとは出力されたjavascriptのコードをお好きなファイル(例えばpublic/asset/js/配下とか)に書き出すとかできるようになります。
これを上手いこと使えば、CoffeeScriptの自動コンパイルの仕組みを作ることができます!

では!

余談

ちなみに私はCoffeeScriptを独自拡張したAsset::coffee()Coffeescriptのソースを読み込ませると、

  • 自動で更新があったのかどうかを判別し、
  • 更新があった場合はpublic/asset/js/配下にjavascriptファイルを設置して、
  • Asset::js()と同じようにHTMLのソースに貼っつける

という仕組みを作れました。(作った拡張Assetクラス↓↓)

ROOtKEY/asset.php at master · shirakiya/ROOtKEY · GitHub

このようにcoffeescript-phpは結構使い方によっちゃあ便利になると思います!

Vagrant+tmux環境下でvimのヤンクデータを共有する

はじめに

vagrant仮想環境で開発を進めているときにめっちゃイラッとすることが2つある。(※自分はMacとiTerm2を使っています。)

  1. 仮想環境下で新しいウィンドウを開くとssh接続が切れてローカルから再スタート
  2. Vimでヤンクしたコードが他のvimウィンドウでペーストできない

1に関してはtmuxを使うことによって回避できているが、2に関しては今までどうすることもできなかった。(調べても記事が無い)

なので、この2に関して力技でなんとかしてみた。

viminfoを使う

viminfoとはコマンド、検索履歴、レジスタなどの情報が格納されているファイルで、通常ホームディレクトリ以下に「.viminfo」の形で存在している。
※わかりやすい解説はこちら

このviminfoにレジスタのデータが書かれており、

# ヤンクした後に
:wv

# 別タブのvimで
:rv!

とすることによって、ヤンクしたデータを複数ウィンドウ間で共有することができる。
これを利用して、ヤンクすると自動的に:wvを実行し、ペーストすると自動的に先に:rv!を実行させることで、わざわざコマンドを叩く事なく、軽快なヤンク+ペーストをさせることができる。

以下を.vimrcに記述する。

"Linuxの場合はviminfoを用いてヤンクデータを共有
let OSTYPE = system('uname')
if OSTYPE == "Linux\n"
    noremap y y:wv<CR>
    noremap p :rv!<CR>p
endif

set viminfo='50,\"3000,:0,n~/.viminfo

基本的にMacのローカル環境は共有できている前提で、今回はOSがLinuxの時のみ有効にさせたが、ローカルでも同じことがしたい場合はif内を書いておけば良い。

またset以下はviminfoの設定で、何行までヤンクしたデータを保存するのかを決めている。
こちらの記事を参照したほうがわかりやすいので詳細については今回は割愛する。