Tworzymy adresowy serwis WEB w PHP + LDAP

Zdarzyło się, że stosunkowo duża firma miała wiele zdalnych biur, w których znajdowało się sporo użytkowników. Wszystkie biura były połączone w jedną sieć z wspólną domeną, a każde biuro zostało zdefiniowane w Active Directory (w dalszej części tekstu AD) jako Organizational Unit (OU), w którym już przypisano użytkowników.

Należało umożliwić użytkownikom szybkie i bez większego wysiłku uzyskiwanie danych kontaktowych potrzebnego pracownika z AD, a administratorów systemu odciążyć od rutynowego edytowania pliku tekstowego, który pełnił rolę książki adresowej.

Nie znaleziono odpowiednich gotowych rozwiązań dla zadanej kwestii, więc trzeba było zrobić wszystko samodzielnie.

Zacznijmy od tego, że najpierw trzeba określić, co wykorzystać, co jest proste — finalny folder powinien być dostępny dla wszystkich użytkowników domeny za pośrednictwem przeglądarki. Pierwsze, co przychodzi na myśl, to PHP w połączeniu z ldap, i to będziemy stosować. Uważam, że dużym plusem używania PHP jest jego względna prostota — każdy administrator systemu, który choć trochę się zna, będzie mógł w razie potrzeby wprowadzić niezbędne poprawki w kodzie, nie mając przy tym zbyt wielu trudności.

Zatem zaczynamy. Na początek definiujemy parametry połączenia z domeną:

$srv ="SERWER";
$srv_domain ="DOMENA.COM";
$srv_login ="USERNAME@".$srv_domain; 
$srv_password ="HASŁO";

Następnym krokiem jest określenie, w jakim OU będziemy szukać użytkowników. Będziemy to robić, przechwytując wartości z $_GET[‘place’]. Na przykład, jeśli użytkownik przechodzi pod adres server/index.php?place=first, to zmiennej $place przypisane zostanie wartość first.

$place = (@$_GET['place']);
$doscript=true;
switch($place){ 
case "first" :
	$dn ="OU=ou1,OU=DOMENA,dc=DOMENA,dc=COM";			
	break;
case "second":
	$dn ="OU=ou2,OU=DOMENA,dc=DOMENA,dc=COM";			
	break;
	// tutaj można dodać więcej warunków.
default:
	$doscript=false; 
	break;
}
if (!$doscript) include "main_table.html";

Zmienna $doscript jest potrzebna do przechowywania wartości — określiliśmy, czy znaleźliśmy OU, w którym będziemy szukać użytkowników, czy nie. Jeśli nie znaleziono żadnych pasujących w „switch-case”, $doscript=false, główna część skryptu nie zostanie wykonana, a wyświetlona zostanie strona startowa „main_table.html” (o której opowiem na końcu).

Jeśli natomiast określiliśmy OU, przechodzimy do kolejnych działań: zaczynamy rysować dla użytkownika stronę katalogu:

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/ '>

Włączamy style dla bardziej przyjemnego wyglądu (tak, można je było załadować jako plik css, jednak niektóre wersje IE nie chcą rozpoznać stylów w ten sposób, więc musimy pisać je bezpośrednio w skrypcie):

*{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;}
	
	/* Niekiedy wiersze */#table tbody tr:nth-child(odd){background: #fff;}
	/* Parzyste wiersze */   #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;}

Z stylami skończone, teraz zapisujemy tytuł zakładki i tworzymy wygodny link powrotu na stronę główną:

<title>Książka adresowa «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>Strona główna</p></a>
</td></tr></table>
";

Definiujemy filtry wyszukiwania według AD i uzyskujemy dane o OU:

$filter ="(&(objectcategory=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))"; // wszyscy użytkownicy, poza wyłączonymi.
$filter2 ="(objectCategory=OrganizationalUnit)"; // aby uzyskać informacje o 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];  			// nazwa miejsca
$PlaceAddres = $placeinfo[0]["street"][0];		// adres miejsca
$PlaceMail = $placeinfo[0]["description"][0]; 	// e-mail miejsca
$PlacePhone = $placeinfo[0]["st"][0]; 		// telefon miejsca

Następnie formatujemy górną część strony:

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">  Nr </td>
	<td width='300' bgcolor = "#f0f0e4"> Nazwa </td>
	<td width='250' bgcolor = "#f0f0e4"> E-mail </td>
	<td width='60' bgcolor = "#f0f0e4"> Telefon </td>
	<td width='150' bgcolor = "#f0f0e4"> Mobilne </td></tr>
	<tr><td></td><td> Dane 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>";

Następnie w pętli uzyskujemy i przetwarzamy dane użytkowników, przy tym, aby ukryć niektóre (na przykład konta serwisowe), wystarczy wpisać „hide” w polu „pokój” w atrybutach użytkownika w AD, tacy użytkownicy nie będą wyświetlani w katalogu:

for ($i=0; $i<$info["count"];$i++) { 
$UserHide = $info[$i]["physicaldeliveryofficename"][0];
if ($UserHide != 'hide') {
$UserName = $info[$i]["cn"][0];                //Imię użytkownika
$UserPosition = $info[$i]["title"][0]; 		// Stanowisko
$UserMail = $info[$i]["mail"][0];			//mail
if (!$UserMail)) $UserMail = "-";                  //jeśli brak danych o skrzynce w AD, pokazujemy myślnik
$UserIpPhone = $info[$i]["ipphone"][0];		// telefon IP
	if (!$UserIpPhone) $UserIpPhone = "-";    //jeśli brak danych o skrzynce w AD, pokazujemy myślnik
$UserMobile = $info[$i]["mobile"][0];		//mobilny
	if (!$UserMobile) $UserMobile = "-";     //jeśli brak danych o skrzynce w AD, pokazujemy myślnik

A tak przy okazji, jeśli potrzebujesz uzyskać wartość innego atrybutu, pamiętaj (to ważne):
przekazujemy nazwę atrybutu w zapytaniu małymi literami literami, inaczej nie zadziała.

I wstawiamy uzyskane dane do tabeli:

    echo "<tr>
	<td>". $n+=1 ."</td>
	<td> ". $UserName ."<br> <div class='smalltext'>". $UserPosition ."</div></td><td>"; // Nazwa użytkownika i stanowisko 
	if ($UserMail !='-') echo "<div class='transition-rotate'><a href="mailto:'$UserMail'">$UserMail  </a></div>";    // jeśli użytkownik ma e-mail, tworzymy link do wysyłania wiadomości
	else echo "-"; // jeśli nie ma e-maila - wstawiamy myślnik.
 	echo "<td> ". $UserIpPhone ." </td>
 	<td> ". $UserMobile ." </td></tr>";
	}
}
echo "</table>";

Następnie zamykamy połączenie przez ldap, lub wyświetlamy komunikat o niemożności połączenia z serwerem:

ldap_close($ds); 
} 
else echo "<h4>Nie można połączyć się z serwerem LDAP</h4>"; 
echo '<br><br><br></body></html>';}

Plik „main_table.html” wewnętrznie reprezentuje prostą stronę HTML z linkami i wygląda mniej więcej tak:

<head>
<link rel="shortcut icon" href="ico.png"/>
<meta charset="windows-1251"/>
<title>Książka adresowa «YourMegaCompanyName»</title>
</head>
<body style='background-color:#ffffff;'>
<center><a href="index.php"><img border="none" src="logo.png"/></a></center>
<center><b>Miejsca i biura</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>

Jeśli komuś mój kod pomoże — będę szczęśliwy, korzystajcie!

Możecie również swobodnie edytować go według własnych upodobań (poprawiać/pogarszać) i rozpowszechniać wszelkimi metodami.

Dziękuję za uwagę!

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster