PDA

View Full Version : [How-to] Decode custom user profile bitfield


joelabq
04 Jan 2006, 22:07
This How to _should_ help someone setup custom profile fields that use multiple selections decode the bitfields for display (or other) purposes.

If you see anything wrong with how I did this, please let me know, likewise if you have suggestions on how to improve it. I'm just putting this out there because no one else has, and I've had a few people ask about it.

Let’s assume you are using Field7, and you have three settings you defined as multi-select checkbox (Yes, No, and Maybe). You can add more fields if you wish to test more.

1.Run a query to extract the data from the database for that profile field… These are all the settings for this field as defined in your custom profile field manager in the AdminCP. The following code will extract the settings you defined…in this case, “Yes”, “No”, and “Maybe”.


$custom_field_qry = $db->query_read("SELECT data from ". TABLE_PREFIX."profilefield where profilefieldid = '7' ");
$custom_field_ary = $db->fetch_array($custom_field_qry);


2. If you are using any of the following field types in the custom field manager – “select”, “radio”, “checkbox”, “select_multiple” the data is stored serialized, see php.net’s manual for serialize and unserialize to understand the meaning of the function if you do not already understand it. In this case, we used “multi-select checkbox”, so we unserialize the data:


$my_custom_data = unserialize($custom_field_ary['data']);


This will load the array structure stored in the “data” field of the database into $my_custom_data

3. Now we need to match the values from $my_custom_data to the values in $custom_user_data. The “odd” thing here is we are matching binary data in custom_user_data, represented in a decimal number, to the real field in $my_custom_data, and set the values in $show[testbit] so we can display them in a template like forumhome. You may choose how you want to do this, of coarse (refer to the operator reference to understand how “&” works at http://us2.php.net/manual/en/language.operators.php):

foreach($my_custom_data AS $key => $val)
{
if ($vbulletin->userinfo[field7] & pow(2,$key))
{
$show[testbit] .= $val." ";
}

}



So for our example, edit the forumhome template, and add “Testing: $show[testbit]” right below $navbar like shown below:


$stylevar[htmldoctype]
<html dir="$stylevar[textdirection]" lang="$stylevar[languagecode]">
<head>
<!-- no cache headers -->
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="-1" />
<meta http-equiv="Cache-Control" content="no-cache" />
<!-- end no cache headers -->
$headinclude
<title><phrase 1="$vboptions[bbtitle]">$vbphrase[x_powered_by_vbulletin]</phrase></title>
</head>
<body>
$header
$navbar
Testing: $show[testbit]

<!-- main -->


Now go into the plugin manage, and add a plugin at “forumhome_start”, copy this code (as explained above):


$custom_field_qry = $db->query_read("SELECT data from ". TABLE_PREFIX."profilefield where profilefieldid = '7' ");
$custom_field_ary = $db->fetch_array($custom_field_qry);

$my_custom_data = unserialize($custom_field_ary['data']);

foreach($my_custom_data AS $key => $val)
{
if ($vbulletin->userinfo[field7] & pow(2,$key))
{
$show[testbit] .= $val." ";
}

}


Make sure the plugin is activated, and save it.

Now load up your UserCP, check mark whatever boxes you like, and then load up your main forumhome homepage. It should show you all the options you select (and only those options) delimited by a space.

Antivirus
04 Jan 2006, 22:34
Joel, that works really nicely for FORUMHOME, but I am trying to get it to work in the MEMBERINFO template and using hook location member_complete and it's returning my profile's data, not the member who's profile i am viewing...

Thanks!

joelabq
04 Jan 2006, 23:22
Joel, that works really nicely for FORUMHOME, but I am trying to get it to work in the MEMBERINFO template and using hook location member_complete and it's returning my profile's data, not the member who's profile i am viewing...

Thanks!

The line that has this:
if ($vbulletin->userinfo[field7] & pow(2,$key))

Is what you need to modify. The var $vbulletin->userinfo[field7] is only the current logged in user's information.

What you need to do is query for that users profile fieldX values.

In memberinfo, only hidden field aren't already decoded... So I'm not sure what you want to do exactly, but you could make sure they are not hidden and vB already will display the correct values for that user in their profile.

If you really need this in member info, you could add a query using a plugin at member_customfields, something to this effect:


$my_qry = $db->query_read("select userfield.field7 where " . TABLE_PREFIX ." userfield as userfield where userfield.userid = " . $userinfo['userid'].";" );


Then pull that data out in a variable, and put that in place of the code above where $vbulletin->userinfo[field7] is used... Like so:


$my_profilefield_data = $db->fetch_array($my_qry);
if ($my_profilefield_data[field7] & pow(2,$key))
{
....
}


Hope that helps.

Joel

Antivirus
05 Jan 2006, 17:31
It took me a couple hours to figure it out due to process of elimination and with your help above as well- but the following works for me:

Create a plugin using hook location member_complete with following code:


$custom_field_qry = $db->query_read("SELECT data from ". TABLE_PREFIX."profilefield where profilefieldid = '26' ");
$custom_field_ary = $db->fetch_array($custom_field_qry);
$my_custom_data = unserialize($custom_field_ary['data']);
foreach($my_custom_data AS $key => $val)
{
if ($userinfo[field26] & pow(2,$key))
{
$show[testbit] .= $val.", ";
}
}

and include $show[testbit] in the template...

BUT...

It does however add 1 additional query to the page. I don't understand why it needs to run another query at all, since the correct serialized data is already in $userinfo[field26] to begin with, but it does now work at the least.

I was attempting to unserialize the data and match it up without having to run the additional query above. I tried the following, but I am still a beginner with php and it wasn't working properly.


$my_custom_data = unserialize($userinfo['field26']);
foreach($my_custom_data AS $key => $val)
{
if ($userinfo[field26] & pow(2,$key))
{
$show[testbit] .= $val.", ";
}
}

vietkieu_cz
05 Jan 2006, 19:48
Some screenshot please?

joelabq
05 Jan 2006, 19:49
You have to run the query because field26 in the user info does not contain the actual data, just the bitfield data. All you get in the bitfield is 1's and 0's. Basically you have to match the real array with $userinfo[field26].

To visualize may be easier... imagine your array with "Yes", "No" and "Maybe" values (in that order in your custom field manager), which is contained NOT in userinfo[$field26] but in $my_custom_data as outlined above. $my_custom_data looks like this:

$my_custom_data[0] = "Yes"
$my_custom_data[1] = "No"
$my_custom_data[2] = "Maybe"

Now, $userinfo[field26] looks like this when "Yes" is set (in binary):
001 (or simply "1", but the leading zero's may help you visualize here)

So when you compare the fields with " if ($userinfo[field26] & pow(2,$key)" you are essentially doing this:

$my_custom_data[0] = "Yes" 1 (YES, user has it)
$my_custom_data[1] = "No" 0 (No, User doesnt have it set)
$my_custom_data[2] = "Maybe" 0 (No, User doesnt have it set)

Now, imagine Yes and Maybe are set for this user. $userinfo[field26] will be set to "5" in decimal, and when converted to binary is "101"... ON, OFF, ON... so lets compare it to $my_custom_data:

$my_custom_data[0] = "Yes" 1 (YES, user has it)
$my_custom_data[1] = "No" 0 (No, User doesnt have it set)
$my_custom_data[2] = "Maybe" 1 (YES, user has it)

Likewise, the code you posted:


$my_custom_data = unserialize($userinfo['field26']);
foreach($my_custom_data AS $key => $val)
{
if ($userinfo[field26] & pow(2,$key))
{
$show[testbit] .= $val.", ";
}
}


...Will not work, because the data that is in $userinfo[field26] is NOT the serialized data, it only hold the binary representation to what is set when compared to the real serialized data. Therefore, you MUST run a query, unless vB already has pulled the data.

In your case, around line 560 in member.php


$customfields = '';
while ($profilefield = $db->fetch_array($profilefields))
{
exec_switch_bg();
$profilefieldname = "field$profilefield[profilefieldid]";
if ($profilefield['type'] == 'checkbox' OR $profilefield['type'] == 'select_multiple')
{
$data = unserialize($profilefield['data']);
foreach ($data AS $key => $val)
{
if ($userinfo["$profilefieldname"] & pow(2, $key))
{
$profilefield['value'] .= iif($profilefield['value'], ', ') . $val;
}
}
}


...Which means, you could use the already queried $userinfo["$profilefieldname"], but ONLY if it's not hidden. I take it your data is hidden, therefore you could either unhide and create some template conditionals, or you add this query.

Hope this helps.

Joel

Some screenshot please?

What?

Antivirus
05 Jan 2006, 20:17
that helps me understand the bitfields more, thanks Joel, you have been a tremendous help! :)

joelabq
05 Jan 2006, 21:28
Glad I could help.

Joel