LDAP search multiple DNs in PHP - php

According to these posts in the php.net manual it should be possible to supply multiple DNs for ldap_search().
However, I can't get the below implementation to work:
$dn[] = 'ou=Red,ou=Teams,ou=Users,dc=example,dc=org';
$dn[] = 'ou=Green,ou=Teams,ou=Users,dc=example,dc=org';
$dn[] = 'ou=Blue,ou=Teams,ou=Users,dc=example,dc=org';
$query = ldap_search($conn, $dn, $filter, $attrs);
Everything is fine when passing through any of the individual DN strings, but supplying an array will error with message: 'No such object'.
An obvious work around for this is to loop over my DN array to fire off separate queries and push everything in to one array. I'd like to avoid having to do that, since I'm bringing back 8000+ objects in one DN (Paginated - Example 2) and ~300 in each of the other two.
Is it actually possible to search multiple DNs?
Perhaps special syntax (symbol/character) within the single DN string?

Search requests must contain a minimum the following parameters:
the base object at which the search starts (no objects above the base objects are returned)
the scope of the search: base is the base object itself, one is the base object and
one level below the base object, sub is the base object and all entries below the base object.
a filter which limits the entries returned to those entries which match the assertion in the
filter
A list of attributes can also be supplied, though many, but not all, LDAP APIs will request all
user attributes if none are supplied in the search request.
In the case listed, set the base object to ou=users,dc=example,dc=com and use an appropriate
filter. If the LDAP client must restrict the returned entries to entries that are subordinate
to ou=red, ou=green, or ou=blue it may be possible to use a compound extensible match filter
like (&(objectClass=inetOrgPerson)(|(ou:dn:=red)(ou:dn:=green)(ou:dn:=blue))) - use the correct object
class if the data does not use inetOrgPerson. All LDAP-compliant servers support extensible
match filters, but non-compliant servers may not support this standard filter.
It is not possible to use multiple base objects, the scope parameter defines how many subordinate
levels, if any, are examined below the base object.
see also
LDAP: Mastering Search Filters
LDAP: Search best practices
LDAP: Programming practices

Did you see this in the manual?
Those arrays must be of the same size as the link identifier array since the first entries of the arrays are used for one search, the second entries are used for another, and so on.
Basically, your $conn variable needs to be an array of connections equal to the size of your $dn array.
If you have 3 elements in your $dn array, you need 3 elements in your $conn array:
$ds = ldap_connect($ldapserver);
$dn[] = 'ou=Red,ou=Teams,ou=Users,dc=example,dc=org';
$dn[] = 'ou=Green,ou=Teams,ou=Users,dc=example,dc=org';
$dn[] = 'ou=Blue,ou=Teams,ou=Users,dc=example,dc=org';
// Match connection elements to count of dn elements
for($x=0, $x < count($dn), $x++)
{
$conn[] = $ds;
}
$query = ldap_search($conn, $dn, $filter, $attrs);

Related

How to do an LDAP search on a muli value Attribute

I am trying to do a LDAP Search on a multivalue attribute ACL using PHP. But when I try to set a filter on ACL $filter="(ACL=*$cn*)" where $cn = prnman03 there are no results returned.
ACL - 16#entry#cn=prnman03,ou=ipp,ou=services,o=uct#[Entry Rights]
3#entry#[Root]#iPrintPrinterIPPURI
8#entry#ou=backup,ou=ipp,ou=services,o=uct#iPrintPrinterUserRole
8#entry#ou=ippl,ou=ipp,ou=services,o=uct#iPrintPrinterUserRole
8#entry#ou=ipp,ou=services,o=uct#iPrintPrinterUserRole
cn - IPP00005
iPrintPrinterIPPURI- ipp://srvnbsidw001.uct.ac.za/ipp/IPP00005
If one of the attribute values matches the filter, then the entry will be considered to be returned (as long as permissions allow).
But remember that LDAP Filters are resolving in True, False, Undefined. Undefined means that there was no way to apply the filter and get a result. If there is no substring matching rule defined for the ACL attribute, then matching a substring filter will be undefined.
As you are doing this on an ACL for eDirectory, I do not think you will find and values that work for substrings. Even though their documentation say there are some conditions where matching will work, I have not be able to find or perform any such matches.

Assign array value to a field

I am working with migration and I am migrating taxonomy terms that the document has been tagged with. The terms are in the document are separated by commas. so far I have managed to separate each term and place it into an array like so:
public function prepareRow($row) {
$terms = explode(",", $row->np_tax_terms);
foreach ($terms as $key => $value) {
$terms[$key] = trim($value);
}
var_dump($terms);
exit;
}
This gives me the following result when I dump it in the terminal:
array(2) {
[0]=>
string(7) "Smoking"
[1]=>
string(23) "Not Smoking"
}
Now I have two fields field_one and field_two and I want to place the value 0 of the array into field_one and value 1 into field_two
e.g
field_one=[0]$terms;
I know this isn't correct and I'm not sure how to do this part. Any suggestions on how to do this please?
If you are only looking to store the string value of the taxonomy term into a different field of a node, then the following code should do the trick:
$node->field_one['und'][0]['value'] = $terms[0];
$node->field_two['und'][0]['value'] = $terms[1];
node_save($node);
Note you will need to load the node first, if you need help with that, comment here and will update my answer.
You are asking specifically about ArrayList and HashMap, but I think to fully understand what is going on you have to understand the Collections framework. So an ArrayList implements the List interface and a HashMap implements the Map interface.
List:
An ordered collection (also known as a sequence). The user of this interface has precise control over where in the list each element is inserted. The user can access elements by their integer index (position in the list), and search for elements in the list.
Map:
An object that maps keys to values. A map cannot contain duplicate keys; each key can map to at most one value.
So as other answers have discussed, the list interface (ArrayList) is an ordered collection of objects that you access using an index, much like an array (well in the case of ArrayList, as the name suggests, it is just an array in the background, but a lot of the details of dealing with the array are handled for you). You would use an ArrayList when you want to keep things in sorted order (the order they are added, or indeed the position within the list that you specify when you add the object).
A Map on the other hand takes one object and uses that as a key (index) to another object (the value). So lets say you have objects which have unique IDs, and you know you are going to want to access these objects by ID at some point, the Map will make this very easy on you (and quicker/more efficient). The HashMap implementation uses the hash value of the key object to locate where it is stored, so there is no guarentee of the order of the values anymore.
You might like to try:
list($field_one, $field_two) = prepareRow($row);
The list function maps entries in an array (in order) to the variables passed by reference.
This is a little fragile, but should work so long as you know you'll have at least two items in your prepareRow result.

Search by term giving empty result using elastica

Using Elastica - Elasticsearch PHP Client. There are so many fields but I want to search in "Screen_name" field. What I have to do for it. I used term but without success. Result is empty array
Here is the code.
// Load index (database)
$elasticaIndex = $elasticaClient->getIndex('twitter_json');
//Load type (table)
$elasticaType = $elasticaIndex->getType('tweet_json');
$elasticaFilterScreenName = new \Elastica\Filter\Term();
$elasticaFilterScreenName->setTerm('screen_name', 'sohail');
//Search on the index.
$elasticaResultSet = $elasticaIndex->search($elasticaFilterScreenName);
var_dump($elasticaResultSet); exit;
$elasticaResults = $elasticaResultSet->getResults();
$totalResults = $elasticaResultSet->getTotalHits();
It's hard to say without knowing your mapping, but there is a good chance the document property "screen_name" does not contain the term "sohail".
Try using a Match query or a Query_String.
"Term" has special meaning in ElasticSearch. A Term is the base, atomic unit of an index. Terms are generated after your text is run through an analyzer. If "screen_name" has an analyzer associated with the index, "sohail" is being modified in some capacity before being saved into the index.

Read from LDAP based on ObjectGUID with PHP

I've created a web based administration system for our AD environment. I'm having issues currently trying to read directory entries based on objectguid. Is this possible to do?
I'm able to do something like:
$filter = "(&(objectclass=*)(objectguid=$objectguid))";
$search = ldap_read($ds, $dn, $filter);
With the $dn being something like CN=Test,OU=Group,DC=OCJ,DC=Domain,DC=Com. So I know it's accepting the guid, but I'd like to skip the $dn part, reading with ONLY the GUID.
Any suggestions? I can't find anything saying that ldap_read can read directly with GUID.
To read only the guid, give the third parameters that controls what attributes you want returned. The second $dn parameter is mandatory, it specifies the search scope, and you can always set it to the root_dn if you want to be less specific.
If you want no dn entries in the result set array, that is not possible directly as this is the API of the ldap_read function, but you can filter them out by traversing the array (map).
$search = ldap_read($ds, $root_dn, $filter, array('objectguid'));
You can bind by GUID also. Set your $dn to <GUID={guid-goes-here}>

Equivalent of std::set in PHP?

What's the equivalent function in PHP for C plus plus "set" ("Sets are a kind of associative containers that stores unique elements, and in which the elements themselves are the keys.")?
There isn't one, but they can be emulated.
Here is a achieve copy before the link died.. all the contents
A Set of Objects in PHP: Arrays vs. SplObjectStorage
One of my projects, QueryPath, performs many tasks that require maintaining a set of unique objects. In my quest to optimize QueryPath, I have been looking into various ways of efficiently storing sets of objects in a way that provides expedient containment checks. In other words, I want a data structure that keeps a list of unique objects, and can quickly tell me if some object is present in that list. The ability to loop through the contents of the list is also necessary.
Recently I narrowed the list of candidates down to two methods:
Use good old fashioned arrays to emulate a hash set.
Use the SPLObjectStorage system present in PHP 5.2 and up.
Before implementing anything directly in QueryPath, I first set out designing the two methods, and then ran some micro-benchmarks (with Crell's help) on the pair of methods. To say that the results were surprising is an understatement. The benchmarks will likely change the way I structure future code, both inside and outside of Drupal.
The Designs
Before presenting the benchmarks, I want to quickly explain the two designs that I settled on.
Arrays emulating a hash set
The first method I have been considering is using PHP's standard array() to emulate a set backed by a hash mapping (a "hash set"). A set is a data structure designed to keep a list of unique elements. In my case, I am interested in storing a unique set of DOM objects. A hash set is a set that is implemented using a hash table, where the key is a unique identifier for the stored value. While one would normally write a class to encapsulate this functionality, I decided to test the implementation as a bare array with no layers of indirection on top. In other words, what I am about to present are the internals of what would be a hash set implementation.
The Goal: Store a (unique) set of objects in a way that makes them (a) easy to iterate, and (b) cheap to check membership.
The Strategy: Create an associative array where the key is a hash ID and the value is the object.
With a reasonably good hashing function, the strategy outlined above should work as desired.
"Reasonably good hashing function" -- that was the first gotcha. How do you generate a good hashing function for an object like DOMDocument? One (bad) way would be to serialize the object and then, perhaps, take its MD5 hash. That, however, will not work on many objects -- specifically any object that cannot serialze. The DOMDocument, for example, is actually backed by a resource and cannot be serialized.
One needed look far for a such a function, though. It turns out that there is an object hashing function in PHP 5. It's called spl_object_hash(), and it can take any object (even one that is not native PHP) and generate a hashcode for it.
Using spl_object_hash() we can build a simple data structure that functions like a hash set. This structure looks something like this:
array(
$hashcode => $object
);
For example, we an generate an entry like so:
$object = new stdClass();
$hashcode = spl_object_hash($object);
$arr = array(
$hashcode => $object
);
In the example above, then, the hashcode string is an array key, and the object itself is the array value. Note that since the hashcode will be the same each time an object is re-hashed, it serves not only as a comparison point ("if object a's hashkey == object b's hashkey, then a == b"), it also functions as a uniqueness constraint. Only one object with the specified hashcode can exist per array, so there is no possibility of two copies (actually, two references) to the same object being placed in the array.
With a data structure like this, we have a host of readily available functions for manipulating the structure, since we have at our disposal all of the PHP array functions. So to some degree this is an attractive choice out of the box.
The most import task, in our context at least, is that of determining whether an entry exists inside of the set. There are two possible candidates for this check, and both require supplying the hashcode:
Check whether the key exists using array_key_exists().
Check whether the key is set using isset().
To cut to the chase, isset() is faster than array_key_exists(), and offers the same features in our context, so we will use that. (The fact that they handle null values differently makes no difference to us. No null values will ever be inserted into the set.)
With this in mind, then, we would perform a containment check using something like this:
$object = new stdClass();
$hashkey = spl_object_hash($object);
// ...
// Check whether $arr has the $object.
if (isset($arr[$hashkey])) {
// Do something...
}
Again, using an array that emulates a hash set allows us to use all of the existing array functions and also provides easy iterability. We can easily drop this into a foreach loop and iterate the contents. Before looking at how this performs, though, let's look at the other possible solution.
Using SplObjectStorage
The second method under consideration makes use of the new SplObjectStorage class from PHP 5.2+ (it might be in 5.1). This class, which is backed by a C implementation, provides a set-like storage mechanism for classes. It enforces uniqueness; only one of each object can be stored. It is also traversable, as it implements the Iterable interface. That means you can use it in loops such as foreach. (On the down side, the version in PHP 5.2 does not provide any method of random access or index-based access. The version in PHP 5.3 rectifies this shortcoming.)
The Goal: Store a (unique) set of objects in a way that makes them (a) easy to iterate, and (b) cheap to check membership.
The Strategy: Instantiate an object of class SplObjectStorage and store references to objects inside of this.
Creating a new SplObjectStorage is simple:
$objectStore = new SplObjectStorage();
An SplObjectStorage instance not only retains uniqueness information about objects, but objects are also stored in predictable order. SplObjectStorage is a FIFO -- First In, First Out.
Adding objects is done with the attach() method:
$objectStore = new SplObjectStorage();
$object = new stdClass();
$objectStore->attach($object);
It should be noted that attach will only attach an object once. If the same object is passed to attach() twice, the second attempt will simply be ignored. For this reason it is unnecessary to perform a contains() call before an attach() call. Doing so is redundant and costly.
Checking for the existence of an object within an SplObjectStorage instance is also straightforward:
$objectStore = new SplObjectStorage();
$object = new stdClass();
$objectStore->attach($object);
// ...
if ($objectStore->contains($object)) {
// Do something...
}
While SplObjectStorage has nowhere near the number of supporting methods that one has access to with arrays, it allows for iteration and somewhat limited access to the objects stored within. In many use cases (including the one I am investigating here), SplObjectStorage provides the requisite functionality.
Now that we have taken a look at the two candidate data structures, let's see how they perform.
The Comparisons
Anyone who has seen Larry (Crell) Garfield's micro-benchmarks for arrays and SPL ArrayAccess objects will likely come into this set of benchmarks with the same set of expectations Larry and I had. We expected PHP's arrays to blow the SplObjectStorage out of the water. After all, arrays are a primitive type in PHP, and have enjoyed years of optimizations. However, the documentation for the SplObjectStorage indicates that the search time for an SplObjectStorage object is O(1), which would certainly make it competitive if the base speed is similar to that of an array.
My testing environments are:
An iMac (current generation) with a 3.06 Ghz Intel Core 2 Duo and 2G of 800mhz DDR2 RAM. MAMP 1.72 (PHP 5.2.5) provides the AMP stack.
A MacBook Pro with a 2.4 Ghz Intel Core 2 Duo and 4G of 667mhz DDR2 RAM. MAMP 1.72 (PHP 5.2.5) provides the AMP stack.
In both cases, the performance tests averaged about the same. Benchmarks in this article come from the second system.
Our basic testing strategy was to build a simple test that captured information about three things:
The amount of time it takes to load the data structure
The amount of time it takes to seek the data structure
The amount of memory the data structure uses
We did our best to minimize the influence of other factors on the test. Here is our testing script:
<?php
/**
* Object hashing tests.
*/
$sos = new SplObjectStorage();
$docs = array();
$iterations = 100000;
for ($i = 0; $i < $iterations; ++$i) {
$doc = new DOMDocument();
//$doc = new stdClass();
$docs[] = $doc;
}
$start = $finis = 0;
$mem_empty = memory_get_usage();
// Load the SplObjectStorage
$start = microtime(TRUE);
foreach ($docs as $d) {
$sos->attach($d);
}
$finis = microtime(TRUE);
$time_to_fill = $finis - $start;
// Check membership on the object storage
$start = microtime(FALSE);
foreach ($docs as $d) {
$sos->contains($d);
}
$finis = microtime(FALSE);
$time_to_check = $finis - $start;
$mem_spl = memory_get_usage();
$mem_used = $mem_spl - $mem_empty;
printf("SplObjectStorage:\nTime to fill: %0.12f.\nTime to check: %0.12f.\nMemory: %d\n\n", $time_to_fill, $time_to_check, $mem_used);
unset($sos);
$mem_empty = memory_get_usage();
// Test arrays:
$start = microtime(TRUE);
$arr = array();
// Load the array
foreach ($docs as $d) {
$arr[spl_object_hash($d)] = $d;
}
$finis = microtime(TRUE);
$time_to_fill = $finis - $start;
// Check membership on the array
$start = microtime(FALSE);
foreach ($docs as $d) {
//$arr[spl_object_hash($d)];
isset($arr[spl_object_hash($d)]);
}
$finis = microtime(FALSE);
$time_to_check = $finis - $start;
$mem_arr = memory_get_usage();
$mem_used = $mem_arr - $mem_empty;
printf("Arrays:\nTime to fill: %0.12f.\nTime to check: %0.12f.\nMemory: %d\n\n", $time_to_fill, $time_to_check, $mem_used);
?>
The test above is broken into four separate tests. The first two test how well the SplObjectStorage method handles loading and containment checking. The second two perform the same test on our improvised array data structure.
There are two things worth noting about the test above.
First, the object of choice for our test was a DOMDocument. There are a few reasons for this. The obvious reason is that this test was done with the intent of optimizing QueryPath, which works with elements from the DOM implementation. There are two other interesting reasons, though. One is that DOMDocuments are not lightweight. The other is that DOMDocuments are backed by a C implementation, making them one of the more difficult cases when storing objects. (They cannot, for example, be conveniently serialized.)
That said, after observing the outcome, we repeated the test with basic stdClass objects and found the performance results to be nearly identical, and the memory usage to be proportional.
The second thing worth mention is that we used 100,000 iterations to test. This was about the upper bound that my PHP configuration allowed before running out of memory. Other than that, though, the number was chosen arbitrarily. When I ran tests with lower iteration counts, the SplObjectStorage definitely scaled linearly. Array performance was less predictable (larger standard deviation) with smaller data sets, though it seemed to average around the same for lower sizes as it does (more predictably) for larger sized arrays.
The Results
So how did these two strategies fare in our micro-benchmarks? Here is a representative sample of the output generated when running the above:
SplObjectStorage:
Time to fill: 0.085041999817.
Time to check: 0.073099000000.
Memory: 6124624
Arrays:
Time to fill: 0.193022966385.
Time to check: 0.153498000000.
Memory: 8524352
Averaging this over multiple runs, SplObjectStorage executed both fill and check functions twice as fast as the array method presented above. We tried various permutations of the tests above. Here, for example, are results for the same test with a stdClass object:
SplObjectStorage:
Time to fill: 0.082209110260.
Time to check: 0.070617000000.
Memory: 6124624
Arrays:
Time to fill: 0.189271926880.
Time to check: 0.152644000000.
Memory: 8524360
Not much different. Even adding arbitrary data to the object we stored does not make a difference in the time it takes for the SplObjectStorage (though it does seem to raise the time ever so slightly for the array).
Our conclusion is that SplObjectStorage is indeed a better solution for storing lots of objects in a set. Over the last week, I've ported QueryPath to SplObjectStorage (see the Quark branch at GitHub -- the existing Drupal QueryPath module can use this experimental branch without alteration), and will likely continue benchmarking. But preliminary results seem to provide a clear indication as to the best approach.
As a result of these findings, I'm much less inclined to default to arrays as "the best choice" simply because they are basic data types. If the SPL library contains features that out-perform arrays, they should be used when appropriate. From QueryPath to my Drupal modules, I expect that my code will be impacted by these findings.
Thanks to Crell for his help, and for Eddie at Frameweld for sparking my examination of these two methods in the first place.
In PHP you use arrays for that.
There is no built-in equivalent of std::set in PHP.
You can use arrays "like" sets, but it's up to you to enforce the rules.
Have a look at Set from Nspl. It supports basic set operations which take other sets, arrays and traversable objects as arguments. You can see examples here.

Categories