Display Thumbnailphoto from Active Directory in PHP

Display thumbnailPhoto from Active Directory in PHP

This seems to be a JPEG-File, so you should be able to send that data together with the appropriate mime-type to the browser. It should be possible to output that image with something like:

<img src="data:image/jpeg;base64,<?php echo base64_encode($imageString); ?>"/>

But it might also be possible to save files of any image format into that thumbnailPhoto attribute. Therefore, I would put the content into a temporary file that will then be served directly from the server. You will need to pass the file through finfo to get the correct mime-type.

So you might do something like this:

$tempFile = tempnam(sys_get_temp_dir(), 'image');
file_put_contents($tempFile, $imageString);
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = explode(';', $finfo->file($tempFile));
echo '<img src="data:' . $mime[0] . ';base64,' . base64_encode($imageString) . '"/>';

PHP - get LDAP thumbnailphoto attribute to display in HTML

I got it working with FILEINFO as described in the link above after testing some more. Thank you.

Pull AD Photo using PHP

Try to run this code example:

<?php

// -------------- CHANGE VARIABLES TO SUIT YOUR ENVIRONMENT --------------
//LDAP server address
$server = "ldap://192.168.1.55";
//domain user to connect to LDAP
$user = "user.name@mydomain.local";
//user password
$psw = "password";
//FQDN path where search will be performed. OU - organizational unit / DC - domain component
$dn = "OU=Accounts,OU=My Company,DC=mydomain,DC=com";
//Search query. CN - common name (CN=* will return all objects)
$search = "CN=*";
// ------------------------------------------------------------------------

echo "<h2>php LDAP query test</h2>";
// connecting to LDAP server
$ds = ldap_connect($server);
$r = ldap_bind($ds, $user , $psw);
// performing search
$sr = ldap_search($ds, $dn, $search);
$data = ldap_get_entries($ds, $sr);

echo "Found " . $data["count"] . " entries";

for ($i = 0; $i < $data["count"]; $i++) {
echo "<h4><strong>Common Name: </strong>" . $data[$i]["cn"][0] . "</h4><br />";
echo "<strong>Distinguished Name: </strong>" . $data[$i]["dn"] . "<br />";

// Check if user photo exists
if (isset($data[$i]["thumbnailphoto"]) && isset($data[$i]["thumbnailphoto"][0])) {
echo "<strong>Photo in Base64: </strong>" . base64_encode($data[$i]["thumbnailphoto"][0]) . "<br />";
}
else {
echo "<strong>Photo not set</strong><br />";
}

// Checking if discription exists
if (isset($data[$i]["description"][0])) {
echo "<strong>Desription: </strong>" . $data[$i]["description"][0] . "<br />";
}
else {
echo "<strong>Description not set</strong><br />";
}

// Checking if email exists
if (isset($data[$i]["mail"][0])){
echo "<strong>Email: </strong>" . $data[$i]["mail"][0] . "<br /><hr />";
}
else {
echo "<strong>Email not set</strong><br /><hr />";
}
}

// close connection
ldap_close($ds);
?>

The problem should be that you check if $data[$i]["thumbnailphoto"][0] is set while you should check the $data[$i]["thumbnailphoto"] first.

Then you can read this question Display thumbnailPhoto from Active Directory in PHP and continue coding to display the image.

How to update photo in Active Directory using PHP ldap_modify

Are you sure you want the photo attribute? By default Outlook, etc. looks at the thumbnailPhoto attribute, which is just a byte array of the file (not base64 encoded). Something like this:

$changes['thumbnailPhoto'] = $data;

Displaying Windows Active Directory thumbnailPhoto in asp:net Search App

I see why it's taking so long. DirectorySearcher and DirectoryEntry can be a little sneaky with how many times it reaches out to AD. You have a lot more network requests going on there than you need.

In your code, you're going out to AD once for the search. Then for each result, you're using GetDirectoryEntry(). Then DirectoryEntry is going out to AD again the first time you use Properties. Worse still, as soon as you use Properties, it downloads every single attribute that has a value, even though you're only actually using 4 of them. That's a whole lot of useless network traffic.

You can avoid this by using Properties collection in the search results, which already has all the attributes (by default it gets every attribute that has a value).

But you can do even better: If you set the PropertiesToLoad property of DirectorySearcher then it will only return the values you want to use. This way, you have one network request for everything you want, and only what you want.

protected void SearchAD(object sender, EventArgs e)
{
string Name = TextBoxSearchFirstName.Text;
Name = Name.Replace("*", "") + "*";
var dsSearcher = new DirectorySearcher {
Filter = "(&(objectClass=user) (sn=" + Name + "))"
};
dsSearcher.PropertiesToLoad.Add("sn");
dsSearcher.PropertiesToLoad.Add("givenName");
dsSearcher.PropertiesToLoad.Add("samAccountName");
dsSearcher.PropertiesToLoad.Add("thumbnailPhoto");

using (var results = dsSearcher.FindAll()) {
var t = new DataTable("ActiveDir");
t.Columns.Add(new DataColumn("SecondName", typeof(string)));
t.Columns.Add(new DataColumn("FirstName", typeof(string)));
t.Columns.Add(new DataColumn("UserID", typeof(string)));
t.Columns.Add(new DataColumn("data", typeof(byte[])));

foreach (SearchResult searchResult in results) {
var myRow = t.NewRow();
myRow[0] = searchResult.Properties.Contains("sn") ? searchResult.Properties["sn"][0] : null;
myRow[1] = searchResult.Properties.Contains("givenName") ? searchResult.Properties["givenName"][0] : null;
myRow[2] = searchResult.Properties.Contains("samAccountName") ? searchResult.Properties["samAccountName"][0] : null;
myRow[3] = searchResult.Properties.Contains("thumbnailPhoto") ? searchResult.Properties["thumbnailPhoto"][0] : null;
t.Rows.Add(myRow);
}
}
GridView1.DataSource = t;
GridView1.DataBind();
}

A few notes:

The calls to Contains are needed because if the attribute is empty, then it doesn't exist in the Properties collection at all.

The search results returns everything as an array, regardless of whether it is or not in AD. Thus, the [0] is needed for every attribute.

You'll notice I put a using statement around the search results. This is needed to prevent memory leaks, according to the documentation of FindAll().



Related Topics



Leave a reply



Submit