Aug 31

お疲れ様です。sasaki-kです。毎日暑いですね。

KLabではPHPで作られたフレームワークの高速化が熱いです。
高速化にあたっては、計測が重要です。

KLabではphpのxdebug extensionを使用し、プロファイル結果をcachegrindファイル形式で取得しWinCacheGrind で解析しています。

また皆でレビューするために Webgrind で解析結果を共有したり、言葉で説明しています。しかし、 Webgrindは一見してボトルネックが分かりにくかったり、言葉では説明がもどかしかったりしていました。

一方、KLabではCodepaste の社内版があり、 フォーマット済みのコードをフォームに貼りつけ、ブラウザのアドレスバーからURLをコピーしてIRC貼りつけてレビュー対象のコードを手軽に共有しています。

「Codepasteみたいにプロファイル結果も共有できたらいいのに・・・」と思い、もっと良いものを作りたいなと思い探してみました。 Continue reading »

Aug 31

はじめまして。
KLabにインターンでお邪魔させていただいている nakatani-s です。

インターンで製作しているアプリの中で、GmailのSMTPサーバにOAuth認証で入る部分があります。

こちら
にあるように、GmailはIMAP・SMTPともにOAuth認証に対応しているのですが、OAuth+IMAPのサンプルコードはあってもOAuth+SMTPのサンプルって中々見つからないんです。
そこで、OAuth+SMTP in Gmail のシンプルなPHPコードを公開して、少しでも世のお役に立てたらなと思うわけです。
いえ、僕が探した範囲なので本当はあるかもしれませんよ?でも恥ずかしいので知っている方も生温かい目でスルーしてください。

開発中にたくさんの助言・アイディアを下さり、インターンの身にこのような機会を与えてくださったKLabの方々には頭が上がらない思いです。

目次

  1. 必要な環境
  2. 下準備
  3. 動作確認
  4. コードと解説
  5. まとめ
  6. 参考

必要な環境

PHPが動くサーバが必要です。サーバのルートに自分でファイルが置ける必要もあります。

下準備

まずはGoogleに、サーバをOAuthのConsumerとして利用するための申請をし
ましょう。これはこちらのページを参考にしました。
OAuth Consumer Key と OAuth Consumer Secret は後で使うので、忘れないようにしておいて下さい。

次に、GoogleオフィシャルのOAuth+IMAPのプログラムを動かしてみます。
Gmail IMAP and SMTP using OAuth - Libraries and SamplesのPHP Sampleをダウンロード・解凍し、 xoauth-php-samples/common.php を開きます。
先ほど仕入れた OAuth Consumer Key と OAuth Consumer Secret の情報を、以下の部分に加えて下さい。

$THREE_LEGGED_CONSUMER_KEY = 'your_consumer_key';  // ここと
$THREE_LEGGED_SIGNATURE_METHOD = 'HMAC-SHA1';
$THREE_LEGGED_CONSUMER_SECRET_HMAC = 'your_consumer_secret';  // ここ

それが終わったら xoauth-php-samples/ ディレクトリ以下のファイルを全て自分のサーバにアップロードし、ブラウザ上から three-legged.php にアクセスしてみて下さい。
表示されたページでエディットボックスにご自分のGmailアドレスを入力し、実行ボタンを押すと、GoogleのOAuth認証画面にリダイレクトされます。

これで、”Total messages: X” と表示されたら、ここまではOKです。

ちなみに、僕はここで入力するアドレスをtypoしたせいで、社員の方を巻き込み6時間は悩みましたw

動作確認

こちらのPHPコードをダウンロードしていただき、エディタで開いて下さい。

190-195行目を、ご自分の環境に合わせて編集します。

  $from = 'your_account@gmail.com'; /* OAuth認証で使ったアカウントを指定 */
  $namefrom = 'your_name';          /* ご自由に */
  $to = 'someone@someserver.foo';       /* 送り先 */
  $nameto = 'someone';              /* 送り相手の名前 */
  $subject = 'test mail';           /* 件名 */
  $message = 'OAuth+SMTP test';     /* 本文 */

これが終わったら、サーバ上の common.php や three-legged.php と同じディレクトリ上に置いて下さい。ブラウザから three-legged-smtp.php にアクセスすると、指定した送信先にメールが届くはずです。

コードと解説

three-legged-smtp.php の解説をさせていただきます。
お気づきな方はお気づきでしょうが、ほぼ three-legged.php と同内容です。
内部で行われている処理の流れを簡単に説明すると、

  1. OAuth認証をし、Googleから認証情報をもらう(1-113行目)
  2. もらった認証情報を使ってssl通信を開始し、SMTPプロトコルで通信する権利を得る(114-187行目)
  3. SMTPプロトコルでメールを送る(190-212行目)
  4. Googleとのコネクションをクローズする(124-126行目)

という感じです。
この「OAuth認証をし、Googleから認証情報をもらう(1-113行目)」と「もらった認証情報を使ってssl通信を開始し、SMTPプロトコルで通信する権利を得る(114-187行目)」の部分が、OAuth+IMAP通信を行っていた three-legged.phpとほぼ共通なので、ほぼ同内容となっています。

さて、元のコードから追加・変更・削除した部分を説明します。

22-23行目: インクルードファイルの変更

require_once 'Zend/Mail/Protocol/Smtp.php'; /* Imap.php -> Smtp.php */
// require_once 'Zend/Mail/Storage/Imap.php';  /* 必要無し */

121-123行目: ssl通信時に送るURLを、SMTP用のものに変更

  $url = 'https://mail.google.com/mail/b/' .
       $email_address .
       '/smtp/';                /* imap -> smtp */

167-216行目: コメント参照。
要は、Googleのドキュメントに従ってssl通信をしているだけです。

  /* GmailのSMTPサーバと通信するためのsocketを開く */
  $smtpServer = "tls://smtp.gmail.com";
  $port = "465";                /* 465番ポートでうまくいかなかったら587番も試してみてください */
  $timeout = "45";
  $localhost = $_SERVER['REMOTE_ADDR'];
  $newLine = "\r\n";

  $smtpConnect = fsockopen($smtpServer, $port, $errno, $errstr, $timeout);

  $smtpResponse = fgets($smtpConnect, 4096);

  /* SMTP+OAuthの認証手続き */
  /* http://code.google.com/intl/ja/apis/gmail/oauth/protocol.html に規格があります */
  fputs($smtpConnect, "HELO $localhost". $newLine);
  $smtpResponse = fgets($smtpConnect, 4096);

  fputs($smtpConnect,"AUTH XOAUTH" . $newLine);
  $smtpResponse = fgets($smtpConnect, 4096);

  fputs($smtpConnect, $initClientRequestEncoded . $newLine);
  $smtpResponse = fgets($smtpConnect, 4096);

  /* 認証終了後にメールを送る */
  $from = 'your_account@gmail.com'; /* OAuth認証で使ったアカウントを指定 */
  $namefrom = 'your_name';          /* ご自由に */
  $to = 'someone@someserver.foo';       /* 送り先 */
  $nameto = 'someone';              /* 送り相手の名前 */
  $subject = 'test mail';           /* 件名 */
  $message = 'OAuth+SMTP test';     /* 本文 */

  fputs($smtpConnect, "MAIL FROM: <$from>" . $newLine);
  $smtpResponse = fgets($smtpConnect, 4096);

  fputs($smtpConnect, "RCPT TO: <$to>" . $newLine);
  $smtpResponse = fgets($smtpConnect, 4096);

  fputs($smtpConnect, "DATA" . $newLine);
  $smtpResponse = fgets($smtpConnect, 4096);

  $headers = "MIME-Version: 1.0" . $newLine;
  $headers .= "Content-type: text/html; charset=iso-8859-1" . $newLine; /* charsetはお好みで */
  $headers .= "To: $nameto $to1" . $newLine;
  $headers .= "From: $namefrom <$from>" . $newLine;

  fputs($smtpConnect, "To: <$to>\r\nFrom: $from\r\nSubject: $subject\r\n$headers\r\n\r\n$message\r\n.\r\n");
  $smtpResponse = fgets($smtpConnect, 4096);

  fputs($smtpConnect,"QUIT" . $newLine);
  $smtpResponse = fgets($smtpConnect, 4096);
  fclose($smtpConnect);

218-245行目: OAuth+IMAPでのメール受信に固有の部分をコメントアウト

  /* IMAP用の認証なので必要無し */
  /**
   * Make the IMAP connection and send the auth request
   */
  /* $imap = new Zend_Mail_Protocol_Imap('imap.gmail.com', '993', true); */
  /* $authenticateParams = array('XOAUTH', $initClientRequestEncoded); */
  /* $imap->requestAndResponse('AUTHENTICATE', $authenticateParams); */

  /* 以下、GMailからメールを受信して表示する部分なので必要無し */
  /**
   * Print the INBOX message count and the subject of all messages
   * in the INBOX
   */
  /* $storage = new Zend_Mail_Storage_Imap($imap); */

  /* include 'header.php';  */
  /* echo '<h1>Total messages: ' . $storage->countMessages() . "</h1>\n"; */

  /**
   * Retrieve first 5 messages.  If retrieving more, you'll want
   * to directly use Zend_Mail_Protocol_Imap and do a batch retrieval,
   * plus retrieve only the headers
   */
  /* echo 'First five messages:
    '; */ /* for ($i = 1; $i <= $storage->countMessages() && $i <= 5; $i++ ){ */ /* echo '
  • ' . htmlentities($storage->getMessage($i)->subject) . "
  • \n"; */ /* } */ /* echo '
'; */

まとめ

いかがでしたか? Google Code に置いてあるコードをベースに、OAuth+SMTP認証ができました。
しかし、このコードでは Google からOAuth認証情報を得る部分が PHP のZend Framework の内部に隠されてしまっています。
インターン中は時間がないのですが、なるべくいろいろな言語に流用できるように認証情報取得部分もホワイトボックス化したいと思います。
もしできたら、僕の個人ブログにでもコードを書きたいと思っています。

最後までお読み下さりありがとうございました。

ソースコード

http://lab.klab.org/young/wp-content/uploads/data/code/three-legged-smtp.php.txt

参考

Jul 16

opt様が主催されている、ソーシャルアプリコンテストタイアップセミナーにKLabの森本が登壇しました。

森本 隼  KLab株式会社 プロジェクトマネジメント部 リーダー
2006年KLab株式会社にプログラマーとして入社。
自社メディア事業、SNS事業の開発リーダーを経験し、現在ソーシャルアプリ開発のPMとして活躍中。

 
セミナーのテーマは 【LAMPで作るソーシャルアプリの負荷対策 ~アプリとインフラの調和のテクニック~】。現在ソーシャルアプリ周りで最もホットな高負荷対策について、KLabの取り組みを紹介しました。

セミナー風景

会場は満員御礼で立ち見もちらほら。おおよそ150人程度の方に聴講頂きました(感謝!)。
以下のとおり当日の資料を公開しました。(ソーシャルアプリに限らず)高負荷にお困りの方は必見です!
 
Lampで作るソーシャルアプリの負荷対策~アプリとインフラの調和のテクニック~

 
同セミナーは当日Ustreamでも配信されました。ちょっと途中で途切れたりしたので3つに別れてしまいましたが雰囲気は伝わると思います。

タイアップセミナーのハッシュタグ#sac2010も盛り上がりましたのでそちらも合わせてご覧ください。
 
 

Apr 20

お久しぶりです、amo-kです!
先日、若手インフラエンジニアにPHPでSessionストレージにmemcachedを使った場合
接続はデフォルトではpersistentなのかそうで無いのかを聞かれました。
最近ほとんどコード書けてないのですが、コードを読む機会ができましたw

彼には、そのWebアプリで利用している拡張モジュールのソースコードを読むのが一番早いよと言って僕はMTGに行ってしまったのですが、さすがに愛想無しだと思ったのと、久しぶりにコードと戯れようと思い、自分で見てみる事にしました。

さて、ということで以下にレポートします!
そのWebアプリではPECL::memcache 2.2.1を利用しているようでした。
まずはソースコードの入手ですね。

$ wget http://pecl.php.net/get/memcache-2.2.1.tgz
$ tar xvzf memcache-2.2.1.tgz
$ cd memcache-2.2.1

ぉっと、memcache_session.c コイツぽいぞ〜
はいはい、ありましたありました!!

PS_OPEN_FUNC(memcache)
{
...
        if (i < j) {
            int persistent = 0, weight = 1, timeout = MMC_DEFAULT_TIMEOUT, retry_interval = MMC_DEFAULT_RETRY;

...
                if (zend_hash_find(Z_ARRVAL_P(params), "persistent", sizeof("persistent"), (void **) &param) != FAILURE) {
                    convert_to_boolean_ex(param);
                    persistent = Z_BVAL_PP(param);
                }
...
}

一旦 0 で初期化して、指定されていれば代入という事ですね。
つまりデフォルトではpersistentでないということですね。

めでたしめでたしw

便利ツール(OSSのフレームワークや各種ツール)を使っていて問題が起こった時や不明点があった際に皆さんどうしますか?
Google検索して解決しなければ諦めるとか言わないで下さいね!!
特にOSSの場合はソースコードを取得出来ますのでWebに情報が無くとも、一番正確な情報(ソースコード)を確認すれば解決できるハズです!
KLab若手エンジニアは日々新たな技術と戯れる一方で、しっかりと技術の本質も追求しております。
便利ツールがたくさんあってWebにたくさん情報がある中、我々は「Google検索やツール使いの達人」に成り下がらず、技術者として発信/成長して行きますのでよろしくお願いします!!

Nov 30

こんにちは。takei-hです。

ちょっと時間が経ってしまったのですが、アシアル株式会社KLab株式会社の合同勉強会でMessagePackとPHP Extensionについて発表しましたので、資料を公開します。



また、PHP Extensionもだいたい形になったので、公開します。

MessagePack PHP Extensionのダウンロード

Continue reading »

Nov 20

tadaka-atです。

最近Haskellの記事ばかり書いていますが、PHPも書いてます!ということでPHPのライブラリを公開しました。

PictgramConverter

サポートする機能は

  • 絵文字sjisバイナリをutf-8バイナリに変換
  • キャリア間の絵文字変換

「ShiftJISからutf-8への文字コード変換とともに、絵文字もutf-8エンコーディングに変換」「異なるキャリアの絵文字も表示キャリアに合わせて変換」という処理が手軽にしかも高速にできるすぐれものです。

インストールは以下のコマンドで完了します。

$ pear channel-discover openpear.org
$ pear install openpear/PictgramConverter-alpha

詳しく知りたい方は以下の勉強会資料もごらんください。
アシアルKLab合同勉強会で発表しました

Sep 28

ども、amo-kです。

先日(9/7)にsymfony開発者Fabien PotencierさんがKLabにお越し下さりました!
▼ 握手!(あんまり若手エンジニアが写ってないw)

▼ ディスカッションの様子

symfonyの使い方から思想まで、色々なことについて話す事ができました。
世界のトップレベルのエンジニアとのディスカッションに、KLab若手エンジニア達も非常に喜んでおりました。
来年のSymfony Conference Japanで何かお役に立てる様にがんばりま〜す。

また、Fabien Potencierさんを連れて来て頂いた秋元さん、月宮さん、大野さんありがとうございました!!
今後ともよろしくお願い致します〜

Mar 01

ども、amo-kです。

先日デプロイ時に実況中継するIRCボットを作ったのでこれについて。

KLabでは通常、
テスト/本番環境に最新のプログラムソースコードを反映する際に
以下のような手順を踏む。

1.踏み台サーバにログイン
2.SVN Export
3.アーカイヴ作成
4.テスト/本番環境にアーカイヴをアップロード
5.テスト/本番環境のコマンドを実行し、アーカイヴ解凍、各Webサーバに同期
6.お掃除

通常はこれを1コマンドで実現するためにデプロイスクリプトを書いて
そのスクリプトを実行する事でデプロイすることとなる。

その際に、デプロイした人はターミナルをチェックしていれば
スクリプトの標準出力で進捗を把握できるが、たの案件メンバは解らない。
そこで、デプロイ実況中継をするIRCボットを作ってみた。

今回は特定のキーワードに反応したり、待機する必要がないので
各ステータス毎にIRCサーバに接続、チャンネルJOIN、レポート、切断ということをする
非常に単純なボットを作った。

以下、IRCクライアント画面サンプルとサンプルソースコード
工夫した点は特に無いが、ライブラリを使わずに
TCPコネクションを張ってIRCサーバと通信している点が若干特徴的かもしれない。
IRCクライアント画面キャプチャサンプル
デプロイ時に実況中継するIRCボット

サンプルコード

#!/usr/bin/ruby

require 'socket'

chan = ARGV[0]
msg  = ARGV[1]

sock = TCPSocket.open("localhost", 6667)
sock.send("NICK DeployBot\r\n", 0);
sock.send("USER DeployBot localhost localhost :DeployBot\r\n", 0);
sock.send(sprintf("JOIN #%s\r\n", chan), 0);
sock.send(sprintf("NOTICE #%s :<-------------- %s -------------->\r\n", chan, msg), 0);
sock.send("QUIT\r\n", 0);
sock.readlines
sock.close

最初はphpでsocket関数を使って実装しようと思ったんだけど
実は踏み台サーバでsocket関数が有効になっていなかったので、設定するのが面倒でもうRubyで杜撰に書いちゃおうと思ってRubyで書きましたww

Feb 22

ども、amo-kです。

今回は、先日RIA的なアプリを作っていて遭遇した
問題について書きます。

IE × SSL × リソースDL

上記が重なった際に生じる問題です。
どうなるかといいますと、
HTTPレスポンスヘッダのキャッシュコントロール系で
意図した動作をしないという問題です。

例えば、

Pragma: no-cache

というレスポンスヘッダを定義していると
逆にcacheファイルを参照しようとするようです。

今回は、HTTPサーバ側でレスポンスの全てを構築していた訳ではありませんでした。
サーバサイドはphpアプリケーションでレスポンスヘッダ/メッセージボディを生成するのですが
phpはデフォルトでレスポンスヘッダを生成してくれます。
その際に

Pragma: no-cache

を入れてくれます。

これは嬉しいのですが、
上記IEのバグに対応するには、ヘッダを書き換える必要があります。
ということで以下のようにヘッダを上書きして対応しました。

header("Pragma: ");

一般的には、Webサイトの管理ツールなどで
SSL通信による集計ファイルのDLサービス等で
同様の現象が再現し得るでしょう。

JavaScriptじゃないんだし、
phpソースコード中にIEの対応を書くなんてと思いましたが
よくよく調べてみると、Microsoftサポートでも公開していたので
まあいっかと思った次第です。

参考: Microsoft サポート オンライン

Dec 08

どうも、相変わらず暴君なyoshida-kです。

今日はMeCabというオープンソースな形態素解析エンジンをphpから利用して見ましょうというお話です。
MeCabを使うと文章を単語に分割したり、分割された単語がどういったものなのかという情報を取得したりできます。

まずは、MeCabをインストールしてみましょう。
リンク先を見ればインストール方法は明らかですが、とりあえず順を追って説明します。
1.sourceforge.netよりMeCabのソースをDownload
2.任意のディレクトリにDownloadしてきたアーカイブを展開
tar -zxvf ./mecab-x.y.tar.gz 的なw
3.mecabのコンパイルを行う。
普通のアプリと同じでconfigureしてmake , make installな感じです。
ディレクトリ内にあるINSTALLファイルを見るととりあえずやり方が書いてあったりします。

ここまでやるととりあえずmecabがインストールされるわけですが、コレだけではmecabはちゃんと動きません。
mecabを動かすには辞書が必要です。
辞書も先ほどのsourceforgeのところからdownloadできるので同様に展開⇒make installしてください。

さて、この状態でmecabを起動することが可能となりました。
mecabを起動すると形態素解析をしてくれます。

よく使われている例ですが
「すもももももももものうち」と入力すると

すもも  名詞,一般,*,*,*,*,すもも,スモモ,スモモ
も      助詞,係助詞,*,*,*,*,も,モ,モ
もも    名詞,一般,*,*,*,*,もも,モモ,モモ
も      助詞,係助詞,*,*,*,*,も,モ,モ
もも    名詞,一般,*,*,*,*,もも,モモ,モモ
の      助詞,連体化,*,*,*,*,の,ノ,ノ
うち    名詞,非自立,副詞可能,*,*,*,うち,ウチ,ウチ

このような形に出力してくれます。

さて、いよいよPHPでこのMeCabを利用するためにPHPのExtensionをインストールしましょう。
MeCabのPHP ExtensionはこちらのPage2さんが公開してくださってます。

インストール方法は
phpize ⇒ configure ⇒ make ⇒ make installです。
インストールが完了したらphp.iniのモジュール読み込みの設定にmecab.soを追加しましょう。

さて、以下の内容がテストコードです。
うまくいくと、mecabを起動して実行したものと同じ結果が出力されます。

<?php
   dl("mecab.so");

   $mecab = mecab_new();
   $string = "すもももももももものうち";

   print mecab_sparse_tostr( $mecab , $str );

   mecab_destroy();
 ?>

いかがでしょう?
コレだけではまだ実用性にかけるので次回はもうちょっと実用的な内容を紹介させていただきます。