-
Notifications
You must be signed in to change notification settings - Fork 82
Expand file tree
/
Copy pathsessionhandler.xml
More file actions
240 lines (210 loc) · 9 KB
/
sessionhandler.xml
File metadata and controls
240 lines (210 loc) · 9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<!-- EN-Revision: 62126c55f1c6ed444043e7272c4f9e233818a44b Maintainer: takagi Status: ready -->
<reference xml:id="class.sessionhandler" role="class" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude">
<title>SessionHandler クラス</title>
<titleabbrev>SessionHandler</titleabbrev>
<partintro>
<!-- {{{ SessionHandler intro -->
<section xml:id="sessionhandler.intro">
&reftitle.intro;
<para>
<classname>SessionHandler</classname> は特殊なクラスで、
これを継承したクラスを作れば PHP が内部的に使っているセッション保存ハンドラを拡張できます。
このクラスには七つのメソッドがあり、それぞれが七つのセッション保存ハンドラコールバック
(<parameter>open</parameter>, <parameter>close</parameter>,
<parameter>read</parameter>, <parameter>write</parameter>, <parameter>destroy</parameter>, <parameter>gc</parameter> および <parameter>create_sid</parameter>)
に対応しています。デフォルトでは、このクラスは
<link linkend="ini.session.save-handler">session.save_handler</link> で定義された内部セッションハンドラをラップします。
通常は <parameter>files</parameter> がデフォルトになっています。
それ以外には、PHP の拡張モジュールとして提供されている SQLite (<parameter>sqlite</parameter>) や
Memcache (<parameter>memcache</parameter>) そして Memcached (<parameter>memcached</parameter>) が使えます。
</para>
<para>
<classname>SessionHandler</classname> のインスタンスを
<function>session_set_save_handler</function> でハンドラとして指定すると、
そのインスタンスが現在の保存ハンドラをラップします。
<classname>SessionHandler</classname> を継承したクラスを作ると、
親クラスのメソッド、つまり PHP の内部セッションハンドラのメソッドをラップして
オーバーライドしたり処理を割り込ませたりフィルタをかけたりできるようになります。
</para>
<para>
これを利用すると、たとえば <parameter>read</parameter> と <parameter>write</parameter>
メソッドに処理を割り込ませ、セッションデータの暗号化/復号の処理を追加することができます。
あるいは、ガベージコレクションコールバック <parameter>gc</parameter>
を完全に自前の処理で置き換えてしまうこともできます。
</para>
<para>
<classname>SessionHandler</classname> は現在の内部保存ハンドラのメソッドをラップしているので、
先述の暗号化の例は任意の保存ハンドラに適用することができます。その際に、ハンドラの内部的な動きを知っておく必要はありません。
</para>
<para>
このクラスを使うには、まず最初に公開したいハンドラを
<link linkend="ini.session.save-handler">session.save_handler</link> で設定してから、
<classname>SessionHandler</classname> あるいはそれを継承したクラスのインスタンスを
<function>session_set_save_handler</function> に渡します。
</para>
<para>
このクラスのコールバックメソッドは PHP が内部的にコールするものであり、
ユーザーのコードから呼ばれることは想定していないことに注意しましょう。
コールバックの戻り値も、PHP が内部的に利用するだけです。
セッションの処理の流れについての詳しい情報は
<function>session_set_save_handler</function> を参照ください。
</para>
</section>
<!-- }}} -->
<section xml:id="sessionhandler.synopsis">
&reftitle.classsynopsis;
<!-- {{{ Synopsis -->
<classsynopsis class="class">
<ooclass>
<classname>SessionHandler</classname>
</ooclass>
<oointerface>
<modifier>implements</modifier>
<interfacename>SessionHandlerInterface</interfacename>
</oointerface>
<oointerface>
<interfacename>SessionIdInterface</interfacename>
</oointerface>
<classsynopsisinfo role="comment">&Methods;</classsynopsisinfo>
<xi:include xpointer="xmlns(db=http://docbook.org/ns/docbook) xpointer(id('class.sessionhandler')/db:refentry/db:refsect1[@role='description']/descendant::db:methodsynopsis[@role='SessionHandler'])">
<xi:fallback/>
</xi:include>
</classsynopsis>
<!-- }}} -->
</section>
<section xml:id="session.notes">
&reftitle.notes;
<warning>
<para>
このクラスは現在の PHP 内部セッション保存ハンドラを公開するように作られています。
自作の保存ハンドラを用意したい場合は、<classname>SessionHandler</classname>
を継承するのではなく <classname>SessionHandlerInterface</classname>
を実装したクラスを作るようにしましょう。
</para>
</warning>
</section>
<section xml:id="sessionhandler.examples">
&reftitle.examples;
<example>
<title>
<classname>SessionHandler</classname> を使って PHP の保存ハンドラに暗号化機能を追加する例
</title>
<programlisting role="php">
<![CDATA[
<?php
/**
* decrypt AES 256
*
* @param data $edata
* @param string $password
* @return decrypted data
*/
function decrypt($edata, $password) {
$data = base64_decode($edata);
$salt = substr($data, 0, 16);
$ct = substr($data, 16);
$rounds = 3; // キーの長さに依存します
$data00 = $password.$salt;
$hash = array();
$hash[0] = hash('sha256', $data00, true);
$result = $hash[0];
for ($i = 1; $i < $rounds; $i++) {
$hash[$i] = hash('sha256', $hash[$i - 1].$data00, true);
$result .= $hash[$i];
}
$key = substr($result, 0, 32);
$iv = substr($result, 32,16);
return openssl_decrypt($ct, 'AES-256-CBC', $key, true, $iv);
}
/**
* crypt AES 256
*
* @param data $data
* @param string $password
* @return base64 encrypted data
*/
function encrypt($data, $password) {
// 暗号学的にセキュアな、ランダムなソルト値を、random_bytes() を使って生成します。
$salt = random_bytes(16);
$salted = '';
$dx = '';
// Salt the key(32) and iv(16) = 48
while (strlen($salted) < 48) {
$dx = hash('sha256', $dx.$password.$salt, true);
$salted .= $dx;
}
$key = substr($salted, 0, 32);
$iv = substr($salted, 32,16);
$encrypted_data = openssl_encrypt($data, 'AES-256-CBC', $key, true, $iv);
return base64_encode($salt . $encrypted_data);
}
class EncryptedSessionHandler extends SessionHandler
{
private $key;
public function __construct($key)
{
$this->key = $key;
}
public function read($id)
{
$data = parent::read($id);
if (!$data) {
return "";
} else {
return decrypt($data, $this->key);
}
}
public function write($id, $data)
{
$data = encrypt($data, $this->key);
return parent::write($id, $data);
}
}
// この例では標準の 'files' ハンドラを横取りしていますが、他のネイティブハンドラである
// PHP 拡張モジュール 'sqlite'、'memcache'、'memcached'
// の場合でもまったく同じように使えます。
ini_set('session.save_handler', 'files');
$key = 'secret_string';
$handler = new EncryptedSessionHandler($key);
session_set_save_handler($handler, true);
session_start();
// $_SESSION への値の設定や格納されている値の取得を進めます
]]>
</programlisting>
</example>
<note>
<para>
このクラスのメソッドは、セッション処理の一環として PHP が内部的にコールするためのものとして作られています。
そのため、子クラスから親のメソッド (実際のネイティブハンドラ) をコールすると、
(自動で開始するか、あるいは <function>session_start</function> を実行するなどして)
セッションを実際に開始していない限りはその戻り値が &false; となります。
この点は、ユニットテストを書く際に注意が必要です。というのも、
ユニットテストではクラスのメソッドを手動でコールする可能性があるからです。
</para>
</note>
</section>
</partintro>
&reference.session.entities.sessionhandler;
</reference>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->