LDIF files

LDIF files – Converting between Net_LDAP2_Entries and LDIF files

Avaible since

LDIF support was added to Net_LDAP2 in release 1.1.0a1.

What are LDIF files?

LDIF files are in detail described at RFC 2849. Shortly, they contain data records in an plain text, human readable format, much like a SQL file does. An LDIF file specifies a set of directory entries, or a set of changes to be applied to directory entries, but not both at the same time: the formats cannot be mixed inside the same file. LDIF-content files are very usable for manual transporting data or for full backups. LDIF-change files are an easy way to perform adjustments to a database like automated data synchonisation. LDIF files can contain comments (first character on line is a hash "#") which are very useful in case humans need to interpret or read the data.

Example LDIF content file

#
# 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 files could describe not only the data an entry contains, but also various changes to the entry itself. If such an LDIF file would then be given to a LDAP server, he would interpret those changes instead just importing the data. It is comparable to a diff file on unix and familiar to the SQL dump.

Example LDIF change file

# 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

Error handling when using Net_LDAP2_LDIF

Before we can start using Net_LDAP2_LDIF we must say some short words about how error handling works. Net_LDAP2_LDIF was designed to have mostly the same API as the original PERL Net::LDAP::LDIF has. Because of this, the methods of Net_LDAP2_LDIF do not return a Net_LDAP2_Error object. You must use the error() method that will return a Net_LDAP2_Error object in case of failure or true in case everything was ok. In LDIF reading mode, you can additionally use error_lines() to get knowledge about where in the input file the error occured.

Construction and options

Regardless if you want to read or write a LDIF file, you always have to use the constructor of Net_LDAP2_LDIF to initialize your access to the LDIF file. You need to pass at least one parameter to Net_LDAP2_LDIF(): the path of the file that should be read or written. You may pass the open mode as second parameter. The possible file open modes are "r" (read), "w" (write, clears the file first) and "a" (append to the end). In case you omit the open mode, read mode is assumed. The third optional parameter is an associative array containing one or several of the following options:

Possible configuration options
Name Description Default
encode Some DN values in LDIF cannot be written verbatim and have to be encoded in some way. Possible values are: "none", "canonical" and "base64" (RFC default) base64
onerror What should be done on errors? "undef" will let error handling in your hands, in this case you use error() and error_lines() to process errors manually. "die" aborts the script printing the error - this is sometimes useful for CLI scripts. "warn" just prints out the error but continues like "undef" would. undef
change Turning this to "1" (true) will tell Net_LDAP2_LDIF to write change sets instead of content files. false
lowercase Set this to true to convert attribute names to lowercase when writing. 0
sort If true, sort attribute names when writing entries according to the rule: objectclass first then all other attributes alphabetically sorted by attribute name 0
version Set the LDIF version to write to the resulting LDIF file. According to RFC 2849 currently the only legal value for this option is 1. 1
wrap Number of columns where output line wrapping shall occur. Setting it to 40 or lower inhibits wrapping. Useful for better human readability of the resulting file. 78
raw Using this option, you are able to tell Net_LDAP2_LDIF which attributes to treat as binary data. If you pass in entries having a valid LDAP connection (eg from some Net_LDAP2->search() operation) this additionally will be detected by automatic checks against the schema. empty

For advanced users: instead of passing a file path, you also may pass an already initialized file handle. In this case, the mode parameter will be ignored. You may use this, if you want to mix LDIF content and LDIF change mode by using two Net_LDAP2_LDIF instances to write to the same filehandle, but it could be very useful in other cases too. To initialize the second instance of Net_LDAP2_LDIF, you can use handle() to get the filehandle from the first instance.

Reading a LDIF file into Net_LDAP2_Entry-objects

One of the two modes how Net_LDAP2_LDIF can be used is to read a LDIF file and parse its contents into an array of Net_LDAP2_Entry objects. This is done using the read_entry()-method which will return the next entry. If you want to fetch all entries, you use the eof() to detect the end of the input file:

Parsing a LDIF file into Net_LDAP2_Entry objects

<?php
// open some LDIF file for reading
$ldif = new Net_LDAP2_LDIF('somefile.ldif''r');
if (
$ldif->error()) {
    
$error_o $ldif->error(); // get Net_LDAP2_Error object on error
            
die('ERROR: '.$error_o->getMessage());
}

// parse the entries of the LDIF file into objects
 
do {
    
$entry $ldif->read_entry();
    if (
$ldif->error()) {
        
// in case of error, print error.
        // here we use the shorthand parameter, so error()
        // returns a string instead of a Net_LDAP2_Object
        
die('ERROR AT INPUT LINE '.$ldif->error_lines().': '.$ldif->error(true));
    } else {
        
// No error: do something with the entry
        // Here we just print the entries DN
        
echo 'sucessfully parsed '.$entry->dn();
    }
} while (!
$ldif->eof());

// We should call done() once we are finished
$ldif->done();
?>

Since version 2.1.0 Net_LDAP2_Filter can do client side filtering on entry objects. This may be especially useful when combined with LDIF reading support as it allows the developer to execute select querys on the LDIF content. That enables for example the development of reports on those files without the need for an LDAP server. Please refer to the documentation of LDAP filters.

Writing Net_LDAP2_Entry objects to a LDIF content file

Writing an LDIF file is very easy too. Just pass the entries you want to have written to the write_entry()-method. Beware, that if you have opened the file in "w" write mode this will clear any previous data of that file. Use "a" (append) if you just want add data.

Writing entries

<?php
// Assume we have some valid Net_LDAP2_Entry objects inside $entries
        // $entries = array( ... );

        // open some file for writing
        
$ldif = new Net_LDAP2_LDIF('somewritefile.ldif''w');
        if (
$ldif->error()) die('ERROR: '.$error_o->getMessage());

        
// write the data and check for error
        // you could pass one single Net_LDAP2_Entry object or
        // several objects inside an array
        
$ldif->write_entry($entries);
        if (
$ldif->error()) die('WRITE ERROR: '.$error_o->getMessage());
?>

Writing Net_LDAP2_Entry objects to a LDIF change file

The process of writing changes is exactly the same like writing entry contents. However there are two differences: Firstly you need to pass the "changes" option and secondly, the entries you want to write need changes. Entries not containing changes will silently be ignored since there is nothing to write.

Writing entry changes

<?php
// cast some test data and three entries
        
$testattrs = array(
                
'attr1' => '1234',
                
'attr2' => 'foo',
                
'attr3' => array('bar''baz')
            );
        
$entries = array(
                
Net_LDAP2_Entry::createFresh('cn=foo,dc=example,dc=cno',
                    
array_merge(array('cn' => 'foo'), $testattrs)),
                
Net_LDAP2_Entry::createFresh('cn=bar,dc=example,dc=cno',
                    
array_merge(array('cn' => 'bar'), $testattrs)),
                
Net_LDAP2_Entry::createFresh('cn=baz,dc=example,dc=cno',
                    
array_merge(array('cn' => 'baz'), $testattrs))
            );

        
// make some changes to the first and the last entry
        
$entries[0]->add(array('someattr' => 'added'));
        
$entries[0]->replace(array('attr1' => 'replaced'));
        
$entries[2]->delete(array('attr2'));
        
$entries[2]->delete(array('attr3' => 'bar'));

        
// open some file for writing, but in change mode
        
$ldif = new Net_LDAP2_LDIF('somewritefile.ldif''w', array('change' => true));
        if (
$ldif->error()) die('ERROR: '.$error_o->getMessage());

        
// write the data and check for error
        // you could pass one single Net_LDAP2_Entry object or
        // several objects inside an array
        
$ldif->write_entry($entries);
        if (
$ldif->error()) die('WRITE ERROR: '.$error_o->getMessage());

        
// Now, only two entries are contained in the LDIF file,
        // cn=foo,dc=example,dc=cno and cn=baz,dc=example,dc=cno.
        // cn=bar,dc=example,dc=cno had no changes and was skipped.
?>

Resulting LDIF change file

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
-

Fetching LDIF data

Sometimes you are interested in the lines inside the LDIF file. For those cases you can use the current_lines() and next_lines() methods. They work in the current context, which may be confusing: current_lines() will always return the lines that have built up the current Net_LDAP2_Entry object when called current_entry() after read_entry() has been called. next_lines() will always return the lines, that will build up the next entry from the current point of view, meaning "relative to the entry that was just been read". However, you can override this by activating the "force" parameter of next_lines() which allows you to loop over all entries. current_entry() behaves exactly like current_lines().

If you think, that the lines you have read would be better in form of an Net_LDAP2_Entry object, use the parseLines() method to parse those lines into an entry. This is a good way if you need just a few specific entries of a large LDIF file.

Reading LDIF lines

<?php
// open some LDIF file for reading
// (error checking code is ommitted in this example for
//  better readability - in production, test for errors!)
$ldif = new Net_LDAP2_LDIF('somefile.ldif''r');

// since nothing has been read until now, this will
// return an empty array
$empty_array $ldif->current_lines();

// so let's read the first entries data
$first_entry_lines $ldif->next_lines();

// if we call it again, we will not read ahead to the
// second entry - we again read the first one!
$first_entry_lines_again $ldif->next_lines();

// If we call current_lines() now, we haven't read ahead
// like we learned from the last statement.
$empty_array_again $ldif->current_lines();

// If we want to shift, we must use
// the read_entry() method, which will read ahead.
$first_entry $ldif->read_entry();

// Now, current_lines() returns the lines of the
// first entry and next_lines() the lines of the second:
$first_entry_lines  $ldif->current_lines();
$second_entry_lines $ldif->next_lines();

// There is another way to shift the lines which is faster if
// you are just interested in the LDIFs content - you
// need to pass the "force" parameter to next_lines():
$third_entry_lines  $ldif->next_lines(true);
$fourth_entry_lines $ldif->next_lines(true);
$fifth_entry_lines  $ldif->next_lines(true);

// If you want to convert the lines to an Net_LDAP2_Entry,
// you may do so anytime by using parseLines()
$fourth_entry $ldif->parseLines($fourth_entry_lines);

// Since we shifted manually only the lines,
// current_lines() will return the lines that built up the
// last (e.g. the first entry) Net_LDAP2_Entry object:
$first_entry_lines  $ldif->current_lines();

// If we decide to read the next entry, we can do that:
$sixth_entry $ldif->read_entry();

// current_lines() is shifted now:
$sixth_entry_lines $ldif->current_lines();
?>
Introduction to and usage of LDAP filters (Previous) How to enable schema caching (Next)
Last updated: Mon, 01 Sep 2014 — Download Documentation
Do you think that something on this page is wrong? Please file a bug report or add a note.
View this page in:

User Notes:

There are no user contributed notes for this page.