Strings of Life

PHP/Phalcon/MySQL/JavaScript/RegExp/Ruby/Perl/ActionScript


「Web技術オーバービュー」と「Webアプリケーション実践入門/PHP編」の感想はこちらの記事に書いています。

「Webアプリケーション実践入門/Ruby編」は、RubyによるWebアプリケーションの構築方法を解説しています。Webアプリケーションフレームワークには、定番のRuby On Railsではなく、マイクロフレームワークのSinatraを使用しています。

PHP編とRuby編のいずれも、マイクロフレームワークを使用して簡単なCRUDのWebアプリケーションを作る実習になっています。この2編を両方やると、PHPとRubyそれぞれの感触がつかめると思います。

両方をやって感じたPHPとRubyの比較は以下のような感じです。

PHPの良いところ
*  環境構築が簡単。ピュアPHPなライブラリが多く、ネイティブ拡張も大抵はOSのパッケージマネージャーからインストールできる。

PHPの悪いところ
* レガシーな環境が残りがち(PHPそれ自体というよりは、外部要因)。

Rubyの良いところ
* エレガントな文法。かゆいところに手が届くクラス。
* ActiveRecordが非常に良い。

Rubyの悪いところ
* gemライブラリは依存関係が激しく、ビルドも失敗しやすい。動かすまでの環境構築が大変。

また、文法については、Rubyは結構自由度が高いのに対して、PHPはあまり融通が効きません。この点、PHPは初心者にやさしく、Rubyは上級者ほどたのしく書ける言語といえるでしょう。


「サーバ環境の作り方」「サービス運用の基礎知識」については、あっさりめですが、Webアプリ制作の初心者が見落としがちな部分でもあるので、結構ためになります。


『Webアプリケーションエンジニア養成読本』全体としては、良い本だと思います。さらに学びを深めるための推薦書籍/WebサイトのリストがあるのもGood。第2章の「Webアプリケーション実践入門」ではレイアウトが見づらく実習を進めるにはストレスが溜まる、という難点がありますが、対象読者に当てはまる人なら、買って損はしません。

『Webアプリエンジニア養成読本』のRuby編をやっていたら、Activerecordのインストールでこけました。

環境は、OS X 10.9.2/Xcode5.1。

どうやら、atomicというRuby拡張のビルドに失敗している模様。

色々と原因を探ってみたところ、gcc(clang)のバージョンが原因でした。なお、私の環境のgccのバージョンは以下の通り。
$ which gcc
/usr/bin/gcc
$ gcc -v
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 5.1 (clang-503.0.38) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin13.1.0
Thread model: posix

OS Xユーザーが使用しているgccは、XCodeのコマンドラインツールとしてインストールしたgccであることが多いと思います。このgcc、コマンドはgccなのですが、gcc -vしてみれば分かるように、実態はclangなのです。

(そもそもgccって何? って人のために説明すると、gccは GNU Compiler Collectionの略で、C言語等の各種言語に対応したコンパイラ(プログラミング言語で書いたソースコードをコンピュータが実行可能なバイナリコードに変換する翻訳機)のこと。clangは、これまたC言語等のコンパイラなのだけど、割と最近出てきたコンパイラで、gccのライバル)

そして、XCode5.1に付属するclangでは、未知のビルドオプションを指定した場合にエラーを吐くようになりました。エラーなので、発生した時点でビルドが強制終了されます。

Xcode 5.1 Release Notes

The Apple LLVM compiler in Xcode 5.1 treats unrecognized command-line options as errors. This issue has been seen when building both Python native extensions and Ruby Gems, where some invalid compiler options are currently specified.

Projects using invalid compiler options will need to be changed to remove those options. To help ease that transition, the compiler will temporarily accept an option to downgrade the error to a warning:

-Wno-error=unused-command-line-argument-hard-error-in-future

このエラーを抑止する方法は、上記引用文に紹介されている「-Wno-error=unused-command-line-argument-hard-error-in-future」オプションをつけてビルドすることです。

このオプションを使用しつつ、ビルドを実行するには、以下のように環境変数をセットしつつbundle installすればOKです。
$ sudo env ARCHFLAGS=-Wno-error=unused-command-line-argument-hard-error-in-future bundle install

2013-04-06 追記

Nokogiriのインストールの際にも、mini_portileというネイティブ拡張のビルドでこけました。上記と同様、ビルドオプション付きのbundle installしたらOK。OS X 10.9でRubyのネイティブ拡張ビルドに失敗したら、まずは上記オプション付きのビルドを試すのが良さそう。

OhLifeというWebサービスがある。メールの送受信をフックとしたログ記録サービスで、以下のような特徴がある。

  • 1日1回、決まった時間にメールを送ってくる
  • このメールに返信すると、返信内容が記録される
  • OhLifeが送ってくるメールの本文には、過去のログが含まれる

OhLifeの主な機能には満足しているのだけど、一点だけ不満がある。それは、過去のログの選ばれる規則を設定できないこと。個人的な用途としては、前日からの進捗確認に使いたいので、必ず昨日のログを表示してほしい。しかし、OhLifeの過去ログ抽出規則は、「前日・1週間前・1ヶ月前」等があり、古いものが優先されているように思える。

類似サービスも探したのだが、どうも無いみたい。

無いなら作ろう。

ということで、作ってみた(現在、一般公開はしていない)。


サーバはさくらVPSで、OSはDebian Wheezy。メールサーバとしてはPostfixを使用。今回一番ハマったのはPostfixの設定だったり。

Postfixで受け取ったメールをPHPスクリプトに渡す方法としては、 この記事が参考になる。

また、メールをパースする方法としては、ライブラリを使用することにした。最初は illuminate/mailなども検討したのだけど、サンプルコードが探しやすかったので PEAR::Mail_MimeDecodeにした(サンプルコードは この記事を参考にした)。

インストールはComposerで。

{
    "repositories": [
        {
            "type": "pear",
            "url": "http://pear.php.net/"
        }
    ],
    "require": {
        "pear-pear.php.net/Mail_mimeDecode" : "*"
    }
}

メールを受信するプログラムはこんな感じ(受け取ったメールの本文をDBに保存する)。

<?php

require_once __DIR__ . '/vendor/autoload.php';

$raw_mail = file_get_contents('php://stdin'); // メール本文を標準入力から受け取る

$params = [];
$params['include_bodies'] = true;
$params['decode_bodies']  = true;
$params['decode_headers'] = true;
$params['input'] = $raw_mail;
$params['crlf'] = '\r\n';

$mail_data    = Mail_mimeDecode::decode($params);
$mail_address = $mail_data->headers['from'];
$mail_address = trim(substr($mail_address, strpos($mail_address, '<')), '<>');
$charset      = $mail_data->ctype_parameters['charset'];
$mail_body    = mb_convert_encoding($mail_data->body, 'UTF-8', $charset);

try {
    $dbh = require_once __DIR__ . '/db_connection.php'; // PDOオブジェクトを取得

    // メールアドレスからユーザーを取得
    $sql = 'SELECT * FROM users WHERE mail = :mail';
    $stmt = $dbh->prepare($sql);
    $result = $stmt->execute([':mail' => $mail_address]);

    // DBにメール本文を保存
    if (true === $result) {
        $row = $stmt->fetchAll(PDO::FETCH_ASSOC)[0];
        $sql = 'INSERT INTO logs (users_id, body, created_at) VALUES (:users_id, :body, :created_at)';
        $stmt = $dbh->prepare($sql);
        $stmt->bindParam('users_id', $row['id']);
        $stmt->bindParam('body', $mail_body);
        $stmt->bindParam('created_at', date('Y-m-d H:i:s'));
        $stmt->execute();
    }
} catch (Exception $e) {
    error_log($e->getMessage() . PHP_EOL, 3, __DIR__ . '/log/receiver.log');
    exit(1);
}

メール送信機能はmb_send_mail()使えば簡単。あとは、cronにメール送信スクリプトを登録して、定期実行すればOK。

このページのトップヘ