Створюємо WEB адресний довідник PHP+LDAP

Так сталося, що (відносно) великої кампанії було багато віддалених офісів, в яких знаходилася пристойна кількість користувачів. Всі офіси з'єднані в одну мережу із спільним доменом, кожен офіс був визначений в Active Directory (далі за текстом AD) як Organization Unit (OU), в якому вже заводилися користувачі.

Необхідно було дати користувачам можливість швидко і без особливих зусиль отримувати контактні дані необхідного співробітника AD, а системних адміністраторів звільнити від рутини редагування текстового файлу, який грав роль адресної книги.

Готових відповідних варіантів для вирішення поставленого завдання не знайшлося, тому довелося робити все своїми руками та головою.

Почнемо з того, що для початку потрібно визначитися, що використовувати, це просто - підсумковий довідник повинен бути доступний всім користувачам домену за допомогою браузера. Перше, що спадає на думку це PHP у зв'язці з ldap, їх і будемо використовувати. Великим плюсом використання PHP я вважаю його відносну простоту — будь-який системний адміністратор, який хоч трохи розуміє, зможе внести, при необхідності, потрібні правки в код, не особливо напружуючись.

Тож почнемо. для початку задаємо параметри підключення до домену:

$srv ="SERVER";
$srv_domain ="DOMAIN.COM";
$srv_login ="USERNAME@".$srv_domain; 
$srv_password ="PASSWORD";

Наступним пунктом потрібно визначити в якому OU шукатимемо користувачів. Робити це будемо перехоплюючи значення $_GET['place']. Наприклад, якщо користувач переходить на адресу server/index.php?place=перший, то змінною $place буде надано значення перший.

$place = (@$_GET['place']);
$doscript=true;
switch($place){ 
case "first" :
	$dn ="OU=ou1,OU=DOMAIN,dc=DOMAIN,dc=COM";			
	break;
case "second":
	$dn ="OU=ou2,OU=DOMAIN,dc=DOMAIN,dc=COM";			
	break;
	//здесь можно добавить ещё условий.
default:
	$doscript=false; 
	break;
}
if (!$doscript) include "main_table.html";

Мінлива $doscript потрібна для того, щоб зберігати значення — ми визначили OU, в якому шукатимемо користувачів чи ні. Якщо не знайшлося збігів, перерахованих у switch-case, то $doscript=false, головна частина скрипту виконуватися не буде, а буде виведена стартова сторінка main_table.html (про неї розповім в самому кінці).

Якщо ж ми визначили OU, тоді розпочинаємо подальші дії: починаємо малювати користувачеві сторінку довідника:

else if ($doscript) {
{echo "
<!DOCTYPE html> 
<html xmlns='http://www.w3.org/1999/xhtml'>
<head>
<link rel='shortcut icon' href='ico.png'>
<meta charset='windows-1251/ '>

Включаємо стилі для приємнішого зовнішнього вигляду (так, їх можна було підключити як css-файл, проте деякі версії IE не хочуть сприймати стилі, задані таким чином, тому доводиться писати прямо в скрипт):

<style>
	*{text-align: center; font-family:tahoma; font-size:14px;}
	a{text-decoration: none; color: #000;}
	a:hover{text-decoration: underline; color: #0059FF;}
	#bold{text-decoration: none; font-weight: 600;font-size:20px;}
	#table,tr,td{border-style:solid;border-width:1px;	border-collapse:collapse;padding:5px; height:22px;border-color:#7d7d7d;}
	/* Нечетные строки */#table tbody tr:nth-child(odd){background: #fff;}
	/* Четные строки */   #table tbody tr:nth-child(even){background: #F7F7F7;}	
	#noborder{border-width: 0 px; border-style: none;}	
	#sp30px{text-indent: 30px;text-align: justify;}
	#smallsize{font-family:tahoma; text-indent: 5px; text-align:left; font-size:12px;}
	#top {background: #ffffff;
		text-align: center;
		left:0;
		top:0px;
		table-layout: fixed;
		border-style:solid;
		border-width:0px;
		border-collapse:collapse;
		padding:0px;
		height:22px;
		border: 0px;
		z-index: 99999;
		display:block;
		width:80px;
		opacity: 0.6;
		filter: alpha(Opacity=60);
		height:100%;
		position:fixed;}
	#top:hover{background: #afafaf;opacity: 100;filter: alpha(Opacity=100);text-decoration: none;color: #000000;}
	.smalltext{padding-top: 1px;
		padding-bottom: 1px;
		text-align: bottom;
		font-family:tahoma;
		color: #a0a0a0;
		line-height: 7px;
		font-size: 10px;}
	.smalltext:hover{color: #0000ff;}		
	.transition-rotate {position: relative;
		z-index: 2;
		margin: 0 auto;
		padding: 5px;
		text-align: center;
		max-width: 500px;
		cursor: pointer;
		transition: 0.1s linear;}
	.transition-rotate:hover {-webkit-transform: rotate(-2deg);	transform: rotate(-2deg);}
	#lineheight{
		text-align: left;
		line-height: 1px;
		text-decoration: none;
		font-weight: 600;
		font-size:20px;}
</style>

Зі стилями покінчено, тепер пишемо заголовок вкладки та малюємо зручне посилання повернення на головну сторінку:

<title>Adressbook of «YourMegaCompanyName»</title>	
</head>
<body style='background-color:#ffffff;'>";
}
echo "
<table id='top'><tr><td id='top'>
<a href='index.php?place=main' id='top' >
<br><br><br>
<img src='back_to_main.png' alt='' border='0' width='75' height='60'/>
<p>На главную</p></a>
</td></tr></table>
";

Визначаємо пошукові фільтри по AD, і отримуємо дані про OU:

$filter ="(&(objectcategory=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))"; //все пользователи, кроме отключенных.
$filter2 ="(objectCategory=OrganizationalUnit)"; // для получения информации о OU
$ds=ldap_connect($srv);   
if ($ds) { 
    $r=ldap_bind($ds,$srv_login,$srv_password);;     
	ldap_set_option($ds,LDAP_OPT_REFERRALS, 0);
	ldap_set_option($ds,LDAP_OPT_PROTOCOL_VERSION,3);
	$sr=ldap_search($ds,$dn ,$filter );   
    ldap_sort($ds,$sr, "givenname");
    $info = ldap_get_entries($ds, $sr); 
    $sr2=ldap_search($ds,$dn ,$filter2 );   
    $placeinfo = ldap_get_entries($ds, $sr2); 
$PlaceName = $placeinfo[0]["l"][0];  			// name of place
$PlaceAddres = $placeinfo[0]["street"][0];		// address of place
$PlaceMail = $placeinfo[0]["description"][0]; 	// mail of place
$PlacePhone = $placeinfo[0]["st"][0]; 		// phone of plase

Далі оформляємо верхню частину сторінки:

echo"<table align='center' height = '80'>
	<td id='noborder' ><div id='lineheight'>". $PlaceName ."</div></td></tr>
	<tr><td id='noborder' >". $PlaceAddres ."</td></tr>
    </table>
<table align='center' id='table'>
	<tr><td width='35' bgcolor = #f0f0e4>  № </td>
	<td width='300' bgcolor = #f0f0e4> Name </td>
	<td width='250' bgcolor = #f0f0e4> E-mail </td>
	<td width='60' bgcolor = #f0f0e4> Phone </td>
	<td width='150' bgcolor = #f0f0e4> Mobile </td></tr>
	<tr><td></td><td> Данные OU </td><td>";
echo "<div class='transition-rotate'><a href=mailto:" . $PlaceMail .">" . $PlaceMail ." </a></div>";
echo "</td><td width='150'> " . $PlacePhone ." </td><td> - </td></tr>";

Далі отримуємо в циклі та обробляємо дані користувачів, при цьому, щоб приховати деякі (наприклад службові) облікові записи, просто прописуємо "hide" у полі "кімната" в реквізитах користувача в AD, такі користувачі не відображатимуться в довіднику:

for ($i=0; $i<$info["count"];$i++) { 
$UserHide = $info[$i]["physicaldeliveryofficename"][0];
if ($UserHide != 'hide') {
$UserName = $info[$i]["cn"][0];                //Имя пользователя
$UserPosition = $info[$i]["title"][0]; 		// Должность
$UserMail = $info[$i]["mail"][0];			//mail
if (!$UserMail)) $UserMail = "-";                  //если нет данных о ящике в AD, то отображаем прочерк
$UserIpPhone = $info[$i]["ipphone"][0];		//ip phone
	if (!$UserIpPhone) $UserIpPhone = "-";    //если нет данных о ящике в AD, то отображаем прочерк
$UserMobile = $info[$i]["mobile"][0];		//mobile
	if (!$UserMobile) $UserMobile = "-";     //если нет данных о ящике в AD, то отображаем прочерк

До речі, якщо вам знадобиться отримати значення іншого атрибуту, то пам'ятайте (це важливо):
у запиті передаємо ім'я атрибута малими літерами, інакше не почне працювати.

І вставляємо отримані дані до таблиці:

    echo "<tr>
	<td>". $n+=1 ."</td>
	<td> ". $UserName ."<br> <div class='smalltext'>". $UserPosition ."</div></td><td>"; //	Имя пользователя и должность 
	if ($UserMail !='-') echo "<div class='transition-rotate'><a href=mailto:'$UserMail'>$UserMail  </a></div>";    // если у пользователя есть e-mail создаём ссылку на отправку письма
	else echo "-"; //если нет e-mail - ставим прочерк.
 	echo "<td> ". $UserIpPhone ." </td>
 	<td> ". $UserMobile ." </td></tr>";
	}
}
echo "</table>";

Далі ми закриваємо підключення по ldap, або виводимо повідомлення про неможливість підключення до сервера:

ldap_close($ds); 
} 
else echo "<h4>Unable to connect to LDAP server</h4>"; 
echo '<br><br><br></body></html>';}

Файл «main_table.html» зсередини представляє просту html сторінку з посиланнями, і виглядає приблизно так:

<head>
<link rel="shortcut icon" href="ico.png"/>
<meta charset="windows-1251"/>
<title>Adressbook of «YourMegaCompanyName»</title>
</head>
<body style='background-color:#ffffff;'>
<center><a href=index.php><IMG border="none" src="logo.png"/></a></center>
<center><b>Places and offices</b></center>
<br>
<table border="0" width="450" bgcolor="#dddddd" align="center" valign="middle" CELLSPACING="0">

<tr id="space"><td></td></tr>
<tr><td align="left" id="abz"><a href="index.php?place=ou1">OU1</a></td></tr>
<tr id="space"><td></td></tr>
<tr><td align="left" id="abz"><a href="index.php?place=ou2">OU2</a></td></tr>

</table></body></html>

Якщо комусь допоможе мій код — я радий, користуйтесь!

Також можете вільно редагувати його як вам завгодно (покращувати/погіршувати) та розповсюджувати будь-якими методами.

Дякуємо за увагу!

Джерело: habr.com

Додати коментар або відгук