終電23時11分って早くね?

都内のIT企業で働くカラオケ大好きエンジニアの雑記

Laravelでradioボタン生成の際にid属性を付与する

Laravelでラジオボタンを生成する際ですが、

http://laravel4.kore1server.com/docs/html#checkboxes-and-radio-buttons

こちらのドキュメントにもある通り、

// チェックボックスの生成
echo Form::checkbox('name', 'value');

// ラジオボタンの生成
echo Form::radio('name', 'value');

とすることで、

<input name="name" value="value" type="radio">

<input name="name" value="value" type="checkbox">

このようなHTMLが生成されます。簡単ですね!


で、ここで悩んだのが、

http://laravel4.kore1server.com/docs/html#labels

このラベルとの組み合わせで使いたい場合です。

男女の選択のラジオボタンがあって、ラベルが付いていてクリックでチェックが付けれる

というような要件を満たすためには、ラジオボタン(ないしはチェックボックス)に
id属性が付与されている必要があります。

そこで、ラジオボタンのドキュメント部分には書いてないのですが、
ラベルのドキュメント部分に

追加のHTML要素の指定
echo Form::label('email', 'E-Mail Address', array('class' => 'awesome'));

というのがありまして、ラベル生成時の最後の引数に、
配列で渡してあげることで、属性が付けられる模様・・・
ということで、

// ラジオボタンの生成
echo Form::radio('name', 'value', array('id'=>'hoge'));

という風に渡してみたんですが、属性はつかず。。。

ただ、オプションとして渡せそうだしなーーということで、
Laravelフレームワーク内のソースコードを追っていくとありました!

/vendor/laravel/framework/src/Illuminate/Html/FormBuilder.php : 500行目

public function radio($name, $value = null, $checked = null, $options = array())
{
     if (is_null($value)) $value = $name;

     return $this->checkable('radio', $name, $value, $checked, $options);
}

はいー結果、第4引数にオプションが渡せる形でした!
(第3引数はデフォルトでチェックをONにするかどうかのフラグ)

にゃので・・・

// ラジオボタンの生成
echo Form::radio('name', 'value', false ,array('id'=>'hoge'));

とすることで、

<input name="name" value="value" type="radio" id="hoge">

のようにid属性の付与ができましたとさ!!

一応上であげた、

男女の選択のラジオボタンがあって、ラベルが付いていてクリックでチェックが付けれる

のサンプルも出してみると、

// ラジオボタンの生成(男)
echo Form::radio('sex', '男' ,false , array('id' => 'men'));

// ラベルの生成(男)
echo Form::label('men', '男');

// ラジオボタンの生成(女)
echo Form::radio('sex', '女' ,false , array('id' => 'women'));

// ラベルの生成(女)
echo Form::label('women', '女');

とすることで、

<input id="men" name="sex" type="radio" value="男"><label for="men"></label>
<input id="women" name="sex" type="radio" value="女"><label for="women"></label>

となり、期待通りの出力ができました^^

LaravelのRESTフルコントローラーでキャメルケース指定ではまった

Laravelではドキュメントにもあるように、以下のようなコントローラの設定が可能です。

LaravelではRESTフルな命名規則を使ったコントローラのアクションへのルートを定義一つだけで簡単に行えます。

http://laravel4.kore1server.com/docs/controllers#restful-controllers

つまり

○routes.php

Route::controller('users', 'UserController');

○UserController.php

class UserController extends BaseController {

    public function getIndex()
    {
        //
    }
    
    public function getProfile()
    {
        //
    }
    
}

の設定がされていた場合、

http://ドメイン名/users にアクセスすると、
→getIndexメソッド内の処理が実行される。

http://ドメイン名/users/profile
→getProfileメソッド内の処理が実行される。

という形になります。

で、またまた「ドキュメントちゃんと読め事件」が発生するのですが、
メソッドをキャメルケースで指定したい・・・
たとえば、 getProfileEdit とか postAddProfileImg とか。
その場合、どういうURIでアクセスすればよいのかー??わからん。。
と悩むこと小一時間。。答えはドキュメントにありました 笑

もしコントローラアクションを複数の単語で命名するのでしたら、「ダッシュ」で分離したURIでアクセスできます。例えば下のコントローラーアクション、UserControllerは、users/admin-profileというURIに対応します。

要するに、
http://ドメイン名/users/admin-profile
→getAdminProfileメソッド内の処理が実行される。
ということです。

ポイントは「ダッシュ(-)」で単語をつなげるということですね。
ノット「アンダーバー(_)」!

【自宅サーバ構築記録】サーバを外部にさらすまえに…セキュリティ!

ちょっと間が空きましたが、今回はサーバのセキュリティ設定を行っていきますよと!

え、セキュリティとかいいから早くApacheとかPHPとか入れてプログラムを動かしたい??


セキュリティ対策しないで外部にサーバ公開「ダメ。ゼッタイ。


まてまて、と。そんなに焦らずコツコツやりましょう!


まだあわてるような時間じゃない」by 仙道


ちょろっとサーバを外部からアクセスできるようにするだけで、
結構な攻撃を受けちゃいますし、サーバのセキュリティを突破された日には、
もう立ち直れません(経験談 笑)

なので、ローカルの環境で動かしている状態のうちに、
セキュリティの確保をば行いたいと存じます次第です。


【大事】とりあえず最低限のセキュリティの確保をしておきましょう!【大事】


ただし、ここで行う設定は、、
絶対にセキュリティを突破されないことを保障するものではないので、
あくまでも自己責任でお願いしますm(__)m(決まり文句)

「もっとこれもやったほうがいいし!」とか「それ逆にヤバくね?」とか、
お気づきの点がございました場合はご教授いただければ幸いです。。


ということで、かなり長いですが、
大事なサーバを守るため!
じゃんじゃか設定していきます。


ログイン用ユーザーの作成

まずはログイン用のユーザを作成します。

rootは制限なくなんでも出来てしまうので、

・基本的に一般ユーザでログインする。
・root権限が必要な操作を行う場合のみ、suコマンドでrootになる。

というのをルールとして運用することにします。

新たに centos というユーザを作成する。
※ユーザ名は任意で変えてくださいね。

[root@luffy ~]# useradd centos
[root@luffy ~]# passwd centos
ユーザー centos のパスワードを変更。
新しいパスワード:
新しいパスワードを再入力してください:
passwd: 全ての認証トークンが正しく更新できました。

これで新しいユーザの作成は完了です。


rootになれるユーザを限定する

Linuxのシステム上には、
wheelグループというグループがあり、
このグループに所属するユーザーのみが、
rootになれるよう設定します。

[root@luffy ~]# usermod -G wheel centos

[root@luffy ~]# vi /etc/pam.d/su
#auth           required        pam_wheel.so use_uid
↓
auth           required        pam_wheel.so use_uid

以降、rootになれるユーザを追加する場合は、
wheelグループに所属させてあげましょう。

rootでのログインを禁止する

ここまでで、rootになれるユーザは限定しましたが、
そもそもrootのユーザがログインできてしまうという状態は、
セキュリティ的にはだいぶよろしくないです。

rootというユーザ名が分かっているので、
後はパスワードさえ分かれば、rootアカウントが乗っ取られてしまうリスクがあがりますね。

ですので、まだ外部にサーバを公開していない状態で、
rootでのログインを禁止してあげると良いと思います。

※「いつやるの?」⇒「今でしょ!」※

[root@luffy ~]# vi /etc/ssh/sshd_config

#PermitRootLogin yes
↓
PermitRootLogin no

#PermitEmptyPasswords no
↓
PermitEmptyPasswords no


ファイル改竄検知システム導入(Tripwire)

Tripwireはファイルの改竄(かいざん)などを検出してくれるツールです。

たとえば・・・
悪意のあるユーザにログインされてしまった。

何かファイルを書き換えられてしまった。

Tripwireがその変更を検知。

メールなどで自分に教えてくれる。

というような動きをしてくれます。

ただ、Tripwireは「ファイルが変更された」というのをチェックしてくれるものなので、
実際、自分で変更した部分もお知らせしてくれる形ではあります。

なので変更が検知されたからといって、誰かにセキュリティを破られているということにはなりませんのでご安心を。

[root@luffy ~]# yum -y install tripwire
[root@luffy ~]# tripwire-setup-keyfiles

----------------------------------------------
The Tripwire site and local passphrases are used to sign a  variety  of
files, such as the configuration, policy, and database files.

Passphrases should be at least 8 characters in length and contain  both
letters and numbers.

See the Tripwire manual for more information.

----------------------------------------------
Creating key files...

(When selecting a passphrase, keep in mind that good passphrases typically
have upper and lower case letters, digits and punctuation marks, and are
at least 8 characters in length.)

Enter the site keyfile passphrase: ← 任意のサイトパスフレーズを入力
Verify the site keyfile passphrase: ← 任意のサイトパスフレーズを入力(確認)

Enter the local keyfile passphrase: ← 任意のローカルパスフレーズを入力
Verify the local keyfile passphrase: ← 任意のローカルパスフレーズを入力(確認)

Signing configuration file...
Please enter your site passphrase: ← サイトパスフレーズを入力

Signing policy file...
Please enter your site passphrase: ← サイトパスフレーズを入力


[root@luffy ~]# vi /etc/tripwire/twcfg.txt
LOOSEDIRECTORYCHECKING =true ← ファイル変更時に所属ディレクトリの変更を通知しないようにする

EMAILREPORTLEVEL       =4 ← リポートレベルを変更する
REPORTLEVEL            =4 ← リポートレベルを変更する


[root@luffy ~]# twadmin -m F -c /etc/tripwire/tw.cfg -S /etc/tripwire/site.key /etc/tripwire/twcfg.txt ← Tripwire設定ファイルの暗号化
Please enter your site passphrase: ← サイトパスフレーズを入力
Wrote configuration file: /etc/tripwire/tw.cfg

[root@luffy ~]# rm -f /etc/tripwire/twcfg.txt ← Tripwire設定ファイル(テキスト版)削除

[root@luffy ~]# vi /etc/tripwire/twpolmake.pl ← ポリシーファイル最適化スクリプト作成
#!/usr/bin/perl
# Tripwire Policy File customize tool
# ----------------------------------------------------------------
# Copyright (C) 2003 Hiroaki Izumi
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
# ----------------------------------------------------------------
# Usage:
#    perl twpolmake.pl {Pol file}
# ----------------------------------------------------------------
#
$POLFILE=$ARGV[0];

open(POL,"$POLFILE") or die "open error: $POLFILE" ;
my($myhost,$thost) ;
my($sharp,$tpath,$cond) ;
my($INRULE) = 0 ;

while (<POL>) {
    chomp;
    if (($thost) = /^HOSTNAME\s*=\s*(.*)\s*;/) {
        $myhost = `hostname` ; chomp($myhost) ;
        if ($thost ne $myhost) {
            $_="HOSTNAME=\"$myhost\";" ;
        }
    }
    elsif ( /^{/ ) {
        $INRULE=1 ;
    }
    elsif ( /^}/ ) {
        $INRULE=0 ;
    }
    elsif ($INRULE == 1 and ($sharp,$tpath,$cond) = /^(\s*\#?\s*)(\/\S+)\b(\s+->\s+.+)$/) {
        $ret = ($sharp =~ s/\#//g) ;
        if ($tpath eq '/sbin/e2fsadm' ) {
            $cond =~ s/;\s+(tune2fs.*)$/; \#$1/ ;
        }
        if (! -s $tpath) {
            $_ = "$sharp#$tpath$cond" if ($ret == 0) ;
        }
        else {
            $_ = "$sharp$tpath$cond" ;
        }
    }
    print "$_\n" ;
}
close(POL) ;

[root@luffy ~]# perl /etc/tripwire/twpolmake.pl /etc/tripwire/twpol.txt > /etc/tripwire/twpol.txt.new ← ポリシーファイル最適化
[root@luffy ~]# twadmin -m P -c /etc/tripwire/tw.cfg -p /etc/tripwire/tw.pol -S /etc/tripwire/site.key /etc/tripwire/twpol.txt.new
 ← 最適化済ポリシーファイルを元にポリシーファイル(暗号署名版)作成
Please enter your site passphrase: ← サイトパスフレーズを入力
Wrote policy file: /etc/tripwire/tw.pol

[root@luffy ~]# rm -f /etc/tripwire/twpol.txt* ← ポリシーファイル(テキスト版)削除

[root@luffy ~]# tripwire -m i -s -c /etc/tripwire/tw.cfg ← Tripwireデータベース作成
Please enter your local passphrase: ← ローカルパスフレーズ応答


[root@luffy ~]# tripwire --check ← Tripwireチェック実行

[root@luffy ~]# vi tripwire.sh ← Tripwire定期自動実行スクリプト作成
#!/bin/bash

PATH=/usr/sbin:/usr/bin:/bin:/usr/local/tripwire/sbin

# パスフレーズ設定
LOCALPASS=xxxxxxxx # ローカルパスフレーズ
SITEPASS=xxxxxxxx  # サイトパスフレーズ

cd /etc/tripwire

# Tripwireチェック実行
tripwire -m c -s -c tw.cfg|mail -s "Tripwire(R) Integrity Check Report in `hostname`" root

# ポリシーファイル最新化
twadmin -m p -c tw.cfg -p tw.pol -S site.key > twpol.txt
perl twpolmake.pl twpol.txt > twpol.txt.new
twadmin -m P -c tw.cfg -p tw.pol -S site.key -Q $SITEPASS twpol.txt.new > /dev/null
rm -f twpol.txt* *.bak

# データベース最新化
rm -f /usr/local/tripwire/lib/tripwire/*.twd*
tripwire -m i -s -c tw.cfg -P $LOCALPASS

[root@luffy ~]# chmod 700 tripwire.sh

[root@luffy ~]# crontab -e
# 毎日03:00にtripwire(ファイル改竄検知)を行う
00 03 * * * /root/tripwire.sh

【参考サイト】
■はじめての自宅サーバ構築 - Fedora/CentOS - ファイル改竄検知システムの導入(Tripwire)
http://kajuhome.com/tripwire.shtml


rootkit検知ツール導入(chkrootkit)

まず、rootkitとは・・・?
http://e-words.jp/w/rootkit.html

サーバに悪意のある第3者に侵入された場合に、
その痕跡を消したり、再度アクセスできるようにしたり、
といったクラッカーの手助けをするツールrootkitです。

そのrootkitを検出してくれるのがこのツールです。

まぁrootkitが検知されてしまったら、
おそらく何かしら悪さをされているであろう状況だと思うので、
早急な被害拡大の防止の対応ができる。
というような二次災害を食い止めるツールというような考え方でよいのかな?と思っています。

[root@luffy ~]# yum -y install chkrootkit

chkrootkit定期自動実行設定
[root@luffy ~]# vi chkrootkit.sh

[root@luffy ~]# chmod 700 chkrootkit.sh

[root@luffy ~]# crontab -e
# 毎日02:00にchkrootkit(rootkit検知)を行う
00 02 * * * /root/tripwire.sh


Clam AntiVirusインストール

Clam AntiVirusは無料で使えるアンチウイルスソフトウェアです。
(当初はUNIX用だったようですが、現在はいろんなプラットフォームで使えるようです。)

Windowsにウイルス○スターとかカス○ルスキーとか入れるのと同じですね 笑

[root@luffy ~]# yum -y install clamd

[root@luffy ~]# freshclam ← ウィルス定義ファイルの更新

[root@luffy ~]# service clamd start

[root@luffy ~]# sed -i 's/Example/#Example/g' /etc/freshclam.conf ← ウィルス定義ファイル更新機能の有効化

[root@luffy ~]# vi virusscan.sh ← ウィルススキャン実行スクリプト作成

[root@luffy ~]# chmod 700 virusscan.sh

#!/bin/bash

PATH=/usr/bin:/bin

# clamd update
yum -y update clamd > /dev/null 2>&1

# excludeopt setup
excludelist=/root/clamscan.exclude
if [ -s $excludelist ]; then
    for i in `cat $excludelist`
    do
        if [ $(echo "$i"|grep \/$) ]; then
            i=`echo $i|sed -e 's/^\([^ ]*\)\/$/\1/p' -e d`
            excludeopt="${excludeopt} --exclude-dir=^$i"
        else
            excludeopt="${excludeopt} --exclude=^$i"
        fi
    done
fi

# virus scan
CLAMSCANTMP=`mktemp`
clamscan --recursive --remove ${excludeopt} / > $CLAMSCANTMP 2>&1
[ ! -z "$(grep FOUND$ $CLAMSCANTMP)" ] && \

# report mail send
grep FOUND$ $CLAMSCANTMP | mail -s "Virus Found in `hostname`" root
rm -f $CLAMSCANTMP

[root@luffy ~]# chmod 700 virusscan.sh

[root@luffy ~]# crontab -e
# 毎日04:00にclamd(ウィルススキャン)を行う
00 04 * * * /root/virusscan.sh


不必要なサービスの停止

[root@luffy ~]# service --status-all

無駄に動いているサービスはとめてしまいましょう。というお話。

サーバのリソース消費を抑えたり、脆弱性が露見する可能性を低くするために、
不必要なサービスは停止してしまいます。

[root@luffy ~]# service haldaemon status
hald (pid  7984) を実行中...
[root@luffy ~]# service haldaemon stop
HAL デーモンを停止中:                                      [  OK  ]
[root@luffy ~]# chkconfig haldaemon off

[root@luffy ~]# service abrtd status
abrtd (pid  8153) を実行中...
[root@luffy ~]# service abrtd stop
abrt デーモンを停止中:                                     [  OK  ]
[root@luffy ~]# chkconfig abrtd off

[root@luffy ~]# service auditd status
auditd (pid  8368) を実行中...
[root@luffy ~]# service auditd stop
auditd を停止中:                                           [  OK  ]
[root@luffy ~]# chkconfig auditd off

[root@luffy ~]# service messagebus status
messagebus (pid  7946) を実行中...
[root@luffy ~]# service messagebus stop
システムメッセージバスを停止中:                            [  OK  ]
[root@luffy ~]# chkconfig messagebus off

[root@luffy ~]# service kdump status
Kdump is operational
[root@luffy ~]# service kdump stop
Stopping kdump:                                            [  OK  ]
[root@luffy ~]# chkconfig kdump off

【参考サイト】
■◇不要デーモンの停止(CentOS6)◇初心者のためのLinuxサーバー構築講座(CentOS 自宅サーバー対応)☆お便利サーバー.com☆
http://www.obenri.com/_minset_cent6/daemon_cent6.html


バッファオーバーフロー対策(Exec-Shield)

Exec-ShieldはCentOSに標準でインストールされている機能で、
バッファオーバーフローを防いでくれるものですが、
デフォルトでは無効になっているので、有効にしておきます。

[root@luffy ~]# cat /proc/sys/kernel/exec-shield
1
[root@luffy ~]# echo 2 > /proc/sys/kernel/exec-shield

[root@luffy ~]# cat /proc/sys/kernel/exec-shield
2


不要なポートへのアクセス制御(iptables)

不要なポートは閉じる!進入経路を減らす!

公開するポートは、
22(ssh)と80(http)と443(https)だけの想定で設定しています。

[root@luffy ~]# vi iptables.sh

#!/bin/bash

#---------------------------------------#
# 設定開始                              #
#---------------------------------------#

# インタフェース名定義
LAN=eth0

#---------------------------------------#
# 設定終了                              #
#---------------------------------------#

# 内部ネットワークのネットマスク取得
LOCALNET_MASK=`ifconfig $LAN|sed -e 's/^.*Mask:\([^ ]*\)$/\1/p' -e d`

# 内部ネットワークアドレス取得
LOCALNET_ADDR=`netstat -rn|grep $LAN|grep $LOCALNET_MASK|cut -f1 -d' '`
LOCALNET=$LOCALNET_ADDR/$LOCALNET_MASK

# ファイアウォール停止(すべてのルールをクリア)
/etc/rc.d/init.d/iptables stop

# デフォルトルール(以降のルールにマッチしなかった場合に適用するルール)設定
iptables -P INPUT   DROP   # 受信はすべて破棄
iptables -P OUTPUT  ACCEPT # 送信はすべて許可
iptables -P FORWARD DROP   # 通過はすべて破棄

# 自ホストからのアクセスをすべて許可
iptables -A INPUT -i lo -j ACCEPT

# 内部からのアクセスをすべて許可
iptables -A INPUT -s $LOCALNET -j ACCEPT

# 内部から行ったアクセスに対する外部からの返答アクセスを許可
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# SYN Cookiesを有効にする
# ※TCP SYN Flood攻撃対策
sysctl -w net.ipv4.tcp_syncookies=1 > /dev/null
sed -i '/net.ipv4.tcp_syncookies/d' /etc/sysctl.conf
echo "net.ipv4.tcp_syncookies=1" >> /etc/sysctl.conf

# ブロードキャストアドレス宛pingには応答しない
# ※Smurf攻撃対策
sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=1 > /dev/null
sed -i '/net.ipv4.icmp_echo_ignore_broadcasts/d' /etc/sysctl.conf
echo "net.ipv4.icmp_echo_ignore_broadcasts=1" >> /etc/sysctl.conf

# ICMP Redirectパケットは拒否
sed -i '/net.ipv4.conf.*.accept_redirects/d' /etc/sysctl.conf
for dev in `ls /proc/sys/net/ipv4/conf/`
do
    sysctl -w net.ipv4.conf.$dev.accept_redirects=0 > /dev/null
    echo "net.ipv4.conf.$dev.accept_redirects=0" >> /etc/sysctl.conf
done

# Source Routedパケットは拒否
sed -i '/net.ipv4.conf.*.accept_source_route/d' /etc/sysctl.conf
for dev in `ls /proc/sys/net/ipv4/conf/`
do
    sysctl -w net.ipv4.conf.$dev.accept_source_route=0 > /dev/null
    echo "net.ipv4.conf.$dev.accept_source_route=0" >> /etc/sysctl.conf
done

# フラグメント化されたパケットはログを記録して破棄
iptables -A INPUT -f -j LOG --log-prefix '[IPTABLES FRAGMENT] : '
iptables -A INPUT -f -j DROP

# 外部とのNetBIOS関連のアクセスはログを記録せずに破棄
# ※不要ログ記録防止
iptables -A INPUT ! -s $LOCALNET -p tcp -m multiport --dports 135,137,138,139,445 -j DROP
iptables -A INPUT ! -s $LOCALNET -p udp -m multiport --dports 135,137,138,139,445 -j DROP
iptables -A OUTPUT ! -d $LOCALNET -p tcp -m multiport --sports 135,137,138,139,445 -j DROP
iptables -A OUTPUT ! -d $LOCALNET -p udp -m multiport --sports 135,137,138,139,445 -j DROP

# 1秒間に4回を超えるpingはログを記録して破棄
# ※Ping of Death攻撃対策
iptables -N LOG_PINGDEATH
iptables -A LOG_PINGDEATH -m limit --limit 1/s --limit-burst 4 -j ACCEPT
iptables -A LOG_PINGDEATH -j LOG --log-prefix '[IPTABLES PINGDEATH] : '
iptables -A LOG_PINGDEATH -j DROP
iptables -A INPUT -p icmp --icmp-type echo-request -j LOG_PINGDEATH

# 全ホスト(ブロードキャストアドレス、マルチキャストアドレス)宛パケットはログを記録せずに破棄
# ※不要ログ記録防止
iptables -A INPUT -d 255.255.255.255 -j DROP
iptables -A INPUT -d 224.0.0.1 -j DROP

# 113番ポート(IDENT)へのアクセスには拒否応答
# ※メールサーバ等のレスポンス低下防止
iptables -A INPUT -p tcp --dport 113 -j REJECT --reject-with tcp-reset

# ACCEPT_COUNTRY_MAKE関数定義
# 指定された国のIPアドレスからのアクセスを許可するユーザ定義チェイン作成
ACCEPT_COUNTRY_MAKE(){
    for addr in `cat /tmp/cidr.txt|grep ^$1|awk '{print $2}'`
    do
        iptables -A ACCEPT_COUNTRY -s $addr -j ACCEPT
    done
}

# DROP_COUNTRY_MAKE関数定義
# 指定された国のIPアドレスからのアクセスを破棄するユーザ定義チェイン作成
DROP_COUNTRY_MAKE(){
    for addr in `cat /tmp/cidr.txt|grep ^$1|awk '{print $2}'`
    do
        iptables -A DROP_COUNTRY -s $addr -m limit --limit 1/s -j LOG --log-prefix '[IPTABLES DENY_COUNTRY] : '
        iptables -A DROP_COUNTRY -s $addr -j DROP
    done
}

# IPアドレスリスト取得
. /root/iptables_functions
IPLISTGET

# 日本からのアクセスを許可するユーザ定義チェインACCEPT_COUNTRY作成
iptables -N ACCEPT_COUNTRY
ACCEPT_COUNTRY_MAKE JP
# 以降,日本からのみアクセスを許可したい場合はACCEPTのかわりにACCEPT_COUNTRYを指定する

# 中国・台湾・ロシア※からのアクセスをログを記録して破棄
# ※全国警察施設への攻撃元上位3カ国(日本・アメリカを除く)
# http://www.cyberpolice.go.jp/detect/observation.htmlより
iptables -N DROP_COUNTRY
DROP_COUNTRY_MAKE CN
DROP_COUNTRY_MAKE TW
DROP_COUNTRY_MAKE RU
iptables -A INPUT -j DROP_COUNTRY

#----------------------------------------------------------#
# 各種サービスを公開する場合の設定(ここから)               #
#----------------------------------------------------------#

# 外部からのTCP22番ポート(SSH)へのアクセスを日本からのみ許可
# ※SSHサーバーを公開する場合のみ
iptables -A INPUT -p tcp --dport 22 -j ACCEPT_COUNTRY

# 外部からのTCP80番ポート(HTTP)へのアクセスを許可
# ※Webサーバーを公開する場合のみ
iptables -A INPUT -p tcp --dport 80 -j ACCEPT

# 外部からのTCP443番ポート(HTTPS)へのアクセスを許可
# ※Webサーバーを公開する場合のみ
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

#----------------------------------------------------------#
# 各種サービスを公開する場合の設定(ここまで)               #
#----------------------------------------------------------#

# 拒否IPアドレスからのアクセスはログを記録せずに破棄
# ※拒否IPアドレスは/root/deny_ipに1行ごとに記述しておくこと
# (/root/deny_ipがなければなにもしない)
if [ -s /root/deny_ip ]; then
    for ip in `cat /root/deny_ip`
    do
        iptables -I INPUT -s $ip -j DROP
    done
fi

# 上記のルールにマッチしなかったアクセスはログを記録して破棄
iptables -A INPUT -m limit --limit 1/s -j LOG --log-prefix '[IPTABLES INPUT] : '
iptables -A INPUT -j DROP
iptables -A FORWARD -m limit --limit 1/s -j LOG --log-prefix '[IPTABLES FORWARD] : '
iptables -A FORWARD -j DROP

# サーバー再起動時にも上記設定が有効となるようにルールを保存
/etc/rc.d/init.d/iptables save

# ファイアウォール起動
/etc/rc.d/init.d/iptables start

[root@luffy ~]# vi iptables_functions

# IPアドレスリスト取得関数定義
IPLISTGET(){
    # http://nami.jp/ipv4bycc/から最新版IPアドレスリストを取得する
    wget -q http://nami.jp/ipv4bycc/cidr.txt.gz
    gunzip cidr.txt.gz
    # 最新版IPアドレスリストが取得できなかった場合
    if [ ! -f cidr.txt ]; then
        if [ -f /tmp/cidr.txt ]; then
            # バックアップがある場合はその旨をroot宛にメール通知して処理を打ち切る
            echo cidr.txt was read from the backup! | mail -s $0 root
            return
        else
            # バックアップがない場合はその旨をroot宛にメール通知して処理を打ち切る
            echo cidr.txt not found!|mail -s $0 root
            exit 1
        fi
    fi
    # 最新版IPアドレスリストを /tmpへバックアップする
    /bin/mv cidr.txt /tmp/cidr.txt
}

[root@luffy ~]# vi /etc/cron.daily/iplist_check.sh ← IPアドレスリストチェックスクリプト作成
#!/bin/bash

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# 新旧IPLIST差分チェック件数(0を指定するとチェックしない)
# ※新旧IPLIST差分がSABUN_CHKで指定した件数を越える場合はiptables設定スクリプトを実行しない
# ※新旧IPLIST差分チェック理由はhttp://centossrv.com/bbshtml/webpatio/1592.shtmlを参照
SABUN_CHK=9999
[ $# -ne 0 ] && SABUN_CHK=${1}

# チェック国コード
COUNTRY_CODE='JP CN TW RU'

# iptables設定スクリプトパス
IPTABLES=/root/iptables.sh

# iptables設定スクリプト外部関数取り込み
. /root/iptables_functions

# IPアドレスリスト最新化
rm -f IPLIST.new
IPLISTGET
for country in $COUNTRY_CODE
do
    if [ -f /tmp/cidr.txt ]; then
        grep ^$country /tmp/cidr.txt >> IPLIST.new
    else
        grep ^$country /tmp/IPLIST >> IPLIST.new
    fi
done
[ ! -f /tmp/IPLIST ] && cp IPLIST.new /tmp/IPLIST

# IPアドレスリスト更新チェック
diff -q /tmp/IPLIST IPLIST.new > /dev/null 2>&1
if [ $? -ne 0 ]; then
    if [ ${SABUN_CHK} -ne 0 ]; then
        if [ $(diff /tmp/IPLIST IPLIST.new | egrep -c '<|>') -gt ${SABUN_CHK} ]; then
            (
             diff /tmp/IPLIST IPLIST.new
             echo
             echo "$IPTABLES not executed."
            ) | mail -s 'IPLIST UPDATE' root
            rm -f IPLIST.new
            exit
        fi
    fi
    /bin/mv IPLIST.new /tmp/IPLIST
    sh $IPTABLES > /dev/null
else
    rm -f IPLIST.new
fi

[root@luffy ~]# chmod 700 /etc/cron.daily/iplist_check.sh

[root@luffy ~]# sh iptables.sh

[root@luffy ~]# chkconfig iptables on

【参考】
ファイアウォール構築(iptables) - CentOS自宅サーバー構築
http://centossrv.com/iptables.shtml


SSHのポート番号を変更

ポート番号を変えておいたほうが、
よりクラッカーからは敬遠されやすいはず!

[root@luffy ~]# vi /etc/ssh/sshd_config

#Port 22
↓
Port 10000 ← 任意のポート番号

[root@luffy ~]# service sshd restart

上で設定した開放するポート番号も変更します。

[root@luffy ~]# vi iptables.sh

# 外部からのTCP22番ポート(SSH)へのアクセスを日本からのみ許可
# ※SSHサーバーを公開する場合のみ
iptables -A INPUT -p tcp --dport 22 -j ACCEPT_COUNTRY
↓
iptables -A INPUT -p tcp --dport 10000 -j ACCEPT_COUNTRY

[root@luffy ~]# sh iptables.sh


パスワードでの認証を禁止し、公開鍵認証方式にする

パスワード認証と公開鍵認証のメリット・デメリットについては、
下記サイト様に非常に分かりやすくまとめられていました!

■[OpenSSH] SSHの2つの認証方式の違い - Life with IT
http://l-w-i.net/t/openssh/auth_001.txt

パスワード認証方式では、ID・PASSが分かればログインできてしまいますが、
公開鍵認証方式では、事前に秘密鍵・公開鍵のセットを発行しておく必要があり、
ひと手間かかる部分ですがセキュリティ的には強固になりますね!
秘密鍵の取り扱いは要注意ですが。。)

さて、まずは、公開鍵認証の設定をします。

公開鍵と秘密鍵の作成

最初のころーにダウンロードした、

PuTTY ごった煮版
http://yebisuya.dip.jp/Software/PuTTY/

に「puttygen.exe」がありますのでこちらを実行します。

f:id:blue_goheimochi:20130731233200j:plain

1.[SSH-2 RSA]を選択
2.[生成する鍵のビット数(B):] に [2048] を指定
3.[生成]をクリック

f:id:blue_goheimochi:20130731233214j:plain

4.[鍵] と表示されている何も書いてない部分で、緑のバーが溜まるまでマウスをぐりぐり動かす。

f:id:blue_goheimochi:20130731233223j:plain

5.[鍵のパスフレーズ] と「パスフレーズの確認」を入力する。
後でログインする際に使うので忘れないように!
→これは現状のサーバへのログインパスワードではないので、任意のものを設定でOKです。
6.[公開鍵の保存]をクリックして、任意の場所に公開鍵を「public-key.pub」という名前で保存する。
7.[秘密鍵の保存]をクリックして、任意の場所に秘密鍵を「scecret-key.pub」という名前で保存する。


サーバに公開鍵の設定をする

先ほど保存した「public-key.pub」のファイルをWinSCP等で、
サーバに転送します。
( /home/centos/public-key.pub に配置した想定で進めます。 )

以下のコマンドを実行。

[centos@luffy ~]$ mkdir -p .ssh

[centos@luffy ~]$ chmod 700 .ssh

[centos@luffy ~]$ ssh-keygen -i -f public-key.pub >> .ssh/authorized_keys

[centos@luffy ~]$ chmod 600 .ssh/authorized_keys

rootユーザに戻って、sshの設定を変更

[root@luffy ~]# vi /etc/ssh/sshd_config

#RSAAuthentication yes
#PubkeyAuthentication yes
#AuthorizedKeysFile     .ssh/authorized_keys

↓各コメントアウトをはずす

RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile     .ssh/authorized_keys

PasswordAuthentication yes
↓パスワード認証を禁止する設定
PasswordAuthentication no

また、私の環境におきましては、
ローカル環境からのアクセス(自宅LAN内からのアドレス)についてだけは、
パスワード認証を許可する設定をしております。

何らかが原因で公開鍵を紛失したとか接続したいPCが複数台あるとか、
ぶっちゃけ設定画面めんどくさいとか
もろもろの理由がございまして・・・笑

その際には、WiFiなどのネットワークにも気を配る必要がありますが。。

[root@luffy ~]# vi /etc/ssh/sshd_config

末尾に追記
↓
# 内部(192.168.1.0/24)からのアクセス時の設定
Match Address 192.168.1.0/24
PasswordAuthentication yes

Puttyの設定

Puttyにて先ほど作成した秘密鍵(scecret-key.ppk)を使ってログインする設定をします。
基本の設定は、こちらの記事を参照していただくとして、追加で下記設定をします。

f:id:blue_goheimochi:20130731233241j:plain

[接続]→[SSH]→[認証]に進み、
[認証パラメータ] の [認証のためのプライベートキーファイル] の [参照]をクリックして、
scecret-key.ppk を指定して[開く]をクリックします。

[セッション]に進み、現状の設定を [保存] したら、[開く]ボタンで開いてみましょう。

login as: centos ← centosを応答
Authenticating with public key "rsa-key-20130729"
Passphrase for key "rsa-key-20130729": ←上のほうでメモっておいたパスフレーズを応答

これで、公開鍵認証方式でのログインの設定は完了です。


おー疲れ様です!
長かったですねぇ、セキュリティ設定!
でもこれで敵がきても(たぶん)大丈夫!気持ち!

というのは嘘で、様々な書籍・Webを参考にまとめてみましたが、
冒頭でも申し上げたとおり、
「もっとこれもやったほうがいいし!」とか「それ逆にヤバくね?」とか、
お気づきの点がございました場合はご教授いただければ幸いです。。

きっとまだできることがあるはずだ!
ということで、ここのコンテンツは気がついた時点で随時増やしていきたいなと思います。

自分だけが被害を被るならまだしも、
踏み台にされたサーバから他人様に迷惑をかけてしまうようなことが無いよう、
セキュリティとは真剣に向き合わないとならないですね。

これにて、
「サーバを外部にさらすまえに…セキュリティ!」
は終了です!

次回、乞うご期待!

Laravel4でローカル環境時でのメールログ出力のカスタマイズ

Laravel4では、ローカル環境時に(まぁそれ以外でもですが)
メールを送信せず、ログに出力するというオプションが備わっています。

■メール メールとローカル開発 - Laravel4 日本語ドキュメント
http://laravel4.kore1server.com/docs/mail#mail-and-local-development

app/config/mail.phpで、

'pretend' => true,

を設定する。

もしくは、

Mail::pretend();

をプログラム中に記述する。

という方法で、ログへの書き出しに変更できます。


ところで、どこに出力されるのか・・・?

pretendモードの場合、受取人に向け送信する代わりに、アプリケーションのログファイルに書き込まれます。

ということなのですが、具体的に「ここよ!」ってのが書いてなかったので、ちょっと探してしまいました。

とはいえ、

■エラーとログ ログ - Laravel4 日本語ドキュメント
http://laravel4.kore1server.com/docs/errors#logging

にも書いてある通り、

app/storage/logs

に、ログは出力されていたんですが、

[2013-07-27 19:40:51] log.INFO: Pretending to mail message to: foo@example.com [] []

この1文だけでした。
勝手に「タイトルとか本文とかもはいってるだろなーー」と思っていたので、
しばらく、ログが出てないじゃん!って右往左往してしまいました 笑


にしてもタイトルとか本文も確認したい。

ちょうどメールアドレス認証のようなことをやろうと思っていて、
「メール本文中に認証用URLをつけて、そこをクリックすると認証される。」
というようなことをやりたかったので、ログにも本文(+タイトル)を入れたいなぁと思ってソースコードを追ってみました。

するとメールのログ出力を行っている部分が、

vendor/laravel/framework/src/Illuminate/Mail/Mailer.php

の305行目

protected function logMessage($message)
{
    $emails = implode(', ', array_keys($message->getTo()));

    $this->logger->info("Pretending to mail message to: {$emails}");
}

で出力していました。上で記述したログとも文言が一致します。
ここらをゴニョゴニョすればいけるかなーという方針。



解決策その1

引数を配列で渡す。

$this->logger->infoのメソッドですが、
引数を追加することができます。

$this->logger->info("Pretending to mail message to: {$emails}", array( 'subject' => 'hoge' ));

http://laravel4.kore1server.com/docs/errors#logging

すると、出力されるログはこんな感じ。

[2013-07-27 19:50:28] log.INFO: Pretending to mail message to: foo@example.com {"subject":"hoge"} []

引数に渡す変数を事前に配列にして渡してあげると、

protected function logMessage($message)
{
    $emails = implode(', ', array_keys($message->getTo()));

    $context['subject'] = $message->getSubject();
    $context['body']    = $message->getBody();

    $this->logger->info("Pretending to mail message to: {$emails}", $context);
}

こんな感じでログが出力されるようになります。

[2013-07-29 20:05:01] log.INFO: Pretending to mail message to: foo@example.com {"subject":"テストタイトル","body":"テスト本文"} []

こんな感じで、タイトル、本文をログに出力できるようになりました。


解決策その2

解決策その1のようにメソッドに配列を渡せば、
それを自動的に展開してログ出力してくれるのですが、
正直自分的には見にくい!と感じたので、
最終的には下記のように修正しました。

protected function logMessage($message)
{
   
   $mail_info = "";
   $mail_info .= "■ To : " . implode(', ', array_keys($message->getTo())) . "\n";
   $mail_info .= "■ Subject : " . $message->getSubject() . "\n";
   $mail_info .= "■ Body : \n" . $message->getBody() . "\n";

   $this->logger->info("Pretending to mail message\n{$mail_info}");
}

ログ出力

[2013-07-29 20:12:39] log.INFO: Pretending to mail message
■ To : foo@example.com
■ Subject : テストタイトル
■ Body :
テスト本文
[] []

引数を渡す処理方法ではなく、
実際にメッセージを作ってそれを出力するという形にしましたとさ。

一応機能的には満足なんですが、
Laravel4のフレームワークのファイルを直接いじってしまっているので、
その部分だけ何とかしたいなぁ。。という感じだったのですが、
何かいい書き方がありましたらご教授願いたいです。

また、ログのフォーマット的にデファクトスタンダード的なものがあるのかなぁ・・・
とちょっと探してみたんですがそれも見つからなかったのでこんな感じになっています。。

そんな点で、ご指摘ある方はどしどしいただければと!!笑

Laravel4のEloquent ORMではまった件

掲題の件、めちゃめちゃはまりました。。

格闘すること数時間。
結果解決したのでホッとしているんですが、
備忘録と同じようなエラーではまっている人のために、
(そもそもはまる人がいるのかわかんないけど 笑)
ログとして残しておこうと思います。

やろうとしたこと


Eloquent ORMはLaravel4にデフォルトで含まれている。
コレを使うとModelとデータベース(のテーブル)を関連付けて、
簡単にデータ操作ができるようになります。

今回、ユーザーを管理するモデルとデータベースのテーブルとして以下をはじめに用意しました。

【Userモデル】

class User extends Eloquent {

     /**
     * モデルに関連付けるデータベースのテーブルを指定
     *
     * @var string
     */
     protected $table = 'users';

}

【usersテーブル】

mysql> desc users;
+------------+------------------+------+-----+---------------------+----------------+
| Field      | Type             | Null | Key | Default             | Extra          |
+------------+------------------+------+-----+---------------------+----------------+
| id         | int(10) unsigned | NO   | PRI | NULL                | auto_increment |
| email      | varchar(255)     | NO   | UNI | NULL                |                |
| login_name | varchar(255)     | NO   |     | NULL                |                |
| created_at | timestamp        | NO   |     | 0000-00-00 00:00:00 |                |
| updated_at | timestamp        | NO   |     | 0000-00-00 00:00:00 |                |
+------------+------------------+------+-----+---------------------+----------------+

※本当はパスワードとかその他もろもろ情報を付け足す予定でしたが、
まず最初の段階でがっつりつまづいたので、最低限のテーブル構造になってます。

■Laravel4 日本語ドキュメント - Eloquent ORM
http://laravel4.kore1server.com/docs/eloquent

この日本語ドキュメントの、
基本的な使用法

にもありますが、

一度モデルを定義したら、テーブルのレコードを取得したり、作成したりする準備は整います。

と書いてある!
「よっしゃー超簡単じゃーん♪」
と思ってしまったのがコトの発端です。。


早速新しいデータを追加してみよう!

と思った私は、

routes.php

Route::get('test', function()
{
    $user = User::create(array('email' => 'test@test.com','login_name' => 'test',));   
});

を追加して、/test にアクセスし、
新規データを追加しようと試みました。

が、
Illuminate \ Database \ Eloquent \ MassAssignmentException
ばっちりエラー画面が表示。。

なぜ・・
挿入するデータを替えてみたり、
データベースの文字コードを確認してみたり、
Eloquentクラスの中身を追ってデバッグしてみたり・・・
と色々試してみたんですが、どうにも解決せず。。


何がいけなかった?

■edongkoy | Tutorials: Laravel 4 MassAssignmentException Error
http://tutorials-edongkoy.blogspot.jp/2013/06/laravel-4-massassignmentexception-error.html

ようやく解決させてくれたのが上の記事でした。

Eloquent ORMを利用して、モデルとデータベースのテーブルを関連付け、
createメソッドでデータを挿入するためには、

protected $guarded = array('hogehoge');

もしくは

protected $fillable = array('hogahoga');

の設定が必ず必要!ということです。

要するに、今回のケースでいくと、

class User extends Eloquent {

     /**
     * モデルに関連付けるデータベースのテーブルを指定
     *
     * @var string
     */
     protected $table = 'users';

     /**
     * createメソッド実行時に、入力を禁止するカラムの指定
     *
     * @var array
     */
     protected $guarded = array('id');

}

または

class User extends Eloquent {

     /**
     * モデルに関連付けるデータベースのテーブルを指定
     *
     * @var string
     */
     protected $table = 'users';

     /**
     * createメソッド実行時に、入力を許可するカラムの指定
     *
     * @var array
     */
     protected $fillable = array('email','login_name');

}

と書く必要がありました。

てか、これぶっちゃけドキュメントに書いてあるんです。。笑
(ちゃんと読め!ってはなし)

もしくは一行で新しいモデルを保存するためにcreateメソッドを使用することも可能です。メソッドから挿入されたモデルのインスタンスがリターンされます。しかしながら全Eloquentモデルは複数代入から保護されているため、これを使用する前に操作対象のモデルに対しfillableかguardedプロパティのどちらかを指定しておく必要があります。

http://laravel4.kore1server.com/docs/eloquent#insert-update-delete

操作対象のモデルに対し、
※ fillableかguardedプロパティのどちらかを指定しておく必要があります。 ※
(これ重要。)

ということで、今回は

class User extends Eloquent {

     /**
     * モデルに関連付けるデータベースのテーブルを指定
     *
     * @var string
     */
     protected $table = 'users';

     /**
     * createメソッド利用時に、入力を受け付けないカラムの指定
     *
     * @var array
     */
     protected $guarded = array('id'); // この行を追加。

}

とプログラムを修正することで、
ようやっと、迷宮から脱出することができましたとさ。。

今回の場合で上記のように設定したのは、
idのカラムはauto_incrementが設定されていて、
createメソッドでの入力に応じて値が変化する想定ではなかったので、
このような指定にしました。


でもさ・・・

一度モデルを定義したら、テーブルのレコードを取得したり、作成したりする準備は整います。

「作成する準備」は整ってないよね(>_<)

composerでPHPUnitがインストールできない

composerでPHPUnitをインストールしたかったんですが、
下記エラーが発生。

環境は

OS: CentOS6.4
PHP: 5.4.17

composer.jsonの内容はこんな感じでいたって普通。

{
    "require-dev": {
        "phpunit/phpunit": "3.7.*"
    },
    "config": {
        "bin-dir": "/usr/local/bin/"
    }
}


【エラー内容】

[root@luffy ~]# composer install
Loading composer repositories with package information
Installing dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - phpunit/phpunit 3.7.9 requires ext-dom * -> the requested PHP extension dom is missing from your system.
    - phpunit/phpunit 3.7.8 requires ext-dom * -> the requested PHP extension dom is missing from your system.
    - phpunit/phpunit 3.7.7 requires ext-dom * -> the requested PHP extension dom is missing from your system.
    - phpunit/phpunit 3.7.6 requires ext-dom * -> the requested PHP extension dom is missing from your system.
    - phpunit/phpunit 3.7.5 requires ext-dom * -> the requested PHP extension dom is missing from your system.
    - phpunit/phpunit 3.7.4 requires ext-dom * -> the requested PHP extension dom is missing from your system.
    - phpunit/phpunit 3.7.3 requires ext-dom * -> the requested PHP extension dom is missing from your system.
    - phpunit/phpunit 3.7.22 requires ext-dom * -> the requested PHP extension dom is missing from your system.
    - phpunit/phpunit 3.7.21 requires ext-dom * -> the requested PHP extension dom is missing from your system.
    - phpunit/phpunit 3.7.20 requires ext-dom * -> the requested PHP extension dom is missing from your system.
    - phpunit/phpunit 3.7.2 requires ext-dom * -> the requested PHP extension dom is missing from your system.
    - phpunit/phpunit 3.7.19 requires ext-dom * -> the requested PHP extension dom is missing from your system.
    - phpunit/phpunit 3.7.18 requires ext-dom * -> the requested PHP extension dom is missing from your system.
    - phpunit/phpunit 3.7.17 requires ext-dom * -> the requested PHP extension dom is missing from your system.
    - phpunit/phpunit 3.7.16 requires ext-dom * -> the requested PHP extension dom is missing from your system.
    - phpunit/phpunit 3.7.15 requires ext-dom * -> the requested PHP extension dom is missing from your system.
    - phpunit/phpunit 3.7.14 requires ext-dom * -> the requested PHP extension dom is missing from your system.
    - phpunit/phpunit 3.7.13 requires ext-dom * -> the requested PHP extension dom is missing from your system.
    - phpunit/phpunit 3.7.12 requires ext-dom * -> the requested PHP extension dom is missing from your system.
    - phpunit/phpunit 3.7.11 requires ext-dom * -> the requested PHP extension dom is missing from your system.
    - phpunit/phpunit 3.7.10 requires ext-dom * -> the requested PHP extension dom is missing from your system.
    - phpunit/phpunit 3.7.1 requires ext-dom * -> the requested PHP extension dom is missing from your system.
    - phpunit/phpunit 3.7.0 requires ext-dom * -> the requested PHP extension dom is missing from your system.
    - Installation request for phpunit/phpunit 3.7.* -> satisfiable by phpunit/phpunit[3.7.0, 3.7.1, 3.7.10, 3.7.11, 3.7.12, 3.7.13, 3.7.14, 3.7.15, 3.7.16, 3.7.17, 3.7.18, 3.7.19, 3.7.2, 3.7.20, 3.7.21, 3.7.22, 3.7.3, 3.7.4, 3.7.5, 3.7.6, 3.7.7, 3.7.8, 3.7.9].

最初はPHPUnitのバージョンがPHPに対応してないとかそんな感じかなー
と思ったので、composer.jsonでPHPUnitのバージョン指定を変えてみてとか
いろいろ試したんですが解決せず。。

てか最初からエラー内容見てみろよって話なんです 笑

phpunit/phpunit 3.7.9 requires ext-dom * -> the requested PHP extension dom is missing from your system.

phpunit/phpunit 3.7.9 には ext-dom が必要です。
・あんたのシステムにPHP extension domをリクエストしたけどなかったよ。

ってことなので、
DOM Extensionをインストール。

[root@luffy ~]# yum install php-xml

で、再度composerでPHPUnitをインストールすると・・・

[root@luffy ~]# composer install

Loading composer repositories with package information
Installing dependencies (including require-dev)
  - Installing symfony/yaml (dev-master 4d80b4f)
    Downloading: 100%

  - Installing phpunit/php-text-template (dev-master 1eeef10)
    Downloading: 100%

  - Installing phpunit/phpunit-mock-objects (1.2.x-dev 3e40f3b)
    Downloading: 100%

  - Installing phpunit/php-timer (1.0.x-dev ecf7920)
    Downloading: 100%

  - Installing phpunit/php-token-stream (dev-master c25dd88)
    Downloading: 100%

  - Installing phpunit/php-file-iterator (dev-master 2deb24c)
    Downloading: 100%

  - Installing phpunit/php-code-coverage (1.2.x-dev d274ffb)
    Downloading: 100%

  - Installing phpunit/phpunit (3.7.x-dev 3.7.22)
    Downloading: 100%

  - Removing symfony/translation (2.3.x-dev v2.3.2)
  - Installing symfony/translation (2.3.x-dev 9451303)
    Downloading: 100%

  - Removing symfony/routing (2.3.x-dev v2.3.2)
  - Installing symfony/routing (2.3.x-dev 036c990)
    Downloading: 100%

  - Removing symfony/process (2.3.x-dev v2.3.2)
  - Installing symfony/process (2.3.x-dev 41801e8)
    Downloading: 100%

  - Removing symfony/http-foundation (2.3.x-dev v2.3.2)
  - Installing symfony/http-foundation (2.3.x-dev b4b8939)
    Downloading: 100%

  - Removing symfony/event-dispatcher (2.3.x-dev v2.3.2)
  - Installing symfony/event-dispatcher (2.3.x-dev 41c9826)
    Downloading: 100%

  - Removing symfony/http-kernel (2.3.x-dev 515d24c)
  - Installing symfony/http-kernel (2.3.x-dev 491ab88)
    Downloading: 100%

  - Removing symfony/finder (2.3.x-dev v2.3.2)
  - Installing symfony/finder (2.3.x-dev b251476)
    Downloading: 100%

  - Removing symfony/dom-crawler (2.3.x-dev v2.3.2)
  - Installing symfony/dom-crawler (2.3.x-dev e05e07f)
    Downloading: 100%

  - Removing symfony/css-selector (2.3.x-dev v2.3.2)
  - Installing symfony/css-selector (2.3.x-dev 8855442)
    Downloading: 100%

  - Removing symfony/console (2.3.x-dev v2.3.2)
  - Installing symfony/console (2.3.x-dev 290fe87)
    Downloading: 100%

  - Removing symfony/browser-kit (2.3.x-dev v2.3.2)
  - Installing symfony/browser-kit (2.3.x-dev 2639dc4)
    Downloading: 100%

  - Removing symfony/filesystem (dev-master 18460cf)
  - Installing symfony/filesystem (dev-master 59ee050)
    Downloading: 100%

phpunit/phpunit-mock-objects suggests installing ext-soap (*)
phpunit/php-code-coverage suggests installing ext-xdebug (>=2.0.5)
phpunit/phpunit suggests installing phpunit/php-invoker (>=1.1.0,<1.2.0)
Writing lock file
Generating autoload files
Generating optimized class loader
Compiling common classes

よし、成功!!

[root@luffy ~]# phpunit --version
PHPUnit 3.7.22 by Sebastian Bergmann.

無事、PHPUnitの3.7.22がインストールされましたとさ!

今、注目度No.1のPHPフレームワーク「Laravel」

今までCakePHPとかsymfonyとか、
PHPフレームワークを試しては挫折し、試しては挫折し・・・
を繰り返した私ですが、
3度目の正直!というのも大げさですが、
今のとこ、かなりしっくりきているフレームワーク
それが、

「Laravel」(読:ららべる)

http://laravel.com/

です!

他のフレームワークに比べれば情報の量も少ないと思いますし、
逆に「なんで本でもネットでも情報いろいろあるのに、CakeとかSymfonyで挫折してんの?情弱?」
って言われてしまったら返す言葉もないんですが、(苦笑)
Webのドキュメントに沿って勉強しているだけなんですが、
すっと体に馴染むような感覚で学べているのは確かな実感です。


2013年注目度No.1のフレームワーク「Laravel」

また、PHPフレームワークのLaravelは、
2013年注目度No.1!(すでに半年折り返しましたが)

■2013年において注目すべき PHP フレームワークは Laravel
http://blog.sarabande.jp/post/48522241291

日本での普及率はもうひとつというような感じみたいですが、
欧米では「いけいけどんどん」(?)状態のようです 笑

ただ、日本においても、

■Laravel4公式日本語ドキュメント
http://laravel4.kore1server.com/docs
川瀬裕久さん(コレ1server)が翻訳されています!

■Laravel日本コミュニティ - Facebookグループ
https://www.facebook.com/groups/laravel.jp/

■Laravel日本語ニュース - Facebookページ
https://www.facebook.com/jp.laravel

■Laravel Meetup Tokyo
[vol.1] http://atnd.org/events/37079
[vol.2] http://atnd.org/events/39924

など、日本語のドキュメントもあり、
コミュニティも盛り上がり、勉強会も行われているようです!
(「laravel」でググッてもたくさんのブログがヒットします)


というわけで、
これからはLaravel関連の情報も扱っていけたらなぁ・・・
と思っています。
(3日坊主になりませんように・・・)