Facebook like registration

Hi,

I was wondering if there is a Facebook like registration extension for Yii out there.

I mean my users would register with a form -> get a big token via email -> they’ll have to click on the email to verify their account -> program would activate their account … etc

I found an extension but it lets you register without verification => [color="#FF0000"]SPAM ALERT[/color]!

thanks,

–iM

I’m currently working on something similar (user enters only him e-mail address, and the e-mail contains the link to the registration page), if you wish I can share its source. :)

Talking about verification, I chose not to save the verification tokens, but to hash the e-mail with random salt. This way I can prevent invalid and non-existent addresses to appear.

hello,

well, if you don’t mind sharing it :) I think, you should create an extension, it would be a very useful one.

I’m pretty sure we are not the only one who need it!

–iM

Well it’s not more than a few lines in the controller, a text file containing the sample e-mail which is to be prepared and sent with pear; and of course a form.

I don’t even know what could be shared as an extension of it.

hmmm… maybe it’s too easy for me then.

I need expiration time on my tokens (let’s say an hour or a day or something like that) for that, I guess I’ll need an extra table to store the tokens and the time stuff.

(I did this before with regular PHP, I just wanted to know if there is an “out-of-the-box” [color="#006400"]Yii[/color] ext … you know, because I’m lazy :)

–iM

:rolleyes:

If you don’t find storing expiration time in the url safe enough, yes, you need extra table.

However, I’d like to note that I never understood why confirmation e-mails expire at all. Is it because if I forgot my mail account password for 24 hours, then I became unworthy of their account as well?

Seems like an unnecessary restriction.

I don’t think you need an extra table.

I have an extra field in my user table: email_confirm_password.

The email verification on my site is treated much like authentication.

Upon registration I generate a random password and save a hashed version of it in email_confirm_password.

The email which I send to the user contains a link with his email and the random password.

When the user clicks on the link I search for the record with the email address and then compare the passwords.

If its correct, then I set email_confirm_password to NULL.

You will probably need another field: email_confirm_start, so that you can have your timeout.

[sluderitz]

and what would you do with all the generated users that never returned to your site? (never verified their email!). your users table would be full of ‘ghost’ accounts, floating around ;)

you could go through your DB every now and then and delete those accounts, but that would create way too much overhead that is unnecessary. Especially, if you have a site that gets thousands of users every day.

pestaa’s solutions sounds a little better, only save the users once he/she verified the account.

we’ll see, I’ll keep you guys informed :D

–iM

Ahh, so you do not want to save any data in your DB until the user has confirmed his email.

I think when you register on Facebook your firstname, lastname, birthdate, etc. is saved in the database.

Don’t worry about overhead, say you have 10000 users signing up every day (good luck), and only 1000 confirm their email. You can have a daily cronjob delete the 9000 users each day, thats no overhead at all.

Perhaps a user MODULE would be better than an extension

I have this implanted in my skeleton app (but not as a module or anything) - http://code.google.com/p/yii-skeleton-app/

Thats a simple elegant solution. If you combine that with maybe a status field, so a user can have different states such as registered but not verified, registered, suspended etc… then I think thats the best way.

I already have status field for non-verified/normal/banned/etc. people. :)

As adrian said, I also cannot see any room for improvement nearby.

I recently worked on a free form application like this myself. It’s not intense but it’ll do the trick. If you want to take the code to make it more efficient and into a module that’s fine by me.

What I did was create 2 db tables that are identical, one user and the other validate. The only difference is validate has a session field. The relation between these two is a 1 to none setup. User doesn’t access validate, but validate will transfer data to user (once validated).

A user controller was made to handle all user actions, register and validate being among them. The register action is just a simple form setup, the typical instantiate the class, isset condition, false show form, true set attributes then before I validate I assign these three parameters, IP isn’t a big concern but time and the session are needed.

This is in the user/register action




 $form->ip = $_SERVER['REMOTE_ADDR'];

 $form->time = time();

 $form->session = md5($form->time.rand(100000,999999));

 

Now all you do is append the session to a link like so:




 $form->sessionLink = $this->createAbsoluteUrl('user/validate', array('code'=>$form->session));

 

Then validate and save - which saves to the validate table not the user table. Within the validate model, make an after save function that creates and sends your email. Now if you want to go a step further, you can insure that the email is sent by uploading the message, subject, email and header information to a table (called mail) in the event the mail function fails. Then elsewhere set a script to send all unsent emails.

The user gets their email with the absolute link in it that includes the session hashed via $_GET.

Then you just follow the link which takes you to the user/validate action and then you check if the session they clicked on and you retrieved with $_GET is located in the validate database. If it is, then transfer all values over to the user database and registration is complete - you can even send another email with an after save override for the user model which will contain the information details of their registration.

The way I implemented it I use the time field to compare if the user validated within a 7 day period or else the validation session is no longer valid meaning they have to re-register. This will be setup to prune with a script later.

Another small note, when you save to the validate table, don’t hash any passwords, that way when they confirm their registration, you can email the plaint text password (storing it in another class private variable before hashing it and saving to the user table).




 $code = $_GET['code'];

         

         $validate = new Validate;

         // find hash

         $validate = Validate::model()->find('session=?', array($code));

         

         if($validate == NULL)

         {

             $validate->sessionValid = "Not Valid";

             $this->render('validate',array('validate'=>$validate));

         }

         else

         {

             $user = new User;

             

             // Define how long until the session expires

             // 7 is the number of days.

             $valid = 3600*24*7;

             $time = time(); 

             $timeElasped = $time - $valid;

             

             if($validate->time < $timeElasped)

             {

                 // Took to long to confirm registration

                 $validate->sessionValid = "Not Valid";

                 // Delete the record

                 $validate->delete();

             }

             else

             {

                 // Session is valid, transfer data to user table

                 $validate->sessionValid = "Valid";

                 // Set all the column values

                 $user->username = $validate->username;

                 $user->password = $validate->password;

                 $user->email = $validate->email;

                 $user->ip = $_SERVER['REMOTE_ADDR'];

                 $user->time = time();

                 $user->question = $validate->question;

                 $user->answer = $validate->answer;

                 

                 if($user->validate())

                 {    

                     // Save to the user table    

                     $user->save();

                     // Delete the record

                     $validate->delete();

                 }

 

It’s pretty basic but works like a charm. This isn’t all the code so if you’re having trouble give me a shout. But what I got is messy with so many if conditions (because of the desire to store the message if it’s not sent).

Now I’m going to explore Jonah’s skeleton application and see what I can add or change there :) .

Also as you can see the hash used for the session is nothing fancy and certainly different than what’s used throughout the site for other things like the password or cookies or w/e. Thus in the event some script kiddy tries to crack it, they crack a hash that’s useless to the site and has random information about time lol.