Home » Networking » Net_LDAP2 » Manual
Net_LDAP2 allows you to query and manipulate the data stored in directory servers using PHP in an object-oriented way. Detailed usage examples are available at: /your/pear/path/docs/Net_LDAP2/examples/
Introduction
Introduction – What Net_LDAP2 is and general information
Welcome to Net_LDAP2!
Net_LDAP2 is a clone of Perls Net::LDAP package. PEAR Net_LDAP2 for PHP does, besides some own features, provide most of Perl Net::LDAP methods. Net_LDAP2 allows you to query and manipulate the data stored in directory servers using PHP in an object-oriented way. A directory server is a database server providing a hierarchical database and is usually queried using the LDAP protocol.
Net_LDAP2 is intendet as replacement of Net_LDAP.
Classes of the Net_LDAP2 package
The following table gives you a short overview which classes are available in Net_LDAP2 and what they can be used for. Their relations will be explained too.
| Class name | Description |
|---|---|
| Net_LDAP2 | This is the main class. It enables you to connect and bind to a LDAP-server and to run ldap-querys like searching and manipulating entries. Most common, you will run a search using a LDAP-Filter and will get a Net_LDAP2_Search-object. You may also fetch an entry directly, which gives you a Net_LDAP2_Entry-object. |
| Net_LDAP2_Search | Objects of this class are returned from search querys. You can use this object to retrieve informations about a search result, like how much entries you have found for the provided filter. You can retrieve the found entries as Net_LDAP2_Entry-objects in various forms: sorted, consecutively starting from the end or beginning or unsorted at once. |
| Net_LDAP2_Entry | Objects of this kind are either produced by casting fresh entries manually, by retrieving the result of a LDAP-search or by fetching an entry directly. It gives you the possibility to read and/or manipulate the attributes of an entry which describes the characteristic of the specific object. |
| Net_LDAP2_Util | The utility class contains only static methods, so you should not need to make an instance of it. It features some helpful methods, some of them are used internally by Net_LDAP2 but may be used externally from you as well. The most methods deal with escaping issues, since LDAP has some metacharacters with special meaning so that they usually need to be properly escaped. |
| Net_LDAP2_Filter | You are free to give LDAP-Filters on your own to the Net_LDAP2->search() method, however this has some drawbacks (including escaping issues). For this reason, you can use the Net_LDAP2_Filter class to easily build and combine your filters. LDAP filters are extensively explained at the chapter LDAP filters. |
| Net_LDAP2_Error | This is a error class. Most methods of Net_LDAP2 will return a object of this class if something went wrong. You can use this object to identify errors and to get detailed knowledge on what went wrong. See Errorhandling for more information. |
| Net_LDAP2_LDIF | LDIF files are human readable, plain text files containing directory data and/or change commands, much like an SQL file. Unlike SQL files, it is data centric, not action centric. Net_LDAP2_LDIF enables you to convert between Net_LDAP2_Entry-objects and LDIF files. Please note, that Net_LDAP2_LDIF has a little different error handling explained later. |
| Net_LDAP2_SimpleFileSchemaCache | Net_LDAP2 features a schema caching facility. This class implements a simple file based cache that allows Net_LDAP2 to store the schema data that get fetched from LDAP inside a file to accelerate schema access. Caching the schema can gain some performance, especially with slow servers or connections. You may use this cache class for example to store the schema object in a linux tmpfs which will result in caching the schema in the computers memory, enabling nearly instant access. This cache also features a cache ageing mechanism. Please see Schema caching for more information. |
Error handling
Error handling – How handling errors works in Net_LDAP2
Error handling
Nearly all of Net_LDAPs methods return a Net_LDAP2_Error object if something went wrong. You always should check for errors after you performed an action to be sure that your application doesn't do things you don't want it to do.
Handling errors is an easy task, you just have to test the return value as shown below. If an error occured, you can halt the script for example. In other cases, you may just log the error, but what exactly happens depends on your specific situation, of course.
You can use the getMessage() method of the error object to retrieve the error message explaining the problem and getCode() to get the error code which is usually the LDAP-Error code (see Table below) and may be used for automated reaction on errors.
Dealing with errors
<?php
// Perform an arbitrary action:
$result = $ldap->search($searchbase, $filter, $options);
// Check, if an error occured and do something.
// Here we use die() to show the message of the error.
if (Net_LDAP2::isError($result)) {
die($result->getMessage());
}
?>
| Error code | Description |
|---|---|
| 0x00 | LDAP_SUCCESS |
| 0x01 | LDAP_OPERATIONS_ERROR |
| 0x02 | LDAP_PROTOCOL_ERROR |
| 0x03 | LDAP_TIMELIMIT_EXCEEDED |
| 0x04 | LDAP_SIZELIMIT_EXCEEDED |
| 0x05 | LDAP_COMPARE_FALSE |
| 0x06 | LDAP_COMPARE_TRUE |
| 0x07 | LDAP_AUTH_METHOD_NOT_SUPPORTED |
| 0x08 | LDAP_STRONG_AUTH_REQUIRED |
| 0x09 | LDAP_PARTIAL_RESULTS |
| 0x0a | LDAP_REFERRAL |
| 0x0b | LDAP_ADMINLIMIT_EXCEEDED |
| 0x0c | LDAP_UNAVAILABLE_CRITICAL_EXTENSION |
| 0x0d | LDAP_CONFIDENTIALITY_REQUIRED |
| 0x0e | LDAP_SASL_BIND_INPROGRESS |
| 0x10 | LDAP_NO_SUCH_ATTRIBUTE |
| 0x11 | LDAP_UNDEFINED_TYPE |
| 0x12 | LDAP_INAPPROPRIATE_MATCHING |
| 0x13 | LDAP_CONSTRAINT_VIOLATION |
| 0x14 | LDAP_TYPE_OR_VALUE_EXISTS |
| 0x15 | LDAP_INVALID_SYNTAX |
| 0x20 | LDAP_NO_SUCH_OBJECT |
| 0x21 | LDAP_ALIAS_PROBLEM |
| 0x22 | LDAP_INVALID_DN_SYNTAX |
| 0x23 | LDAP_IS_LEAF |
| 0x24 | LDAP_ALIAS_DEREF_PROBLEM |
| 0x30 | LDAP_INAPPROPRIATE_AUTH |
| 0x31 | LDAP_INVALID_CREDENTIALS |
| 0x32 | LDAP_INSUFFICIENT_ACCESS |
| 0x33 | LDAP_BUSY |
| 0x34 | LDAP_UNAVAILABLE |
| 0x35 | LDAP_UNWILLING_TO_PERFORM |
| 0x36 | LDAP_LOOP_DETECT |
| 0x3C | LDAP_SORT_CONTROL_MISSING |
| 0x3D | LDAP_INDEX_RANGE_ERROR |
| 0x40 | LDAP_NAMING_VIOLATION |
| 0x41 | LDAP_OBJECT_CLASS_VIOLATION |
| 0x42 | LDAP_NOT_ALLOWED_ON_NONLEAF |
| 0x43 | LDAP_NOT_ALLOWED_ON_RDN |
| 0x44 | LDAP_ALREADY_EXISTS |
| 0x45 | LDAP_NO_OBJECT_CLASS_MODS |
| 0x46 | LDAP_RESULTS_TOO_LARGE |
| 0x47 | LDAP_AFFECTS_MULTIPLE_DSAS |
| 0x50 | LDAP_OTHER |
| 0x51 | LDAP_SERVER_DOWN |
| 0x52 | LDAP_LOCAL_ERROR |
| 0x53 | LDAP_ENCODING_ERROR |
| 0x54 | LDAP_DECODING_ERROR |
| 0x55 | LDAP_TIMEOUT |
| 0x56 | LDAP_AUTH_UNKNOWN |
| 0x57 | LDAP_FILTER_ERROR |
| 0x58 | LDAP_USER_CANCELLED |
| 0x59 | LDAP_PARAM_ERROR |
| 0x5a | LDAP_NO_MEMORY |
| 0x5b | LDAP_CONNECT_ERROR |
| 0x5c | LDAP_NOT_SUPPORTED |
| 0x5d | LDAP_CONTROL_NOT_FOUND |
| 0x5e | LDAP_NO_RESULTS_RETURNED |
| 0x5f | LDAP_MORE_RESULTS_TO_RETURN |
| 0x60 | LDAP_CLIENT_LOOP |
| 0x61 | LDAP_REFERRAL_LIMIT_EXCEEDED |
| 1000 | Unknown Net_LDAP2 Error |
Configuration and connecting
Configuration and connecting – How to configure Net_LDAP2 and connect to an LDAP server
Connecting to an LDAP server
To connect to an LDAP server, you should use Net_LDAP2's static connect() method. It takes one parameter, an array full of configuration options, and either returns a Net_LDAP2 object if connecting works, or a Net_LDAP2_Error object in case of a failure.
The following table lists all configuration options. If the default value for an option fits your needs, you don't need add it to your configuration array.
| Name | Description | Default |
|---|---|---|
host |
LDAP server name to connect to. You can provide several hosts in an array in which case the hosts are tried from left to right. | localhost |
port |
Port on the server | 389 |
version |
LDAP version | 3 |
starttls |
TLS is started after connecting | false |
binddn |
The distinguished name to bind as (username). If you don't supply this, an anonymous bind will be established. | (none) |
bindpw |
Password for the binddn. If the credentials are wrong, the bind will fail server-side and an
anonymous bind will be established instead. An empty bindpw string requests an unauthenticated bind. This can cause
security problems in your application, if you rely on a bind to make security decisions (see
RFC-4513, section 6.3.1). |
(none) |
basedn |
LDAP base name (root directory) | (none) |
options |
Array of additional ldap options as key-value pairs | array() |
filter |
Default search filter (string or preferably Net_LDAP2_Filter object). See LDAP filters | (objectClass=*) |
scope |
Default search scope, see Search | sub |
Connecting to an LDAP server
<?php
// Inclusion of the Net_LDAP2 package:
require_once 'Net/LDAP2.php';
// The configuration array:
$config = array (
'binddn' => 'cn=admin,ou=users,dc=example,dc=org',
'bindpw' => 'password',
'basedn' => 'dc=example,dc=org',
'host' => 'ldap.example.org'
);
// Connecting using the configuration:
$ldap = Net_LDAP2::connect($config);
// Testing for connection error
if (PEAR::isError($ldap)) {
die('Could not connect to LDAP-server: '.$ldap->getMessage());
}
?>
Search
Search – Searching entries
A short note on DNs
It may be possible that restricted characters (",", "+", """, "\", "<", ">", ";", "#", "=", space or a hexpair) are used in attributes or values inside the DN. You should have a look to the APIdoc of Net_LDAP2_Util::escape_dn_value(), Net_LDAP2_Util::unescape_dn_value(), Net_LDAP2_Util::ldap_explode_dn() and Net_LDAP2_Util::canonical_dn(). These functions can be used to safely handle DNs.
Searching some entries
After connecting to the server, you can use Net_LDAP2's search() method to search the directory. The method takes three parameters:
-
$baseis the base search DN. If keptnull, the default base DN configured when connecting is used. -
$filteris the query filter that determines which results are returned. It is either a string (experts use only) or better a Net_LDAP2_Filter-object. Net_LDAP2_Filter automatically deals with LDAP-Filter escaping issues. LDAP filters are extensively explained at the chapter LDAP filters. -
$paramsis an array of configuration options for the current query.Possible configuration parameters Name Description Default scopeThe scope used for searching: -
base- Just one entry -
sub- The whole tree -
one- Immediately below$base
subsizelimitNumber of entries returned at maximum 0(no limit)timelimitSeconds to spent for searching 0(no limit)attrsonlyIf true, only attribute names are returnedfalseattributesArray of attribute names, which the entry should contain. It is good practice to limit this to just the ones you need. array()(all attributes) -
The search() method will return either a Net_LDAP2_Search object or a Net_LDAP2_Error. You can use the Net_LDAP2_Search-object to trigger further actions like counting how many entries where found or to retrieve the found entries.
Making a search query
<?php
// Building a very basic filter
// we want to find all Entries whose surnames start with "Joe":
$filter = Net_LDAP2_Filter::create('sn', 'begins', 'Joe');
// We define a custom searchbase here. If you pass NULL, the basedn provided
// in the Net_LDAP2 configuration will be used. This is often not what you want.
$searchbase = 'ou=addressbook,dc=example,dc=org';
// Some options:
// We search all subtrees beneath 'ou=addressbook,dc=example,dc=org'
// and we select the attribute 'sn'. It is a good practice to limit the
// requested attributes to only those you actually want to use later.
// However, note that it is faster to select unneeded attributes than
// refetching an entry later to just get those attributes.
$options = array(
'scope' => 'sub',
'attributes' => array('sn')
);
// Perform the search!
$search = $ldap->search($searchbase, $filter, $options);
// Test for search errors:
if (PEAR::isError($search)) {
die($search->getMessage() . "\n");
}
// Say how many entries we have found:
echo "Found " . $search->count() . " entries!";
?>
Fetching entries
Fetching entries – Retrieving entries directly or from a searchresult
Retrieving entries directly
You can retrieve directory entries in several ways, either directly or from a performed search request. If you want to fetch an entry directly, you need to know its absolute distinguished name (DN). To directly fetch an known entry from the directory server, you use Net_LDAP2's getEntry() method. It takes two parameters: The DN of the entry and the attributes you want to read from the entry. It returns a Net_LDAP2_Entry object if fetching worked, or a Net_LDAP2_Error object in case of a failure.
You may also check if the entry exists in the server before you fetch it. This can be achieved by Net_LDAP2's dnExists() which takes the DN to test and returns either true or false.
Fetching an entry directly
<?php
// Defining the DN we want to fetch;
// we want to select the given- and the surname
$dn = 'cn=admin,o=example,dc=org';
$entry = $ldap->getEntry($dn, array('gn', 'sn'));
// Error checking is important!
if (Net_LDAP2::isError($entry)) {
die('Could not fetch entry: '.$entry->getMessage());
}
?>
Retrieving entries from a searchresult
The second way to retrieve entries is from a searchresult. As described in chapter "Search", you access the entries of a search result through the Net_LDAP2_Search-object resulting from Net_LDAP2's search() method. Each of the following methods return a Net_LDAP2_Error-object if something goes wrong, so remember to test for errors! You have several ways to read the entries:
| Method of Net_LDAP2_Search | Description |
|---|---|
| entries() | This returns the entries at once unsorted. |
| as_struct() | This returns all entries as multidimensional array instead of Net_LDAP2_Entry-objects. The array keys of the first dimension are the DNs and the value is an array containing all attributes. The array keys of the second level are the attributes names; the value of the second level is an array containing all the attributes values. Note, that even if there are no or just one value, an array is present. |
| sorted() | Use this if you want to get the entries at once but sorted. You can sort by several attributes which can contain multiple values.
You can of course sort ascending (default) or descending - just pass the PHP constant SORT_ASC or SORT_DESC as second parameter. |
| sorted_as_struct() | Like as_struct(), this returns the entries as multidimensional array, but in this case sorted. For parameters, see sorted() |
| shiftEntry() | This returns one entry from the beginning of the search result.
Since this returns FALSE if all entries are fetched, shiftEntry() is perfectly
appropriate to get used inside a while-loop.
Take care not to mix shiftEntry() and popEntry()! |
| popEntry() | Exactly the same as shiftEntry, but returns the entry from the end of the searchresult. Again, be sure to not mix shiftEntry() and popEntry()! |
To directly fetch an known entry from the directory server, you use Net_LDAP2's getEntry() method. It takes two parameters: The DN of the entry and the attributes you want to read from the entry. It returns a Net_LDAP2_Entry object if fetching worked, or a Net_LDAP2_Error object in case of a failure.
You may also check if the entry exists in the server before you fetch it. This can be achieved by Net_LDAP2's dnExists() which takes the DN to test and returns either true or false.
Fetching all entries from searchresult
<?php
// return all entries:
$entry = $search->entries();
?>
Fetching all entries from searchresult: sorted
<?php
// return sorted by first 'sn' then 'gn', but descending:
$entry = $search->sorted(array('sn', 'gn'), SORT_DESC);
?>
Fetching entries one by one inside a while loop
<?php
// return entries one by one:
while ( $entry = $search->shiftEntry() ) {
// do something, like printing the DN of the entry;
// in a real case, dont forget to test for errors!
echo "ENTRY: " . $entry->dn();
}
?>
Retrieving entries via iteration (foreach)
Since Net_LDAP2 you are able to use PHPs Standard Library (SPL) to iterate over search results. This is done easily by just using the Net_LDAP2_Search search result object inside an foreach loop similar to an array. You may optionally retrieve the DN of each entry by the same mechanism you use to retrieve the key of an associative array.
Fetching entries via foreach()
<?php
foreach ($search as $dn => $entry) {
// do something:
$sn = $entry->getValue('sn', 'single');
echo "Fetched DN: $dn; Surname: $sn";
}
?>
Attributes
Attributes – Reading/adding/changing/deleting attributes from entries
Reading attributes
Reading attribute values depends on the selection of those attributes at search time. You can only access attributes that where selected! You can read attribute values using either Net_LDAP2_Entry's getValues() or getValue() method. getValue() will return an array where the keys are the attributes names. If you use getValues() you may pass an option:
-
'single': only the first value is returned as string -
'all': all values including the value count are returned in an array -
'default': in all other cases an attribute value with a single value is returned as string, if it has multiple values it is returned as an array (without value count)
Also note that if you try to fetch an attribute, that is not set at the entry, an empty string will be returned.
Reading attributes
<?php
// read Surename, singlevalued
$surename = $entry->getValue('sn', 'single');
// read mail adress which may be multivalued
$mail = $entry->getValue('mail', 'all');
?>
If you want to read the distinguished name of an Entry (DN), you must use a different method: dn()
Reading an entries DN
<?php
$dn = $entry->dn();
?>
Regular expressions on attributes
PEAR::Net_LDAP2 has the unique feature to apply a regular expression match directly against attributes, so you do not need to manually fetch all values and run the regex against them. Instead, you can use Net_LDAP2_Entry's preg_match() function. The behavior of this function is the same as PHPs preg_match(), but the $matches array is slightly different. It features one dimension more, since it may match for several attribute values if the attribute is multivalued. If you pass $matches, be sure to do it via REFERENCE, because otherwise $matches remains empty. preg_match() returns true or false, depending on match.
Performing preg_match on attribute values
<?php
// Look, if the user has an emailadress for 'example', if so,
// we want to display the tld:
// (be sure to pass $matches as reference!)
$matches = array();
if ( $entry->preg_match('mail', '/example\.(.+)/', &$matches) ) {
// print every TLD found for 'example':
foreach ($matches as $match) {
echo $match[1];
}
}
?>
General information regarding attribute changing
It is important to know how attribute changing works. Modifications to an entry
through the Net_LDAP2_Entry-object are local only.
After you have made all changes and want to transfer them to the directory server, you must
call update() of the Net_LDAP2_Entry object.
This will return either TRUE or an Net_LDAP2_Error.
Another good information is, that you must select attributes at search time
if you want to add/change/delete attribute values. Otherwise Net_LDAP2 will most likely fail
silently giving you the wrong assumtion that everything was okay - Net_LDAP2 needs knowledge
of the attributes it should work with!
Modification of attributes is also possible through Net_LDAP2's modify() method. This method will call the methods described here on the Net_LDAP2_Entry object given, and directly calls an update() after that, thus performing the changes directly on the server. The parameter is an complex array describing the changes to be performed. It is considered for more advanced users, because it is more compact, so please refer to the latest API documentation for more information.
Adding attributes
Adding attrbiute values to an entry is an easy task. You just need to call add()! The parameter is an array whose keys are the attribute names and values the attributes values. If only one attribute value should be added, the second level may be a string. If the attribute doesn't exist so far, it will be added, if it exists, the attributes values will be added.
Adding attributes
<?php
// Adding several attributes:
$result = $entry->add(
array(
'sn' => 'Doe',
'gn' => array('John'),
'mail' => array('john@doe.org', 'j.doe@example.org')
)
);
?>
Changing attributes
Changing values is with the replace() method as easy as adding values. However, you have to be a little more careful.
The expected parameter is an array describing the new absolute state of the named
attributes. This means, if you specify a NULL value for an attribute,
this attribute will get deleted!
You may specify single values as string too.
The keys of the array are expected to be the attributes names.
Changing attributes
<?php
// Changing several attributes:
// 'sn' is changed to "Smith", 'gn' gets deleted and mail will
// be changed to te two new adresses
$result = $entry->replace(
array(
'sn' => 'Smith',
'gn' => null,
'mail' => array('smith@example.org', 'smith@example.de')
)
);
?>
Deleting attributes
Using the delete() method you are able to delete specific attributes values as well
as delete a whole attribute.
You need to specify the attribute names as array keys, the array values are the values you want to delete.
If you want to delete whole attributes, specify them as single level array.
Special care must be taken not to delete the whole entry which will be the case if the parameter array is
omitted or set to NULL!
Also, don't mix syntax modes. If you want to delete whole attributes you can't delete specific values from another attribute
in the same function call.
Deleting attributes
<?php
// Delete the whole entry:
$result = $entry->delete();
// Delete the whole telephone number attribute:
$result = $entry->delete('telephoneNumber');
// Delete one specific mail attributes value:
$result = $entry->delete( array('mail' => 'j.doe@example.org') );
// Delete mail and telephone attributes as a whole:
$result = $entry->delete( array('mail', 'telephoneNumber') );
// Delete two specific mail adresses:
$result = $entry->delete( array('mail' => array('smith@example.org', 'smith@example.de')) );
?>
Changing Objectclasses
Object classes describe the attribute set of an entry with this objectclass set. The entry stores the objectclass in a special attribute named "objectClass", and of course you may alter that attribute like any other attribute.
However, special care must be taken if changing this attribute since most directory servers impose rules on the other attributes the object class define. For example, it is usually not possible to delete an objectclass if some of the attributes the class describes are still in use by the entry. This should be not much of a problem with optional attributes, but sometimes objectclasses have mandatory attributes set. Also structural objectclasses can only be added when creating new entrys. Because of the internal architecture of Net_LDAP2 it is currently not possible to resolve those cases.
To add or remove objectclasses with mandatory attributes or new structural object classes, you need to delete the old entry from the directory server and add the new one with the new objectclass and attributes as fresh entry.
Changing complex objectclasses
<?php
// Let's assume that the objectclass myClass enforce the attribute "fooattr"
// Take care that you have all attributes requested, otherwise the new
// entry will not have all attributes set!
$entry->add(array(
'objectClass' => 'myClass',
'fooatrr' => 'foo',
'someotherattr' => array('bar', 'baz')
));
// Calling $entry->update() now will not succeed under some circumstances!
// We construct a fresh entry object which is in fact a copy of the already
// existing entry with all changes already applied (the local copy).
// It is important, that at fetching time of $entry all attributes where selected!
// Only the selected attributes will get copied.
$changed_entry = Net_LDAP2_Entry::createFresh($entry->dn(), $entry->getValues());
// Now delete the old entry and add the new one:
$ldap->delete($entry);
$ldap->add($changed_entry);
?>
Schema checks
When operating on an LDAP connection, you might want to retrieve informations regarding the directory servers schema. Often this is the case to verify that your program only querys attributes that are valid for an entry or to ensure that you only try to write such attributes to the server.
To get that inforamtion, you can use the Net_LDAP2_Schema which is retrieved via the Net_LDAP2 object. It allows you to perform various querys, not only on attributes and object classes, but also on DIT content rules, for example. For often needed functionality, shorthand methods are implemented since version 2.0.10 like attributeExists(), objectClassExists(), getAssignedOCLs() and checkAttribute().
Performing basic schema checks
<?php
// Fetch the schema object for the connected directory server.
$schema = $ldap->schema();
// this may have failed since not every server allows us
// to fetch the schema without permission. Also technical
// problems may prevent us from this.
if ( Net_LDAP2::isError($schema) ) {
die('SCHEMA ERROR: '.$schema->getMessage()."\n");
}
// lets see, if an attribute is defined in the schema:
if ( $schema->attributeExists('myCoolAttribute') ) {
echo "Attribute 'myCoolAttribute' is defined in the schema!";
}
// lets see, if an object class is defined in the schema:
if ( $schema->attributeExists('myCoolOCL') ) {
echo "Object class 'myCoolOCL' is defined in the schema!";
}
// Check, if the attribute is defined in objectClasses.
// This is especially useful if you want to know if
// attributes are valid for a given set of object classes.
if ( $schema->checkAttribute('myCoolAttribute', array('person', 'myCoolOCL')) ) {
echo "Attribute 'myCoolAttribute' is defined for the given OCLs!";
}
?>
Managing entries
Managing entries – Adding/renaming/moving/deleting entries
Adding (fresh or old) entries to the directory
Adding new entries is performed in two ways. First, you need to establish a fresh Net_LDAP2_Entry object. After that, you can add that entry like you would add already-existent entries using Net_LDAP2's add() method.
Adding a fresh entry
<?php
// Build a new fresh entry:
$dn = 'cn=new-admin,o=example,dc=org';
$attributes = array(
'cn' => 'new-admin',
'mail' => array('new-admin@exaple.org', 'n.admin@example.de'),
'telephoneNumber' => '1234567890'
);
$entry = Net_LDAP2_Entry::createFresh($dn, $attributes);
// Add the entry to the directory:
$ldap->add($entry);
?>
Renaming or moving entries
Renaming and/or moving an entry is an operation on the DN of an entry. Moving an entry means, to rename a DN in such a way, that the entry becomes a new base-DN. You can rename or move an entry, if you call the dn() method of the entry you want to relocate. Alternatively, you may call Net_LDAP2's move() method that also ca handle only DNs. Remember that you must call the entires update() method to carry out the move/rename. Net_LDAP2's move() will move the entry immediately. If you use an entryobject togehter with Net_LDAP2's move(), you are able to perform cross directory moves.
Moving an entry using Net_LDAP2_Entry
<?php
// Defining the DN we want to fetch;
$dn = 'cn=admin,o=example,dc=org';
$newdn = 'cn=admin,o=new-example,dc=org';
$entry = $ldap->getEntry($dn);
$entry->dn($newdn);
?>
Moving an entry using Net_LDAP2 and Net_LDAP2_Entry
<?php
// Defining the DN we want to fetch;
$dn = 'cn=admin,o=example,dc=org';
$newdn = 'cn=admin,o=new-example,dc=org';
$entry = $ldap->getEntry($dn);
$ldap->move($entry, $newdn);
?>
Renaming an entry using Net_LDAP2 and DNs
<?php
// Defining the DN we want to fetch;
$dn = 'cn=admin,o=example,dc=org';
$newdn = 'cn=admin2,o=new-example,dc=org';
$ldap->move($dn, $newdn);
?>
Performing a cross directory move
<?php
// $ldap_src is the source ldap and $ldap_tgt the target
$dn = 'cn=admin,o=example,dc=org';
$newdn = 'cn=admin,o=new-example,dc=org';
$entry = $ldap_src->getEntry($dn);
$ldap_src->move($entry, $newdn, $ldap_tgt);
?>
Deleting entries
Deleting entries is performed using Net_LDAP2's delete() method.
Just pass the Net_LDAP2_Entry object or the DN of the entry you want to delete.
In the case that the DN contains subentrys, you need to pass TRUE as second parameter
which will make delete() delete recursive.
A second way exist: You may simply call delete() from the Net_LDAP2_Entry you want to delete. Don't forget that you must call update() to carry out the delete in this case.
Deleting an entry
<?php
$dn = 'cn=new-admin,o=example,dc=org';
$ldap->delete($dn);
?>
Deleting an entry using a Net_LDAP2_Entry object
<?php
$entry->delete();
$entry->update();
?>
LDAP filters
LDAP filters – Introduction to and usage of LDAP filters
What are LDAP filters?
LDAP filters usually serve as parameter to a LDAP Search request.
LDAP filters are defined in RFC 2254 and can be compared to the WHERE clause in SQL select statements - they filter the data returned from some search request - in this case the entries returned from the directory server. With Net_LDAP2, you may use plain strings as filters, or preferably, the Net_LDAP2_Filter class which mostly releases you of the burden to escape yourself and to remember all the various special characters needed for constructing and combining filters.
Some LDIF filter basics
Although you should preferably use the Net_LDAP2_Filter class to construct your LDAP filters, some theory may be interesting and helpful in understanding how to construct LDAP filters and what they are capable of.
Basic LDAP filters are composed of an "[attribute][operator][value]" pair enclosed by round brackets. There are several comparison operators available: "=" (equal), ">" (greater), "<" (less), ">=" (greater or equal), "<=" (less or equal) and "=~" (phonetical similar). The exact match behavior is defined by the attribute syntax of the attribute to which the filter should apply.
Some basic string filters
<?php
// Filter entries whose first name is 'Benedikt':
$filter = '(givenName=Benedikt)';
// Filter entries which have an employeenumber higher or equal than 1424:
$filter = '(employeeNumber>=1424)';
// Filter entries whose first name sounds similar to "Stephane"
// This should also find "Stephen" and "Stefan" (depending on implementation)
$filter = '(givenName~=Stephane)';
?>
The value part of the basic filter construct could also include a special character: "*". The star acts as placeholder for none, one or several characters at that position. "V*lue" would therefore match against "Value", "Vlue", "VaaAaAalue" and so on. There are some special named combinations using the star, but they work exactly the same way:
| Name | Filter | Description |
|---|---|---|
| present | (attr=*) | Also refered to as "any". Finds any entry containing any (unless empty) value for the named attribute. |
| begins | (attr=value*) | value starts with some fixed string |
| ends | (attr=*value) | value ends with some fixed string |
| contains | (attr=*value*) | value contains some fixed string |
Combining string filters
Basic filters can be combined using the three logical operators "&" (and), "|" (or) and "!" (not). Note, that the smallest filter component, the basic filter enclosed in round brackets, remains isolated: instead of just adding another "[attribute][operator][value]" pair into the brackets, a new bracket level is introduced that contains all filter components that should be combined. Note also, that the logical operator does stand in front of all filter components, not between them as common in programming languages.
Combining string filters
<?php
// Search all 'Benedikt's with phone number 1234567890
$filter = '(&(givenName=Benedikt)(telephoneNumber=1234567890))';
// Search the same, but exclude person "Benedikt Foobar"
// Note that the "not" is a logical operator and thus needs its own
// surrounding bracket. This explains nicely, that each bracket level
// is evaluated independently from surrounding brackets.
$filter = '(&(givenName=Benedikt)(telephoneNumber=1234567890)(!(sureName=Foobar)))';
?>
The Net_LDAP2_Filter class
As you will read below, there are some special characters inside the LDAP filter definition and thus must be escaped. These are mainly the special characters used directly by the filter syntax like braces and the logical operators. Despite those, there are some other cases which need special threatment. Nearly all of this cases are hidden through the Net_LDAP2_Filter class so you should only consider using string filters if you need to or you know what you are doing. If you need a filter string, you may also use Net_LDAP2_Filters asString() function after building the filter.
The filter class has two different usage models: one for constructing basic filters and another to combine them logically. This has to do with the syntax of LDAP filters you may read below.
Creating filters
For creating basic filter components, you need to use the create() factory method.
There, you combine three items: an attribute to filter for, a matching rule for comparison and a value
that is beeing compared with the servers entries.
The given value is automatically escaped, so you need take care if you want to use the star placeholder.
In this case, you need to pass FALSE as fourth parameter to create()
which causes value to be threaten as-is. This of course also means, that you need to
escape the parts of the value that may contain restricted characters yourself using
Net_LDAP2_Util::escape_filter_value(). To learn what characters
are restricted, refer to RFC 2254 or the documentation of
Net_LDAP2_Util::escape_filter_value(); otherwise its safe to always escape.
The matching rules partly follow the basic filter matching rules described above, but are enhanced to make your life easier:
| Rule | Description |
|---|---|
| equals | One of attributes values is exactly value. Please note that case sensitiviness depends on the matching rule defined in the attributes schema syntax. |
| begins | One of attributes values must begin with value |
| ends | One of attributes values must end with value |
| contains | One of attributes values must contain value |
| present | any | The attribute can contain any value but must be existent |
| greater | The attributes value is greater than value |
| less | The attributes value is less than value |
| greaterOrEqual | The attributes value is greater or equal than value |
| lessOrEqual | The attributes value is less or equal than value |
| approx | One of attributes values sounds similar to value. The matching behavior depends on the server implementation. |
Since Net_LDAP2 2.0.12 you can also negate the match rules by using the not keyword
to easily negate the basic filter expression. Prior to that, you had to use combine()
manually.
Creating LDAP filters
<?php
// Filter entries whose first name is 'Benedikt':
$filter = Net_LDAP2_Filter::create('givenName', 'equals', 'Benedikt');
// Filter entries whose first name is NOT 'Benedikt':
// (this was first introduced in 2.0.12)
$filter = Net_LDAP2_Filter::create('givenName', 'not equals', 'Benedikt');
$filter = Net_LDAP2_Filter::create('givenName', '! =', 'Benedikt'); // works too :)
// Filter entries whose first name starts with 'Steph':
$filter = Net_LDAP2_Filter::create('givenName', 'begins', 'Steph');
// Filter entries containing 'Lone*'; matching the star character.
// The automatic escaping of $value will conveniently escape the star for us.
$filter = Net_LDAP2_Filter::create('givenName', 'contains', 'Lone*');
// Filter entries containing 'Foo[something]Bar'; not matching the star character.
// For this to work, we need to disable automatic escaping of $value by passing
// false as fourth parameter. This however implies, that we take care of
// proper escaping, which is showed in the example.
$escaped_values = Net_LDAP2_Util::escape_filter_value(array('Foo', 'Bar'));
$foo =& $escaped_values[0];
$bar =& $escaped_values[1];
$filter = Net_LDAP2_Filter::create('givenName', 'contains', "$foo*$bar", false);
// Filter entries whose first name sounds similar to "Stephane"
// This should also find "Stephen" and "Stefan" (depending on implementation)
$filter = '(givenName=~Stephane)';
?>
Combining filters
Although the filters can be used stand alone, they can be combined to match sophisticated
search requiremets. This is done by using the combine() to combine
several present Net_LDAP2_Filter objects using a logical operator.
The execption is the not operator since it only allows one filter
object to be negated.
| Rule | Description |
|---|---|
| and | All filter components must evaluate to true for the combined filter to be true |
| or | At least one filter component must evaluate to true for the combined filter to be true |
| not | The result of the filter component is inversed (true becomes false and vice versa).
Note that this operator only accepts one filter object. |
Combining LDAP filters
<?php
// Create some test filters
$filter_benedikt = Net_LDAP2_Filter::create('givenName', 'equals', 'Benedikt');
$filter_steph = Net_LDAP2_Filter::create('givenName', 'begins', 'Steph');
$filter_foobar = Net_LDAP2_Filter::create('sureName', 'equals', 'Foobar');
$filter_height = Net_LDAP2_Filter::create('personHeight', 'greater', '175');
// Negate 'foobar' filter.
// This filters every entry whose sure name is not 'Foobar'
$filter_not_foobar = Net_LDAP2_Filter::combine('not', $filter_foobar);
// Build a 'and' combination to be able to search for people whose
// first names start with 'Steph' and who are are taller than 175
// except those whose surname is 'Foobar'
$filter_stephs_tall = Net_LDAP2_Filter::combine('and',
array($filter_steph, $filter_height, $filter_not_foobar));
// In any case, add every person whose first name is
// 'Benedikt' to the search result.
$filter_add_benedikt = Net_LDAP2_Filter::combine('or', array($filter_benedikt, $filter_stephs_tall));
?>
Client side filtering
Since version 2.1.0 the filter class can filter entries client side. Just pass an entry or an array of entries to the filter objects matches() method. With this you can check that an given entry matches some LDAP filter as well as select matching entries out of an array containing many of them. The method always returns the number of matched entries. If you want to retrieve the filtered entries you have to provide some result array to which the matching entries are appended.
| Feature | Description | Since |
|---|---|---|
Matching Operators: equals, begins, ends, contains, present|any | Matching of the basic "=" filter argument with wildcards in value. As of 2.1.0, the match performed is not case sensitive (this will change once schema attribute syntax is honored). | 2.1.0 |
Matching Operators: greater, greaterOrEqual, less, lessOrEqual, approx | Comparisons and approximate literal matching | unsupported |
| Matching rules of attribute syntax | Using of the matching rule of the schema attribute syntax (eg. date/time comparisons, case sensitiveness, etc) | unsupported |
Logical Operators: AND, OR, NOT | Combining filters for more advanced expressions. | 2.1.0 |
Client side filter matching
<?php
// Create a simple test filter (may be arbitary complex and combined)
$filter = Net_LDAP_Filter::create('givenName', 'equals', 'Benedikt');
// see if the filter matches a given Entry
// (note that you should check for Net_LDAP2_Error)
$matches_count = $filter->matches($singleEntry);
// $matches_count contains the number of matched entries, here 0 or 1.
// see, if the filter matches some entries of a given array of entries
$matches_count = $filter->matches($arrayOfEntries);
// $matches_count contains again the number of matched entries, here 0 or n.
// what entries do match exactly?
$filteredEntries = array(); // provide a results array (doesn't have to be empty)
$matches_count = $filter->matches($arrayOfEntries, $filteredEntries);
// $filteredEntries array contains now all matched entries, eg a filtered result.
?>
Advanced features
You may need some advanced functionality if you have to deal with string representation of filters.
| Method | Description |
|---|---|
| parse() | Takes an filter string and parses it into a Net_LDAP2_Filter object. It also verifies, that the filter syntax is correct. |
| printMe() | In PERLs interface, this method is called "print" but due to language constraints, we cannot use that name. Prints the string representation of this filter object to standard output or to an optional filehandle passed as parameter. |
| asString() | Returns the string representation of the filter object. |
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:
| 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();
?>
Schema caching
Schema caching – How to enable schema caching
Net_LDAP2s schema caching facility
Net_LDAP2 features an easy schema caching facility. Caching the schema can gain some performance, especially with slow servers or connections. The facility works with an plugin object that must be passed to Net_LDAP2s registerSchemaCache() method. The cache object can be registered (or unregistered) at any time, but of course it is the best time right after initializing Net_LDAP2.
Enabling/disabling Net_LDAP2s schema caching facility
<?php
// registering a valid schema cache object is enough to enable the caching facility:
$ldap->registerSchemaCache($myCacheObject);
// unregistering is easy too: just supply null as schema cache object:
$ldap->registerSchemaCache(null);
?>
The object that gets passed to registerSchemaCache() must implement the Net_LDAP2_SchemaCache interface which demands two methods. Initialisation of the cache object is dependent on the class itself but should be handled inside the cache class constructor, however this may vary. Please refer to the cache class documentation for those details.
| Method | Parameter | Return value | Description |
|---|---|---|---|
| loadSchema() | none |
Net_LDAP2_Schema,
Net_LDAP2_Error or false |
Returns the cached schema object. Net_LDAP2 will consider anything returned invalid, except a valid Net_LDAP2_Schema object. In case you return a Net_LDAP2_Error, this error will be routed to the return of the $ldap->schema() call. If you return something else, Net_LDAP2 will fetch a fresh Schema object from the LDAP server and tries to cache it via store(). You may also want to implement a cache aging mechanism here too. |
| storeSchema() | Net_LDAP2_Schema object | true or (in special cases) Net_LDAP2_Error |
Stores a schema object in the cache. This method will be called, if Net_LDAP2 has fetched a fresh schema object from LDAP and wants to init or refresh the cache. In case of errors you may return a Net_LDAP2_Error which will be routet to the client. Note that doing this prevents, that the schema object fetched from LDAP will be given back to the client, so only return errors if storing of the cache is something crucial (e.g. for doing something else with it). Normaly you dont want to give back errors in which case Net_LDAP2 needs to fetch the schema once per script run and use the error functionality of loadSchema(). |
Packaged schema cache classes
As of Net_LDAP2 2.0.0, there is one default schema caching class: Net_LDAP2_SimpleFileSchemaCache to make your life a little easier. Caching to files should also be the most commonly used case.
This cache class is built to be flexible yet simple to use and may serve as example to write own caching classes. This cache stores the schema object in a flat file. The path is freely configurable. It also servers a cache aging mechanism that can be used to invalidate the cached schema after some time so it will be refreshed regularly.
To use this cache, you firstly need to initialize and configure a fresh cache object. Then the cache must be registered with the Net_LDAP2 instance. After that, Net_LDAP2 will use the cache.
Initializing the SimpleFileSchemaCache
<?php
$myCacheConfig = array(
'path' => '/tmp/Net_LDAP_Schema.cache', // may reside on an linux tmpfs for improved performance
'max_age' => 1200 // in seconds, use 0 for endlessly
);
$myCacheObject = new Net_LDAP2_SimpleFileSchemaCache($myCacheConfig);
$ldap->registerSchemaCache($myCacheObject);
?>
| Option | Mandatory? | Default | Description |
|---|---|---|---|
path |
No | /tmp/Net_LDAP_Schema.cache |
The full path to the cache file. To improve the caches performance under linux, you can place the cache file in a tmpfs mounted directory. This will put the file in the computers memory instead on disk, enabling nearly instant access. |
max_age |
No | 1200 |
Maximum cache age in seconds. The age of the cache is determined by the files
last change time. If max_age is reached, Net_LDAP2 will fetch
a fresh Net_LDAP2_Schema object which is then stored in the cache file again.
Setting this to "0" will make the cache endlessly valid.
|
Writing own schema cache classes
However this is basicly an easy task, this is beyond the scope of this manual. If you want to write your
own custom schema cache, please refer to the detailed example at
/your/pear/path/docs/Net_LDAP2/examples/schema_cache.php as well as the source/APIdoc of
the interface Net_LDAP2_SchemaCache.