String Comparison Through Loop and Array Variables

Hi,

I’ve been trying to get code working for a few hours now and can only manage one of two results. The code is Wordpress based but the issue is pure PHP.

Basically I’m trying to find a users Wordpress role. I’m achieving this by storing a meta_value in a string and then checking the string for the name of the role. This works perfectly in practice, however I’m trying to make it more dynamic but I can only do it manually or get the end of the array.

Allow me to explain.

[php]
function set_status() {

global $wp_roles;
global $wpdb;

$roles_list = $wp_roles->role_names;
$id = get_logged_in_user_id();

$query = $wpdb->get_var("SELECT wp_usermeta.meta_value FROM $wpdb->usermeta WHERE user_id = $id AND wp_usermeta.meta_key = 'wp_capabilities'");

$role = find_role($query, $roles_list);

}

//Returns the current user ID
function get_logged_in_user_id() {

global $current_user;  //Include the global $current_user variable
get_currentuserinfo();  //Populate the $current_user variable with the logged in users info

if(is_user_logged_in()){  //If the user is logged in
	if(is_object($current_user)){  //Check the $current_user variable is populated
		$current_user_id = $current_user->ID;  //Retrieve the current users ID
	}
}
return $current_user_id;  //Return the current user ID

}

function find_role($in_me, $find) {
foreach($find as $role){
$role = strtolower($role);
(strpos($in_me, $role) !== false);
continue;
}
return $role;
}
[/php]

What’s happening here is the first function is calling the second function to find the user id of the currently logged in user, then using that user id to find the correct database entry. The database entry looks like this:

a:1:{s:7:"patient";s:1:"1";}

As you can see “patient” is the currently logged in users role.

The get this from the string I’m comparing the string using strpos. This works perfectly like this:

[php]
$role = (strpos($query, “patient”) !== false);
[/php]

This will return true, so I can then say if it’s true return “patient”.

What I am trying to achieve with the third function is to pass the list of roles from the “$wp_roles->role_names” call as the second parameter and then loop through them all until it finds a match, then return that match.

$wp_roles->role_names returns this:

array(16) { ["administrator"]=> string(13) "Administrator" ["editor"]=> string(6) "Editor" ["author"]=> string(6) "Author" ["contributor"]=> string(11) "Contributor" ["subscriber"]=> string(10) "Subscriber" ["patient"]=> string(7) "Patient" ["care_home_user"]=> string(14) "Care_Home_User" ["care_home_admin"]=> string(15) "Care_Home_Admin" ["gp"]=> string(2) "GP" ["doctors_chemist_staff"]=> string(21) "Doctors_Chemist_Staff" ["pending"]=> string(7) "Pending" ["s2member_level1"]=> string(16) "s2Member Level 1" ["s2member_level2"]=> string(16) "s2Member Level 2" ["s2member_level3"]=> string(16) "s2Member Level 3" ["s2member_level4"]=> string(16) "s2Member Level 4" ["customer"]=> string(8) "Customer" }

But the for each loop I’ve got just returns the last item in the array every time. Breaking results in only the first item, I’ve tried do, while and simply while and I just cannot get the syntax right. I’m sure it’s me and I know this works in theory. In case it’s not clear the sudo code would read something like:

Does $role appear in the string “$query”?

If not try the next role in list.

If it matches exit loop and return matched value.

I hope that makes it clear.
Can someone please straighten this out for me, it’s driving me nuts as I’m not very good with loops.

Thanks in advance.

strpos looks to see where something is in a string, try using in_array() instead if all you want to do is see if that role is in the array.

I see what you mean but I think I need the search to work the other way round. Initially I have a string like this:

a:1:{s:7:"patient";s:1:"1";}

and I need to find what the word is in it, in this case patient but it could be administrator or several other things.

Whatever it is it will be stored in the array “$wp_roles->role_names”, so I was using strpos to check if it existed in the string. What I really want to do is use every entry of the array in turn to check and see if that entry is present in the string.

I can’t narrow the string down as the numbers change and if they become double digits it wouldn’t work, hence the string searching.

Does that make any sense?

Can anyone help? I’ve got this working as an If Else statement but it’s not dynamic:

[php]
//Returns the current user ID
function get_logged_in_user_id() {

global $current_user;  //Include the global $current_user variable
get_currentuserinfo();  //Populate the $current_user variable with the logged in users info

if(is_user_logged_in()){  //If the user is logged in
	if(is_object($current_user)){  //Check the $current_user variable is populated
		$current_user_id = $current_user->ID;  //Retrieve the current users ID
	}
}
return $current_user_id;  //Return the current user ID

}

function current_user_role() {
global $wpdb;
$id = get_logged_in_user_id();
$in_me = $wpdb->get_var(“SELECT wp_usermeta.meta_value FROM $wpdb->usermeta WHERE user_id = $id AND wp_usermeta.meta_key = ‘wp_capabilities’”);

	if(strpos($in_me, "administrator")){
		$role = "administrator";
	}elseif(strpos($in_me, "patient")){
		$role = "patient";
	}elseif(strpos($in_me, "patient")){
		$role = "patient";
	}elseif(strpos($in_me, "care_home_user")){
		$role = "care_home_user";
	}elseif(strpos($in_me, "care_home_admin")){
		$role = "care_home_admin";
	}elseif(strpos($in_me, "gp")){
		$role = "gp";
	}elseif(strpos($in_me, "doctors_chemist_staff")){
		$role = "doctors_chemist_staff";
	}

// }
return $role;

}
[/php]

Please note, any functions I call that aren’t shown in detail are Wordpress functions that basically do what they say on the tin.

Can no one help?

Hi theslink2000,

I am assuming the value returned by $wp_roles->role_names is an actual array and that the value you posted is from a var_dump. If this is incorrect, we will need to account for that. Also, I am assuming you are looking to match the role key and return the role value. Please let me know if I am wrong.

I believe the following will do what you are looking for.[php]function find_role($in_me, $find) {
$target = strtolower(array_keys(unserialize($in_me))[0]);
$rolekeys = array_keys($find);
if(in_array($target,$rolekeys)) echo $find[$target];
}[/php]

I would be glad to explain what is going on here, but lets make sure it does what you need first.

Hi malasho,

Thanks for the reply. I’m following you about 90% but I’m a little unsure of one or two things (my PHP knowledge is basic to intermediate as I’m sure you guessed).

You’re spot on with the data posted above coming from a var_dump so that’s bang on target.

However I’m not familiar with the unserialize function, but from what I’ve read in the manual is it to do with converting objects to other variable types, like a string in this case?

The other thing I’m not 100% on is the role keys. I thought a key was like an indexing number, but looking at the dump from $wp_roles->role_names it seems the roles array stores the role name in lower case as the key. Am I understanding this correctly?

So just to clarify, the point of this function was to pull the role name out of the user_id (it’s buried in amongst other stuff remember) then compare that to the array or role names until it finds a match, then return that match as a string. So the function will find your currently logged in users role name.

I really appreciate the help but, does this make any sense?

This is a serialized array. If you do the following with it:[php]$test = unserialize(‘a:1:{s:7:“patient”;s:1:“1”;}’);[/php]
Test will be a php array:Array ( [patient] => 1 )

So instead of having to use strpos and try to match a preset role, the role is given to you as the array key: patient.

What the function I posted does is:

Receive two variables: $in_me and $find

It then unserializes the serial data discussed above (which is passed as $in_me).

As we saw above, this array has one member with a key that is the role we are looking for. Since we need the key and not its value, I am using the array_keys function to get an array with the key value (the user’s role) as its first member. Since array_keys returns an array and we only need the value for the first element, I am isolating that with the [0] immediately following the call to array_keys. At this point we have a string that is the user’s role; extracted from $in_me.

I included the strtolower, as you were using it previously and I am assuming that you have identified a possible conflict with the cases of the user’s role and the roles that you are matching against.

So, now we should have a variable ($target) that is equal to the user’s role that was obtained from the prior db query. It has also been converted to all lower case.

At this point, we have also received an array ($find) that contains a list of all possible roles as the keys and something resembling a Label for the role as the value for each element. (eg ‘patient’=>‘Patient’).

At this point, I wouild change how I proceed from the code that I originally posted.

For some reason I was isolating all the possible role keys and then using in_array to see if the $target was contained in the array. A better solution would be to simply see if a value exists for the key. This can be accomplished with isset and I wouild use this instead (see below).

Lastly, I was echoing the “Label” for your testing purposes. This would need to be replaced with your return if everything was testing OK. This was not necessary, but I find it helpful when working on code.

This is how the final code should look with the change noted above and the testing output replaced with a return:
[php]function find_role($in_me, $find) {
$target = strtolower(array_keys(unserialize($in_me))[0]);
if(isset($find[$target])) return $find[$target];
}
The result of this function should be false or empty if there was no match, and it should be the “Label” that was in the roles array if a match was found.

Hopefully this will make sense, but please let me know if it doesn’t, or if I misunderstood the data or your intent.

You Sir, are a genius!

I had to make one tiny modification to make it work as your code as given was producing this error:

Parse error: syntax error, unexpected '[' in C:\xampp\htdocs\wordpress\wp-content\themes\MyTheme\functions\data.php on line 71

This seemed to be caused by strtolower expecting a string and array_keys and unserialize both expecting arrays. I know you seemed to compensate for this by placing the array position accordingly but whatever I did it still generated the above error.

So I simply split the code out over several lines and it works like a charm!

Note: I corrected a stupid mistake I made originally by swapping $find and $in_me, it’s kinda obvious when you think about it as $find should contain the users role, ie. what you wish to find, and $in_me should contain the data to search in. Makes sense don’t it?

[php]
function current_user_role() {
global $wp_roles;
global $wpdb;
$in_me = $wp_roles->role_names;

$id = get_logged_in_user_id();
$find = $wpdb->get_var("SELECT wp_usermeta.meta_value FROM $wpdb->usermeta WHERE user_id = $id AND wp_usermeta.meta_key = 'wp_capabilities'");
$role = find_role($find, $in_me);
return $role;

}

function find_role($find, $in_me) {
$target = array_keys(unserialize($find));
$target = $target[0];
$target = strtolower($target);
if(isset($in_me[$target]));
return strtolower($in_me[$target]);
}
[/php]

Laid out like this the code works perfectly and I couldn’t be happier!

I wanted to ask you one quick question though bud. Given the success I’ve found here and the issue getting Wordpress roles seems to be, I would like to package this code with a few bells and whistles and post it as a Wordpress plugin to give others access to some role related functions and obviously I owe you a great deal of credit so if you would like to post back or probably PM me how you would like to be referred to (if at all) in the documentation for the plugin I would be grateful. On the same note if you say out right you do not wish this code to be published in such a way then fair do’s bud but I doubt it somehow :slight_smile:

Let me know and thanks once again, you’ve been incredibly helpful.

I’m thrilled it is working for you!

I certainly don’t mind you using the code any way that you would like, especially if it can help others as well. It is very generous of you to offer to credit me in your project, but that definitely isn’t necessary - it’s your baby! It sounds like an exciting project and I wish you good luck on it. Please let me know if you run into any other challenges, I’m more than happy to try to help.

I wondered about the $find and $in_me but thought there must be a reason… :smiley:

It’s interesting that it wouldn’t parse for you. I didn’t expect it to work for me when I put it together but I decided to try it and it worked on my server! I just checked it again to confirm and it does work. I am using PHP 5.4.7 (the latest release). It might be the version number or it might be some other configuration, but good job in figuring out the solution!

That’s very kind of you.

Given that its WordPress it’ll all be a free to use plugin anyway, my plan for it is to give it some extra abilities such as specifing the user id and if you want it to return the role in lowercase as I’ve done or exactly as its stored etc. Simple parameters basically.

I’ve learnt a huge amount about array manipulation here and I’m sure that knowledge will be invaluable in the future. As for the PHP versioni couldn’t tell you as I’m not sat at the laptop right now, but its whatever version is currently bundled with XAMPP if youre interested in checking, but I’m surprised it worked for you too lol.

If your totally sure you don’t want a mention in the docs then I’ll simply say thank you one last time and this has been a huge help to my main project as well (the original purpose of the thread) and if you change your mind or wish to preview the plugin code please don’t hesitate to contact me.

Many thanks.

Sponsor our Newsletter | Privacy Policy | Terms of Service