2011年8月25日

Codeigniter on fluxflex


日本人が起業したfluxflexはGithubと連動する安くて簡単なクラウド・ホスティング・サービスを目指す
http://jp.techcrunch.com/archives/20110817github-integrated-fluxflex-aims-at-making-cloud-hosting-easier-and-cheaper/
(だいぶ亀ですが・・・)現在作成中のショッピングカートをどこかでデモさせてもらえないかと探していたら、タイミングよくTechCrunchに記事が掲載されていたので試してみました。
記事が出た次の日には一時アクセスできなくなる、プライベートURLが動かないなど、まだまだ色々とこれからのサービスのようですが同じ日本人が起業したということで頑張って欲しいですね!

fluxflexの構成がApache+FastCGIの組み合わせで、index.phpをURLから削除して動作させるのに少し苦労したので、メモしておきます。

■ .htaccessを使ってindex.phpをURLから削除する on fluxflex
コンフィグのuri_protocolをREQUEST_URIに変更
code/config.php
$config['uri_protocol'] = 'REQUEST_URI';

.htaccessにRewriteBaseを追加(2行目)。
.htaccess
RewriteEngine on
RewriteBase /
RewriteCond $1 !^(index\.php|robots\.txt|favicon\.ico)
RewriteRule ^(.*)$ /index.php?/-- default controller --$1 [L]
そして最後にRewriteRuleにCodeigniterのdefault_controllerを指定して動作させることができました。
(一定の条件下では指定しなくても動作するようですが、指定した方が確実に動きます。)


fluxflexが安定稼動し、ショッピングカーとがもう少し見れるようになったらデモ用のURLをこのブログで公開します(^_^)

2011年8月19日

Codeigniter と オートロード(Autoload in PHP5)

※注:この記事はCodeigniter付属のautoloadに関するものではありません。

PHP5にはクラスのオートローディングという便利な関数(function __autoload())があります。
未定義のクラス/インターフェイスを使用しようとした時に 自動的にコールされる __autoload 関数を定義することができます。 この関数をコールすることにより、 スクリプトエンジンは、PHPがエラーで止まる前にクラスをロードする最後の チャンスを与えます。
引用元:php.net
これを使ってモデルを呼べれば楽なんですよね。そうすると
$this->load->model('model-name');
$this->model-name->function();
という書き方から以下のように普通のPHP5の書き方に変えられる。
$model = new Model-name;
$model->function();

そこで軽く調査してみたんですが、どうやら以下のサイトのような方法が多数散見されました。
6 CodeIgniter Hacks for the Masters
http://net.tutsplus.com/tutorials/php/6-codeigniter-hacks-for-the-masters/
ほうほう、config/config.phpの最後に__autoload()を入れるとな。

・・・いやいやいや、これダメだろ(゜Д゜) ??
config.phpの最後になんか入れたらログとかベンチマークとか全部こっちいっちゃうんじゃ?
ということで念のためテスト。config.phpの最後にコピーしてlog_messageで何をロードしようとしてるかチェック。

config/config.php
function __autoload($class)
{
    log_message('debug', 'Trying to load class: '.$class);
    if(file_exists(EXTPATH."models/".strtolower($class).EXT))
    {
        include_once(EXTPATH."models/".strtolower($class).EXT);  
    }
}


■ 結果

思った通り。load_class()で呼んでるものは全部オートロードに行っちゃう。この方法は採用しちゃダメな方法です。

それならどうすればいいのか?
正解はspl_autoload_registerを使う、です(断言しちゃったけど大丈夫かな?w)

オートローディングを追加するなら、ヘルパにしてautoload.phpに追加するのが一番簡単でいいんじゃないでしょうか。
(個人的にはファイルが増えるの嫌なのでLoader.phpにstaticメソッドを作ってcore/Controller.phpの最後に追加してますが)

■ spl_autoload_registerをコールするヘルパ
spl_autoload_register — 指定した関数を __autoload() の実装として登録する
http://nz.php.net/manual/ja/function.spl-autoload-register.php
引用元:php.net
サンプルヘルパ: spl_autoload_helper.php
<?php
/**
 * SAMPLE SPL Autoload Helper
 * ファイル名、メソッド名は適宜修正してください。
 */
 
function sample_loader($class) 
{
	if(file_exists(APPPATH."models/".strtolower($class).EXT))
	{
		log_message('debug', 'Load '.$class.' models in php5 style');
		include_once(APPPATH."models/".strtolower($class).EXT);  
	}
}
 
spl_autoload_register('sample_loader');
上記ではモデルだけ追加してますが、ライブラリもヘルパも追加することが可能です。
$this->load->model(~~~) とか面倒な人向けの方法でした。

2011年8月16日

Codeigniterを使ってショッピングカートをゼロから作ってみよう。 # 6

今回はユーザ管理です。
ユーザの一覧表示、新規作成(追加)、編集、最後に削除です。
苦手なjavascriptで手間取って時間かかりました( ̄Д ̄;;


■ File Tree


■ コントローラ:User
admin/application/controllers/user.php
<?php
class User extends Controller
{
    function __construct()
    {
        parent::__construct();
        if( ! _s('admin')) redirect();
        $this->load->model('users_model', 'usersdb');
    }
    
    function index()
    {
        $this->accounts();
    }
    
    function accounts($page=0)
    {
        $this->form_validation->set_rules('delete', '', 'isArray');
        if($this->form_validation->run())
        {
            $this->usersdb->delete_array($this->input->post('delete'));
        }
        
        $data['breadcrumbs'] = array(_l('HOME')=>'', _l('USERLIST')=>'user');
        $data['h1'] = _l('USERLIST');
        $data['all'] = $this->usersdb->all($page);
        $this->layout->view('user/accounts', $data);
    }
    
    function create()
    {
        $this->form_validation->set_error_delimiters('<span class="error">', '</span>');
        $this->form_validation->set_rules('email',_l('EMAIL'),'required|valid_email|email_exist');
        $this->form_validation->set_rules('firstname',_l('FIRSTNAME'),'required|min_length[2]');
        $this->form_validation->set_rules('lastname',_l('LASTNAME'),'required|min_length[2]');
        $this->form_validation->set_rules('passwd',_l('PASSWORD'),'required|min_length[6]|matches[passwdconf]');
        if($this->form_validation->run())
        {   // insert into db
            $data = array(
                'email'     => $this->input->post('email'),
                'password'  => $this->input->post('passwd'),
                'firstname' => $this->input->post('firstname'),
                'lastname'  => $this->input->post('lastname'),
                'status'    => $this->input->post('status')
            );
            
            $this->usersdb->newuser($data);
            
            redirect('user');
        }

        $data['breadcrumbs'] = array(_l('HOME')=>'', _l('USERLIST')=>'user', _l('CREATE_USER')=>'user/create');
        $data['h1'] = _l('CREATE_USER');
        $this->layout->view('user/create', $data);
    }
    
    function edit($id)
    {   // just in case
        if($user = $this->usersdb->byId($id))
        {
            $this->form_validation->set_error_delimiters('<span class="error">', '</span>');
            $this->form_validation->set_rules('email',_l('EMAIL'),'required|valid_email|email_exist['.$id.']');
            $this->form_validation->set_rules('firstname',_l('FIRSTNAME'),'required|min_length[2]');
            $this->form_validation->set_rules('lastname',_l('LASTNAME'),'required|min_length[2]');
            if($this->input->post('passwd')) $this->form_validation->set_rules('passwd',_l('PASSWORD'),'required|min_length[6]|matches[passwdconf]');

            if($this->form_validation->run())
            {   // update user info
                $data['email'] = $this->input->post('email');
                $data['firstname'] = $this->input->post('firstname');
                $data['lastname'] = $this->input->post('lastname');
                $data['status'] = $this->input->post('status');
                if($this->input->post('passwd')) $data['password'] = $this->input->post('password');
                
                $this->usersdb->update($user, $data);
                
                redirect('user');
            }

            $data['breadcrumbs'] = array(_l('HOME')=>'', _l('USERLIST')=>'user', _l('EDIT_USER')=>'user/edit');
            $data['h1'] = _l('EDIT_USER');
            $data['user'] = $user;
            $this->layout->view('user/edit', $data);
        }
        else redirect();
    }
}
□ メソッド
index ( accounts )で一覧表示と削除。
create で新規ユーザ作成
edit で編集しています。

■ モデル:Users_model.php
extension/models/users_model.php
function newuser($data)
    {
        $data['hash'] = $this->auth->_generate_hash();
        $data['password'] = $this->auth->_encode($data['password'], $data['hash']);
        $this->db->insert($this->table, $data);
        setMessage('success', _l('SUCCESS_CREATE_USER'));
    }
    
    function update($obj, $data)
    {
        if(array_key_exists('password', $data)) $data['password'] = $this->auth->_encode($data['password'], $obj->hash);
        $this->db->where('id', $obj->id);
        $this->db->update($this->table, $data);
        setMessage('success', _l('SUCCESS_UPDATE_USER'));
    }
ユーザ追加用とアップデート用のメソッドを追加。

■ Form_validationライブラリにルール追加
extension/libraries/MY_Form_validation.php
<?php
class MY_Form_validation extends Form_validation
{
    function __construct()
    {
        parent::__construct();
    }
    
    function email_exist($email, $id=FALSE)
    {
        $this->CI->form_validation->set_message('email_exist', $this->CI->lang->line('in_use'));
        $this->CI->load->model('users_model', 'usersdb');
        return ($this->CI->usersdb->exist($email, $id)) ? FALSE : TRUE;
    }
    
    function isArray($arr)
    {
        $this->CI->form_validation->set_message('isArray', $this->CI->lang->line('is_array'));
        return (is_array($arr) && count($arr) > 0) ? TRUE : FALSE;
    }
}

■ ビュー:一覧表示&削除
admin/application/views/user/accounts.php
<div class="buttons">
<button onclick="javascript:location.href = '<?php echo base_url('user/create'); ?>';"><?php echo _l('CREATE_USER'); ?></button>
<button onclick="confirmDelSelected();"><?php echo _l('DELETE_SELECTED'); ?></button>
</div>
<?php echo form_open(uri_string()); ?>
<?php if($all): ?>
<table class="list">
<tr>
    <th><input type="checkbox" onclick="applyToAll(this);" /></th>
    <th><?php echo _l('FULLNAME'); ?></th>
    <th><?php echo _l('EMAIL'); ?></th>
<?php /*    <th><?php echo _l('ROLE'); ?></th> */ ?>
    <th><?php echo _l('STATUS'); ?></th>
    <th><?php echo _l('ACTION'); ?></th>
</tr>
<?php foreach($all as $a): ?>
<tr>
    <td><input type="checkbox" name="delete[]" value="<?php echo $a->id; ?>"<?php if($a->id==1): ?> disabled="disabled"<?php endif; ?>></td>
    <td><?php echo $a->firstname.' '.$a->lastname; ?></td>
    <td><?php echo $a->email; ?></td>
<?php /*    <td><?php echo $a->role; ?></td> */ ?>
    <td><?php echo ($a->status) ? _l('ACTIVE') : _l('INACTIVE') ; ?></td>
    <td>
        <a href="<?php echo base_url('user/edit/'.$a->id); ?>"><?php echo _l('EDIT'); ?></a>
    </td>
</tr>
<?php endforeach; ?>
</table>
<?php endif; ?>
<?php echo form_close(); ?>

<script type="text/javascript">
function confirmDelSelected() {
    var c = 0;            
    $(":checkbox").each(function(){
        if($(this).attr('checked')) c++;
    })
    if(c > 0) { 
        if(confirm("<?php echo _l('CONFIRM_DELETE_SELECTED'); ?>")) $('form').submit();
    }
    else { alert("<?php echo _l('ALERT_PLZ_SELECT'); ?>"); }
}
</script>



全くスタイルしてない画面ですが(苦)
後でユーザレベル(タイプ)なんかを付け加えることになるでしょう。

削除する時には確認用のポップアップが表示されます。



■ ビュー:新規作成
admin/application/views/user/create.php
<?php echo form_open(uri_string()); ?>
<input type="button" value="<?php echo _l('CANCEL'); ?>" onclick="javascript:location.href = '<?php echo base_url('user'); ?>';" tabindex="9" />

<h2><?php echo _l('USER_DETAILS'); ?></h2>
<dl class="horizontal">
    <dt><?php echo _l('EMAIL'); ?></dt>
    <dd><input class="field" id="email" type="email" name="email" value="<?php echo set_value('email'); ?>" tabindex="1" /><?php echo form_error('email'); ?></dd>
    <dt><?php echo _l('LASTNAME'); ?></dt>
    <dd><input class="field" id="lastname" type="text" name="lastname" value="<?php echo set_value('lastname'); ?>" tabindex="2" /><?php echo form_error('lastname'); ?></dd>
    <dt><?php echo _l('FIRSTNAME'); ?></dt>
    <dd><input class="field" id="firstname" type="text" name="firstname" value="<?php echo set_value('firstname'); ?>" tabindex="3" /><?php echo form_error('firstname'); ?></dd>
    <dt><?php echo _l('PASSWORD'); ?></dt>
    <dd><input class="field" id="passwd" type="password" name="passwd" value="" tabindex="4" /><?php echo form_error('passwd'); ?></dd>
    <dt><?php echo _l('PASSWORDCONF'); ?></dt>
    <dd><input class="field" id="passwdconf" type="password" name="passwdconf" value="" tabindex="5" /></dd>
    <dt><?php echo _l('STATUS'); ?></dt>
    <dd>
        <select name="status" class="field" tabindex="6">
            <option value="1"><?php echo _l('ACTIVE'); ?></option>
            <option value="0"><?php echo _l('INACTIVE'); ?></option>
        </select>
    </dd>
    
    <dd><input type="submit" value="<?php echo _l('SAVE'); ?>" onclick="return check(['email','lastname','firstname','passwd','passwdconf']);" tabindex="7" /> <input type="reset" value="<?php echo _l('RESET'); ?>" tabindex="8" /></dd>
</dl>
<?php echo form_close(); ?>



javascriptは非常に簡単なチェックだけですが、javascriptとphpの両方で入力チェックしてます。
入力しないとこんな感じにハイライトされます。




■ ビュー:編集
admin/application/views/user/edit.php
<?php echo form_open(uri_string()); ?>
<input type="button" value="<?php echo _l('CANCEL'); ?>" onclick="javascript:location.href = '<?php echo base_url('user'); ?>';" tabindex="9" />

<h2><?php echo _l('USER_DETAILS'); ?></h2>
<dl class="horizontal">
    <dt><?php echo _l('EMAIL'); ?></dt>
    <dd><input class="field" id="email" type="email" name="email" value="<?php echo $user->email; ?>" tabindex="1" /><?php echo form_error('email'); ?></dd>
    <dt><?php echo _l('LASTNAME'); ?></dt>
    <dd><input class="field" id="lastname" type="text" name="lastname" value="<?php echo $user->lastname; ?>" tabindex="2" /><?php echo form_error('lastname'); ?></dd>
    <dt><?php echo _l('FIRSTNAME'); ?></dt>
    <dd><input class="field" id="firstname" type="text" name="firstname" value="<?php echo $user->firstname; ?>" tabindex="3" /><?php echo form_error('firstname'); ?></dd>
    <dt><?php echo _l('PASSWORD'); ?></dt>
    <dd><input class="field" id="passwd" type="password" name="passwd" value="" tabindex="4" /><?php echo form_error('passwd'); ?></dd>
    <dt><?php echo _l('PASSWORDCONF'); ?></dt>
    <dd><input class="field" id="passwdconf" type="password" name="passwdconf" value="" tabindex="5" /></dd>
    <dt><?php echo _l('STATUS'); ?></dt>
    <dd>
        <select name="status" class="field" tabindex="6">
            <option value="1"<?php if($user->status==1): ?> selected="selected"<?php endif; ?>><?php echo _l('ACTIVE'); ?></option>
            <option value="0"<?php if($user->status==0): ?> selected="selected"<?php endif; ?>><?php echo _l('INACTIVE'); ?></option>
        </select>
    </dd>
    
    <dd><input type="submit" value="<?php echo _l('SAVE'); ?>" onclick="return check(['email','lastname','firstname']);" tabindex="7" /> <input type="reset" value="<?php echo _l('RESET'); ?>" tabindex="8" /></dd>
</dl>
<?php echo form_close(); ?>



編集画面も似たようなものです。パスワードが入力されてない場合はスルーします。
パスワードのエラーはphpでのみ表示。javascriptは苦手・・・


だいぶ長くなってしまったので、今日はここまでにします。

2011年8月11日

Codeigniterを使ってショッピングカートをゼロから作ってみよう。 # 5

前回ユーザ登録やりますと言って実際作り始めたんですが①ユーザ一覧表示②ユーザ登録ボタンをクリックしたら登録画面という流れを考えると、ユーザ一覧表示した時にナビを表示する必要あるんじゃ・・・

ということでユーザ登録の前にナビ用のパンくずリストを作ります。


■ パンくずリスト( Breadcrumb )
まずパンくずHTMLを返すメソッドをヘルパーに作成。
extension/helpers/html_helpers.php
<?php
function breadcrumb($array)
{
    $count = count($array); $i = 1;
    $html = '<div id="breadcrumb"><ul>';
    foreach($array as $k=>$v)
    {
        $class = (empty($v)) ? ' class="home"' : '';
        if($i != $count)
            $html .= '<li><a href="'.base_url($v).'"'.$class.'>'.$k.'</a></li>';
        else    // no link for the last one
            $html .= '<li class="last"><span>'.$k.'</span></li>';
        $i++;
    }
    $html .= '</ul></div>';
    
    return $html;
}

コントローラーにパンくず用の配列を作成。
admin/application/controllers/users.php
<?php
class User extends Controller
{
    function __construct()
    {
        parent::__construct();
        if( ! _s('admin')) redirect();
    }
    
    function index()
    {
        $this->accounts();
    }
    
    function accounts($page=0)
    {
        $data['breadcrumbs'] = array(_l('HOME')=>'', _l('USERLIST')=>'admin/user');
        $this->layout->view('user/accounts', $data);
    }
}

レイアウトにパンくず表示ラインを追加
admin/application/views/_layouts/main.php
<?php if(isset($breadcrumbs) && is_array($breadcrumbs)) echo breadcrumb($breadcrumbs); ?>


見た目はAppleのようなパンくずリストにしてみました。




■ 最後に
この方法だとパンくずを表示するなら全てのメソッド内に$data['breadcrumbs']を追加しなければいけないんですよね。
他に良いやり方を思いつかなかったのですが、正直このパンくずリストあまりいい方法ではないと思います。
「こうしたほうが良いよ~」とアイデアのある方は是非アドバイスください。

2011年8月10日

Codeigniterを使ってショッピングカートをゼロから作ってみよう。 # 4

前回フロントエンドとバックエンドを分けたので、そこに認証機能をつけます。




■ ユーザに関する考察
ショッピングカートにはサイトの管理者と登録ユーザという2種類のユーザがいると思います。
サイトを運営するのは個人であったり会社であったりしますが、管理者が1人じゃないこともあるでしょう。そう考えると登録ユーザ(お客さん)と管理ユーザはわけたほうが良いかもしれません。

そこで登録ユーザをCustomer、管理ユーザをUserと位置づけ開発を続けていきたいと思います。


■ Usersテーブル作成
まず管理ユーザ用のDBテーブルを作成します。
(とりあえず現在のところは最低限必要な情報で構成しています。)

CREATE TABLE IF NOT EXISTS `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `email` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
  `password` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `firstname` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
  `lastname` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
  `status` tinyint(4) NOT NULL,
  `role` int(11) NOT NULL,
  `hash` varchar(32) COLLATE utf8_unicode_ci NOT NULL,
  `lastlogin` timestamp NULL DEFAULT NULL,
  `updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `email` (`email`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ;



■ Authライブラリ作成
Codeigniterでは有名(?)なDX Authなどのライブラリの使用も考慮しましたが、結局どれを使っても用途に合わせてカスタマイズしないといけないので自作します。
△要件△
- メールアドレスとパスワードで認証。ユーザ名は別途考慮。
- パスワード暗号化
- UserとCustomerの別認証

/extension/libraries/Auth.php
<?php
class Auth
{
    var $_error;

    public function __construct()
    {
        $this->ci =& get_instance();
    }
        
    function error()
    {
        return $this->_error;
    }
    
    function login($email, $passwd, $target='customer')
    {
        if($target === 'user')
        {   // load user model
            $this->ci->load->model('users_model','usersdb');
            // check if exists
            if($user = $this->ci->usersdb->exist($email))
            {   // retrieve user hash & matching up with entered password
                if($this->_encode($passwd, $user->hash) === $user->password)
                {   // update last login
                    $this->ci->usersdb->lastlogin($user->id);
                    // set admin session
                    $this->ci->session->set_userdata('admin',TRUE);
                    
                    return TRUE;
                }
                else $this->_error = _l('error_wrong_combination');
            }
            else $this->_error = _l('error_not_exist');
        }
        
        return FALSE;
    }
    
    private function _encode($passwd, $hash)
    {
        /* 暗号化スクリプト */
        
        return $passwd;
    }
}

/extension/models/users_model.php
<?php
class Users_model extends Model
{
    var $table = 'users';
    
    function __construct()
    {
        parent::__construct();
    }
    
    function exist($email)
    {
        $q = $this->db->get_where($this->table, array('email'=>$email));
        return ($q->num_rows() == 1) ? $q->row() : FALSE;
    }
    
    function lastlogin($id)
    {
        $this->db->where('id',$id);
        $this->db->update($this->table, array('lastlogin'=>date('Y-m-d H:i:s')));
    }
}



パスワードはユーザごとにハッシュを作成し、一定の法則で入力パスワードとマッチングさせてます。
法則は_encodeメソッド内に好きなように指定してください。
ユーザごとのハッシュは登録時に作成しないといけないので、それは次回に。

とりあえずのところ認証ライブラリ(Auth)はできたので、テストユーザを直接DBに作ってテストしてみます。

DBにテストユーザ追加
INSERT INTO `users` (`id`, `email`, `password`, `firstname`, `lastname`, `status`, `role`, `hash`, `lastlogin`, `updated`) VALUES
(1, 'test@test.com', '723e66f900dcb555d089050c80455331feb2b7ca', 'firstname', 'lastname', 0, 0, '5898e88516d636dbd3571c7d24550f67', '2011-08-04 10:49:04', '2011-08-04 10:49:04');


■ autoload変更
認証でデータベース、およびセッションを使うようになるのでconfig/autoload.phpを以下のように変更します。
$autoload['libraries'] = array('Auth','database','Form_validation','Session');


■ コントローラ
admin/application/controllers/login.php
<?php
class Login extends Controller
{
    function __construct()
    {
        parent::__construct();
        if(_s('admin')) redirect();
    }
    
    function index()
    {
        $this->form_validation->set_rules('email',_l('EMAIL'),'required|trim|valid_email');
        $this->form_validation->set_rules('password', _l('PASSWORD'), 'required|trim');
        if($this->form_validation->run())
        {
            $login = $this->auth->login($this->input->post('email'), $this->input->post('password'), 'user');
            if($login)  redirect();
            else $data['error'] = $this->auth->error();
        }
        else $data['error'] = validation_errors();
        
        $data['css'] = array('login');
        $data['page_title'] = _l('CONTROLPANEL');
        $this->layout->view('login', $data);
    }
}


■ ビュー
admin/application/view/login.php
<?php echo form_open(uri_string()); ?>
<div>
<h1><?php echo _l('CONTROLPANEL'); ?></h1>
<p><?php echo _l('MSG_LOGIN'); ?></p>
<dl>
    <dt><?php echo _l('EMAIL'); ?></dt>
    <dd><input type="email" name="email" value="<?php echo set_value('email'); ?>" /></dd>
    <dt><?php echo _l('PASSWORD'); ?></dt>
    <dd><input type="password" name="password" value="" /></dd>
    <dd><input type="submit" value="<?php echo _l('LOGIN'); ?>"></dd>
    <?php if(isset($error)): ?><dd><?php echo $error; ?></dd><?php endif; ?>
</dl>
</div>
<?php echo form_close(); ?>

これで準備は完了です。


■ログイン画面
どうせだったらと簡単にデザインしてみました。デザインは苦手なんですよねー(^_^;;



上で追加したユーザでログインしてみます。


うん、ちゃんと admin セッションが登録されていますね。
ログインした時に登録するべきセッションは admin だけではないですが、それは必要に応じて追加して行きたいと思います。


次回はユーザ登録をやります。