amari3のはてなダイアリー このページをアンテナに追加 RSSフィード

2014-03-29

[]PHPマイクロフレームワークSlimを使ってTinyURLを作ってみた

Slim は RubySinatra の様なマイクロフレームワークで、PHP で簡単な Webアプリを書くにはちょうどいいと思う。今回はその Slim を使って、短縮 URL(bitly みたいなやつ)を作ってみた。なお、tokuhirom さんの Amon2 のサンプルからアイデアを拝借しています。

環境

Mac OS X 10.9.2

PHP 5.4.26

See also

Slim Framework v2

インストール

Slim のインストールは Composer で行う。Ruby の Bundler や Perl の Carton の様なライブラリ管理ツールである。

% cd /path/to/project
% curl -s https://getcomposer.org/installer | php

composer.json に以下を記述する。

{
    "require": {
        "slim/slim": "2.*"
    }
}

以下のコマンドでインストールする。vendor ディレクトリに slim が格納される。

% php composer.phar install

ディレクトリレイアウト

ベターなディレクトリレイアウトがあるかもしれないけど、手探り状態で作ったので、良いディレクトリレイアウトがあったら教えて下さい!

project/
    composer.json
    composer.lock
    composer.phar
    root/  # ドキュメントルート
        .htaccess  # PHP ビルトインサーバを使用したので今回は必要なし
        index.php
    tmpl/  # テンプレート
        index.php
        result.php
    vendor/
        slim/slim/   # Slimライブラリ
    sql/
        sqlite3.sql
    development.db

TinyURL を作る

まずは DB のテーブルを作成する。以下のスキーマを作成して、sql/sqlite3.sql で保存する。

sql/sqlite3.sql

create table tinyurl (
    key varchar(20) primary key,
    url text
);

以下のコマンドを実行して、DB のテーブルを作成する。

% sqlite3 development.db < sql/sqlite3.sql

これで DB の準備は完了。

今回はあくまで動くものを作ることが目的なので、エラーチェックやバリデーション等は甘いです。

root/index.php

<?php
require '../vendor/autoload.php';

$app = new \Slim\Slim(array(
    "debug" => true,
    "templates.path" => "../tmpl"
));
$db = new PDO('sqlite:../development.db');

// 引数で指定した長さのランダムな文字列を生成
function stringRandom($len = 5) {
    if (!is_numeric($len) || $len <= 0) {
        die("positive interger is required.");
    }

    $str = '';
    for ($i = 0; $i < $len; ) {
        $num = mt_rand(0x30, 0x7A);
        if ((0x30 <= $num && $num <= 0x39) || (0x41 <= $num && $num <= 0x5A) ||
(0x61 <= $num && $num <= 0x7A)) {
            $str .= chr($num);
            $i++;
        }
    }
    return $str;
}

$app->get('/', function () use ($app) {
    $app->render("index.php");
});

$app->post('/create/', function () use ($app, $db) {
    $req = $app->request();
    $url = $req->post("url");
    if (!$url) {
        $app->redirect('/');
        return;
    }

    // dup check
    $sth = $db->prepare('SELECT key FROM tinyurl WHERE url = ? LIMIT 1;');
    $sth->execute(array($url));
    $result = $sth->fetch(PDO::FETCH_ASSOC);
    $key = $result['key'];
    if (!$key) {
        // create new one
        $key = stringRandom(6);
        $sth = $db->prepare('INSERT INTO tinyurl (key, url) VALUES (?, ?);');
        $sth->execute(array($key, $url));
    }
    $app->render('result.php', array("tinyurl" => $req->getUrl() . '/g/' . $key));
});

$app->get('/g/:key', function ($key) use ($app, $db) {
    if (!$key) {
        $app->redirect('/');
        return;
    }

    $sth = $db->prepare('SELECT url FROM tinyurl WHERE key = ? LIMIT 1;');
    $sth->execute(array($key));
    $result = $sth->fetch(PDO::FETCH_ASSOC);
    $url = $result['url'];
    $app->redirect(($url) ? $url : '/');
});

$app->run();
?>

tmpl/index.php

<!DOCTYPE html>
<html>
  <head>
    <title>TinyURL</title>
    <meta charset="UTF-8">
  </head>
  <body>
    <h1>tinyurl</h1>
    <form action="/create/" method="POST">
      <input type="text" name="url" value="">
      <input type="submit" name="submit" value="tiny!">
    </form>
  </body>
</html>

tmpl/result.php

<!DOCTYPE html>
<html>
  <head>
    <title>TinyURL</title>
    <meta charset="UTF-8">
  </head>
  <body>
    <h1>tinyurl</h1>
    <div><?php echo htmlspecialchars($tinyurl, ENT_QUOTES, "UTF-8"); ?></div>
    <a href="/">return to top</a>
  </body>
</html>

実際に作ってみた感想

小さな Webアプリを早く作るには非常に使いやすいと感じた。フルスクラッチで書くと煩雑になりがちな、ルーティングを気にしないでいいのが個人的には大きいかな。PHP で簡単な Webアプリを書く時にはぜひ使っていこうと思う。

2014-01-31

[]特定のディレクトリの特定のオーナーの時にだけ chown する時のメモ

特定のディレクトリの中に複数のオーナーのディレクトリやファイルがあって、特定のオーナーだけ変更したい時がたまにある。find コマンドを使ってうまくできるのでメモとして残しておく

# find /path/to/dir -user old_owner -exec chown new_owner {} \;

これからは、こういった小さなことでもブログに書きとめることにしよう。

2013-08-26

[] CentOS(6.4) に daemontools をインストールした

PSGI なアプリを運用するにあたり、落ちた時に自動起動して欲しいなと思うわけです。そこで daemontools を導入しようと考えている。runit や monit 等同様なツールもあるわけだけど、 ネットで調べる限りだと daemontools での運用実績はかなり多そうなので良さそうかと思ったのだ。

インストール手順

何はともあれインストールしないと始まらないし、さくっとインストールしてみる。

パッチを当てないとコンパイルに失敗するので、併せてダウンロードしておこう。

本体&パッチのダウンロード

% wget http://cr.yp.to/daemontools/daemontools-0.76.tar.gz
% tar xpvf daemontools-0.76.tar.gz
% cd admin/daemontools-0.76
% wget http://qmail.org/moni.csi.hu/pub/glibc-2.3.1/daemontools-0.76.errno.patch

パッチ適用&コンパイル

% patch -s -p1 <./daemontools-0.76.errno.patch
% ./package/compile

このままインストールすると /command にシンボリックリンクが張られて、そこからさらに /usr/local/bin にシンボリックが張られるのだが、気持ち悪いし直接 /usr/local/bin にインストールする。

svscanboot の設定に /command の記述があるので、/usr/local/bin に修正しておこう。他のファイルも同様に修正しておくとよい。

% cd command/
% sudo install -o root -g root -m 0755 -s envdir /usr/local/bin
% sudo install -o root -g root -m 0755 -s envuidgid /usr/local/bin
% sudo install -o root -g root -m 0755 -s fghack /usr/local/bin
% sudo install -o root -g root -m 0755 -s multilog /usr/local/bin
% sudo install -o root -g root -m 0755 -s pgrphack /usr/local/bin
% sudo install -o root -g root -m 0755 -s readproctitle /usr/local/bin
% sudo install -o root -g root -m 0755 -s setlock /usr/local/bin
% sudo install -o root -g root -m 0755 -s setuidgid /usr/local/bin
% sudo install -o root -g root -m 0755 -s softlimit /usr/local/bin
% sudo install -o root -g root -m 0755 -s supervise /usr/local/bin
% sudo install -o root -g root -m 0755 -s svc /usr/local/bin
% sudo install -o root -g root -m 0755 -s svok /usr/local/bin
% sudo install -o root -g root -m 0755 -s svscan /usr/local/bin
% sudo install -o root -g root -m 0755 -s svstat /usr/local/bin
% sudo install -o root -g root -m 0755 -s tai64n /usr/local/bin
% sudo install -o root -g root -m 0755 -s tai64nlocal /usr/local/bin
% sudo install -o root -g root -m 0755 svscanboot /usr/local/bin

/service ディレクトリを作成する。

% sudo ./package/run

Upstart の設定をする。

% sudo vim /etc/init/svscan.conf
start on runlevel [12345]
respawn
exec /usr/local/bin/svscanboot

起動する

% sudo initctl reload-configuration
% sudo initctl list
% sudo initctl start svscan

これで daemontools が使用できるようになった。

と、daemontools のインストールをしておいてなんだが、supervisor を使ってみたいと今思ってる。

2011-12-19

[]Apache を同一サーバ上で複数プロセス起動するときに注意する点

Apache を同一サーバ上で、複数プロセスを起動させる需要がそもそもあるのかっていうのはあるけど、Apache をリバースプロキシとして使って、同一ホストで mod_perl や mod_php をアプリケーションサーバとして動作させたい等があると思う。

以下の事を気を付けることで、複数のプロセス起動することができる。

  • コンフィグファイルを分ける
  • Listen IPアドレス or ポート番号を別にする
  • PIDファイルを別にする

コンフィグファイルを分ける

Apache は起動時に読み込むコンフィグファイルを指定することができる。これにより、設定の異なる Apache を複数起動することが出来る。

apachectl の -f オプションを使えば読み込むコンフィグファイルを指定することができる。

% sudo /usr/local/apache2/bin/apachectl -f コンフィグファイル -k 実行したいコマンド
% sudo /usr/local/apache2/bin/apachectl -f /usr/local/apache2/conf2/httpd.conf -k start

Listen IPアドレス or ポート番号を別にする

Listen する IPアドレスかポート番号を別にする必要がある。同一 IPアドレス且つポート番号で Listen する設定にしていた場合は、起動時に以下の様なエラーが出る。

(98)Address already in use: make_sock: could not bind to address 192.168.150.128:80
no listening sockets available, shutting down
Unable to open logs

PIDファイルを別にする

Apache を別プロセスとして起動する場合には、プロセスID を別に記録(管理)する必要がある。PIDファイルを同一にしていると、別のプロセスを起動時に以下の様なエラーが出る。

httpd (pid 18512) already running

すでにそのプロセスは起動しているから当たり前のこと。

変更するには、PidFile ディレクティブで指定するPIDファイルを別名にするだけでよい。ディレクトリ自体を分けてしまうのが間違いがなく楽でいいと思う。ただし、所有者やパーミッションには気をつけること。

まとめ

以上の事を気を付ければ、Apache を別プロセスで起動させることが出来る。perl なら nginx + Starman という組み合わせもあるだろうし、正直需要があるかどうかは分からないけど、こういった事も出来るというメモを兼ねて。

2011-12-03

[][]tiarra を入れたので設定をメモしておく

Perl とかのコミュニティに参加してみたいと思って、最近やっと IRC を使い始めてみた(まだまだ活動は出来てないけど)。id:nekokak さんに「自由になるサーバがあるなら tiarra を入れるとログが残せたりして便利」と教えてもらったので設定してみた。

tiarra って何?

一言で言えば IRC Proxy。IRCクライアントから直接 IRCサーバに接続するんじゃなくて、自前のサーバに IRC Proxy を立てておいて IRCサーバとの接続を保持しておく。実際に接続する時は、IRCクライアントから自前のサーバに接続することになる。

イメージとしてはこんな感じ。

|IRCサーバ| - |自前のサーバ| - |IRCクライアント|

ここからは僕の環境である、さくらのVPSに設定した時の説明となる。当然自宅サーバでも同じ。

準備

本家のサイト Tiarra : Archive からダウンロード&解凍。

% wget http://www.clovery.jp/tiarra/archive/2010/02/tiarra-20100212.tar.bz2
% tar xpvf tiarra-20100212.tar.bz2

設定

解凍したディレクトリにある、「sample.conf」を「tiarra.conf」にコピーしてリネーム。

% cp -pv sample.conf tiarra.conf
パスワード設定

以下のコマンドを実行する。

% ./tiarra --make-password

入力したパスワードが crypt された値で返ってくる。

general ブロック

以下をそれぞれ設定する。

nick: 使用するニックネーム
user: 使用するユーザ名
name: 使用する名前
tiarra-password: crypt されたパスワード
例)
nick: amari3
user: amari3
name: amari3 example
tiarra-password: crypt されたパスワード
networks ブロック

後述するネットワーク設定に使う名前をつける。

name: 任意の設定名
例)
name: hoge

複数のネットワークに接続する場合はその分だけ記述する。

各ネットワークの設定

networks ブロックで設定した name に対する設定を行う。

hoge {
  host: irc.example.com
  port: 6667
}

ここまでの設定で動作させる事が出来るけど、ログの設定とかやっときます。

ログを取得できるようにする

以下の記述に変更する。

- Log::Channel {
  ↓
+ Log::Channel {

デフォルトでは log ディレクトリに保存してくれる。

クライアント接続時に最近のログを表示するようにする

以下の記述に変更する。

- Log::Recent {
  ↓
+ Log::Recent {
サーバ接続時に自動的入るチャンネル設定

以下の記述に変更する。

- Channel::Join::Connect {
  ↓
+ Channel::Join::Connect {

自動的に入りたいチャンネルの設定をする。

channel: #foo@irc.example.com
channel: #bar@irc.example.com
切断時に設定した nick に変更

以下の記述に変更する。

- User::Nick::Detached {
  ↓
+ User::Nick::Detached {

nick は任意のニックネームに。

detached: amari3_away

この設定をしておくと、切断時に設定した nick にしてくれる。

tiarra を起動する

% ./tiarra &

常駐させるプログラムなので、バックグラウンドで実行する。

これで IRCクライアントから、設定したサーバの指定したポートで接続すると接続できるはずです。

tiarra の設定ファイルの更新方法

tiarra の設定ファイルを変更した場合、IRCクライアントから

/load

とコマンドを打つと設定の読み込みができる。

最後に

実際に設定をしてみると、難しい箇所もなくあっさり導入できると思う。個人的にはログを残せる事が大きなメリットだと感じるので、当面使ってみます。