LDIF ファイル -- Net_LDAP_Entries と LDIF ファイルとの相互変換
利用可能なバージョン
LDIF のサポートは Net_LDAP リリース 1.1.0a1 以降で追加されました。
LDIF ファイルとは?
LDIF ファイルの詳細については RFC 2849
に説明されています。簡単に言うと、これはディレクトリのデータを可読形式のテキストにしたものです。
データベースにおける SQL ファイルのようなものです。
しかし、SQL がアクションベースであるのに対して LDIF ファイルはデータが主になっている点が異なります。
LDIF ファイルの中身にはコンテンツファイルとチェンジファイルの二種類の形式があり、
これらを混ぜて使うことができます。
もっともよく使われる形式である LDIF コンテンツファイルをまず紹介します。
例 54-1LDIF コンテンツファイルの例 #
# This is a content LDIF file.
# It contains one single entry featuring several
# attributes and one comment (this one).
# attr1, attr4 and cn are single valued, the others are
# multivalued. objectclass is a special case, LDAP servers
# will interpret this operational attribute to define the
# classes the object will belong to and thus, which attributes
# it may contain. the OCL-attribute is usually multivalued.
#
version: 1
dn: cn=test1,ou=example,dc=cno
objectclass: someobjectclass
attr1: 12345
attr2: 1234
attr2: baz
attr3: foo
attr3: bar
attr4: brrrzztt
cn: test1 |
|
LDIF ファイルに記述できるのはエントリのデータだけではありません。
エントリ自体への変更についても記述することができます。
そのような LDIF ファイルを LDAP サーバに渡すと、
データをインポートするのではなくその変更をサーバに適用します。
以下の例でお気づきのように、LDIF の中にはコンテンツとチェンジを両方含めることができます。
ただしこれらは別のエントリという扱いになります。
ひとつのエントリはコンテンツあるいはチェンジのいずれかを表すものであり、
その両方を指定することはできません。
例 54-2LDIF チェンジファイル #
# This is a content+change LDIF file.
# It does contain the (shortened) entry from the example above to show
# that LDIF files can contain multiple entry modes.
# The second entry is a change entry. In this case, some
# operations will be done on the entries attributes.
#
version: 1
dn: cn=test1,ou=example,dc=cno
objectclass: someobjectclass
attr1: 12345
cn: test1
# Delete attr1, replace values of attr2 and add new attribute attr42
# The attribute "changetype" is special: it says, what to do with
# this entries dataset. It could also be "delete" or "add" to delete
# a whole entry or to add a completely fresh one. "modrdn" will
# move the entry to a new location once the LDIF file is imported.
dn: cn=test2,ou=example,dc=cno
changetype: modify
delete: attr1
-
replace: attr2
attr2: 123456_newtest
-
add: attr42
attr42: the answer |
|
Net_LDAP_LDIF でのエラー処理
Net_LDAP_LDIF を使い始める前に、まずエラー処理の方法について説明しておきましょう。
Net_LDAP_LDIF の API の大半は、お手本となった Perl の
Net::LDAP::LDIF と同じです。ということは、Net_LDAP_LDIF
のメソッドは Net_LDAP_Error オブジェクトを返さないということです。
代わりに error() メソッドを使う必要があります。
このメソッドは、エラー時には Net_LDAP_Error オブジェクトを返し、
すべてうまくいっている場合には true を返します。LDIF 読み込みモードでは、
さらに error_lines() を使うこともできます。
これは、入力ファイルのどこでエラーが発生したのかを取得するためのものです。
オブジェクトの作成とそのオプション
LDIF ファイルの読み書きどちらを行うかにかかわらず、LDIF ファイルを使用するには
Net_LDAP_LDIF のコンストラクタを用いてそのインスタンスを作成しなければなりません。
Net_LDAP_LDIF() には、少なくとも使用するファイルへのパスを渡す必要があります。
2 番目のパラメータとして、オープン時のモードを指定することもできます。
使用できるオープンモードは "r" (読み込み)、"w" (書き込み、最初にファイルをクリアする)
そして "a" (追記) のいずれかです。省略した場合は読み込みモードとみなします。
オプションの 3 番目のパラメータには、以下のようなオプションを含む連想配列を指定することができます。
表 54-1使用できる設定オプション
名前 | 説明 | デフォルト |
---|
encode |
LDIF の DN の値の中には、そのままでは書き込めず何らかのエンコードを要するものもあります。
"none"、"canonical" あるいは "base64" (RFC のデフォルト) のいずれかを指定します。
| base64 |
onerror |
エラーが発生したときにどうするかを指定します。
"undef" はエラー処理をプログラマに任せます。
この場合は error() と error_lines()
を用いて手動でエラー処理を行うことになります。
"die" の場合はエラーを表示してその場でスクリプトを終了させます。
これはコマンドラインのスクリプトなどで有用です。
"warn" はエラーを表示しますが、それ以外の挙動は "undef" と同様です。
| undef |
change | これを "1" (true) にすると Net_LDAP_LDIF はコンテンツファイルではなくチェンジセットを書き出します。 | false |
lowercase | これを true にすると、書き込み時に属性の名前を小文字に変換します。 | 0 |
sort |
true にすると、エントリの書き込み時に属性名を並べ替えます。まず最初が
objectclass で、それに続けてその他の属性をアルファベット順に並べます。
| 0 |
version |
書き込み時に、作成する LDIF のバージョンを設定します。
RFC 2849 によると、今のところこのオプションに指定できる値は 1 だけです。
| 1 |
wrap |
出力時に行の折り返しを行う桁数。40 以下を指定した場合は折り返しを行いません。
できあがるファイルの可読性を上げるために有用です。
| 78 |
熟練者向けの情報: ファイルのパスではなく、事前に作成済みのファイルハンドルを渡すこともできます。
その場合はモードの指定は無視されます。これを使用すると、
ふたつの Net_LDAP_LDIF インスタンスで同じファイルハンドルを共用することで
LDIF コンテンツと LDIF チェンジセットを同じファイルに書き込むことができます。
それ以外の場合でもこの機能は便利です。
ふたつめ以降の Net_LDAP_LDIF インスタンスを作成する際には、
handle() を使用して最初のインスタンスのファイルハンドルを取得します。
Net_LDAP_Entry オブジェクトへの LDIF ファイルの読み込み
Net_LDAP_LDIF の 2 つのモードのうちのひとつが、
LDIF ファイルを読み込んでそれをパースし、 Net_LDAP_Entry オブジェクトの配列にするものです。
これは read_entry() メソッドで行います。
このメソッドは、次のエントリを返します。すべてのエントリを取得したい場合は、
eof() を用いて入力ファイルの終端を検出します。
例 54-3LDIF ファイルを Net_LDAP_Entry オブジェクトに渡す // LDIF ファイルを読み込みモードでオープンします
$ldif = new Net_LDAP_LDIF('somefile.ldif', 'r');
if ($ldif->error()) {
$error_o = $ldif->error(); // エラー時は Net_LDAP_Error オブジェクトを取得します
die('ERROR: '.$error_o->getMessage());
}
// LDIF ファイルのエントリをパースし、オブジェクトに格納します
do {
$entry = $ldif->read_entry();
if ($ldif->error()) {
// エラー時にはエラーを表示します。
// ここでは短縮パラメータを使用しているので、error()
// は Net_LDAP_Object ではなく文字列を返します
die('ERROR AT INPUT LINE '.$ldif->error_lines().': '.$ldif->error(true));
} else {
// エラーなし: エントリに対して何らかの処理をします
// ここでは単にエントリの DN を表示しています
echo 'sucessfully parsed '.$entry->dn();
}
} while (!$ldif->eof());
// 最後は done() をコールします
$ldif->done(); |
|
Net_LDAP_Entry オブジェクトの LDIF コンテンツファイルへの書き出し
LDIF ファイルへの書き出しも非常に簡単です。
単に、書き出したいエントリを write_entry()
メソッドに渡すだけでいいのです。注意しなければならないのは、
ファイルを "w" モードでオープンした場合は
そのファイルにこれまで書かれていたデータがすべて消えてしまうということです。
単にデータを追加したいだけの場合は "a" (追記) モードでオープンしましょう。
例 54-4エントリの書き込み // $entries の中には Net_LDAP_Entry オブジェクトが格納されているものとします
// $entries = array( ... );
// 書き込み用にファイルをオープンします
$ldif = new Net_LDAP_LDIF('somewritefile.ldif', 'w');
if ($ldif->error()) die('ERROR: '.$error_o->getMessage());
// データを書き込み、エラーチェックをします
// 単一の Net_LDAP_Entry オブジェクトか、
// オブジェクトの配列を渡します
$ldif->write_entry($entries);
if ($ldif->error()) die('WRITE ERROR: '.$error_o->getMessage()); |
|
Net_LDAP_Entry オブジェクトの LDIF チェンジファイルへの書き出し
変更内容の書き出し処理は、コンテンツの書き出しと同じです。
しかし、違うところがふたつあります。まず、オプションとして "changes"
を渡さなければなりません。また、書き込む内容が変更でなければなりません。
変更を含まないエントリを指定した場合は、何も書き出されません。
例 54-5エントリの変更の書き出し // テストデータと 3 つのエントリを用意します
$testattrs = array(
'attr1' => '1234',
'attr2' => 'foo',
'attr3' => array('bar', 'baz')
);
$entries = array(
Net_LDAP_Entry::createFresh('cn=foo,dc=example,dc=cno',
array_merge(array('cn' => 'foo'), $testattrs)),
Net_LDAP_Entry::createFresh('cn=bar,dc=example,dc=cno',
array_merge(array('cn' => 'bar'), $testattrs)),
Net_LDAP_Entry::createFresh('cn=baz,dc=example,dc=cno',
array_merge(array('cn' => 'baz'), $testattrs))
);
// 最初のエントリと最後のエントリに変更を加えます
$entries[0]->add(array('someattr' => 'added'));
$entries[0]->replace(array('attr1' => 'replaced'));
$entries[2]->delete(array('attr2'));
$entries[2]->delete(array('attr3' => 'bar'));
// 書き込み用のファイルを change モードでオープンします
$ldif = new Net_LDAP_LDIF('somewritefile.ldif', 'w', array('change' => true));
if ($ldif->error()) die('ERROR: '.$error_o->getMessage());
// データを書き込み、エラーチェックをします
// 単一の Net_LDAP_Entry オブジェクトか、
// オブジェクトの配列を渡します
$ldif->write_entry($entries);
if ($ldif->error()) die('WRITE ERROR: '.$error_o->getMessage());
// LDIF ファイルに含まれるのは
// cn=foo,dc=example,dc=cno と cn=baz,dc=example,dc=cno のふたつだけです。
// cn=bar,dc=example,dc=cno には変更が加えられていないのでスキップされます。 |
|
例 54-6できあがった LDIF チェンジファイル version: 1
dn: cn=foo,dc=example,dc=cno
changetype: modify
add: someattr
someattr: added
-
replace: attr1
attr1: replaced
-
dn: cn=baz,dc=example,dc=cno
changetype: modify
delete: attr2
-
delete: attr3
attr3: bar
- |
|
LDIF データの取得
時には LDIF ファイルの内容を読み込みたいこともあるでしょう。
その際には current_lines() メソッドや
next_lines() メソッドを使用します。
これらのメソッドの挙動は、ちょっととまどうことがあるかもしれません。
current_lines() が返す行は、常に現在の
Net_LDAP_Entry オブジェクトで read_entry()
の後に current_entry() をコールしたときの行と同じものになります。
next_lines() が返す行は、その時点での次のエントリのものとなります。
つまり "最後に読んだエントリの次のエントリ" ということです。
しかし、この挙動をオーバーライドすることもできます。
next_lines() で "force" パラメータを使用すると、
全エントリをループするようになります。current_entry()
の挙動はまさに current_lines() と同じようになります。
読み込んだ行情報を Net_LDAP_Entry オブジェクトにしたい場合は、
parseLines() メソッドで行をパースしてエントリに格納します。
これは、巨大な LDIF ファイルの一部のエントリだけを使いたい場合に便利です。
例 54-7LDIF の行の読み込み // LDIF ファイルを読み込み用にオープンします
// (この例では読みやすくするためにエラーチェックを省略していますが、
// 実際に使用する際には必ずエラーチェックをしましょう!)
$ldif = new Net_LDAP_LDIF('somefile.ldif', 'r');
// まだ何も読んでいないので、これは空の配列を返します
$empty_array = $ldif->current_lines();
// ではまず、最初のエントリのデータを読んでみましょう
$first_entry_lines = $ldif->next_lines();
// もう一度コールしたとしても、2 番目のエントリを読むわけではありません。
// これはもう一度最初の行を読むことになります!
$first_entry_lines_again = $ldif->next_lines();
// ここで current_lines() をコールしても、
// 先ほどと同様に次には進みません
$empty_array_again = $ldif->current_lines();
// 次に進めたい場合は read_entry() メソッドを使用します。
// これは、読み込んだ後に次に進みます
$first_entry = $ldif->read_entry();
// ここで、current_lines() は最初のエントリを返します。
// 一方 next_lines() は 2 番目の行を返します。
$first_entry_lines = $ldif->current_lines();
$second_entry_lines = $ldif->next_lines();
// 行を移動するにはもうひとつのやりかたもあります。
// もし LDIF のコンテンツを読みたいだけなのならこちらのほうが高速です。
// この場合は "force" パラメータを next_lines() に渡します
$third_entry_lines = $ldif->next_lines(true);
$fourth_entry_lines = $ldif->next_lines(true);
$fifth_entry_lines = $ldif->next_lines(true);
// 行を Net_LDAP_Entry に変換したい場合は
// parseLines() を使用します
$fourth_entry = $ldif->parseLines($fourth_entry_lines);
// 手動で移動させたのは行だけなので、
// current_lines() は直近の Net_LDAP_Entry オブジェクト
// (最初のエントリ) の行を返します
$first_entry_lines = $ldif->current_lines();
// 次のエントリに移動したい場合は、このようにします
$sixth_entry = $ldif->read_entry();
// これで current_lines() が移動しました
$sixth_entry_lines = $ldif->current_lines(); |
|