ダメプログラマの技術メモ

プログラミングの技術メモや駄文など

CentOS6.5にphpRedisAdminをインストール

開発中などに手軽にRedisに保存した値を確認できる便利な管理ツールをご紹介します。

その名もphpRedisAdmin!!

画面は2ペインのシンプルな構成でkey-valueの検索、追加、編集、削除が可能です。

管理画面

topページ
f:id:damepg:20140807120041j:plain

key-valueページ
f:id:damepg:20140807120045j:plain

phpRedisAdminのインストール

  • phpRedisAdminのダウンロード
# cd
# git clone https://github.com/ErikDubbelboer/phpRedisAdmin.git
# cd phpRedisAdmin
# git clone https://github.com/nrk/predis.git vendor
  • phpRedisAdminをドキュメントルートにコピー
# cd
# cp -r phpRedisAdmin /var/www/html
  • phpRedisAdmin用のApache設定ファイル作成
    • サーバを外部公開する場合は必要?
# vi /etc/httpd/conf.d/phpRedisAdmin.conf

phpRedisAdmin.confの内容
================================================================================
<Location /phpredisadmin>
    Order deny,allow
    Deny from all           # 全て拒否
    Allow from 127.0.0.1    # 自身からのアクセスを許可
    Allow from 192.168.56.1 # 特定IPからのアクセスを許可(適宜変更して下さい)
</Location>
================================================================================
  • 動作確認
# vi /var/www/html/redis.php

redis.phpの内容
================================================================================
<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$val = array('key1'=>'value1', 'key2'=>'value2');
$redis->setex('key', 60 * 60, serialize($val)); // 有効期間 3600sec
var_dump(unserialize($redis->get('key')));
================================================================================
  • http://192.168.56.101/redis.php にアクセスしてRedisに値を保存する。
  • http://192.168.56.101/phpRedisAdmin/ にアクセスして管理画面が表示されることを確認する。

設定ファイルについて

  • Redisの接続設定は /phpRedisAdmin/includes/config.sample.inc.php をコピーして/phpRedisAdmin/includes/config.inc.php というファイルを作成して行います。
  • もしconfig.inc.phpが存在しない場合は、config.sample.inc.phpを参照します。
  • config.sample.inc.phpの接続先は127.0.0.1になっているので、RedisとphpRedisAdminが同じサーバ内にある場合はconfig.inc.phpがなくても動きます。

CentOS6.5にApache2.2+PHP5.4+Redis2.4をインストール

の続きです。

Apache2.2のインストール

# yum install httpd
  • インストール内容の確認
# yum list installed | grep httpd
httpd.x86_64         2.2.15-31.el6.centos
httpd-tools.x86_64   2.2.15-31.el6.centos
# cp /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.bk
# vi /etc/httpd/conf/httpd.conf
================================================================================
    修正前(338行目付近)
    AllowOverride None

    修正後
    AllowOverride ALL
================================================================================
================================================================================
    修正前(402行目付近)
    DirectoryIndex index.html index.html.var

    修正後
    DirectoryIndex index.html index.php
================================================================================
# chkconfig httpd on
# /etc/init.d/httpd start
  • 動作確認
    • ブラウザで http://192.168.56.101/ にアクセスして「Apache 2 Test Page」の画面が表示されることを確認する。

PHP5.4のインストール

# yum install --enablerepo=remi php php-mysql php-mbstring php-gd php-redis php-pecl-apc
  • インストール内容の確認
# yum list installed | grep php
php.x86_64           5.4.31-1.el6.remi  @remi
php-cli.x86_64       5.4.31-1.el6.remi  @remi
php-common.x86_64    5.4.31-1.el6.remi  @remi
php-gd.x86_64        5.4.31-1.el6.remi  @remi
php-mbstring.x86_64  5.4.31-1.el6.remi  @remi
php-mysql.x86_64     5.4.31-1.el6.remi  @remi
php-pdo.x86_64       5.4.31-1.el6.remi  @remi
php-pear.noarch      1:1.9.5-2.el6.remi @remi
php-pecl-apc.x86_64  3.1.15-0.4.20130912.el6.remi.5.4
php-pecl-igbinary.x86_64
php-pecl-redis.x86_64
php-process.x86_64   5.4.31-1.el6.remi  @remi
php-xml.x86_64       5.4.31-1.el6.remi  @remi
  • php.iniの編集
# cp /etc/php.ini /etc/php.ini.bk
# vi /etc/php.ini   
================================================================================
    文字コード設定
    default_charset = "UTF-8"

    タイムゾーン設定
    date.timezone = Asia/Tokyo
        
    エラー設定
    display_errors = On
    error_log = /var/log/php.log
        
    マルチバイト文字設定
    mbstring.language = Japanese
    mbstring.internal_encoding = UTF-8
    mbstring.http_input = pass
    mbstring.http_output = pass
    mbstring.encoding_translation = Off
    mbstring.detect_order = UTF-8
    mbstring.substitute_character = none
================================================================================
  • エラーログファイル作成
# touch /var/log/php.log
# chown apache:apache /var/log/php.log

# /etc/init.d/httpd restart

  • 動作確認
# echo "<?php phpinfo(); ?>" > /var/www/html/phpinfo.php
  • ブラウザで http://192.168.56.101/phpinfo.php にアクセスしてphpinfoの画面が表示されることを確認する。

Redisのインストール

# yum --enablerepo=epel install redis
  • インストール内容の確認
# yum list installed | grep redis
php-pecl-redis.x86_64               2.2.5-1.el6.remi.5.4               @remi
redis.x86_64                        2.4.10-1.el6                       @epel
# chkconfig redis on
  • Redis起動
# /etc/init.d/redis start
  • 動作確認
# echo '<?php $redis = new Redis(); if ($redis->connect("127.0.0.1", 6379)) print("redis connect OK"); ?>' > /var/www/html/redis.php
  • ブラウザで http://192.168.56.101/redis.php にアクセスして「redis connect OK」が表示されることを確認する。

CentOS6.5にMySQL5.5をインストール

VirtualBoxにCentOS6.5をインストール ~ 初期設定 の続きです。

MySQL5.5のインストール

# yum --enablerepo=remi install mysql mysql-server mysql-devel
  • インストールの確認
# yum list installed | grep mysql
compat-mysql51.x86_64
mysql.x86_64         5.5.39-1.el6.remi  @remi
mysql-devel.x86_64   5.5.39-1.el6.remi  @remi
mysql-libs.x86_64    5.5.39-1.el6.remi  @remi
mysql-server.x86_64  5.5.39-1.el6.remi  @remi

初期設定

  • my.cnfの編集
# cp /etc/my.cnf /etc/my.cnf.bk
# vi /etc/my.cnf
==================================================
[mysqld]
character-set-server=utf8   # 追記する。
==================================================
# chkconfig mysqld on
# /etc/init.d/mysqld start
  • セキュリティ周りの設定
# mysql_secure_installation
=======================================================
Enter current password for root (enter for none):
rootのパスワードは未設定なので Enterキー を押下する。

Set root password? [Y/n]
rootのパスワードを設定するので Y を選択する。

New password:
rootの新しいパスワードを入力する。

Re-enter new password:
もう一度パスワードを入力する。

Remove anonymous users? [Y/n]
匿名ユーザは不要なので Y を選択する。

Disallow root login remotely? [Y/n] 
rootのリモートログインは不要なので Y を選択する。

Remove test database and access to it? [Y/n]
testデータベースは不要なので Y を選択する。

Reload privilege tables now? [Y/n]
権限テーブルの再読み込みを行うので Y を選択する。
=======================================================
  • ログインの確認
# mysql -u root -p[新しいパスワード]

接続用ユーザーの作成

  • 以下のユーザーを作成する。
    • ユーザ名:dev
    • パスワード:dev001
mysql> grant all privileges on *.* to dev@'%' identified by 'dev001';
mysql> grant all privileges on *.* to dev@'localhost' identified by 'dev001';
mysql> grant all privileges on *.* to dev@'127.0.0.1' identified by 'dev001';
  • 登録したユーザが存在するか確認
mysql> select user,host from mysql.user;
+---------+-----------+
| user    | host      |
+---------+-----------+
| dev     | %         |
| dev     | 127.0.0.1 |
| root    | 127.0.0.1 |
| root    | ::1       |
| dev     | localhost |
| root    | localhost |
+---------+-----------+
6 rows in set (0.00 sec)
  • 一旦終了
mysql> exit;
  • ログインの確認(作成したユーザーで再接続できればOK)
# mysql -u dev -pdev001
  • SQLクライアントツール等で外部から192.168.56.101に対してDB接続できることも確認する。

VirtualBoxにCentOS6.5をインストール ~ 初期設定

やりたいこと

  • CentOS6.5を最小構成でVirtualBoxにインストールする。
  • ターミナルソフトでsshログインできるようにする。

CentOS6.5のダウンロード

  1. 次のダウンロードサイトにアクセスする。
  2. CentOS-6.5-x86_64-minimal.iso」リンクをクリックする。

仮想マシンの作成

  1. VirtualBoxを起動する。
  2. 「新規」ボタンをクリックする。
  3. 仮想マシンを作成する。
    • 名前とオペレーティングシステム
      • 名前:CentOS
      • タイプ:Linux
      • バージョン:Red Hat(64 bit)
      • 「次へ」ボタンを押下する。
    • メモリーサイズ
      • 2048MB割り当てる(メモリサイズに応じて変更)
      • 「次へ」ボタンを押下する。
    • ハードドライブ
      • 「仮想ハードドライブを作成する」を選択する。
      • 「作成」ボタンを押下する。
    • ハードドライブのファイルタイプ
      • 「VDI(VirtualBox Disk Image)」を選択する。
      • 「次へ」ボタンを押下する。
    • 物理ハードドライブの作成
      • 「可変サイズ」を選択する。
      • 「次へ」ボタンを押下する。
    • ファイルの場所とサイズ
      • 8.00GBに設定する(ディスク容量に応じて変更)
      • 「作成」ボタンを押下する。

CentOSのインストール

  1. VirtualBoxを起動する。
  2. 「設定」ボタンを押下する。
  3. 「ストレージ」を選択する。
  4. ストレージツリーの空となっている部分を選択する。
  5. 右側の属性CD/DVDドライブにあるCDのアイコンをクリックする。
  6. 「仮想CD/DVDディスクファイルの選択」を選択する。
  7. ダウンロードした「CentOS-6.5-x86_64-minimal.iso」を選択する。
  8. 「OK」ボタンを押下する。
  9. VirtualBoxのホーム画面に戻る。
  10. 「起動」ボタンを押下してCentOSを起動する。
    • Welcome to CentOS 6.5!
      • 「Install or upgrade an existing system」を選択する。
      • Enterキーを押下する。
    • Disc Found
      • 「Skip」ボタンを押下する。
    • CentOS6
      • 「Next」ボタンを押下する。
    • インストールで使用する言語
      • 「japanese(日本語)」を選択する。
      • 「次」ボタンを押下する。
    • キーボード
      • 「日本語」を選択する。
      • 「次」ボタンを押下する。
    • ストレージタイプ
      • 「基本ストレージデバイス」を選択する。
      • 「次」ボタンを押下する。
    • ストレージデバイスの警告
      • 「選択したすべてのデバイス(検出されていないパーティションもしくはファイルシステムを含む)に適用します」にチェックを付ける。
      • 「はい。含まれていません。どのようなデータであっても破棄してください。」ボタンを押下する。
    • ホスト名
      • ホスト名に「localhost.localdomain」を入力する。
      • 「ネットワークの設定」ボタンを押下する。
      • 「System eth0」を選択して「編集」ボタンを押下する。
      • 「自動接続する」にチェックを付ける。
      • 「適用」ボタンを押下する。
      • 「閉じる」ボタンを押下する。
      • 「次」ボタンを押下する。
    • タイムゾーン
      • 「アジア/東京」を選択する。
      • 「システムクロックでUTCを使用」にチェックを付ける。
      • 「次」ボタンを押下する。
    • rootユーザのパスワード
      • rootパスワードと確認に「root001」を入力する(パスワードは何でもよい)
      • 「次」ボタンを押下する。
      • 「パスワードが弱すぎる」ダイアログが表示されたら「とにかく使用する」ボタンを押下する。
    • どのタイプのインストール?
      • 「既存のLinuxシステムを入れ替える」を選択する。
      • 「次」ボタンを押下する。
      • 「ストレージ構成をディスクに書き込み中」ダイアログが表示されたら「変更をディスクに書き込む」ボタンを押下する。
    • インストールが完了したら「再起動」ボタンを押下する。
  11. rootユーザでログインできることを確認する。

ネットワーク設定

  • ホストオンリーアダプター追加
    • VirtualBoxを起動する。
    • 「設定」ボタンを押下する。
    • 「ネットワーク」を選択する。
    • 「アダプター2」タブをクリックする。
    • ネットワーク設定を行う。
    • 「高度」をクリックして下にある項目を展開する。
    • 「OK」ボタンを押下する。
  • ifcfg-eth1作成
    • CentOSを起動する。
    • rootユーザでログインする。
    • 次のコマンドを実行する。
# cd /etc/sysconfig/network-scripts
# vi ifcfg-eth1
===================================
DEVICE=eth1
TYPE=Ethernet
ONBOOT=yes
BOOTPROTO=static
HWADDR=08:00:27:F5:9E:07  # メモしたMACアドレスを記載
NAME="System eth1"
IPADDR=192.168.56.101     # 適当でよい
NETMASK=255.255.255.0
NETWORK=192.168.56.0
===================================
# ifup eth1
  • ターミナルソフトで192.168.56.101にsshログインできることを確認する。
    • ターミナルソフト上で次のCentOSの設定を行う。

CentOS設定

# service iptables stop
# chkconfig iptables off
# setenforce 0
# vi /etc/sysconfig/selinux
===================================
修正前
SELINUX=enforcing

修正後
SELINUX=disabled
===================================
  • 再起動
# shutdown -r now
# yum -y update
  • パッケージグループのインストール
# yum groupinstall "Base"
# yum groupinstall "Development tools"
# yum groupinstall "Japanese Support"
# rpm -ivh http://ftp-srv2.kddilabs.jp/Linux/distributions/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm
# rpm -ivh http://pkgs.repoforge.org/rpmforge-release/rpmforge-release-0.5.3-1.el6.rf.x86_64.rpm
# rpm -ivh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm

enabled=1になっている箇所を全てenabled=0に変更する。
# vi /etc/yum.repos.d/epel.repo
# vi /etc/yum.repos.d/rpmforge.repo
# vi /etc/yum.repos.d/remi.repo

リポジトリを指定する場合は次のようにする。
# yum --enablerepo=epel install XXXX
# yum --enablerepo=rpmforge install XXXX
# yum --enablerepo=remi install XXXX
  • ユーザ作成
# useradd admin
# passwd admin
# usermod -G wheel admin
# visudo
===================================
修正前
# %wheel ALL=(ALL) ALL

修正後(コメントを外す)
%wheel ALL=(ALL) ALL
===================================
# chmod 755 /home/admin
  • 設定後、adminユーザがログインできること、rootユーザになれることを確認する。

CakePHP2.x系で多次元(三次元)配列をソートする

array_multisort関数を使用した二次元配列のソートはネット上によくあるのですが、三次元配列のソートに言及しているところはほとんどなかったので自作してみました。

CakePHPはモデルメソッドの戻り値が[インデックス][モデル名][フィールド名]のような三次元配列で表現されることが多いので利用できるシチュエーションは多いと思います。

また、CakePHPにはHash::sortという多次元配列をソートできるメソッドが存在するのですが、ソート対象のフィールドを1つしか指定できないため若干不便です。そのため自作したメソッドは何個でもフィールドを指定できるようにしています。

サンプルプログラム

ソートメソッドの使用例

<?php
public function index() {

	// ソート対象配列(Model::findの戻り値を想定)
	$models = array();

	// 1レコード目
	$models[0]['A']['field_a_1'] = '4';
	$models[0]['A']['field_a_2'] = '1';
	$models[0]['B']['field_b_1'] = '2';
	// 2レコード目
	$models[1]['A']['field_a_1'] = '30';
	$models[1]['A']['field_a_2'] = '1';
	$models[1]['B']['field_b_1'] = '4';
	// 3レコード目
	$models[2]['A']['field_a_1'] = '30';
	$models[2]['A']['field_a_2'] = '2';
	$models[2]['B']['field_b_1'] = '6';
	// 4レコード目
	$models[3]['A']['field_a_1'] = '9';
	$models[3]['A']['field_a_2'] = '3';
	$models[3]['B']['field_b_1'] = '6';

	// 多次元配列ソート
	$result = Common::sortArr($models, '{n}.A.field_a_1', SORT_ASC, '{n}.B.field_b_1', SORT_DESC);
	debug($result);
/*
	array(
		(int) 0 => array(
			'A' => array(
				'field_a_1' => '4',
				'field_a_2' => '1'
			),
			'B' => array(
				'field_b_1' => '2'
			)
		),
		(int) 1 => array(
			'A' => array(
				'field_a_1' => '9',
				'field_a_2' => '3'
			),
			'B' => array(
				'field_b_1' => '6'
			)
		),
		(int) 2 => array(
			'A' => array(
				'field_a_1' => '30',
				'field_a_2' => '2'
			),
			'B' => array(
				'field_b_1' => '6'
			)
		),
		(int) 3 => array(
			'A' => array(
				'field_a_1' => '30',
				'field_a_2' => '1'
			),
			'B' => array(
				'field_b_1' => '4'
			)
		)
	)
*/
	exit;
}

Common::sortArrがソートを行うメソッドです。

この手のコントローラやモデルなど様々なところで利用されるメソッドはapp/Vendorディレクトリの下にCommonクラス(名前は何でもよい)を作成して、その中でメソッドを定義すると使い勝手がよいと思います。

Common::sortArrメソッドの引数

第一引数にはソート対象配列を指定します。

第二引数(第四引数、、)はソート対象フィールドをCakePHPのHashパスで指定します。
Hashパスがわからない方は下のサイトを参考にして下さい。

■Hash — CakePHP Cookbook 2.x ドキュメント
http://book.cakephp.org/2.0/ja/core-utility-libraries/hash.html

Hashクラスには配列を操作するための便利なメソッドが沢山あり、特にHash::extractは本当によく使用します!!

第三引数(第五引数、、)は昇順ソートしたい場合はSORT_ASC、降順ソートしたい場合はSORT_DESCを指定します。

ソートメソッドの定義

<?php
/**
 * 多次元配列ソート
 * @param ソート対象配列、Hashパス、ソート方法(Hashパス、ソート方法は可変)
 * @return ソート後の多次元配列
 */
public static function sortArr() {

	// 引数取得
	$args = func_get_args();

	// ソート対象配列取得
	$data = array_shift($args);

	// ソート対象配列のキー取得(これをソートする)
	$orgKeys = array_keys($data);

	// ソート対象配列のキーをソート
	$params = array();
	$argc = count($args);
	for ($i = 0; $i < $argc; $i += 2) {
		$params[] = Hash::extract($data, $args[$i]);
		$params[] = $args[$i + 1];
		$params[] = SORT_NATURAL;
	}
	$params[] = &$orgKeys;
	call_user_func_array('array_multisort', $params);

	// ソート後のソート対象配列のキーを取得
	$sortedData = array_pop($params);

	// ソート後のキーを使用してソート対象配列をソートする
	$result = array();
	foreach ($sortedData as $s) {
		$result[] = $data[$s];
	}

	return $result;
}

結局、array_multisort関数を使用してソートしています(;´・ω・)

配列そのものではなく、配列のキーをソートしているのがポイントです。

ソート後はソートされたキーの順番で配列要素を取り出して、あたかも配列自体をソートしたかのように見せています。

あと「SORT_NATURAL」は自然順を意味しており、以下のサイトのarray1_sort_flagsのフラグ定数であれば何でも設定できます。

PHP: array_multisort - Manual
http://www.php.net/manual/ja/function.array-multisort.php

これについては状況に応じて「SORT_REGULAR」や「SORT_NUMERIC」などを設定してください。

パラメータにして外部から渡すようにした方が汎用性が高まってよいかもしれません。

最後に

このメソッドを使うメリットの一つは、Model::findメソッドなどでORDER BY句を指定する必要がなくなるということです。

インデックスを張っていないカラムをORDER BY句に含めると、EXPLAINのExtraフィールドにusing filesortが発生することがあります。

処理件数が少ない場合であればメモリ内で処理が完結するので気にしなくてよいですが、処理件数が多い場合は対策を講じる必要があります。

一番簡単な対策はインデックスを張ることですが、ディスク容量の増加・更新処理による負荷の増大などを考慮する必要があります(ここら辺はサーバスペック次第ですが。。)

またソーシャルゲームでありがちなカードのID順・レアリティ順・入手順などのように複数のソートがある場合、その全てに対応したインデックスを張るのは現実的ではありません。

そういった場合や少しでもDB負荷を軽くしたい場合は、SQLではなくアプリ側でソート処理を行った方がよいと思います^^