Laravel3 データベースを使わない簡易認証

CakePHP以外のフレームワークを、と思っていくつか手を出したけど利用するところまで到達できない状態でした。ですがLaravelを習い始めてみると何となくイケそうな気がします。で、折角ですので備忘録も兼ねてブログに残そうかと思います。

Laravelの取り付きには、川瀬さんが翻訳されて出版されている電子書籍 Code Happy(JP) が良いかと思います。このネタもCode Happyの説明を利用したものです。以下「である調」で記述します。

小さなWebアプリで認証管理にユーザー登録機能を用意するのは、大した作業ではないが管理画面の処理も用意しなければならないので面倒だ。管理者1,2人程度ならプログラムに埋め込んで認証できればお手軽で良い。Laravelでは、認証の仕組みを利用して簡単に実現できた。

先ずは動きを見るための、外堀のプログラムから。

サイトのURLを「http://www.example.com」とし、「http://www.example.com/home」はログインユーザーのみ公開されているとする。ログインしていない状態で「home」を表示しようとするとログイン画面にリダイレクトされる。

LaravelはフレームワークなのでMVCのアプリケーションを組めるが、routes.php を利用してRESTfulなアプリケーションが組めるようになっており、オートロードの機能もありクラスを柔軟に活用できる。

home をアクセスしたとき homeビューを表示するプログラムは次の通り。

application/routes.php

Route::get('home', function() {
    return View::make('home');
});

簡単な homeビューを用意する。

application/views/home.blade.php

<div class="header">
    ようこそ!<br />
    {{ HTML::link('logout', 'ログアウト') }}
</div>
<div class="content">
    <h1>管理画面トップ</h1>
    <p>データベースを使わない簡易認証のページです。</p>
</div>

これだけで home にアクセスするとビューが表示される。

次はログインフォームのビュー。

application/views/login.blade.php

{{ Form::open('login') }}
    @if (Session::has('login_errors'))
        <span class="error">ログインエラー</span>
    @endif
    <p>{{ Form::label('username', 'ユーザー名:') }}
       {{ Form::text('username') }}</p>
    <p>{{ Form::label('password', 'パスワード:') }}
       {{ Form::password', 'パスワード' }}</p>
    <p>{{ Form::submit('ログイン') }}</p>
{{ Form::close() }}

で、ログイン画面の表示と送信されたログインデータを処理するプログラムの用意。どちらも routes.php 内で動作するように以下を追加。

application/routes.php

Route::get('login', function() {
    return View::make('Login');
});

Route::post('login', function() {
    return 'ログイン送信';
});

とりあえず、「http://www.example.com/login」でログインフォームの表示を確認し、ログインボタンを押すと「ログイン送信」が表示されるか確認する。

次に、home がアクセスされた時ログインチェックをして未ログインならログインフォームへ移行するようにする。これは、「Route::get(‘home’, …」で、処理をする前に認証チェックのフィルタプログラムを実行するように、次のように書き換える。

application/routes.php

Route::get('home', array('before' => 'auth', 'do' => function() {
    return View::make('home');
}));

そしてフィルタ「auth」をroutes.phpに追加する。が、「auth」フィルタは通常次のように routes.php に組み込まれている。

application/routes.php

Route::filter('auth', function()
{
    if (Auth::guest()) return Redirect::to('login');
}));

Auth::guest() はログインされていなければ true を戻す。Auth::check() はログインされていると true を戻す。

では、http://www.example.com/home へアクセスするとリダイレクトするか確認する。

いよいよLaravelの認証の仕組みを利用して簡易認証する手順に入る。

簡易認証のプログラムの内容は簡単で、usernameとpasswordを受け取り、プログラム内に書き込んだユーザー名とパスワードに一致するかどうかを判定するだけだ。なお、Laravelの仕組みに合わせるため認証プログラムは「Laravel\Auth\Drivers\Driver」から派生させ、認証メソッド「attempt()」とログインユーザーデータを戻すメソッド「retrieve()」を準備する。ファイルは「application/libraries/myauth.php」とする。これでオートロードされる。

application/libraries/myauth.php

<?php
class Myauth extends Laravel\Auth\Drivers\Driver
{
    private static $auth_users = array(
        array('id' => 1, 'username' => 'admin', 'password' => 'admin',
        array('id' => 2, 'username' => 'root', 'password' => 'root',
    );

    public function attempt($arguments = array())
    {
        $username = $arguments['username'];
        $password = $arguments['password'];

        foreach (self::$auth_users as $user) {
            if ($user['username'] == $username)
             && $user['password'] == $password) {
                return $this->login($user['id'],
                    array_get($arguments, 'remember'));
            }
        }

        return false;
    }

    public function retrieve($id)
    {
        foreach (self::$auth_users as $user) {
            if ($user['id'] == $id) {
                $data = new stdClass();
                $data->id = $user['id'];
                $data->username = $user['username'];
                $data->password = $user['password'];
                return $data;
            }
        }

        return null;
    }
}

Laravelで認証をどのように実行するかについての設定が「application/config/auth.php」にある。この中で、myauthを利用する設定とデータのusernameの項目名が何かの設定の2つ、変更しなければならない。

application/config/auth.php

'dirver' => 'myauth',
'username' => 'username',

そしてこれを使用することをAuthクラスに登録するため、「application/start.php」に次のように追加する(ファイルの最後に追加)。

Auth::extend('myauth', function() {
    return new Myauth();
});

ところで、ログインデータが送信されたときこのプログラムでユーザーを確認し、認証がOKならhomeへリダイレクトし、認証が失敗した場合はログイン画面へ戻るようにする部分を先の「Route::post(‘login’,…」に組み込む。合わせてログアウトするとログイン画面へリダイレクトする機能も実装する。いずれも routes.php 上である。

application/routes.php

Route::post('login', function() {
    $userdata = array(
        'username' => Input::get('username'),
        'password' => Input::get('password'),
    );

    if (Auth::attempt($userdata)) {
        return Redirect::to('home');
    }

    return Redirect::to('login')
        ->with('login_errors', true);
});

Route::get('logout', function() {
    Auth::logout();
    return Reidrect::to('login');
});

最後に、実際にログインして表示できた時「ようこそ、xxさん!」と表示するように、home.blade.phpビューを次のように変更しておく。

application/views/home.blade.php

:
ようこそ、{{ Auth::user()->username }}さん!<br />
:

動作するのを見て、Laravel 使いやすいな、と思った。

ところで、「application/config/session.php」にセッションデータのソースを操作するドライバの指定がある。この中で「’driver’ => ‘cookie’,」となっている部分を「’driver’ => ‘file’,」に変更するとセッションデータが、「storage/sessions」に書き込まれるようになる。

 

Laravel3 データベースのキャラクターセット

PHPのフレームワークLaravelが気になったので、電子書籍「Code Happy」を購入し、バージョン3を試している。

いよいよデータベースを使い始めるところで、テーブルusersをartisanを利用して生成したところ、何とdefault charset が ujis になっていた。これはレンタルサーバーのMySQLの設定で、default charsetがujisになっているためなのだろう。

フレームワークならSQLを書かなくてもテーブルが生成できるので、クラスのメソッドに何か仕掛けがあるに違いない、と思い込んで探したけれど残念ながら見つからなかった。

だからと言って、charsetのために丸々CREATE文を書くのも癪に障る。

そこでSSHでmysqlを起動し、直接データベースをutf8に設定する。

mysql -h xxx.db.sakura.ne.jp -u xxx -p xxx
mysql> alter database xxx default character set utf8;

で、artisan migrate を実行したところ、無事utf8のテーブルができた。

そこで一歩進めて「DB::query()」で上のalter文をプログラムに組み込んだところ、今度は「This command is not supported in the prepared statement protocol yet」とエラー表示され、正常に動作しない。

あー、もう、ガッカリだ。また今度何か対策を考えよう。

 

FirefoxのアドオンJSViewが削除されて残念、何とか再インストール

JSViewの再インストールは次のブログ記事を見て実行しました。

Where to find the JSView Firefox Addon – Discontinued from Addons Repo.

再インストールは次のURIをFirefoxで開けばOKです。

http://downloads.mozdev.org/xsidebar/mods/jsview-2.0.8-mod.xpi

ところで、現在トラブルに見舞われています。

Windows Server 2003のHDDがアクセス不能となり、ネットワーク処理が大変なことになってしまいました。ドメインPCが2台とも逝ってしまったので、改めて2012でドメインを再構築することになりそうです。クライアントの皆様には申し訳ないけどデスクトップ環境の再構築をお願いしなければなりません。

 

Ubuntu 12.04 PHP 5.3.10からPHP5.4.15へアップグレード

PHPのバージョンを5.3から5.4へアップグレードする際、ちょっと引っかかったのでその備忘録です。

検索すると「how do I upgrade from php 5.3 to php 5.4.6 in ubuntu?」のように割と簡単にできる感じだ。

$ sudo add-apt-repository ppa:ondrej/php5
$ sudo apt-get update
$ sudo apt-get install php5

で、そのまま実行したのだがうまくいかない。で、後で気がついたのだが「add-apt-repository」コマンドが command not found エラーだった。

そこでgoogle検索すると「How to Fix Error sudo: add-apt-repository: command not found」で、「python-software-properies」パッケージがインストールされていないということで、パッケージをインストールした。

$ sudo apt-get install python-software-properties

でこの後、前述の「apt-get install php5」を利用せず、あっちこっち検索していたときに見つけた「Upgrade PHP 5.3.x to 5.4.11 in UBUNTU 12.04」ページで説明されていた手順でアップグレードした。

$ sudo add-apt-repository ppa:ondrej/php5
$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get dist-upgrade

以上でPHP5.3.10からPHP5.4.15へアップグレードが完了した。

突然Apacheが動かなくなった

今日は4月1日月曜日、出勤すると朝一番、「システムに接続できませーん」と連絡が。何、朝から4月バカ言ってんの、だったら良かったのに。

サーバーは動作しているし、pingは通るし、SSHで接続はできるので問題はそこではない。どうやらApacheが落ちているようで早速再起動、[失敗]の表示。えーーーっ?

サーバー管理者と言っても運用に入れば、年に数回ユーザー管理で操作するぐらいなので、全く対応ができない。とにかく業務ができるようにする方が先決なので、Pentium 4の古いPCを引っ張り出して来て、代替動作させることにした。

心配なのは運用サーバーはAsianux Server 3でPHPが5.2、一方代替えはUbuntu Server 12.04でPHPが5.3。業務システムはCakePHP1.2系で組み込んでいるので「きっと何かあるだろうなぁ」と思いつつ、作業を進める事を決断した。

データベースを移植し、Apache2を設定、DNS切り替えて何とか昼過には使えるようになった。ええそうです、ドタバタしました(´Д`;)。あとは野となれ山となれ。

さて元のサーバーで何故Apacheの起動ができなくなったのか?見事ビンゴな回答が@ITの会議室にあり、Google先生に指示していただきました。

Apacheが突然起動できなくなった
http://ap.atmarkit.co.jp/bbs/core/flinux/27877

blunderさんが回答して下さった内容で、ログ「logs/nss_error_log」を覗くと

[error]Certificate not verified: 'Server-Cert'
[error]SSL Library Error: -8181 Certificate has expired
[error]Unable to verify certificate 'Server-Cert'. Add "NSSEnforceValidCerts off to nss.conf so the server can start until the problem can be resolved.

と出力されていた。で、

# certutil -L -d /etc/httpd/alias -n Server-Cert

とすると「Validity」の表示に

Validity:
    Not Before: Thu Mar 26 20:50:22 2009
    Not After : Tue Mar 26 20:50:22 2013

と。先週の火曜日に切れていたようだけど、連絡はなかったので暫く動作していたということか。

メッセージの通り、nss.confに「NSSEnforceValidCerts off」とセットしてApacheを再起動したら[ OK ]と表示。

これでエイプリルフールの一日が終りました。

ところで、Kindle Paperwhite買ったらいろいろ買い込んでしまい、楽しんでいるのでちょっと紹介します。

   

と、定番かも知れませんが一通り購入しました。自分持ちのPDFはメールでクラウドに送れば、WiFi接続することでKindleにダウンロードされます。自分は3G付きを購入したので、Kindleストアで購入したものは直ぐにダウンロードされて読めます。便利いいです。

で、最近藤本壱さんの

を購入して、曖昧だった正規表現の勉強をし直してます。