Adding ad php музыкальные инструменты. Подключение к AD

Like the article?

There is one major question that may be asked to this tutorial’s subject: “Why would I want PHP to access Active Directory? I can use Users and Groups to manage it already.” The answer to this is (though I am sure there are others): Quite often, management wants to delegate some Active Directory (AD) functions to users who don’t or shouldn’t have access to LDAP Users and Groups. As a real-life example, I once worked at a company that wanted their secretary to be able to add users, delete users, and update user passwords and contact info from a nice, user-friendly, web interface. I put together a simple web-based interface using PHP and LDAP, and thus this tutorial was born.

Step 1: Configure PHP with LDAP Support

If PHP doesn’t already have LDAP support enabled, depending on your OS, you’ll need to enable it. On Linux, there are a few different ways to do it – either compile PHP with LDAP support like so (universal across all distros):

./configure --with-ldap

or install your distro-specific php-ldap package and then add the following line in your php.ini :

Extension=mod_ldap.so

and restart Apache.

On Windows, uncomment or add the following line in your php.ini :

Extension=php_ldap.dll

and restart Apache/IIS

Step 2: Connect to Your Existing Active Directory

Once your PHP installation has been updated to include LDAP support (or had it in the first place), it’s time to initiate a connection. Pop this into a PHP file:

So in the code above, we’ve created a connection and assigned it to ldap.example.com . Some LDAP installations and functions require an explicit setting of the protocol version; for me, it has become a habit to set it to avoid any errors, and I have done so in the line following the connection.

Step 3: Binding PHP to Active Directory

An anonymous connect is all well and good, but we’ve got to bind to the Active Directory before we can do anything with it. Depending on your security settings, an anonymous bind might suffice for performing searches on the Active Directory; for anything requiring access, however, you’ll need a user with the appropriate permissions. Since users come and go, it might be a good idea to make a user with permissions solely for PHP that interacts with LDAP on an administrative level – in this example, we’ll go with “ldapweb”.

To bind to your Active Directory:

$ldap_bind = ldapbind($adconn, "ldapweb", "password");

So far, still nice and self-explanatory – this line binds against our open Active Directory connection with username “ldapweb” and password “password”).

Despite existing, $ldap_bind won’t be used again – this is a source of common confusion for many first-timers to the PHP LDAP library, myself included. It is a boolean and is only used to check if the ad is bound or not. All queries from now on will query against $adconn , the original LDAP connection.

Step 4: Searching against the Active Directory

Here’s where the real meat of the PHP LDAP library lies! The ldap_search function is incredibly powerful, though it’s also incredibly complex; it’s akin to a SQL query in terms of power and possible options. We are going to use it in a far simpler manner, however – we are going to get a list of usernames from the Active Directory:

$dn = "OU=People,OU=staff,DN=ldap,DN=myawesomesite,DN=com"; $attribute = array("samAccountName"); $result = ldap_search($adconn, $dn, "(cn=*)", $attribute); $entries = ldap_get_entries($ad, $result); for ($i = 0; $i < $entries["count"]; $i++) { echo $entries[$i]["samAccountName"]; echo "

"; }

This isn’t entirely self-explanatory, so let’s run through this line-by-line to figure out what’s going on. When accessing LDAP through PHP, all of the variables come back in the form of an array- this is why we can’t simply use $results straight away. By using ldap_get_entries , we iterate through $results and get back a multidimensional array that contains both the number of the entry in question as well as the Active Directory variable in question (in this case, “samAccountName”). The for loop iterates through each entry and echoes the name as well as an HTML break, giving you a line by line breakdown of every displayname variable in the database.

Step 5: Adding, Modifying, and Deleting Database Entries

I’ll cover all of these in one section because the syntax for them is more or less the same. To add, replace, and remove any entries from the database you use (predictably) ldap_mod_add , ldap_mod_replace , and ldap_delete . Let’s take a look at adding an entry into the database.

$newuser["samAccountName"] = "awesomeman"; $newuser["givenname"] = "awesome"; $newuser["sn"] = "man"; $result = ldap_mod_add($adconn, $dn, $newuser);

That covers ldap_mod_add . ldap_mod_replace uses the exact same syntax, except you have to make the $dn variable specific to what you want to replace. For example, if you wanted to replace those entries in awesomeman instead of adding them, you would do:

$dn = "CN=Awesome Man,OU=People,OU=staff,DN=ldap,DN=myawesomesite,DN=com"; $newuser["samAccountName"] = "awesomeman"; $newuser["givenname"] = "awesome"; $newuser["sn"] = "man"; $result = ldap_mod_replace($adconn, $dn, $newuser);

ldap_delete is even easier, only requiring the specific DN and the $adconn :

$dn = "CN=Awesome Man,OU=People,OU=staff,DN=ldap,DN=myawesomesite,DN=com"; $result = ldap_delete($adconn, $dn);

Step 6: Putting It All Together

In this step, we’re going to write a small function that searches the database for a given username and replaces it with a specified username.

Step 7: Conclusion

There are, of course, many other powerful uses to the PHP + LDAP combination, but this quick tutorial is designed to give you the quick and dirty of getting PHP to connect and interact with an Active Directory server; you never know when that manager’s going to ask you for a slick, password-changing web front-end for their secretaries. Good luck, and happy coding!

Help us spread the word!

2 comments

    Nice article, all basic information how to work with LDAP is mentioned. Nowadays you normally use a Framework component for that, so you don’t have to work with this low level functions (like Zend_Ldap).

    Hey … i am using the same kinda setup as you have explained. Nice article thou.

    I am using Windows Active Directory on 2008 I keep getting this error

    Warning: ldap_mod_replace() : Modify: Server is unwilling to perform in ……

    Search quite a bit on this. Can any one help

Comment

    Upcoming Training

  • Don’t Miss Subscriber-only Content!

    Join our newsletter to get exclusive tutorials, latest posts, free courses, and much more!

  • Recent Client Testimonials

    • Serge has good knowledge and answers all the questions.

      - harsh

      Boris, you were just fantastic at delivering this course to us! Hope Italy treated you as well in return!

      - Paolo, Telecom Italia

      Just wanted to say THANK YOU SO MUCH for the classes this week! You did a great job and it was very informative! I"ve been an Oracle developer for almost 20 years now and with my busy work could never find time to get my hands on one of these new technologies. It was an eye opener.

      - Dmitry, EMC

      This course could easily have taken longer than two days, but Boris did an awesome job breaking it down into a shorter course. He explains and demonstrates extremely well!

      - Gregory, LSI

      I am an experienced OOP programmer/developer, and I believe that the programming examples were extremely relevant. Mr. Cole put in much effort and ensured that the programming templates were relevant and workeable.

      - MAJ Jarrod, Fort Gordon School of Information Technology

      This course was excellent! Guy Cole was able to create a great learning environment. He is technical, eloquent, and funny all at the same time. I"d take this course again any time!

      - Regina, IBM

      Instructor is knowlegable and capable of answering questions w/o "parking" them.

      Great Pace, Great Faculty, Great Topic

      - Ashish, Meltwater Group

      Good practical android course. Lots of material but if you pay attention in class you will get your money"s worth. Instructor knows his stuff.

      - Gene, Verizon

      Serge was willing and able to jump off the scheduled presentation and answer specific questions relevant to our organization, which really helped answer some important questions we had.

      - Bill, 4Info

      What I liked about this training was the professionalism of the course layout and Andre was full of knowledge. Andre took the time to answer all of my questions and made sure I was understanding everything we covered.

      - Melissa

      Good introduction to Android development with lots of practical examples. Instructor is knowledgeable and jovial.

      - Kyocera

      I was looking for an Android bootcamp that solidified some of the basics that I already knew and progressed quickly to more advanced topics. This course definitely did that. Overall, I am very happy and I have a large example set to draw from to continue to build my skills. The lab was very practical and robust. Although it was difficult to complete, I managed to get most of it finished and the example for the lab that was provided is an excellent example as well. Also, the instructor was well-spoken and easy to listen to. This is a huge plus.

      - David, Gateway Church

      Really good instructor combining theory with examples- excellent training.

      - GUILLERMO, Intel Corporation

      The instructor was extremely knowledgeable and made it a great learning enviroment.

      - Paul, American Thermal Instruments

      Damodar was very kind and patient to keep everyone in sync, if they behind with the labs. Thank you, Damodar!

      Guy Cole is both an expert Android instructor and a great entertainer. I thoroughly enjoyed this course!

      - Chris, Rockwell Collins

      Our team was able to obtain training with only our company team members so that we were able to focus on our specific needs. Thank you.

      - Jeff, Marriott Ownership Resorts

      Like the teacher shared with us his experience and insights.

      - Echo, Disney

      I learned a great deal in just a days" Networking Fundamentals Course. Boris, you made my day...

      - Rob, Microsoft Corporation

      Guy is a knowledgeable instructor and skillful presenter. He made this course really come together with exercises and practical project. I hope he teaches other courses!!!

      - Andrew, Kyocera

      Very knowledgable, motivated, and responsive instructor

      - Intel Corporation

      Instructor very knowledgeable and amicable. Class materials well suited to stated goal.

      - Preston, Intel

      The Android App Development class was very effective for me. In just two days, I learned enough material to get me started on my own. Instructor and facility were both top notch!

      - Shekhar, MIPS Technologies

      Thank you very much - it was very informative! Ken and Boris were patient and tried their best to answer our questions - very stimulating...

      - Abhijit

      I come from a Java background, and Android seems natural for me to pick up. Guy made the transition from Java to Android very easy. He is a very good teacher. I enjoyed this training.

      - Leonid

      I really liked the exercises where we were asked to do some coding and assignments. Also the last day hands on lab was really good and enjoyed it throughly!

      - Intel

      Great presentation of material and engagement of the class. Learned a lot about services that I have been aligned with for years and got a better and deeper understanding of the content and data behind these transactions.

      - Greg, Intel Corporation

      The Apache Trainer was extremely knowledgeable and personable to make the experience worth the time, expense and effort.

      - Rick, GTech

      Enjoyed taking class online (instead of traveling). Instructor knowledge was strong.

      - Brian, Avnet

      Good interaction over online chat w/ the instructors and others, kept an otherwise potentially dreary online experience quite interesting.

      - Ganesh, EMC Corporation

      This was an intense 3-day course. The great part though is you don"t need to remember everything. As long as you complete the class project, you will learn many valuable lessons. I highly recommend this course!

      - Pradeep, US Government

      Serge, Boris, thank you very much. Very good class!

      Instructor Guy Cole was excellent!

      - Intel

      Instructor was extremely knowledgeable about the topic. He doesn"t just teach it, he uses it. That makes all the difference.

      - Deborah, City of Arlington

      I liked the interactive approach the Guy used during chapter demos and sample app. We all shared our products and learned from each others" blunders. ;-)

      - Derek, Verizon

      Instructor knew all details and explained everything with extreme patience

      - Kyocera

      Examples were easy to understand and practical. Instructor was candid about challenges in development.

      - Robert

      The instructor is very patient to explain, I think that is great. I liked the course, very good!

      - Alex, LogicStudio

      Good training material and lots of labs and samples relevent to the course. The instructor spoke very clearly and at a pace that was comfortable.

      - Douglas

      Excellent instructor. Patient and diligent - methodically going over the material until the students have a full grasp on it.

      - Derek, NSi

      Android Application Development class is cutting edge. It covers best of both worlds - the basics and advanced SDK functions. The project is very relevant to the course.

      - Josh, Stanford University

      Great instructor, down to earth and very knowledgeable. Taught in a manner that was easy to pick up on. Provided a ton of great code examples that I will always be able to look back to.

      The Android Application Development course was very well delivered and left me with a wealth of real code I can use at work.

      - Vlad, Wells Fargo

      I enjoyed the exposure to Eclipse and exploring interactions within the Android environment.

      - Hollis, TCI

      The instructor was very knowledgeable, also in the iOS area, what enabled me to get answers about platform differences and similarities.

      - Adam, Roche

      Goal of training met , in terms of the course objectives set my course managers

      - CPT Peter Johnson, U.S.ARMY 53A ISM course

      Instructor was very knowledgeable, helpful, and clear.

      - Franklin, Time Warner Inc.

      Instructor was excellent and made the course interesting.

      - Elbert, AO Smith WPC

      I learned alot more in 3 days and could do alot more than i thought possible.

      - Joe, Mattel

      It was just what I needed!

      - Brian, EMC

      Thanks I learned a lot about Hadoop

      - Scott, 614-797-5550

      Guy is a great "guy", and did an excellent job presenting the material and ensuring people "got" it. I looked at bootcamps provided by a number of organizations, and this one was the most thorough, and had the least fluff. I don"t think I"ve ever been as pleased with a course.

      - Winston

      Instructor was knowledgeable, systematic and responsive to questions. I have enjoyed the course and have learned a lot about Hadoop. GoToMeeting is an effective medium for presentations and was used very well for communication and resolving problems.

      - Lubomir, EMC

      Trainer was extremely knowledgeable. I really appreciate as trainer helped me understand avro files and how to load them which was one of my expectations out of this course.

      - ankush, EMC

      A lot of great examples! The instructor is an Android expert and skillful presenter.

      - Krystian, Roche Polska

    Training Categories

16 years ago

Try this script if you don"t know how to add an user in the AD Win2K.
To have more informations about the attributes, open the adsiedit console in the Support Tools for Win2K.

$adduserAD["cn"] =
$adduserAD["instancetype"] =
$adduserAD["objectclass"] = "top";
$adduserAD["objectclass"] = "person";
$adduserAD["objectclass"] = "organizationalPerson";
$adduserAD["objectclass"] = "user";
$adduserAD["displayname"] =
$adduserAD["name"] =
$adduserAD["givenname"] =
$adduserAD["sn"] =
$adduserAD["company"] =
$adduserAD["department"] =
$adduserAD["title"] =
$adduserAD["description"] =
$adduserAD["mail"] =
$adduserAD["initials"] =
$adduserAD["samaccountname"] =
$adduserAD["userprincipalname"] =
$adduserAD["profilepath"] =
$adduserAD["manager"] = ***Use DistinguishedName***

if (!($ldap = ldap_connect("localhost"))) {
die ("Could not connect to LDAP server");
}
if (!($res = @ldap_bind($ldap, "[email protected]", $password))) {
die ("Could not bind to the LDAP account");
}
if (!(ldap_add($ldap, "CN=New User,OU=OU Users,DC=pc,DC=com", $adduserAD))){
echo "There is a problem to create the account
echo "Please contact your administrator !";
exit;
}
ldap_unbind($ldap);

12 years ago

Here is how to add a user with a hashed MD5 password to OpenLDAP. I used this technique to migrate Drupal accounts into OpenLDAP for a single-sign-on solution.

The trick to it is to tell OpenLDAP the hash type (e.g. {MD5}) before the password, and also to base64 encode the BINARY hashed result. You cannot just base64 encode what is returned by PHP"s md5() or sha() hash functions, because they return a hexadecimal text string. First you must use pack("H*", $hash_result) to make that a binary string, THEN you can base64 encode it.

Here is complete code for connecting and adding a user with a hashed password. You don"t have to use {MD5}, you could pick a different hash if that is what you have. The output from one of these hashed passwords will look like this: {md5}bdwD04RS9xMDGVi1n/H36Q==

Finally some caveats: This technique will not work if you hashed the password using a salt value (but Drupal does not). This technique will also certainly not work with active directory, where passwords can definitely only be set over SSL connections and hashing probably works differently.

$ds = ldap_connect($serverAddress);
if ($ds) {
ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3); // otherwise PHP defaults to ldap v2 and you will get a Syntax Error!
$r = ldap_bind($ds, $managerDN, $managerPassword);
$ldaprecord["cn"] = $newuser_username;
$ldaprecord["givenName"] = $newuser_firstname;
$ldaprecord["sn"] = $newuser_surname;
// put user in objectClass inetOrgPerson so we can set the mail and phone number attributes
$ldaprecord["objectclass"] = "person";
$ldaprecord["objectclass"] = "organizationalPerson";
$ldaprecord["objectclass"] = "inetOrgPerson";
$ldaprecord["mail"] = $newuser_email_address;
$ldaprecord["telephoneNumber"] = $newuser_phone_number;
// and now the tricky part, base64 encode the binary hash result:
$ldaprecord["userPassword"] = "{MD5}" . base64_encode(pack("H*",$newuser_md5hashed_password));
// If you have the plain text password instead, you could use:
// $ldaprecord["userPassword"] = "{MD5}" . base64_encode(pack("H*",md5($newuser_plaintext_password)));
$r = ldap_add($ds, $base_user_dn, $ldaprecord);
} else { die "cannot connect to LDAP server at $serverAddress."; }

11 years ago

I created a simple function that can be called to create global distribution groups in Active Directory:

function ldap_createGroup ($object_name , $dn , $members , $ldap_conn )
{
$addgroup_ad [ "cn" ]= " $object_name " ;
$addgroup_ad [ "objectClass" ][ 0 ] = "top" ;
$addgroup_ad [ "objectClass" ][ 1 ] = "group" ;
$addgroup_ad [ "groupType" ]= "2" ;
$addgroup_ad [ "member" ]= $members ;
$addgroup_ad [ "sAMAccountName" ] = $object_name ;

Ldap_add ($ldap_conn , $dn , $addgroup_ad );

If(ldap_error ($ldap_conn ) == "Success" )
return true ;
else
return false ;
}
?>

You can call this function using the follow code:

$ldap_conn = ldap_bind ();
$object_name = "Test Group" ;
$dn = "CN=" . $object_name . ",OU=PathToAddGroupTo,OU=All Users,DC=YOURDOMAIN,DC=COM" ;
$members = "CN=User1,OU=PathToAddGroupTo,OU=All Users,DC=YOURDOMAIN,DC=COM" ;
$members = "CN=User2,OU=PathToAddGroupTo,OU=All Users,DC=YOURDOMAIN,DC=COM" ;

Ldap_createGroup ($object_name , $dn , $members , $ldap_conn );
?>

The other function I created is ldap_bind(), and this can be used to bind to an LDAP server:

function ldap_bind ()
{
$ldap_addr = "192.168.1.1" ; // Change this to the IP address of the LDAP server
$ldap_conn = ldap_connect ($ldap_addr ) or die("Couldn"t connect!" );
ldap_set_option ($ldap_conn , LDAP_OPT_PROTOCOL_VERSION , 3 );
$ldap_rdn = "domain_name\\user_account" ;
$ldap_pass = "user_password" ;

// Authenticate the user against the domain controller
$flag_ldap = ldap_bind ($ldap_conn , $ldap_rdn , $ldap_pass );
return $ldap_conn ;
}
?>

13 years ago

When adding/editing attributes for a user, keep in mind that the "memberof" attribute is a special case. The memberOf attribute is not an accessible attribute of the user schema. To add someone to a group, you have to add the user in the group, and not the group in the user. You can do this by accessing the group attribute "member":

$group_name = "CN=MyGroup,OU=Groups,DC=example,DC=com" ;
$group_info [ "member" ] = $dn ; // User"s DN is added to group"s "member" array
ldap_mod_add ($connect , $group_name , $group_info );

?>

11 years ago

This solution works for us.
In the form the CN and pwdtxt are randomly generated from strict rules.
This script creates 50-60 users i AD pr.day! and never even had a glitch!

## From form
$CN = $_POST [ "CN" ];
$givenName = $_POST [ "givenName" ];
$SN = $_POST [ "SN" ];
$mail = $_POST [ "mail" ];
$Phone = $_POST [ "Phone" ];
$pwdtxt = $_POST [ "pwdtxt" ];

$AD_server = "localhost:390" ; // Local Stunnel --> http://www.stunnel.org/
$AD_Auth_User = "[email protected]" ; //Administrative user
$AD_Auth_PWD = "duppiduppdupp" ; //The password

$dn = "CN=" . $CN . ",OU=Brukere,DC=student,DC=somwhere,DC=com" ;

## Create Unicode password
$newPassword = "\"" . $pwdtxt . "\"" ;
$len = strlen ($newPassword );
$newPassw = "" ;

for($i = 0 ; $i < $len ; $i ++) {
$newPassw .= " { $newPassword { $i }} \000" ;
}

## CONNNECT TO AD
$ds = ldap_connect ($AD_server );
if ($ds ) {
ldap_set_option ($ds , LDAP_OPT_PROTOCOL_VERSION , 3 ); // IMPORTANT
$r = ldap_bind ($ds , $AD_Auth_User , $AD_Auth_PWD ); //BIND

$ldaprecord [ "cn" ] = $CN ;
$ldaprecord [ "givenName" ] = $givenName ;
$ldaprecord [ "sn" ] = $SN ;
$ldaprecord [ "objectclass" ][ 0 ] = "top" ;
$ldaprecord [ "objectclass" ][ 1 ] = "person" ;
$ldaprecord [ "objectclass" ][ 1 ] = "organizationalPerson" ;
$ldaprecord [ "objectclass" ][ 2 ] = "user" ;
$ldaprecord [ "mail" ] = $mail ;
$ldaprecord [ "telephoneNumber" ] = $Phone ;
$ldaprecord [ "unicodepwd" ] = $newPassw ;
$ldaprecord [ "sAMAccountName" ] = $CN ;
$ldaprecord [ "UserAccountControl" ] = "512" ;
//This is to prevent the user from beeing disabled. -->
http : //support.microsoft.com/default.aspx?scid=kb;en-us;305144

$r = ldap_add ($ds , $dn , $ldaprecord );

} else {
echo "cannot connect to LDAP server at $AD_server ." ;
}

?>

This is code example creates a user i AD.
We use this on an internal web page to create
temporary users that kan access the wireless network.
We have a .pl script that deletes the users after 24H.

11 years ago

Once i"am having problmes to add attributes with boolean syntax (1.3.6.1.4.1.1466.115.121.1.7)

$["boolean_attr"]=true; //give me one warning, ldap_add(): Add: Invalid syntax

solved this by setting the value on this:

$["boolean_attr"]="TRUE";

hope this can helps.

16 years ago

In response to jharnett"s question about accounts disabled by default from ldap_add, we have found a solution.

The attribute userAccountControl contains a value that includes whether the account is disabled or enabled. The default for us is 546; when we changed that to 544 the account became enabled. Changing whatever value is in userAccountControl by 2 seems to enable or disable the account.

The following code worked for us to create a new user with an enabled account:

$adduserAD["userAccountControl"] = "544";

We just added this element to the above example"s array.

7 months ago

Create Group in Active Directory

$ds = ldap_connect ("IP-server/localhost" );
$base_dn = "CN=Group name,OU=Organization Unit,DC=Domain-name,DC=com" ; //distinguishedName of group

If ($ds ) {
// bind with appropriate dn to give update access
ldap_bind ($ds , , "some-password" );

//Add members in group
$member_array = array();
$member_array [ 0 ] = "CN=Administrator,OU=Organization Unit,DC=Domain-name,DC=com" ;
$member_array [ 1 ] = "CN=User,OU=Organization Unit,DC=Domain-name,DC=com" ;

$entry [ "cn" ] = "GroupTest" ;
$entry [ "samaccountname" ] = "GroupTest" ;
$entry [ "objectClass" ] = "Group" ;
$entry [ "description" ] = "Group Test!!" ;
$entry [ "member" ] = $member_array ;
$entry [ "groupType" ] = "2" ; //GroupType="2" is Distribution / GroupType="1" is Security

Ldap_add ($ds , $base_dn , $entry );

Ldap_close ($ds );
} else {
echo "Unable to connect to LDAP server" ;
}
?>

14 years ago

Another fun thing: ldap_add() doesn"t like arrays with empty members: so
array (
= "name"
= ""
= "value"
will yield a syntax error!

solve this with a simple peice of code:

foreach ($originalobject as $key => $value){
if ($value != ""){
$object[$key] = $value;
}
}

where $originalobject is the uncecked array and $object is the one without empty members.

19 years ago

Ldap_add() will only honour the $entry["attribute"][x]="value" *if there are multiple values for the attribute*. If there is only one attribute value, it *MUST* be entered as $entry["attribute"]="value" or ldap_add() sets the value for the attribute to be "Array" instead of what you put into $entry["attribute"].

Here is a little routine I wrote up to do this automatically. when you"re parsing the input, just use multi_add():
function multi_add ($attribute , $value )
{
global $entry ; // the LDAP entry you"re gonna add

If(isset($entry [ $attribute ]))
if(is_array ($entry [ $attribute ]))
$entry [ $attribute ][ count ($entry [ $attribute ])] = $value ;
else
{
$tmp = $entry [ $attribute ];
unset($entry [ $attribute ]);
$entry [ $attribute ][ 0 ] = $tmp ;
$entry [ $attribute ][ 1 ] = $value ;
}
else
$entry [ $attribute ] = $value ;
}
?>
multi_add() checks to see if there is already a value for the attribute. if not, it adds it as $entry[$attribute]=$value. If there is already a value for the attribute, it converts the attribute to an array and adds the multiple values correctly.

How to use it:
switch($form_data_name )
{
case "phone" : multi_add ("telephoneNumber" , $form_data_value ); break;
case "fax" : multi_add ("facsimileTelephoneNumber" , $form_data_value ); break;
case "email" : multi_add ("mail" , $form_data_value ); break;
...
}
?>
In the system I designed the form has pulldowns with names ctype1, ctype2, ctype3, etc. and the values are "fax, mail, phone...". The actual contact data (phone number, fax, email, etc) is contact1, contact2, contact3, etc. The user pulls down what the contact type is (phone, email) and then enters the data (number, address, etc.)

I use variable variables to fill the entry and skip blanks. Makes for a very clean form entry system. email me if you"re interested in it, as I think I"m outgrowing the size of note allowed here. :-)

6 years ago

I kept getting "Object Class Violation" when I tried adding posixAccount and shadowAccount as an objectclass. It turned out that these object classes had a lot of required fields that I was not adding. You may need to export a working user (if you have phpLDAPadmin) and see exactly what fields they have, then try to copy it exactly in the script. It also doesn"t hurt if you make everything an Array the first time around, you can fix those fields later.

Серия контента:

Для выполнения основных операций по работе с AD, таких как добавление или удаление пользователя, изменение данных или членства в группах, и в особенности для массовых операций (например, сформировать список всех пользователей по отделам) вовсе не обязательно изучать Visual Basic или PowerShell - для этого достаточно знания PHP (а также наличия пользователя с необходимыми правами).

Часто используемые сокращения:

  • AD - Active Directory (служба каталогов);
  • LDAP - облегченный протокол доступа к каталогу (lightweight directory access protocol);
  • DN - отличительное имя (distinguished name).

В первой части статьи рассматривался конфигурационный файл приводимого примера, а также некоторые используемые в нем функции, с указанием их особенностей реализации. Приводились также примеры данных входных и выходных массивов. В данной части приводится основная часть скрипта, непосредственно запускаемая в консоли и вызывающая все описанные в прошлой части функции.

Основной скрипт

Скрипт начинается с вводной части, которая определяет места подгрузки функций, пути по умолчанию к файлам журнала и конфигурации, открывает файл журнала, читает и разбирает конфигурационный файл и опции командной строки. Конфигурационный файл разбирается функцией parse_config_file, размещенной в файле parseconfig.php и не приводимой здесь, но присутствующей в полной версии скрипта на . Вводная часть программы приведена в Листинге 1.

Листинг 1. Вводная часть основного скрипта.
array ("debug" => 0, "clean" => 0, "verbose" => 0)); // Открыть файл журнала $handle = fopen($logfile, "a") or die(sprintf("Log file %s cannot open", $logfile)); // Разобрать конфигурационный файл $_config = parse_configfile($config); // Разобрать опции командной строки $rev = parse_options($_config, $_params); // Началный запуск программы закончен safe_logger(sprintf("PHPListADUsers ver. %s started", $rev), "");

Далее идет собственно чтение данных из LDAP - это самая короткая часть скрипта, потому что все делается функциями: подключиться, запросить, получить. Часть, в которой выполняется чтение данных, приведена в Листинге 2. Стоит обратить внимание на то, как строится массив атрибутов, которые будут прочитаны для передачи в ldap_data_query: если консоль поддерживает UTF-8, то параметр recode можно поставить в false.

Листинг 2. Чтение данных из LDAP-сервера.
// Подключиться к LDAP-серверу if (!$ldapconn = ldap_server_connect($_config)) safe_logger(sprintf("Cannot connect to LDAP server $s", $_config["root"]["ldap_server"]), "DIE"); // Построить путь к выходном файлу $_sarglist = sprintf("%s/%s", $_config["root"]["etcdir"], $_config["root"]["sarglist"]); // Счетчик обработанных записей $_processed = 0; // Из AD будут запрошены вот эти атрибуты $attrs = array(0 => array("name" => "cn", "recode" => "true"), 1 => array("name" => "samaccountname", "recode" => "true")); // Получить данные из AD $info = ldap_data_query($_config, $ldapconn, $attrs);

Далее идет чтение существующего файла, если он есть и его не надо удалять. Если файл существует, то он считывается, и из логинов, указанных в нем (первый столбец), формируется массив уже присутствующих в файле записей - для того, чтобы пропускать уже существующие. Часть, занимающаяся чтением файла, приведена в Листинге 3.

Листинг 3. Чтение существующего файла sarglist.
// Записи, которые уже есть в выходном файле $presented = array(); // Удалить файл, если надо if ($_params["modes"]["clean"]) unlink($_sarglist); // Если файл существует, то прочитать его if (file_exists($_sarglist)) { // Если существует, но не читается, аварийно завершить if (!is_readable($_sarglist)) safe_logger(sprintf("File %s cannot open to read", $_sarglist), "DIE"); // Получить данные существующего файла $lines = file($_sarglist); // Разбить каждую строку и выбрать логин foreach ($lines as $_oneline) { $pieces = explode(" ", $_oneline); $presented = $pieces; } // Вывести, сколько записей прочитано из файла safe_logger(sprintf("Read %d records from file %s", count($presented), $_sarglist),""); }

Ну и, собственно, основная часть скрипта - до этого, вообще говоря, все шла подготовка: получить данные из одного места, получить данные из другого... Каждая запись, прочитанная из AD, проверяется на наличие в файле, и если она там отсутствует, то в файле формируется новая запись с необходимыми данными, иначе же запись просто пропускается. В конце работы скрипт пишет, сколько он добавил записей, закрывает соединения и завершается. Основная часть скрипта приведена в Листинге 4.

Листинг 4. Основная часть скрипта.
// Основной цикл обработки - берется одна запись, полученная из AD и ищется в файле // Если она уже есть - пропускается, иначе добавляется $add = fopen($_sarglist, "a+") or safe_logger(sprintf("Sorry, I could not open file %s for writing", $_sarglist), "DIE"); $ignored = explode(",", $_config["root"]["ignore_list"]); for ($i = $_processed = 0, $j = count($info); $i < $j; $i++) { // Если логин отсутствует в файле и в списке игнорируемых if ((!in_array($info[$i]["samaccountname"], $presented)) && (!in_array($info[$i]["samaccountname"], $ignored))) { // Вывести строку в файл $oneadd = sprintf("%s \t%s\n", $info[$i]["samaccountname"], $info[$i]["cn"]); fwrite($add, $oneadd); $_processed++; } } if ($_processed) safe_logger(sprintf("Added %d records in file %s", $_processed, $_sarglist), ""); ldap_unbind($ldapconn); fclose($add); fclose($handle); ?>

Заключение

Как совершенно очевидно, языки высокого уровня предоставляют несравнимо большее удобство при программировании взаимодействия с AD. Фактически все в данном скрипте сводится к манипулированию элементами массивов. И хотя PHP вовсе не считается языком для программирования консольных приложений, это может оказаться всего лишь предубеждением: вот вам вполне полноценная программа.

16 years ago

Try this script if you don"t know how to add an user in the AD Win2K.
To have more informations about the attributes, open the adsiedit console in the Support Tools for Win2K.

$adduserAD["cn"] =
$adduserAD["instancetype"] =
$adduserAD["objectclass"] = "top";
$adduserAD["objectclass"] = "person";
$adduserAD["objectclass"] = "organizationalPerson";
$adduserAD["objectclass"] = "user";
$adduserAD["displayname"] =
$adduserAD["name"] =
$adduserAD["givenname"] =
$adduserAD["sn"] =
$adduserAD["company"] =
$adduserAD["department"] =
$adduserAD["title"] =
$adduserAD["description"] =
$adduserAD["mail"] =
$adduserAD["initials"] =
$adduserAD["samaccountname"] =
$adduserAD["userprincipalname"] =
$adduserAD["profilepath"] =
$adduserAD["manager"] = ***Use DistinguishedName***

if (!($ldap = ldap_connect("localhost"))) {
die ("Could not connect to LDAP server");
}
if (!($res = @ldap_bind($ldap, "[email protected]", $password))) {
die ("Could not bind to the LDAP account");
}
if (!(ldap_add($ldap, "CN=New User,OU=OU Users,DC=pc,DC=com", $adduserAD))){
echo "There is a problem to create the account
echo "Please contact your administrator !";
exit;
}
ldap_unbind($ldap);

12 years ago

Here is how to add a user with a hashed MD5 password to OpenLDAP. I used this technique to migrate Drupal accounts into OpenLDAP for a single-sign-on solution.

The trick to it is to tell OpenLDAP the hash type (e.g. {MD5}) before the password, and also to base64 encode the BINARY hashed result. You cannot just base64 encode what is returned by PHP"s md5() or sha() hash functions, because they return a hexadecimal text string. First you must use pack("H*", $hash_result) to make that a binary string, THEN you can base64 encode it.

Here is complete code for connecting and adding a user with a hashed password. You don"t have to use {MD5}, you could pick a different hash if that is what you have. The output from one of these hashed passwords will look like this: {md5}bdwD04RS9xMDGVi1n/H36Q==

Finally some caveats: This technique will not work if you hashed the password using a salt value (but Drupal does not). This technique will also certainly not work with active directory, where passwords can definitely only be set over SSL connections and hashing probably works differently.

$ds = ldap_connect($serverAddress);
if ($ds) {
ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3); // otherwise PHP defaults to ldap v2 and you will get a Syntax Error!
$r = ldap_bind($ds, $managerDN, $managerPassword);
$ldaprecord["cn"] = $newuser_username;
$ldaprecord["givenName"] = $newuser_firstname;
$ldaprecord["sn"] = $newuser_surname;
// put user in objectClass inetOrgPerson so we can set the mail and phone number attributes
$ldaprecord["objectclass"] = "person";
$ldaprecord["objectclass"] = "organizationalPerson";
$ldaprecord["objectclass"] = "inetOrgPerson";
$ldaprecord["mail"] = $newuser_email_address;
$ldaprecord["telephoneNumber"] = $newuser_phone_number;
// and now the tricky part, base64 encode the binary hash result:
$ldaprecord["userPassword"] = "{MD5}" . base64_encode(pack("H*",$newuser_md5hashed_password));
// If you have the plain text password instead, you could use:
// $ldaprecord["userPassword"] = "{MD5}" . base64_encode(pack("H*",md5($newuser_plaintext_password)));
$r = ldap_add($ds, $base_user_dn, $ldaprecord);
} else { die "cannot connect to LDAP server at $serverAddress."; }

11 years ago

I created a simple function that can be called to create global distribution groups in Active Directory:

function ldap_createGroup ($object_name , $dn , $members , $ldap_conn )
{
$addgroup_ad [ "cn" ]= " $object_name " ;
$addgroup_ad [ "objectClass" ][ 0 ] = "top" ;
$addgroup_ad [ "objectClass" ][ 1 ] = "group" ;
$addgroup_ad [ "groupType" ]= "2" ;
$addgroup_ad [ "member" ]= $members ;
$addgroup_ad [ "sAMAccountName" ] = $object_name ;

Ldap_add ($ldap_conn , $dn , $addgroup_ad );

If(ldap_error ($ldap_conn ) == "Success" )
return true ;
else
return false ;
}
?>

You can call this function using the follow code:

$ldap_conn = ldap_bind ();
$object_name = "Test Group" ;
$dn = "CN=" . $object_name . ",OU=PathToAddGroupTo,OU=All Users,DC=YOURDOMAIN,DC=COM" ;
$members = "CN=User1,OU=PathToAddGroupTo,OU=All Users,DC=YOURDOMAIN,DC=COM" ;
$members = "CN=User2,OU=PathToAddGroupTo,OU=All Users,DC=YOURDOMAIN,DC=COM" ;

Ldap_createGroup ($object_name , $dn , $members , $ldap_conn );
?>

The other function I created is ldap_bind(), and this can be used to bind to an LDAP server:

function ldap_bind ()
{
$ldap_addr = "192.168.1.1" ; // Change this to the IP address of the LDAP server
$ldap_conn = ldap_connect ($ldap_addr ) or die("Couldn"t connect!" );
ldap_set_option ($ldap_conn , LDAP_OPT_PROTOCOL_VERSION , 3 );
$ldap_rdn = "domain_name\\user_account" ;
$ldap_pass = "user_password" ;

// Authenticate the user against the domain controller
$flag_ldap = ldap_bind ($ldap_conn , $ldap_rdn , $ldap_pass );
return $ldap_conn ;
}
?>

13 years ago

When adding/editing attributes for a user, keep in mind that the "memberof" attribute is a special case. The memberOf attribute is not an accessible attribute of the user schema. To add someone to a group, you have to add the user in the group, and not the group in the user. You can do this by accessing the group attribute "member":

$group_name = "CN=MyGroup,OU=Groups,DC=example,DC=com" ;
$group_info [ "member" ] = $dn ; // User"s DN is added to group"s "member" array
ldap_mod_add ($connect , $group_name , $group_info );

?>

11 years ago

This solution works for us.
In the form the CN and pwdtxt are randomly generated from strict rules.
This script creates 50-60 users i AD pr.day! and never even had a glitch!

## From form
$CN = $_POST [ "CN" ];
$givenName = $_POST [ "givenName" ];
$SN = $_POST [ "SN" ];
$mail = $_POST [ "mail" ];
$Phone = $_POST [ "Phone" ];
$pwdtxt = $_POST [ "pwdtxt" ];

$AD_server = "localhost:390" ; // Local Stunnel --> http://www.stunnel.org/
$AD_Auth_User = "[email protected]" ; //Administrative user
$AD_Auth_PWD = "duppiduppdupp" ; //The password

$dn = "CN=" . $CN . ",OU=Brukere,DC=student,DC=somwhere,DC=com" ;

## Create Unicode password
$newPassword = "\"" . $pwdtxt . "\"" ;
$len = strlen ($newPassword );
$newPassw = "" ;

for($i = 0 ; $i < $len ; $i ++) {
$newPassw .= " { $newPassword { $i }} \000" ;
}

## CONNNECT TO AD
$ds = ldap_connect ($AD_server );
if ($ds ) {
ldap_set_option ($ds , LDAP_OPT_PROTOCOL_VERSION , 3 ); // IMPORTANT
$r = ldap_bind ($ds , $AD_Auth_User , $AD_Auth_PWD ); //BIND

$ldaprecord [ "cn" ] = $CN ;
$ldaprecord [ "givenName" ] = $givenName ;
$ldaprecord [ "sn" ] = $SN ;
$ldaprecord [ "objectclass" ][ 0 ] = "top" ;
$ldaprecord [ "objectclass" ][ 1 ] = "person" ;
$ldaprecord [ "objectclass" ][ 1 ] = "organizationalPerson" ;
$ldaprecord [ "objectclass" ][ 2 ] = "user" ;
$ldaprecord [ "mail" ] = $mail ;
$ldaprecord [ "telephoneNumber" ] = $Phone ;
$ldaprecord [ "unicodepwd" ] = $newPassw ;
$ldaprecord [ "sAMAccountName" ] = $CN ;
$ldaprecord [ "UserAccountControl" ] = "512" ;
//This is to prevent the user from beeing disabled. -->
http : //support.microsoft.com/default.aspx?scid=kb;en-us;305144

$r = ldap_add ($ds , $dn , $ldaprecord );

} else {
echo "cannot connect to LDAP server at $AD_server ." ;
}

?>

This is code example creates a user i AD.
We use this on an internal web page to create
temporary users that kan access the wireless network.
We have a .pl script that deletes the users after 24H.

11 years ago

Once i"am having problmes to add attributes with boolean syntax (1.3.6.1.4.1.1466.115.121.1.7)

$["boolean_attr"]=true; //give me one warning, ldap_add(): Add: Invalid syntax

solved this by setting the value on this:

$["boolean_attr"]="TRUE";

hope this can helps.

16 years ago

In response to jharnett"s question about accounts disabled by default from ldap_add, we have found a solution.

The attribute userAccountControl contains a value that includes whether the account is disabled or enabled. The default for us is 546; when we changed that to 544 the account became enabled. Changing whatever value is in userAccountControl by 2 seems to enable or disable the account.

The following code worked for us to create a new user with an enabled account:

$adduserAD["userAccountControl"] = "544";

We just added this element to the above example"s array.

7 months ago

Create Group in Active Directory

$ds = ldap_connect ("IP-server/localhost" );
$base_dn = "CN=Group name,OU=Organization Unit,DC=Domain-name,DC=com" ; //distinguishedName of group

If ($ds ) {
// bind with appropriate dn to give update access
ldap_bind ($ds , , "some-password" );

//Add members in group
$member_array = array();
$member_array [ 0 ] = "CN=Administrator,OU=Organization Unit,DC=Domain-name,DC=com" ;
$member_array [ 1 ] = "CN=User,OU=Organization Unit,DC=Domain-name,DC=com" ;

$entry [ "cn" ] = "GroupTest" ;
$entry [ "samaccountname" ] = "GroupTest" ;
$entry [ "objectClass" ] = "Group" ;
$entry [ "description" ] = "Group Test!!" ;
$entry [ "member" ] = $member_array ;
$entry [ "groupType" ] = "2" ; //GroupType="2" is Distribution / GroupType="1" is Security

Ldap_add ($ds , $base_dn , $entry );

Ldap_close ($ds );
} else {
echo "Unable to connect to LDAP server" ;
}
?>

14 years ago

Another fun thing: ldap_add() doesn"t like arrays with empty members: so
array (
= "name"
= ""
= "value"
will yield a syntax error!

solve this with a simple peice of code:

foreach ($originalobject as $key => $value){
if ($value != ""){
$object[$key] = $value;
}
}

where $originalobject is the uncecked array and $object is the one without empty members.

19 years ago

Ldap_add() will only honour the $entry["attribute"][x]="value" *if there are multiple values for the attribute*. If there is only one attribute value, it *MUST* be entered as $entry["attribute"]="value" or ldap_add() sets the value for the attribute to be "Array" instead of what you put into $entry["attribute"].

Here is a little routine I wrote up to do this automatically. when you"re parsing the input, just use multi_add():
function multi_add ($attribute , $value )
{
global $entry ; // the LDAP entry you"re gonna add

If(isset($entry [ $attribute ]))
if(is_array ($entry [ $attribute ]))
$entry [ $attribute ][ count ($entry [ $attribute ])] = $value ;
else
{
$tmp = $entry [ $attribute ];
unset($entry [ $attribute ]);
$entry [ $attribute ][ 0 ] = $tmp ;
$entry [ $attribute ][ 1 ] = $value ;
}
else
$entry [ $attribute ] = $value ;
}
?>
multi_add() checks to see if there is already a value for the attribute. if not, it adds it as $entry[$attribute]=$value. If there is already a value for the attribute, it converts the attribute to an array and adds the multiple values correctly.

How to use it:
switch($form_data_name )
{
case "phone" : multi_add ("telephoneNumber" , $form_data_value ); break;
case "fax" : multi_add ("facsimileTelephoneNumber" , $form_data_value ); break;
case "email" : multi_add ("mail" , $form_data_value ); break;
...
}
?>
In the system I designed the form has pulldowns with names ctype1, ctype2, ctype3, etc. and the values are "fax, mail, phone...". The actual contact data (phone number, fax, email, etc) is contact1, contact2, contact3, etc. The user pulls down what the contact type is (phone, email) and then enters the data (number, address, etc.)

I use variable variables to fill the entry and skip blanks. Makes for a very clean form entry system. email me if you"re interested in it, as I think I"m outgrowing the size of note allowed here. :-)

6 years ago

I kept getting "Object Class Violation" when I tried adding posixAccount and shadowAccount as an objectclass. It turned out that these object classes had a lot of required fields that I was not adding. You may need to export a working user (if you have phpLDAPadmin) and see exactly what fields they have, then try to copy it exactly in the script. It also doesn"t hurt if you make everything an Array the first time around, you can fix those fields later.

Some HTML and text ads can be aligned horizontally using the text-align CSS property. More complicated issues of alignment and position within the various template files can be solved using proper CSS styling.

Adding Style to Ads

You may want to use some simple CSS to wrap the post around your advertising. In this example, the ad will appear in the upper right of each post, with the post text wrapped around it.

<>

Of course, you can also create styles for ads in your stylesheet.

Plugins for Advertising

Cg-PowerPack Includes the CG-Inline plugin and CG-Amazon CG-Inline is a powerful macro system for embedding auto-generated items within your posts/articles. In combination with CG-Amazon, allows for quick insertion of Amazon links/images within a post. Flexible image inlines, for floating/embedded thumbnails or image links. Powerful permalink creation. CG-Amazon provides live Amazon data feeds, product links, wishlist links, keyword lookups, all product types/catalogs, article inlined and sidebars, keyword lookups, admin interface and caching system. MooseCandy Adds content before specified posts (ex: an advertising banner between 1st and 2nd post). WP-Amazon Search and include items from Amazon.com to your post entries. This plugin adds a link called "Insert item from Amazon.com"? on the post page. This link launches a search window which allows an author to search for items from Amazon.com to be included on the author"s post entry. Adsense Beautifier Adsense beautifier is a plugin available for Wordpress to make your Adsense look beautiful in order to increase you Adsense earnings. Images adjacent to ads can help increase click through rate (CTR).

Troubleshooting Ads

If you are having trouble with your ads, here are some possible solutions.

Why Aren"t My Ads Showing Up?

In many cases it has nothing to do with WordPress, but here are a few things to remember or questions to ask yourself:

  1. With the context sensitive ad services, often the reason is that the keywords for context sensitive ads come from a search engine. Try a search for the URL where the ads should appear in the associated search engine and if the URL is not indexed, you will not get ads.
  2. Many ads use Javascripts. Some of those scripts do not validate correctly and some of them may behave oddly with certain stylesheet features or even with other scripts on the same page.
  3. Doublecheck your placement. For example, if you included the ad code in the Post section of the Main template file and now you are looking at a Page instead of a Post.
  4. Are you running a firewall, ad blocker or other software that may block the ad code? Do you have Javascript enabled in your browser? If the ad uses Flash or another plugin, do you have the required plugin installed?
  5. Try a thorough reload of the page. Clear your browser cache and cookies. Shut down your browser. Restart the browser. Load the page.

All I Get are Ads for Blogs

Context sensitive ads spider your site and index the keywords. If your site is heavy on words and links related to blogging, you will get lots of ads related to blogging. There are two things you can do to improve this. First, eliminate unnecessary blogging references. Second, make longer, keyword rich posts. Posts over 250 words tend to produce better context sensitive ads.

If you are using Google"s Adsense and having this problem, you may be able to see some improvement by using section targeting .

I Get Different Ads on Different Pages

If you find you are getting different ads at example.com/index.php than from the URI example.com , this issue with context sensitive ads may be because the search engine reads these as two separate URLs and may index them on different days.

The URL with index.php may be read by the search engine more or less often than the same page without the index.php . Once both are properly indexed, the ads should match -- at least for a while. The only solution, other than time, is to do everything you can to eliminate the use of the index.php in links, etc. A similar situation can occur with www.example.com reading differently than example.com without the www .