+353 (0)87 1254033
+33 (0)617 104022

 
Technical Articles

Recent News & Articles

» Timeware Roster System (v2.0 S...
» Recommended site architecture ...
» Enabling Gzip compression on y...
» Secure file_get_contents PHP f...
» Puerto Plata Website Launched ...

Live Support
Contact one of our team members now to discuss your project requirements. Helpful & knowledgable team members are on hand to provide you with expert advice. Live support is currently


PhpFox (by invitation only!)

Posted: Fri, 30th March 2007 in PHP

What's this all about then? Well, since the launch of phpFox Konsort v1.5, we receive at least 2 weekly enquiries about shutting off the signup section so that a site is exclusively built by existing members. This tactic has a couple of advantages from a web marketing perspective. Firstly, it makes the site exclusive which, at the early stages of development, helps to create a certain atmospheric 'buzz' in the real world. Secondly, by de facto standard, each member is known by at least 1 other member so it could be argued that a phpFox invitation only site is safer than the social free-for-all that is so prevalent on the web today.

What's involved in making a phpFox site invitation only? Well, we'll get to the details in a moment but the basic theory is as follows. Each time an invitation is sent out, record a unique stamp with the invitation information. Then when anybody comes to the signup page of your site, if they have a valid unique stamp, they're allowed in, if not, they are rejected. Simple. There are a couple of phpFox mods scattered around the web which implement 'by invitation only' functionality. Some are free, some require payment of princely sums. Due to our nature, we've decided to give it away for free. Why?

1) It's only a few lines of code
2) There's no particular ingenuity behind it
3) We're fairly sure that by publishing this, it isn't going to destroy anyone else's business model
4) It will stem the tide of 'invitation only' requests that we get to our inbox (wishful thinking!)
5) We have a giving nature (honestly!)

Ok, let's get down to it. As I've said, it's really quite a small mod, there are about 6 or 7 minor changes in order to get this working. I'll list the file, list the code you need to add and give a bit of a background on the theory and what it does. Feel free to skip that last bit if you simply don't care. First off though, we have a small database modification to perform.

Database Table: invite

Add a field called 'signup_key' of type varchar(32) to the invite table. You can do this either through phpMyAdmin or some other mySQL client or by running the following in the context of the database (either through a shell or in some php code if you don't have shell access):


ALTER TABLE `invite` ADD `signup_key` VARCHAR( 32 ) NOT NULL;


File: includes/modules/Account/classes/PhpFox_ServiceInvite.class.php

Look for:

/** Send invitation emails
 * @param array                          $aEmails  emails array
 * @param PhpFox_Mod_Account_ItemAccount $oAcc     sender user account object
 * @return array sended emails
 */
function sendInvites($aEmails, $oAcc, $sText)


Above that add:


function generatePassword ($length = 8)
{
   $password = "";
   $possible = "0123456789bcdfghjkmnpqrstvwxyz";
   $i = 0;

   while ($i < $length)
   {
      $char = substr($possible, mt_rand(0, strlen($possible)-1), 1);
      if (!strstr($password, $char))
      {
         $password .= $char;
         $i++;
      }
   }
   return $password;
}


What's going on:
As the name goes, this function generates a password which will be reasonably unique (we'll make sure it's really unique later). It's used to identify a particular invitation sent out by a member of your site.

Look for:


$aVars = array(
	'SITENAME'    => App::format('site.name'),
	'USERNAME'    => $oAcc->aData['user'],
	'HOME'        => App::makeUrl('public.signup', array('refid'=>$oAcc->aData[$oAcc->sId])),
	'EXTRATEXT'   => $sText,
);


Take that block of code and move it to just above this block of code a few lines down:

$aVars['IMG'] = smarty_function_img($aParams, $oTpl);
$oMailer->send('email_invite', $sEmail, 'Invitation from '.$oAcc->aData['user'], $aVars);
$oInvite->aData['user']  = $oAcc->aData['user'];
$oInvite->aData['email'] = $sEmail;


What's going on:
The important line here is
'HOME' => App::makeURL('...')
. This constructs the URL that the person who is being invited will see in the e-mail they receive from your site. As we need to uniquely identify each invitation, that's the reason for moving the above block of code inside the
foreach
loop.

Now the bit of code that you've just moved, i.e.
$aVars = array(...
. Immediately before that block of code, add the following:


do
{
   $signup_key = md5($this->generatePassword());
} while(mysql_num_rows(mysql_query("SELECT * FROM invite WHERE signup_key = '".$signup_key."';"))>0);


What's going on:
In the
do-while
loop, a "signup key" is generated using the
generatePassword
function that we added in our first modification. We keep on generating the password while there are more than 0 records of the
signup_key
in our
invite
table. To repeat, if the
signup_key
isn't unique, keep at it until it is unique. If you're worried about this getting stuck, don't be! If you're still worried, increase the length and variety of characters of the generated password to decrease the likelihood of generating the same password twice.

Look for:

'HOME' => App::makeUrl('public.signup', array('refid'=>$oAcc->aData[$oAcc->sId])),


After
'refid'=>$oAcc->aData[$oAcc->sId]
add the following:
,'key'=>$signup_key


So now that piece of code should look like:

'HOME' => App::makeUrl('public.signup', array('refid'=>$oAcc->aData[$oAcc->sId],'key'=>$signup_key)),


What's going on:
This will add your newly generated signup key to the URL that is sent out to the invitee. Effectively, this uniquely identifies the invitation and so makes it possible to reject any signups where a valid signup key isn't provided.

Look for:

unset($oInvite->aData[$oInvite->sId]);
$oInvite->insert();


Above that add:

$oInvite->aData['signup_key'] = $signup_key;


What's going on:
This is the final modification in this file. All you are saying here is to include the
signup_key
when the "invite" record in the database is created. That's also the half way mark. There are a few internal changes to make to one more file and then your site will be invitation only.

File: includes/modules/Account/classes/PhpFox_ComponentSignup.class.php

Look for:

$oAcc = $this->_oModule->getItem('Account');
$bProcessed = false;
$oReq = &App::getRequest();


Below that add:


$invitation_valid = false;
$signup_key = $oReq->get('key');
if(!empty($signup_key))
{
   $invitation_only_signup_email = '';
   $a = mysql_query("SELECT email FROM invite WHERE signup_key = '".$signup_key."';") or die(mysql_error());
   while($b = mysql_fetch_array($a))
   {
      $invitation_only_signup_email = $b["email"];
      $oAcc->aData['email'] = $invitation_only_signup_email;
      $invitation_valid = true;
   }
}
if(!$invitation_valid)
{
   $this->addErrors('You must have an invitation to signup to My Site');
}


What's going on:
If all went well in the previous file, when the invitee receives their invite, a 'key' parameter will now be included which will identify the invitation. At this point, we need to validate the invitation. Query the database asking for the email address of the invitee who is attached to the signup key. If we find someone, it's a valid invitation, if not, this person hasn't provided the correct key associated with their invitation and so we may in fact assume that they never received an invitation at all. In the event that the invitation isn't valid, trigger an error. We also set a flag
$invitation_valid
here so that we can display an alternate template (optional) for the signup page.

Look for:

if (!App::getSetting('signup_email'))


Above that add:

mysql_query("UPDATE invite SET signup_key = '' WHERE signup_key = '".$signup_key."' LIMIT 1;");


What's going on:
At this point, the signup has been processed so we should remove the signup key from the list of invitations. Why? Well, it gives us a larger pool of available keys to use if there is 1 less key in the database.

Look for:


$oTpl->assignSrc(array(
	'aCountries'   => $aCountryList,
    'jsValidation' => $oValidator->makeJS(),
    'jsValMess'    => $oValidator->makeJsMess(),
));


Below that add and replace the remainder of the function with:

$to_fetch = ($invitation_valid) ? 'Signup.html' : 'Signup_No_Form.html';
$srcHtml = $oTpl->fetch($to_fetch);
return $srcHtml;


What's going on:
Here, we utilise the flag that we previously set if the invitation wasn't valid. It wouldn't be prudent software development to display the entire signup form if the user didn't provide a valid key otherwise the page would read as follows: Signup Here, Error: You need an invitation to signup here, Here's the form anyway. Not good enough. So, we created a copy of design/templates/_modules/Account/Signup.html, called it Signup_No_Form.html which basically has, eh, no form and we display that if the user doesn't have a valid invitation. Remember to leave in the rest of the code as it is still responsible for displaying the error, just remove everything from
<form>
to
</form>
.

That's it! You should now have a fully functioning 'invitation only' phpFox site up and running all for the price of a few minutes PHP coding. Enjoy!

As with all articles on Celtic Productions, this article is protected by international copyright laws. It may be linked to, however, it may never be reproduced without the prior express permission of its owners, Celtic Productions.


About Us | Our Products | Our Services | Technical Articles | How we work | News | Contact Us | Privacy Policy