読者です 読者をやめる 読者になる 読者になる

バカンス駆動開発

この前バカンスって言ったら「古っ」って言われました

PHPのsessionファイルの生成場所、中身、有効期限など

PHPでセッションを開始すると$_SESSIONに値を出し入れできますが実態はsessionファイルに物理的に書き込まれています。*1
中身見たことなかったのでちょっと調べました。

sessionファイルの場所

生成場所の優先順位

  1. php.iniのsession.save_path
  2. php.iniのsys_temp_dir
  3. /tmpとか

sess_v4vqefhjjllja1bqsabekihpc4みたいな感じでsess_xxxxxxxxxxxxxxという名前のファイル名で保存されます。

sessionファイルの中身

試しにこれを実行すると

<?php
session_start();
$_SESSION['hoge'] = 'hoge';
$_SESSION['huga'] = 'huga';

自分の環境だと/tmp/sess_v4vqefhjjllja1bqsabekihpc4が生成されました。中身をみると

cat /tmp/sess_v4vqefhjjllja1bqsabekihpc4

// 結果
hoge|s:4:"hoge";huga|s:4:"huga";

ぱっと見配列をserialize()したものっぽいですが微妙に違います。
session_encodeという関数を使ってエンコードしているようです。
PHP: session_encode - Manual

デフォルトのアンシリアライズの方法は PHP が内部的に実装しているものであり、 unserialize() とは違います。 シリアライズの方法は、session.serialize_handler で設定できます。

phpinfoを確認するとsession.serialize_handlerにはphpと設定されていました。これがデフォルト値です。試しにphp_serializeに変えてphpを再起動してsessionファイルを確認してみると

cat /tmp/sess_v4vqefhjjllja1bqsabekihpc4

// 結果
a:2:{s:4:"hoge";s:4:"hoge";s:4:"huga";s:4:"huga";}

とまぁおなじみのシリアライズされた文字列になりました。ハンドラがデフォルトのphpだと$_SESSIONの中で数値のインデックスや特殊文字 (| や !) を含む文字列のインデックスが使えません。

sessionファイル名とセッションID

リクエストヘッダーを見るとv4vqefhjjllja1bqsabekihpc4というセッションIDを送っています。

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip, deflate, sdch
Accept-Language:ja,en-US;q=0.8,en;q=0.6,de;q=0.4,fr;q=0.2,ko;q=0.2
Cache-Control:max-age=0
Connection:keep-alive
Cookie:PHPSESSID=v4vqefhjjllja1bqsabekihpc4 // ←!
Host:local.example.com
Upgrade-Insecure-Requests:1

クライアントから送信されたセッションIDとsessionファイルの関連付けをどうやっているのかというとそのままセッションIDに接頭辞としてsess_をつけているだけだけでした。セッションIDをそのままファイル名に使っているというのはなにやら不安な気持ちになりますね。

session_regenerate_id ()を実行するとセッションIDが新しく変わるので新しいsess_xxxxxxが生成され、クライアントに新しいセッションIDを返します。

有効期限

セッションスタート時にgcが走ります。
sessionファイルのうち生成からsession.gc_maxlifetime秒経っているファイルが対象で、session.gc_divisor分のsession.gc_probabilityの確率で削除が実行されます。

*1:デフォルトでは。

phpenvで複数バージョンのPHPを同時に利用する

1つのvagrantで複数のPHPを同時に利用できるようにします。この記事では5.6.23と7.0.0を共存させます。

CentOS6.5でapache2.4.6+PHP-FPMの構成です。

phpenv,php-buildはインストールされている前提で始めます。

起動スクリプトの用意とListenするポートの設定

php5.6.23のインストール

$ phpenv install 5.6.23

[Info]: Loaded extension plugin
[Info]: Loaded apc Plugin.
[Info]: Loaded composer Plugin.
[Info]: Loaded github Plugin.
[Info]: Loaded uprofiler Plugin.
[Info]: Loaded xdebug Plugin.
[Info]: Loaded xhprof Plugin.
[Info]: php.ini-production gets used as php.ini
[Info]: Building 5.6.23 into /home/vagrant/.phpenv/versions/5.6.23
[Downloading]: https://secure.php.net/distributions/php-5.6.23.tar.bz2
[Preparing]: /tmp/php-build/source/5.6.23
[Compiling]: /tmp/php-build/source/5.6.23
[xdebug]: Installing version 2.3.3
[xdebug]: Compiling xdebug in /tmp/php-build/source/xdebug-2.3.3
[xdebug]: Installing xdebug configuration in /home/vagrant/.phpenv/versions/5.6.23/etc/conf.d/xdebug.ini
[xdebug]: Cleaning up.
[Info]: Enabling Opcache...
[Info]: Done
[Info]: The Log File is not empty, but the Build did not fail. Maybe just warnings got logged. You can review the log in /tmp/php-build.5.6.23.20160911071038.log
[Success]: Built 5.6.23 successfully.

// 設定ファイルを作成
$ cp /home/vagrant/.phpenv/versions/5.6.23/etc/php-fpm.conf.default /home/vagrant/.phpenv/versions/5.6.23/etc/php-fpm.conf

サービスに追加

// 起動スクリプトを移動
sudo cp /tmp/php-build/source/5.6.23/sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm-5.6.23
// 実行権限付与
sudo chmod 775 /etc/init.d/php-fpm-5.6.23
// システム起動時に自動起動するように設定
sudo chkconfig php-fpm-5.6.23 on
// 確認
sudo chkconfig --list | grep php-fpm

php-fpm-5.6.23  0:off   1:off   2:on    3:on    4:on    5:on    6:off

ポートを変更

FPMはデフォルトで9000番のポートをリッスンするようになっていますが、複数バージョンのPHPを共存させる場合はこのポート番号をずらして運用します。

vi /home/vagrant/.phpenv/versions/5.6.23/etc/php-fpm.conf

listen = 127.0.0.1:9000
↓
listen = 127.0.0.1:9001

同じことをPHP7.0.0で繰り返します。ポートは9002にします。

vi /home/vagrant/.phpenv/versions/7.0.0/etc/php-fpm.conf

listen = 127.0.0.1:9000
↓
listen = 127.0.0.1:9002

注)etc/php-fpm.confにlistenの記述がない場合は、etc/conf.d/www.confにあると思うのでそちらを変更してください。

vhostsの設定

あとはvhostsの設定でドメインごとにfcgiに投げるポート番号を対応させればOKです。

  • local.php5 → 9001番ポート
  • local.php7 → 9002番ポート
## PHP5.6.23
<VirtualHost *:80>
  ServerName local.php5
  #DocumentRoot /var/www/html/php5
  <FilesMatch \.php$>
    SetHandler application/x-httpd-php
  </FilesMatch>
  ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9001/var/www/html/php5/$1
  <Directory "/var/www/html/php5">
    AllowOverride All
    Options -Indexes +FollowSymLinks
    Require all granted
  </Directory>
</VirtualHost>

## PHP7.0.0
<VirtualHost *:80>
  ServerName local.php7
  <FilesMatch \.php$>
    SetHandler application/x-httpd-php
  </FilesMatch>
  ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9002/var/www/html/php7/$1
  <Directory "/var/www/html/php7">
    AllowOverride All
    Options -Indexes +FollowSymLinks
    Require all granted
  </Directory>
</VirtualHost>

ブラウザから見てみる

それぞれのパブリックにphpinfo()スクリプトを置いて、

http://local.php5 f:id:egapool:20160911171148p:plain

http://local.php7 f:id:egapool:20160911171756p:plain

あとがき

個人的なポイントとしては起動スクリプトにバージョン名を入れてわかりやすくしたところですかね。あと試してないですがunixソケットで通信する場合はphp-fpm.sockをphp-fpm-なんとか.confで複数つくれば良いのかなぁ。それはまた今度。

ajaxのエラー(500 internal server error)の解決方法

ajax通信処理でこの画像のように500 (Internal Server Error)と表示さる場合、js側ではなくサーバープログラムが間違っています。

f:id:egapool:20160903155605p:plain

どういうエラーなのか確かめるにはデベロッパーツールのNetworkタブを確認します。サーバーからレスポンスを受け取った以降のすべての通信内容がNetworkに表示されます。

f:id:egapool:20160903161022p:plain

エラーで返ってきた通信(ここはではajax.php)をクリックして右に出てくるパネルのPreviewタブを見るとエラー内容を確認できます。

f:id:egapool:20160903161314p:plain

500エラーで返ってきているのにPreviewタブに何も表示されない場合は、サーバー側でエラーを出力させない設定になっている可能性があります。
その場合は該当のPHP処理の先頭で

<?php
ini_set('display_errors',1);

と記述してみてください。

エラー内容を確認して原因が明らかな場合はそこを修正しておしまい。ただどこがバグの原因かわからない場合はデバッグしてく必要があります。

ひとつはprintデバッグです。printやvar_dumpを挟んでデバッグします。直後にexitかdieさせればprint内容もNetworkタブのPreviewタブで確認できます。

f:id:egapool:20160903162414p:plain

もう一つデバッガーです。ajaxリクエストもステップ実行が可能なのでそれで確認していきます。

以上、ajaxエラーの原因突き止め方法でした。

余談)google search consoleで検索ワード見てると「ajax 500 internal server error」とかでこのブログが表示されている回数が多かったのでちょっと書いてみました。

Ansible+Vagrant(ansible_localプロビジョナ)でPHPのローカル開発環境を作る

注意

この記事ではVagrant1.8から導入されたansible_localプロビジョナを使用していますが、現在インストールされるansibleのバージョンが上がってしまいVagrant側がまだそれに対応していません。 issueにも上がっていますので近々対応されるかも・・?

github.com

なので現状うごきません・・!

進展があったら追記していきます。

追記(2016/06/18)

追記時点でVagrantのバージョン1.8.4が公開されており、このバージョンでは上記の不具合は解消されております。

使い方

github.com

git clone git@github.com:egapool/centos66-ansible.git
cd centos66-ansible
vi Vagrantfile // プライベートIPとsynced_folderを各自の環境に合わせて編集

vhosts.confに記載する内容のベースとなる情報(ドメインとパブリックディレクトリのパス)を予め与えると自動でvhostsに記述されます。 下の例のようにapache_vhosts_sslに記載するとSSL自己証明書の自動生成も行います。

(略)
- role: apache
      apache_vhosts:
        - {servername: "local.example.com", documentroot: "/var/www/html/example/public"}
      apache_vhosts_ssl:
        - {servername: "local.sslexample.com", documentroot: "/var/www/html/sslexample/public"}

(略)

準備が整ったら

vagrant up

基本的にはvagrant upするだけですむようにしています。
デフォルトで以下の構成が構築されます。

Ansible

Ansibleとは構成管理ツールの一つです。類似のツールにchef,puppetなどがあります。構成管理ツールとはサーバーにインストールするミドルウェアや設定ファイルの内容などをテキスト(Ansibleではplaybookと呼びます)に書き起こし、それを元に状態を再現することを簡単にするためのツールです。これによって、大規模なサーバー管理が簡単になったり、サーバーに入り内容を確認しなくてもどんな状態かわかるなどのメリットがあります。

必要なもの

Ansibleを使用するにあたってローカルPC(ホスト側)にはVagrant以外なにも必要ありません。Ansibleすらインストールする必要がありません(後述します)。

事前知識

Ansibleの基本はこのチュートリアルをこなせば一通り学べると思います。1時間もかかりませんのでこれからAnsibleをやってみたいという方は是非チャレンジしてみてください。

Ansible チュートリアル | Ansible Tutorial in Japanese

こちらの書籍はAnsibleを使う上で必要十分な知識が載っています。値段もお買い得なのでおすすめです。

Amazon.co.jp: 入門Ansible eBook: 若山史郎: Kindleストア

また、playbookはYAMLで書きます。YAMLの文法はとても簡単なので一瞬で習得できます。こちらをオススメします。

Rubyist Magazine - プログラマーのための YAML 入門 (初級編)

ansible_localプロビジョナについて

Vagrant1.8からansible_localプロビジョナが追加されました。このプロビジョナを使うと、ゲストOSの方にansibleをインストールさせてから、ゲストOSがローカルに対してplaybookを実行します。今回はこれを使います。

roleついて

roleとはミドルウェアをインストールするひとまとまりの単位です。例えば「httpdのrole」や「phpのrole」など。一つのrole内でソフトウェアのインストールから設定ファイルの編集、再起動などを行わせます。roleはそれぞれ独立しています。

roleのディレクトリ配置(apacheの例)

└apache/
    ├ defaults/   # roleで使う変数のデフォルト設定を置くディレクトリ
    │  └ main.yml
    ├ handlers/   # ハンドラータスクを置くディレクトリ
    │  └ main.yml
    ├ tasks/      # タスク用ディレクトリ。roleを実行するとこのmain.ymlが呼ばれる
    │  └ main.yml
    ├ templates/    # 設定ファイルなどのテンプレートを置くディレクトリ
    ├ meta/
    │  └ main.yml   # メタ情報を置くディレクトリ
    └ vars/
       └ main.yml     # 変数を置くディレクトリ

playbook全体のディレクトリ配置

playbook/
    ├ hosts   # インベントリファイル。今回はローカル開発環境ということでほぼ必要なし
    ├ site.yml # playbookの起点になる処理
    └ roles/ # 各roleを配置する
        ├ commaon/
        ├ repositries/
        ├ git/
        ├ apache/
        ├ phpenv/
        ├ mysql/
        └ redis/

site.ymlについて

---
- hosts: localhost  # hostsは何か指定しないといけない
  connection: local  # localに対してplaybookを実行させる
  become: yes  # コマンドをsudoユーザーで実行するかどうか

  roles:
    - role: common  # 各ロールディレクトリのtasks/main.ymlを実行する
    - role: repositries
    ・
    ・

apache

httpでもhttpsでもplaybook実行時にservernameとdocumentrootの組を配列で指定すると指定した分だけdocumentrootディレクトリの作成と対応するvhostの設定が記述されます。 また、httpsの場合はservernameごとに秘密鍵サーバ証明書を生成します。

SSLの仕組みと各種必要なファイルの説明はこのポストが詳しいです。
オレオレ証明書をopensslで作る(詳細版) - ろば電子が詰まっている

apacheロールでは以下のモジュールをepel-httpd24レポジトリを使ってインストール。

  1. httpd24-httpd
  2. httpd24-httpd-devel
    • httpdにDSOモジュールを追加するためにapxsなどが含まれているパッケージ
      • DSO(Dynamic Shared Object)とはhttpdに後から動的に追加できるモジュールのことです。httpd.confのLoadModuleディレクティブを用いて追加/削除を行えます。
      • apxsはDSOモジュールをインストールするためのツールです。
  3. httpd24-mod_ssl
    • opensslに対するインターフェース
  4. openssl

git

ソールからビルド。
git/defaults/mains.ymlでダウンロードするソースのバージョンを指定します。

phpenv

  • CHHを使用
  • php-fpmを使用
    • php-fpmはFastCGIリクエストに対応したインターフェースを持つPHP実装です(という理解で合ってるかな・・
  • PHPの各バージョンをビルドすると/tmp/php-build/source/5.6.xx/sapi/fpm/init.d.php-fpmに起動スクリプトが吐き出されるので/etc/init.d/へコピーして、そのあとchkconfigに登録します

mysql

repositries

各種リポジトリyumでインストールします。また、すべてのサードパーティリポジトリのenabledを0にします。

repositries roleはtask/main.yml以外使用しません。インストールするリポジトリを変数ファイルに切り出しても良いかなと思いましたがそんなにころころ変わるものでもないのでひとまずこれでいきます。

PHP BLT #3 発表まとめ! #phpblt

2016年3月1日、メルカリオフィスで開催されたPHPBLT#3に参加してきました!
オーディエンスより発表者の方が多いという血気盛んなこのイベント、LT枠以外にも「ブログ書く枠」が用意されていて自分はこの枠で参加してきました。
第3回の今回初参加でしたがめちゃくちゃ面白かったです!
もうすでに第4回の募集が始まってますのでまだ参加したことないPHPerの方々は是非!(一番↓にリンクあります)

写真撮り忘れていたので@uzullaさんのつぶやきを拝借・・

では発表を紹介していきます!

続きを読む

yumのリポジトリの追加とか設定とか

サードパーティリポジトリを追加する(2016/02/01時点)

// epel
sudo rpm -Uvh "http://ftp-srv2.kddilabs.jp/Linux/distributions/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm"

//RPMForge
sudo rpm -Uvh "http://pkgs.repoforge.org/rpmforge-release/rpmforge-release-0.5.3-1.el6.rf.x86_64.rpm"

// remi
sudo rpm -Uvh "http://rpms.famillecollet.com/enterprise/remi-release-6.rpm"

//IUS
sudo rpm -Uvh "https://dl.iuscommunity.org/pub/ius/stable/CentOS/6/x86_64/ius-release-1.0-14.ius.centos6.noarch.rpm"

他のリポジトリCentOSWikiに記載されています。
AdditionalResources/Repositories - CentOS Wiki

インストールされているリポジトリ一覧を確認する

yum repolist

設定ファイルを確認する

// yumの設定ファイル
/etc/yum.conf

各項目の内容はこちら
2.2 Yumの構成

// リポジトリごとの設定ファイル
/etc/yum.repos.d/*.repo

/etc/yum.confにグローバルに設定して、/etc/yum.repos.d/*.repoで個別に上書きします。

パッケージを探す/パッケージの情報を確認する

// httpdが名前または説明に含まれるパッケージを探す
yum search httpd

// mod_sslについてremiリポジトリを指定して探す
yum search --disablerepo=* --enablerepo=remi mod_ssl

// httpdのパッケージ情報を見る
yum info httpd

// httpd24uのパッケージ情報をIUSリポジトリを指定して見る
yum info --disablerepo=* --enablerepo=ius httpd24u

雑記

基本はコマンド実行時に--enablerepo=xxリポジトリを指定して使っています。複数リポジトリを使用して依存関係が混乱するより、リポジトリは少なくしてリポジトリにないものはソースからビルドするのが良いのかどうかとかその辺りはまだ良くわかっていません。

python始めるにあたって漁った記事など

自然言語処理楽しそうだなーとかPHP飽きたなーとかでpython始めました。

pythonの始めの一歩をスタートするために読んだ記事などをメモしておきます。

現在のpythonのバージョンは3系が最新らしいのでできるだけ2系は排除する。

PHPでいうところのPHP: The Right Waypython版があれば一番助かる感じです。見つかりませんでしたが。

ドキュメント

概要 — Python 3.4.3 ドキュメント

環境構築

Mac

Macでpyenv+virtualenv - Qiita
phpenv,rubyenv的な。~~envを使うことで各言語の任意のバージョンをプロジェクトディレクトリごとに変えることができて便利です。もしかしたら2系も使うかもしれませんのでこれで入れます。素晴らしすぎますね。。

Linux

PyenvをCentOS6.3でセットアップする(超かんたんリファレンス付き) - Qiita

パッケージ管理

pipを使います。python3.4以降の場合は始めから付随してきます。

文法

Python3系 基礎文法 - Qiita

Google Python スタイルガイド — PyGuide - 2.29

Dive Into Python 3 日本語版

[python] 年末大感謝祭!初心者脱出のためのPythonTipsを50個紹介 | 私の小岩ホッチキス

Pythonらしいコードの書き方 - Kesin's diary

[python] 細かすぎて伝わりにくい、Pythonの本当の落とし穴10選 | 私の小岩ホッチキス

チュートリアル

Pythonで学ぶWebアプリ開発のABC みんなのPython Webアプリ編 HTML版(無料) | TRIVIAL TECHNOLOGIES 4 @ats のイクメン日記

php プログラマのための Python チュートリアル — phpy 0.1 documentation
PHPからpythonへ移行するためのチュートリアルです。素晴らしい!僕にぴったりじゃないですか。

Pythonでつくる検索エンジン(Webクローラ, Mecab, MongoDB, Flask) - c-bata web

Webアプリケーションフレームワークとか

PythonのWebフレームワーク6種をかんたんに紹介 - モジログ

Pythonの軽量WebフレームワークBottleを試してみた(その1) - ルーティング編 (Advent Calendar 23日目) | アライドアーキテクツ エンジニアブログ