Creando un directorio web en PHP + LDAP

Sucede que una gran empresa tenía muchas oficinas remotas, donde había una cantidad considerable de usuarios. Todas las oficinas estaban conectadas a una red con un dominio común, y cada oficina se definió en Active Directory (en adelante AD) como una Unidad Organizativa (OU), donde ya se creaban los usuarios.

Era necesario permitir que los usuarios obtuvieran rápidamente y sin mucho esfuerzo los datos de contacto del empleado necesario de AD, y liberar a los administradores del sistema de la rutina de editar un archivo de texto que actuaba como una libreta de direcciones.

No se encontraron opciones adecuadas para resolver la tarea planteada, así que tuvimos que hacerlo todo nosotros mismos.

Empecemos por definir qué usar. Es sencillo: el directorio final debe ser accesible para todos los usuarios del dominio a través del navegador. Lo primero que se me ocurre es utilizar PHP combinado con ldap, y esos serán nuestros instrumentos. Un gran beneficio de usar PHP es su relativa simplicidad: cualquier administrador del sistema que tenga algo de conocimiento podrá hacer las modificaciones necesarias en el código sin mucho problema.

Así que, comencemos. Primero, definamos los parámetros de conexión al dominio:

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

El siguiente paso es determinar en qué OU vamos a buscar a los usuarios. Esto lo haremos capturando los valores de $_GET[‘place’]. Por ejemplo, si el usuario accede a la dirección server/index.php?place=first, entonces la variable $place se le asignará el valor first.

$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;
	// aquí se pueden añadir más condiciones.
default:
	$doscript=false; 
	break;
}
if (!$doscript) include "main_table.html";

Variable $doscript sirve para almacenar el valor: si definimos o no la OU en la que buscaremos usuarios. Si no encontramos coincidencias en el 'switch-case', entonces $doscript=false y la parte principal del script no se ejecutará, sino que se mostrará la página de inicio 'main_table.html' (de la cual hablaré al final).

Si hemos definido la OU, entonces continuamos con los siguientes pasos: comenzamos a crear la página del directorio para el usuario:

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

Activamos estilos para una apariencia más agradable (sí, podrían haberse incluido como un archivo CSS, pero algunas versiones de IE no reconocen los estilos de esta manera, por lo que debemos escribirlos directamente en el script):

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

Ya hemos terminado con los estilos, ahora escribimos el título de la pestaña y diseñamos un conveniente enlace para volver a la página principal:

<title>Agenda de «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>Inicio</p></a>
</td></tr></table>
";

Definimos filtros de búsqueda por AD y obtenemos datos sobre OU:

$filter ="(&(objectcategory=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))"; // todos los usuarios, excepto los desactivados.
$filter2 ="(objectCategory=OrganizationalUnit)"; // para obtener información sobre 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];  			// nombre del lugar
$PlaceAddres = $placeinfo[0]["street"][0];		// dirección del lugar
$PlaceMail = $placeinfo[0]["description"][0]; 	// correo del lugar
$PlacePhone = $placeinfo[0]["st"][0]; 		// teléfono del lugar

A continuación, organizamos la parte superior de la página:

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">  Nº </td>
	<td width='300' bgcolor = "#f0f0e4"> Nombre </td>
	<td width='250' bgcolor = "#f0f0e4"> Correo electrónico </td>
	<td width='60' bgcolor = "#f0f0e4"> Teléfono </td>
	<td width='150' bgcolor = "#f0f0e4"> Móvil </td></tr>
	<tr><td></td><td> Datos de 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>";

Luego obtenemos en un ciclo y procesamos los datos de los usuarios, y para ocultar algunos (por ejemplo, cuentas de servicio), simplemente escribimos «hide» en el campo «room» en los atributos del usuario en AD, esos usuarios no aparecerán en el directorio:

for ($i=0; $i<$info["count"];$i++) { 
$UserHide = $info[$i]["physicaldeliveryofficename"][0];
if ($UserHide != 'hide') {
$UserName = $info[$i]["cn"][0];                //Nombre de usuario
$UserPosition = $info[$i]["title"][0]; 		//Puesto
$UserMail = $info[$i]["mail"][0];			//correo
if (!$UserMail)) $UserMail = "-";                  //si no hay datos del buzón en AD, mostramos un guion
$UserIpPhone = $info[$i]["ipphone"][0];		//teléfono IP
	if (!$UserIpPhone) $UserIpPhone = "-";    //si no hay datos del buzón en AD, mostramos un guion
$UserMobile = $info[$i]["mobile"][0];		//móvil
	if (!$UserMobile) $UserMobile = "-";     //si no hay datos del buzón en AD, mostramos un guion

Por cierto, si necesita obtener el valor de otro atributo, recuerde (esto es importante):
en la consulta pasamos el nombre del atributo en minúsculas letras, de lo contrario no funcionará.

Y pegamos los datos obtenidos en la tabla:

    echo "<tr>
	<td>". $n+=1 ."</td>
	<td> ". $UserName ."<br> <div class='smalltext'>". $UserPosition ."</div></td><td>"; \	Nombre de usuario y posición 
	if ($UserMail !='-') echo "<div class='transition-rotate'><a href="mailto:'$UserMail'">$UserMail  </a></div>";    \	Si el usuario tiene e-mail, creamos un enlace para enviar un mensaje
	else echo "-"; \	Si no hay e-mail, colocamos un guion.
 	echo "<td> ". $UserIpPhone ." </td>
 	<td> ". $UserMobile ." </td></tr>";
	}
}
echo "</table>";

Luego cerramos la conexión por ldap, o mostramos un mensaje sobre la imposibilidad de conectarse al servidor:

ldap_close($ds); 
} 
else echo "<h4>No se pudo conectar al servidor LDAP</h4>"; 
echo '<br><br><br></body></html>';}

El archivo «main_table.html» en su interior representa una simple página html con enlaces, y se ve aproximadamente así:

<head>
<link rel="shortcut icon" href="ico.png"/>
<meta charset="windows-1251"/>
<title>Agenda de «YourMegaCompanyName»</title>
</head>
<body style='background-color:#ffffff;'>
<center><a href="index.php"><img border="none" src="logo.png"/></a></center>
<center><b>Lugares y oficinas</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>

Si a alguien le ayuda mi código, estaré contento, ¡úsalo!

También puede editarlos libremente como desee (mejorar/empeorar) y distribuirlo de cualquier manera.

¡Gracias por su atención!

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster