demolog

備忘録. 雑なあまりにも雑な

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

実行結果

f:id:skit_n:20180422212244p:plain

対応方法

日本語フォントが入ってないか、フォント設定が上手くいってなかったので設定する。

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

実行結果(再実行)

f:id:skit_n:20180422212315p:plain

無事に日本語フォントが読み込まれた。

phpdotenvで環境変数を制御する

phpdotenvとは

phpdotenv(PHP dotenv)は、.envファイルに環境変数を記述することで、getenv()$_ENV$_SERVERからの環境変数呼び出しを.envファイルから取得することができる Rubydotenvライブラリがベース

特徴

インストール方法

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
)
*/

HOGEFUGEはそれぞれの環境変数ファイルから読み込まれているが、SUBDOMAINURLは上書きされていない

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
)
*/

HOGEFUGEはそれぞれの環境変数ファイルから読み込まれ、SUBDOMAINURLは上書きされた

読みこんだ環境変数の型

これらは全て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サーバーを再起動して確認。

→画面上でのカタカナチェック通った ApachePHPで認識しているPCREに違いがあった

最後に

  • 原因特定に時間がかかった
  • PHPApacheで見ている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でチェックし補強した
    • クラスメソッド内・インスタンスメソッド内・クラス内・特異クラス内のselfの違い
    • メソッド探索系の動き(複数include・複数prepend・組み合わせなど)
    • クラス変数・インスタンス変数・定数・ローカル変数のスコープ
    • オブジェクト指向系の問題が多いので、irbでなるべく動かして確認した
  • ITトレメ 3〜4週
  • tamata78さんのRuby Gold対策記事を3週くらい
  • その他受験体験者の方々のブログなどから問題の傾向をチェック
  • 試験前日に模擬問題(模擬問題参照)を発掘した。この時点で85点とってて、間違えたところはirbでチェック

受験当日の振る舞い

  • 立ち上がり10問目まで
    • 標準添付ライブラリなど多様な問題が連続するので、向こうのペースに嵌らないようメンタルを取り戻すよう心がけた
  • 折り返し地点から見慣れた問題が増えてきた
    • コードが長い問題もでてくるが、何について問われているのかの本質さえ見誤らなければ冷静に対処できる
  • 試験には後で見直すチェックができるので有効活用する
    • 少しでもわからない場合は回答しつつ、後で見直すチェックをし、ひと通り回答したあとは順番に見直しをした
  • メモシートを使って試験の感触を大雑把に見積もってた
    • 正答確度の高い問題のみ正の字を書いたりして試験の感触を予測してた
    • 自分は40箇所くらい確度高い判断だった

参考

模擬問題

参考記事

参考書籍

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]