How to move an eDirectory entry via php? - php

I have this ldap entry:
cn=blah,ou=apples,ou=people,dc=yay,dc=edu
I need to move that entry to:
cn=blah,ou=oranges,ou=people,dc=yay,dc=edu
My scripts are all PHP so I've been trying to use php.net/ldap_rename
ldap_rename($connection, "cn=blah,ou=apples,ou=people,dc=yay,dc=edu", "cn=blah", "ou=oranges,ou=people,dc=yay,dc=edu", true);
Does not work. It returns false.
This http://us2.php.net/manual/en/function.ldap-rename.php#82393 comment mentions that eDirectory wants to leave the parent as NULL. Like:
ldap_rename($connection, "cn=blah,ou=apples,ou=people,dc=yay,dc=edu", "cn=blah", NULL, true);
That returns TRUE but does not actually move the entry. Not surprising since it's not changing the parent... I'm sure it could change the cn=blah to something else...
I have thought of deleting the entry and recreating it. But that's a painful way to go about it. Writing out and running a LDIF file would also be painful.
So, how do I move an entry from one OU to another, in php, without the pain of my other two options?
What I'm running:
Ubuntu 12.04 LTS
PHP 5.3.10
eDirectory 8.8 is on SLES 11
Edit
So, I found this:
The modrdn change type cannot move an entry to a completely different subtree. To move an entry to a completely different branch, you must create a new entry in the alternative subtree using the old entry's attributes, and then delete the old entry.
From http://www.centos.org/docs/5/html/CDS/ag/8.0/Creating_Directory_Entries-LDIF_Update_Statements.html
I found a couple other pages with similar statements.
So it sounds like I have to make a new entry, copying the attributes, the delete the old one. Like the second painful option I mentioned above.

Well, I ended up using the "create new entry, delete old one" method. I still think I had another way working a while back, but I can't remember what. So here's a basic move function.
function move($connection, $ldapEntryReference, $new_dn){
//First, get the values of the current attributes.
$attributes = array(); //start attributes array
$firstattr = ldap_first_attribute($connection, $ldapEntryReference);
$value = ldap_get_values($connection, $ldapEntryReference, $firstattr);
$attributes[$firstattr] = $value;
while($attr = ldap_next_attribute($connection, $ldapEntryReference)) {
if (strcasecmp($attr, 'ACL') !== 0) { //We don't want ACL attributes since
//eDir/ldap should deal with them for us.
if (strcasecmp($attr, 'jpegPhoto') === 0) {
//binary values need to use the ldap_get_values_len function.
$value = ldap_get_values_len($this->connection, $ldapEntryReference, $attr);
} else {
$value = ldap_get_values($this->connection, $ldapEntryReference, $attr);
}
$attributes[$attr] = $value;
}
}
//Create a new entry array with the values.
$entry = array(); //start entry array.
foreach($attributes as $key => $value) {
foreach($value as $key2 => $value2) {
if (strcasecmp($key2, 'count') !== 0) {//get rid of 'count' indexes
//ldap_add chokes on them.
$entry[$key][$key2] = $value2;
}
}
}
//Add the new entry.
if (ldap_add($connection, $new_dn, $entry)) {
//Delete the old entry.
if (ldap_delete($connection, ldap_get_dn($connection, $ldapEntryReference)) {
return true;
} else {
return false;
}
} else {
return false;
}
}
Hopefully this helps someone, sometime.

There actually isn't a need to recreate in eDir. Doing a recreate causes problems in an environment that runs IDM as the object will have a new GUID and the IDM engine will not see the event as a true "move".
The following code moves users fine (tested eDir 8.8.x & eDir 9.x):
$olduserdn = "cn=userid,ou=container1,o=org";
$newdestdn = "ou=container2,o=org";
if (preg_match('/^(cn=[A-Za-z0-9]+)\,(.+)/i', $olduserdn, $rdnmatches))
{
if (ldap_rename($ldapconn, $olduserdn, $rdnmatches[1], $newdestdn, TRUE))
{
print("Moved $olduserdn to $rdnmatches[1],$newdestdn");
}
else
{
print("Failed move because " . ldap_error($ldapconn));
}
}
Don't forget to give a bit of time for replication...
Also consider constraints around modifying/moving objects that are still being replicated from a previous move event.

Try this:
ldap_rename($ldapconn, "cn=blah,ou=apples,ou=people,dc=yay,dc=edu", "cn=blah", "ou=oranges,ou=people,dc=yay,dc=edu", true);

Related

PHP fgets returns an empty string

So I'm making a webshop, well, trying to atleast for a course project using WAMP. But when trying to register new users and in the process checking their password against a list of common ones the use of fgets() returns an empty string.
if(empty(trim($_POST["password"]))){
...
} elseif (!checkPassword($_POST["password"])) {
$password_err = "Password to common.";
echo "<script>alert('Password to common.'); location.href='index.php';</script>";
}
The checkPassword() is where the fault lies.
function checkPassword($passwordtocheck) {
$passwordtocheck = strtolower($passwordtocheck);
$common_passwords = fopen("commonpasswords.txt", "r");
while(!feof($common_passwords)) {
$check_against = fgets($common_passwords);
echo "<script>alert('Checking $passwordtocheck against $check_against.'); location.href='index.php';</script>";
if($check_against == $passwordtocheck) {
fclose($common_passwords);
return false;
}
}
fclose($common_passwords);
return true;
}
Lets say that I input the password 12345678 when registering, then the scripted alert will say "Checking 12345678 against ." and send me back to index.php. So it looks like it doesn't succeed in reading the file at all. The commonpasswords.txt is in the same folder as the rest of the files and with a single password on each row.
And there is no problem opening the file to begin with either, if I do this instead:
$common_passwords = fopen("commonpasswords.txt", "a");
fwrite($common_passwords, "test");
'test' will appear at the bottom of the file under the existing words on its own row without a hitch. And this is where I'm at, would appreciate whatever input people can give!
EDIT; I do understand that this probably breaks a ton of good-practice 'rules' in general and regarding security. But the website is not really supposed to function or look good, it just need to barely work so that we can later try and use different methods of attacking it and the connected database.
If you insist on doing this yourself – which I do not recommend – you can simplify things a lot by using the file() function. This returns an array of every line in the file. Then use array_filter(); it runs a callback on each element of the array where you can check if there's a match with your password. If the callback returns false, the element is removed from the array. After that, if you have any elements left you know there was a match.
function checkPassword($pwd) {
$pwd = strtolower($pwd);
$common = file("commonpasswords.txt", FILE_IGNORE_NEW_LINES);
$results = array_filter($common, function($i) use ($pwd) {return $i == $pwd;});
return count($results) === 0;
}
But really, there are dozens of libraries out there to check password strength. Use one of them.
Or, as pointed out in the comment, even simpler array_search:
function checkPassword($pwd) {
$pwd = strtolower($pwd);
$common = file("commonpasswords.txt", FILE_IGNORE_NEW_LINES);
return array_search($pwd, $common) === false;
}

Dynamically created directory returns "Array" 1 in 1000 times

I'm fixing up some old code that is supposed to create a directory for a customer based on the customer's last name. 999 out of 1000 times it works as expected but every now and then I get an "Unable to create base directory" error message and the debug shows me that the $file_directory in that case is simply "Array" instead of something like "\\network\path\order_data\1234567890_Smith".
Could anyone explain how this code could work the vast majority of the time but still consistently fail about .1% of instances? Or is it something other than the code? Thanks!
Note: I did not originally write this code but am tring to leave it as close to the original as possible
Edit I had a typo in my previous code but I think tliokos and Fluinc had a very good point but just wanted to fix my mistake
Code:
<?php
$file_directory = build_directory($customer, $UID);
if(!is_dir($file_directory)){ //Check to make sure it does not already exist
if(!mkdir($file_directory)){
mail("debug#example.com","Unable to create base directory","$file_directory");
}
}
function build_directory($customer, $UID){
if($customer->related_orders){
$related = explode(",", $customer->related_orders);
foreach($related as $r_UID){
$rel_order = get_order($r_UID); //fetches order object
if((isset($rel_order->file_directory) && $rel_order->file_directory != "")){
return $rel_order->file_directory;
}
}
}
//Here is where I made my correction
$paths = array('\\\\network\\path');
$base = $paths[0];
//Test if directory is already assigned
if(is_dir($base . "\\order_data\\".$UID."_".str_replace(" ","_",$customer->last_name)."\\")){
return $base . "\\order_data\\".$UID."_".str_replace(" ","_",$customer->last_name)."\\";
}
if($base){
return $base . "\\order_data\\".$UID."_".str_replace(" ","_",$customer->last_name)."\\";
}
}
?>
Change $base = array('\\network\path');
To $base = '\\network\path';
I think the problem is in the build_directory() function and more specifically after the first if.
So if the customer has no related orders, you are trying to concatenate an Array with a string and the result is like
Array\order_data\....
Try o change
$base = array('\\network\path');
to
$base = '\\network\path';
So the problem ended up being framework/user related.
We discovered that if the user refreshed the page during the directory creation it would create the same directory twice which our framework would save as an array of identical paths.

How to associate multiple Doctrine objects in a foreach loop before flushing the entity manager

i need your help for persist data, i explain :
i have entity Player with variable refer Team :
class DataPlayer
{
/**
* #ORM\ManyToOne(targetEntity="Team")
* #ORM\JoinColumn(name="tag_team", referencedColumnName="tag_team")
*/
private $team;
...
}
but when i include the data, i have only tag of team, not entity team...
because the team is not probably present in database (i include team after).
how can i do to set team with string (the tag directly) whitout to change Entity player
thank!
Okay, I believe I see what you're trying to achieve.
You are doing some sort of import, and during the foreach loop, you're creating Team entities that get associated with your DataPlayer. Obviously you don't want to end up making multiple Teams after the first one has been made with a certain tag, but since you haven't performed a flush() using the Entity Manager yet, you can't findOneByTag() because the Team doesn't yet exist in the database.
This is obviously problematic. So what's the solution? Create a temporary array!
$tempTeams = array();
foreach($teams as $team){
$info = explode(',', str_replace("'", "", $team));
if (isset($tempTeams[$info[1]])) {
$db_team = $tempTeams[$info[1]];
} else {
$db_team = $db->getRepository("ApplicationTestBundle:Team")->findOneByTag($info[1]);
}
if(!$db_team){
$db_team = new Team();
$db_team->setTag($info[1]);
$db_team->setName($info[0]);
$em->persist($db_team);
$tempTeams[$info[1]] = $db_team;
}
$dataT = new DataTeam();
$dataT->setTeam($db_team);
$em->persist($dataT);
$db_team = false; // Need to make sure $db_team is cleared out for the next iteration of the foreach
}
This takes all of your temporary PHP objects before persistence and buffers it into the temporary array, which allows you to recall your new Objects by tag name with no problems. The other solution is to $em->flush(); after $em->persist($db_team);
You can then access the $tempTeams array for later lookups (I believe there was an issue with using $info[4] for the tag this time):
foreach($players as $player){
$info = explode(',', str_replace("'", "", $player));
$db_player = $db->getRepository("ApplicationTestBundle:Player")->findOneByPseudo($info[1]);
$dataJ = new DataPlayer();
$dataJ->setJoueur($db_player);
if (isset($tempTeams[$info[4]])) {
$db_team = $tempTeams[$info[4]];
} else {
$db_team = $db->getRepository("ApplicationTestBundle:Team")->findOneByTag($info[4]);
}
$dataJ->setTeam($db_team);
$em->persist($dataJ);
$db_team = false;
}

Entry field not available for recovery?

I'm working with LDAP and for some odd reason I am able to recover all entries via PHP but I am not able to get telephonenumber. It acts as it if was empty but clearly isn't.
Here is the relevant code:
$ds = ldap_connect($LDAP_SERVER);
$sr = ldap_search($ds, $LDAP_PEOPLE, "(|(cn=*$search*)(sn=*$search*)(gn=*$search*)(uid=*$search*)(mail=*$search*))", array('uid', 'sn', 'givenname', 'mail', 'telephoneNumber', 'o') );
ldap_sort($ds, $sr, $_GET['tri']);
foreach ($entries as $entry) {
if (! isset($entry['uid'])) continue;
$uid = $entry['uid'][0];
$telnum = $entry['telephoneNumber'][0];
if (! isset($entry['telephonenumber'])) continue; //THIS IS EVALUATED AS TRUE
...
}
Forgive me if the error is obvious somehow. I've already worked on this a few hours but I'm new to LDAP and what works for other fields does not seem to be working for telephonenumber. I am aware there are other entries on LDAP+telephone but I didn't find one that seemed to suit my question properly.
EDIT:
I found that the LDAP manager didn't allow access to certain fields, including telephonenumber. I am not responsible for authorizations. I sent a request to the sysadmin in order to change authorizations. I think it should fix the problem. I will keep you posted. Thanks.
There is a difference between an array item being set and an array item having a value.
For example:
$array['test'] = "";
if (!isset($array['test'])) //false
if (empty($array['test'])) //true
I imagine your LDAP server always returns a telephone number, regardless of whether there is a value.
You could use
if (empty($entry['telephonenumber'])) continue;
Instead?
Try var_dump($entry['telephonenumber']) and view the output to see what that $entry is set to

php activerecord save does not work in codeigniter

I use the latest code igniter (2.0.3) and php-active 0.0.1.
All are working fine except save();
Code:
if($_POST)
{
$entry= Customers::find_by_routeid('4');
$entry->routeid=5;
$entry->save();
}
Here's my problem: for some reason that I cannot understand the above code does not work, but if I take the code out of if ($_POST), it works fine.
What I am doing wrong?
EDIT:
Thanks Damien Pirsy $this->input->post() does the trick, but when I uncomment the comments in the code the problems returns.
The code now is:
if($this->input->post())
{
$id = $this->input->post('id');
$oldRoute = $this->input->post('oldRoute');
$newRoute = $this->input->post('newRoute');
$entry= Customers::find_by_routeid($this->input->post('oldRoute'));
$entry->routeid=$this->input->post('newRoute');
$entry->save();
/*
if($oldRoute<$newRoute)
{
for ($i=$newRoute; $i>$oldRoute; $i--)
{
$element = Customers::find_by_routeid($i);
echo $element->routeid -= 1;
$element->save();
}
}
*/
}
The elements new IDs ($element->routeid -= 1;) are echoing right, but I have the same problem as in the beginning and neither of two saves work.
You didn't provide much details or debug info, so I'll just guess: try using the CI's native post handler instead. You should have var_dump()ed the $_POST array, see if isset() or not, also, since you're using it as a condition
if($this->input->post())
{
//...
}
UPDATE:
Since we're talking about Post variables, don't assume they're exactly as you want them. Keep in mind that $this->input->post('field') returns FALSE when the index is not present; that might well brake your if condition.
Assuming you need numbers to do this, you can do a check like
if($this->input->post('newRoute') AND is_numeric($this->input->post('newRoute'))
{
$newRoute = $this->input->post('newRoute');
}
else
{
// give it a default value, or raise an error, for example. If you need this
// variables, and need them to be numbers, you cannot go on in case these
// conditions are not met, right?
}
And the same for $oldRoute.
And yeah, OK, maybe you can write a cleaner code than mine, but you get the picture ;)

Categories