Title: PhpFox (by invitation only!)
Posted: Fri, 30th March 2007
Category: PHPWhat'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.
del.icio.us
.
Digg It
.
BlinkList
.
Fark
.
Google
.
Ma.gnolia
.
Netvouz
NewsVine
.
RawSugar
.
Shadows
.
Stumble
.
Technorati