Apache設定ファイルでIncludeファイルにパラメータを渡す方法
やりたいこと
個人用開発環境を沢山作りたい時にApache設定ファイルの内容が冗長化してしまうので整理したい。 Includeで共通化をしてみたものの一部の記述が特定の環境に依存してしまったため、パラメータを渡すなりして他の個人用開発環境にも応用したい。
RewriteEngine on RewriteRule ^/contents.php$ - [L] RewriteRule ^/hoge/(.*)$ http://1.dev.new.hoge.com/hoge/$1 [L,P]
<VirtualHost *:80> DocumentRoot "/home/httpd/dev1/hoge.com/htdocs" ServerName 1.dev.hoge.com Include conf.d/include/rewrite_rule.conf . . . </VirtualHost>
対応方法
SetEnvIf
ディレクティブを使うことで解決した。
SetEnv
ディレクティブでも環境変数を制御することができるが、Includeの直前に設定してもInclude先の設定ファイル側では環境変数を参照することができなかった。
SetEnv
ではなくSetEnvIf
を使うことで環境変数を参照することができた。
RewriteEngine on RewriteRule ^/contents.php$ - [L] RewriteRule ^/hoge/(.*)$ http://%{ENV:ENV_NO}.dev.new.hoge.com/hoge/$1 [L,P]
<VirtualHost *:80> DocumentRoot "/home/httpd/dev1/hoge.com/htdocs" ServerName 1.dev.hoge.com SetEnvIf _ .* ENV_NO=1 Include conf.d/include/rewrite_rule.conf . . . </VirtualHost>
参考ページ
CentOSからPhantomJSを実行すると画面キャプチャの日本語が表示されなくなる問題
CentOSからPhantomJSを実行すると画面キャプチャの日本語が表示されなくなる問題
はじめに
PhantomJSをCentOS(6.5)から実行すると、保存した画面キャプチャの日本語が文字化けする問題があった。
コード
var page = require('webpage').create(); page.open('https://www.google.co.jp/intl/ja/about/', function() { window.setTimeout(function() { page.render('test.png'); phantom.exit(); }, 200); });
実行コマンド
phantomjs test.js
実行結果
対応方法
日本語フォントが入ってないか、フォント設定が上手くいってなかったので設定する。
yumから日本語フォントをインストール
sudo yum groupinstall "Japanese Support"
フォント設定ファイルを修正
sudo cp /etc/fonts/fonts.conf /etc/fonts/fonts.conf.original sudo vim /etc/fonts/fonts.conf
「Font directory list」から/usr/share/fonts
以外をコメントアウト。
すべて読み込むと文字化けされていた。
<!-- Font directory list --> <dir>/usr/share/fonts</dir> <!-- <dir>/usr/share/X11/fonts/Type1</dir> <dir>/usr/share/X11/fonts/TTF</dir> <dir>/usr/local/share/fonts</dir> <dir>~/.fonts</dir> -->
フォントキャッシュ更新
sudo fc-cache -fv
実行結果(再実行)
無事に日本語フォントが読み込まれた。
phpdotenvで環境変数を制御する
phpdotenvとは
phpdotenv(PHP dotenv)は、.env
ファイルに環境変数を記述することで、getenv()
、$_ENV
、$_SERVER
からの環境変数呼び出しを.env
ファイルから取得することができる
Rubyのdotenvライブラリがベース
特徴
- PHPで使う環境変数をDocumentRoot配下でまとめて管理することができる
- Twelve Factor App::設定
- 「Twelve-Factor Appは設定を 環境変数 に格納する」
- Twelve Factor App::設定
- ApacheやnginxなどVirtualHost内で環境変数を設定する必要がなくなる
- 設定済みの環境変数を上書きするかどうか制御が可能(デフォルトは上書き不可)
インストール方法
composerでインストールする
php composer.phar require vlucas/phpdotenv
使い方
基本的な使い方
.env
ファイルとsample.php
を用意する
URL="http://example.com"
<?php require_once './vendor/autoload.php'; // 引数は「.env」ファイルが存在するディレクトリを指定する $dotenv = new Dotenv\Dotenv(__DIR__); $dotenv->load(); echo getenv('URL'); // http://example.com echo $_ENV['URL']; // http://example.com echo $_SERVER['URL']; // http://example.com
環境変数ファイルにコメントを入れる
#
をつけるとコメント扱いになる
一行コメントと行末コメントに対応している
#comment1 URL="http://example.com"#comment2
<?php require_once './vendor/autoload.php'; $dotenv = new Dotenv\Dotenv(__DIR__); $dotenv->load(); echo $_ENV['URL']; // http://example.com
定義した環境変数を変数として扱う
${}
で環境変数を囲うと変数として読み込むことができる
SUBDOMAIN="hoge" URL="http://${SUBDOMAIN}.example.com"
<?php require_once './vendor/autoload.php'; $dotenv = new Dotenv\Dotenv(__DIR__); $dotenv->load(); echo $_ENV['URL']; // http://hoge.example.com
Tips
.env以外のファイルを指定する方法
Dotenv
コンストラクタの第二引数にファイル名を指定すると任意のファイルを呼ぶことができる
URL="http://hoge.example.com"
<?php require_once './vendor/autoload.php'; // 第二引数にファイル名を指定する $dotenv = new Dotenv\Dotenv(__DIR__, 'hoge.env'); $dotenv->load(); echo $_ENV['URL']; // http://hoge.example.com
環境変数の上書き制御について
同一環境変数の場合、デフォルトでは上書きされない
overload
メソッドを呼ぶと上書きされる
.env
と.env2
を用意して、デフォルト(load
)とoverload
それぞれの動きを確認した
.env
の設定内容
SUBDOMAIN="hoge" URL="http://${SUBDOMAIN}.example.com" HOGE=".env"
.env2
の設定内容
SUBDOMAIN="fuge" URL="http://${SUBDOMAIN}.example2.com" FUGE=".env2"
デフォルトの挙動
<?php require_once './vendor/autoload.php'; $dotenv = new Dotenv\Dotenv(__DIR__); $dotenv->load(); $dotenv = new Dotenv\Dotenv(__DIR__, ".env2"); $dotenv->load(); print_r($_ENV); /* Array ( [SUBDOMAIN] => hoge [URL] => http://hoge.example.com [HOGE] => .env [FUGE] => .env2 ) */
HOGE
とFUGE
はそれぞれの環境変数ファイルから読み込まれているが、SUBDOMAIN
とURL
は上書きされていない
overload呼び出しの挙動
同一環境変数を上書きたい場合は、overload
メソッドを呼び出す
<?php require_once './vendor/autoload.php'; $dotenv = new Dotenv\Dotenv(__DIR__); $dotenv->load(); $dotenv = new Dotenv\Dotenv(__DIR__, ".env2"); $dotenv->overload(); print_r($_ENV); /* Array ( [SUBDOMAIN] => fuge [URL] => http://fuge.example2.com [HOGE] => .env [FUGE] => .env2 ) */
HOGE
とFUGE
はそれぞれの環境変数ファイルから読み込まれ、SUBDOMAIN
とURL
は上書きされた
読みこんだ環境変数の型
これらは全てstring型で扱っている
SAMPLE_1="true" SAMPLE_2=true SAMPLE_3="1" SAMPLE_4=1
requiredメソッドについて
phpdotenvにはrequired
メソッドがある
以下の例は、SAMPLE_1
が未定義だった場合に、Dotenv\Exception\ValidationException
がスローされる
<?php require_once './vendor/autoload.php'; $dotenv = new Dotenv\Dotenv(__DIR__); $dotenv->load(); $dotenv->required('SAMPLE_1');
required
は配列として引数に指定することができる
// 「SAMPLE_1」「SAMPLE_2」両方の環境変数がセットされていなければ例外スロー
$dotenv->required(['SAMPLE_1', 'SAMPLE_2']);
required
の後にチェーンメソッドをつなげることができる
// SAMPLE_1が数値であればOK $dotenv->required('SAMPLE_1')->isInteger(); // SAMPLE_1が数値かつ100か101であればOK $dotenv->required('SAMPLE_1')->isInteger()->allowedValues([100, 101]);
required
メソッドは環境変数の中身を厳密にチェックしたいときに使えそう
PHP+Apacheで日本語正規表現が動かないケース
はじめに
PHP5.6系 + Apache2.2系で日本語正規表現が動かない問題があった。 その時の調査と対処について備忘録。 (PHP7系との組み合わせは未検証)
現象
画面上から以下のカタカナチェックがfalse
を返している。
preg_match("/^[ァ-ヶー]+$/u", "テスト");
調査内容
PHP5.6のビルド
pcreは8.12を使用
#! /bin/sh # # Created by configure './configure' \ '--prefix=/usr/local/php5.6.12' \ '--with-apxs2=/usr/local/httpd2/bin/apxs' \ '--with-config-file-path=/etc/php5.6.12' \ '--with-config-file-scan-dir=/etc/php5.6.12/php.d' \ '--enable-mbstring' \ '--enable-mbregex' \ '--with-mysql=/usr/local/mysql' \ '--with-mcrypt' \ '--with-curl' \ '--with-iconv' \ '--enable-exif' \ '--enable-sockets' \ '--with-gd' \ '--with-openssl' \ '--with-png-dir=/usr/lib' \ '--with-jpeg-dir=/usr/lib' \ '--with-pdo-mysql=/usr/local/mysql' \ '--with-pcre-regex=/usr/local/pcre8.12' \ '--with-pcre-dir=/usr/local/pcre8.12' \ '--with-xsl' \ '--with-zlib' \ '--with-bz2' \ "$@"
そこから「make test」すると、以下のテストに失敗した
Bug #37911 (preg_replace_callback ignores named groups) [ext/pcre/tests/bug37911.phpt] preg_grep() 2nd test [ext/pcre/tests/grep2.phpt] preg_match() flags 3 [ext/pcre/tests/match_flags3.phpt]
→この時点のビルドで、画面上でのカタカナチェック通らず
PCREを最新にアップデート
PHP5.6はPCRE8.37がバンドルされている。(参照)
ただ --with-pcre-regex
が未指定だとmakeでこけてしまったので別途インストール。
PCREインストール手順
# ./configure --prefix=/usr/local/pcre8.37 --enable-utf8 --enable-unicode-properties # make # make install
PCREインストール後、PHP再ビルド
#! /bin/sh # # Created by configure './configure' \ '--prefix=/usr/local/php5.6.12' \ '--with-apxs2=/usr/local/httpd2/bin/apxs' \ '--with-config-file-path=/etc/php5.6.12' \ '--with-config-file-scan-dir=/etc/php5.6.12/php.d' \ '--enable-mbstring' \ '--enable-mbregex' \ '--with-mysql=/usr/local/mysql' \ '--with-mcrypt' \ '--with-curl' \ '--with-iconv' \ '--enable-exif' \ '--enable-sockets' \ '--with-gd' \ '--with-openssl' \ '--with-png-dir=/usr/lib' \ '--with-jpeg-dir=/usr/lib' \ '--with-pdo-mysql=/usr/local/mysql' \ '--with-pcre-regex=/usr/local/pcre8.37' \ '--with-pcre-dir=/usr/local/pcre8.37 ' \ '--with-xsl' \ '--with-zlib' \ '--with-bz2' \ "$@"
ここで「make test」すると、上記のテストが通った。
→この時点のビルドで、画面上でのカタカナチェックが通らなかったが、phpコマンド経由で実行すると問題なく通った
Apache側に問題あり?
phpファイルの先頭(<?php
の直後)に書いた所カタカナチェックが通らなかったので、Apache側に問題ありと判断。
Apache側のビルドオプションを確認
#! /bin/sh # # Created by configure CFLAGS="-fPIC -O3 -DUSE_MMAP"; export CFLAGS "./configure" \ "--prefix=/usr/local/httpd2" \ "--with-mpm=prefork" \ "--enable-ssl=static" \ "--enable-rewrite" \ "--enable-mods-shared=most" \ "CFLAGS=-fPIC -O3 -DUSE_MMAP" \ "$@"
pcreの指定はないが、configure
のオプションには--with-pcre
が指定可能である。
--with-pcre
を指定してApache再ビルドしてインストール。
#! /bin/sh # # Created by configure CFLAGS="-fPIC -O3 -DUSE_MMAP"; export CFLAGS "./configure" \ "--prefix=/usr/local/httpd2" \ "--with-mpm=prefork" \ "--enable-ssl=static" \ "--enable-rewrite" \ "--with-pcre=/usr/local/bin/pcre-config" \ "--enable-mods-shared=most" \ "CFLAGS=-fPIC -O3 -DUSE_MMAP" \ "$@"
Webサーバーを再起動して確認。
→画面上でのカタカナチェック通った ApacheとPHPで認識しているPCREに違いがあった
最後に
Ruby Gold 2.1合格できました
Ruby Goldの試験を受けてきました。
受験前にRuby Goldを受けられてきた多くの受験体験記事にかなり助けられたところがありましたので 自分の方でも合格体験記事という形で、今後受けられる方にとって参考になる部分があれば幸いです。
結果
- 92/100点(合格点:75)
試験勉強期間
- 1ヶ月(1日3〜4時間)
- 電車の行き帰り
- 帰宅後1時間程度(隙間時間も有効活用)
自分について
- 実務経験
モチベーション
- プロを目指す人のためのRuby入門(チェリー本)を読み始めてRuby熱が再び高まったことがきっかけ
- Rails特有のコード(メタプログラミング)の書き方が慣れてなく、都度都度の付け焼き刃でRailsの知識を広げていくより、Rubyの基礎体力を高めた方がRailsへの理解が効果的になるだろうと思った
勉強方法
- 公式テキストからGoldに触れられているところを繰り返し読んだ(4週くらい)
- メタプログラミングRubyの2〜5章を繰り返し読んだ(4週くらい)
- ビルの「このメソッドは複雑すぎる!」的なセリフが癖に
- オブジェクト指向のメソッド探索など読んでもわからなかったり穴がありそうなところは、irbでチェックし補強した
- ITトレメ 3〜4週
- tamata78さんのRuby Gold対策記事を3週くらい
- その他受験体験者の方々のブログなどから問題の傾向をチェック
- 試験前日に模擬問題(模擬問題参照)を発掘した。この時点で85点とってて、間違えたところはirbでチェック
受験当日の振る舞い
- 立ち上がり10問目まで
- 標準添付ライブラリなど多様な問題が連続するので、向こうのペースに嵌らないようメンタルを取り戻すよう心がけた
- 折り返し地点から見慣れた問題が増えてきた
- コードが長い問題もでてくるが、何について問われているのかの本質さえ見誤らなければ冷静に対処できる
- 試験には後で見直すチェックができるので有効活用する
- 少しでもわからない場合は回答しつつ、後で見直すチェックをし、ひと通り回答したあとは順番に見直しをした
- メモシートを使って試験の感触を大雑把に見積もってた
- 正答確度の高い問題のみ正の字を書いたりして試験の感触を予測してた
- 自分は40箇所くらい確度高い判断だった
参考
模擬問題
参考記事
参考書籍
- プロを目指す人のためのRuby入門 言語仕様からテスト駆動開発・デバッグ技法まで (Software Design plusシリーズ)
- [改訂2版]Ruby技術者認定試験合格教本(Silver/Gold対応)Ruby公式資格教科書
- メタプログラミングRuby 第2版
- 最強の独学術 自力であらゆる目標を達成する「勝利のバイブル」
- 受験体験が乗っている本などから試験の参考にすることへの重要性について述べています
Refinementsメモ
Ruby2.1で追加されたRefinementsのメモ
バージョンは、2.1.10にて確認
class Parent def hoge puts "Parent::hoge" end end class Child < Parent def hoge puts "Child::hoge" end end module RefineExample refine Child do def hoge2 puts "RefineExample::Child::hoge2" end def hoge super puts "RefineExample::Child::hoge" end end end h = Child.new h.hoge # Child::hoge p Child.ancestors # [Child, Parent, Object, Kernel, BasicObject] p h.methods().grep(/hoge/) # [:hoge] h2 = Child.new using RefineExample # Child::hoge # RefineExample::Child::hoge h2.hoge h2.hoge2 # RefineExample::Child::hoge2 p Child.ancestors # [Child, Parent, Object, Kernel, BasicObject] p h2.methods().grep(/hoge/) # [:hoge]
メモ
- usingしたタイミングでRefinementsに切り替わる
- インスタンス作成前でも後でも関係なしに
- refineのメソッド内でsuperを指定すると、refine元のメソッドがコールされる
- refineされてもModule#ancestorsの中身は変化しない
- refineされてもobj.methodsの中身は変化しない
Rubyでinclude/prependがそれぞれ連続したときの継承ツリー
Ruby Association Certified Ruby Programmer Gold version 2.1取得に向けてincludeとprependの動きを確認。
include
クラスの上に、最後に定義された順でモジュールが積み上がっていくイメージと覚える。
module M1; end module M2; end module M3; end class C1 include M1 include M2 include M3 end C1.ancestors # [C1, M3, M2, M1, Object, Kernel, BasicObject]
prepend
クラスの下に、最初に定義された順でモジュールがぶら下がっていくイメージと覚える。
module M1; end module M2; end module M3; end class C1 prepend M1 prepend M2 prepend M3 end C1.ancestors # [M3, M2, M1, C1, Object, Kernel, BasicObject]
親子クラスで同じモジュールをinclude / prependした場合
継承ツリー上、同じモジュールは複数セットされない。 親クラスのモジュールの定義が優先される。
include
module M1; end class P1 include M1 end class C1 < P1 include M1 end C1.ancestors # [C1, P1, M1, Object, Kernel, BasicObject]
prepend
module M1; end class P1 prepend M1 end class C1 < P1 prepend M1 end C1.ancestors # [C1, M1, P1, Object, Kernel, BasicObject]
include / prepend混合
module M1; end module M2; end module M3; end class P1 include M1 include M2 include M3 end class C1 < P1 prepend M2 end C1.ancestors # [C1, P1, M3, M2, M1, Object, Kernel, BasicObject]