Xataface  2.0alpha2
Xataface Application Framework
 All Data Structures Namespaces Files Functions Variables Groups Pages
register.php
Go to the documentation of this file.
1 <?php
2 /*-------------------------------------------------------------------------------
3  * Xataface Web Application Framework
4  * Copyright (C) 2005-2007 Steve Hannah (shannah@sfu.ca)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *-------------------------------------------------------------------------------
20  */
33 
38  var $form;
39  var $params;
40  var $ontology;
41 
42 
43  function handle(&$params){
44  $this->params =& $params['action'];
45  unset($params);
47 
49 
50 
53 
54 
55  import('Dataface/Ontology.php');
56  Dataface_Ontology::registerType('Person', 'Dataface/Ontology/Person.php', 'Dataface_Ontology_Person');
57  $this->ontology =& Dataface_Ontology::newOntology('Person', $app->_conf['_auth']['users_table']);
58 
59  $atts =& $this->ontology->getAttributes();
60 
61  $query =& $app->getQuery();
62  if ( !is_array(@$app->_conf['_auth']) ){
63  return PEAR::raiseError("Cannot register when authentication is not enabled.", DATAFACE_E_ERROR);
64  }
65 
66  if ( isset($app->_conf['_auth']['email_column']) ){
67 
68 
69  $atts['email'] =& $this->ontology->table->getField( $app->_conf['_auth']['email_column'] );
70  $this->fieldnames['email'] = $app->_conf['_auth']['email_column'];
71  }
72 
73 
74  if ( $auth->isLoggedIn() ){
75  return Dataface_Error::permissionDenied("Sorry you cannot register once you are logged in. If you want to register, you must first log out.");
76  }
77 
78 
79 
80  if ( !@$app->_conf['_auth']['allow_register'] ){
81  return PEAR::raiseError("Sorry, registration is not allowed. Please contact the administrator for an account.", DATAFACE_E_ERROR);
82  }
83 
84 
86 
87 
88  // Create a new record form on the users table
89  $this->form =& df_create_new_record_form($app->_conf['_auth']['users_table']);
90 
91  // add the -action element so that the form will direct us back here.
92  $this->form->addElement('hidden','-action');
93  $this->form->setDefaults(array('-action'=>$query['-action']));
94 
95  // Check to make sure that there isn't another user with the same
96  // username already.
97  $validationResults = $this->validateRegistrationForm($_POST);
98  if ( count($_POST) > 0 and PEAR::isError($validationResults) ){
99  $app->addMessage($validationResults->getMessage());
100  $this->form->_errors[$app->_conf['_auth']['username_column']] = $validationResults->getMessage();
101  }
102  if ( !PEAR::isError($validationResults) and $this->form->validate() ){
103  // The form input seems OK. Let's process the form
104 
105  // Since we will be using our own form processing for this action,
106  // we need to manually push the field inputs into the Dataface_Record
107  // object.
108  $this->form->push();
109 
110  // Now we obtain the Dataface_Record object that is to be added.
111  $rec =& $this->form->_record;
112  $delegate =& $rec->_table->getDelegate();
113 
114 
115  // Give the delegate classes an opportunity to have some fun
116  if ( isset($delegate) and method_exists($delegate, 'beforeRegister') ){
117  $res = $delegate->beforeRegister($rec);
118  if ( PEAR::isError($res) ){
119  return $res;
120  }
121  }
122 
123  $appdel = & $app->getDelegate();
124  if ( isset($appdel) and method_exists($appdel, 'beforeRegister') ){
125  $res = $appdel->beforeRegister($rec);
126  if ( PEAR::isError($res) ) return $res;
127  }
128 
129  // This is where we actually do the processing. This passes control
130  // to the processRegistrationForm method in this class.
131  $res = $this->form->process(array(&$this, 'processRegistrationForm'), true);
132 
133  // If there was an error in processing mark the error, and show the
134  // form again. Otherwise we just redirect to the next page and
135  // let the user know that he was successful.
136  if ( PEAR::isError($res) ){
137  $app->addError($res);
138 
139  } else {
140 
141  // Let the delegate classes perform their victory lap..
142  if ( isset($delegate) and method_exists($delegate, 'afterRegister') ){
143  $res = $delegate->afterRegister($rec);
144  if ( PEAR::isError($res) ) return $res;
145  }
146 
147  if ( isset($appdel) and method_exists($appdel, 'afterRegister') ){
148  $res = $appdel->afterRegister($rec);
149  if ( PEAR::isError($res) ) return $res;
150  }
151 
152 
153  // We accept --redirect markers to specify which page to redirect
154  // to after we're done. This will usually be the page that the
155  // user was on before they went to the login page.
156  if ( isset($_SESSION['--redirect']) ) $url = $_SESSION['--redirect'];
157  else if ( isset($_SESSION['-redirect']) ) $url = $_SESSION['-redirect'];
158  else if ( isset($_REQUEST['--redirect']) ) $url = $_REQUEST['--redirect'];
159  else if ( isset($_REQUEST['-redirect']) ) $url = $_REQUEST['-redirect'];
160  else $url = $app->url('-action='.$app->_conf['default_action']);
161 
162  if ( @$params['email_validation'] ){
163  $individual = $this->ontology->newIndividual($this->form->_record);
164  $msg = df_translate('actions.register.MESSAGE_THANKYOU_PLEASE_VALIDATE',
165  'Thank you. An email has been sent to '.$individual->strval('email').' with instructions on how to complete the registration process.',
166  array('email'=>$individual->strval('email'))
167  );
168  } else {
169  // To save the user from having to log in after he has just filled
170  // in the registration form, we will just log him in right here.
171  $_SESSION['UserName'] = $this->form->exportValue($app->_conf['_auth']['username_column']);
172  $msg = df_translate('actions.register.MESSAGE_REGISTRATION_SUCCESSFUL',
173  "Registration successful. You are now logged in."
174  );
175  }
176  // Now we actually forward to the success page along with a success message
177  if ( strpos($url, '?') === false ) $url .= '?';
178  $app->redirect($url.'&--msg='.urlencode($msg));
179  }
180  }
181 
182  // We want to display the form, but not yet so we will use an output buffer
183  // to store the form HTML in a variable and pass it to our template.
184  ob_start();
185  $this->form->display();
186  $out = ob_get_contents();
187  ob_end_clean();
188 
189  $context = array('registration_form'=>$out);
190 
191  // We don't want to keep the registration page in history, because we want to
192  // be able to redirect the user back to where he came from before registering.
193  $app->prefs['no_history'] = true;
194  df_display($context, 'Dataface_Registration.html');
195 
196  }
197 
202  if ( !Dataface_Table::tableExists('dataface__registrations', false) ){
203  $sql = "create table `dataface__registrations` (
204  registration_code varchar(32) not null,
205  registration_date timestamp not null,
206  registration_data longtext not null,
207  primary key (registration_code))";
208  // registration_code stores an md5 code used to identify the registration
209  // registration_date is the date that the registration was made
210  // registration_data is a serialized array of the data from getValues()
211  // on the record.
212 
213 
214  $res = mysql_query($sql, df_db());
215  if ( !$res ) throw new Exception(mysql_error(df_db()), E_USER_ERROR);
216  }
217  return true;
218 
219  }
220 
227  function validateRegistrationForm($values){
228 
230  $del =& $app->getDelegate();
231  if ( $del and method_exists($del,'validateRegistrationForm') ){
232  $res = $del->validateRegistrationForm($values);
233  if ( PEAR::isError($res) ) return $res;
234  else if ( is_int($res) and $res === 2 ) return true;
235  }
236  $conf =& $app->_conf['_auth'];
237 
238  // Make sure username is supplied
239  if ( !@$values[$conf['username_column']] )
240  return PEAR::raiseError(
241  df_translate('actions.register.MESSAGE_USERNAME_REQUIRED', 'Please enter a username')
242  );
243 
244 
245  // Check for a duplicate username
246  $res = mysql_query("select count(*) from `".$conf['users_table']."` where `".$conf['username_column']."` = '".addslashes($values[$conf['username_column']])."'", df_db());
247  if ( !$res ) throw new Exception(mysql_error(df_db()), E_USER_ERROR);
248 
249  list($num) = mysql_fetch_row($res);
250  if ( $num>0 ){
251  return PEAR::raiseError(
252  df_translate('actions.register.MESSAGE_USERNAME_ALREADY_TAKEN', 'Sorry, that username is already in use by another user.')
253  );
254  }
255 
256  // Make sure that the user supplied a password
257  if ( !@$values[$conf['password_column']] )
258  return PEAR::raiseError(
259  df_translate('actions.register.MESSAGE_PASSWORD_REQUIRED', 'Please enter a password')
260  );
261 
262  // Make sure that the user supplied an email address - and that the email address is valid
263  $emailField = $this->ontology->getFieldname('email');
264  if ( !@$values[$emailField] or !$this->ontology->validate('email', @$values[$emailField], false /*No blanks*/))
265  return PEAR::raiseError(
266  df_translate('actions.register.MESSAGE_EMAIL_REQUIRED', 'Please enter a valid email address in order to register. A valid email address is required because an email will be sent to the address with information on how to activate this account.')
267  );
268 
269  return true;
270  }
271 
272 
273  function _fireDelegateMethod($name, &$record, $params=null){
275  $table = & Dataface_Table::loadTable($app->_conf['_auth']['users_table']);
276 
277  $appdel =& $app->getDelegate();
278  $tdel =& $table->getDelegate();
279 
280  if ( isset($tdel) and method_exists($tdel, $name) ){
281  $res = $tdel->$name($record, $params);
282  if ( !PEAR::isError($res) or ($res->getCode() != DATAFACE_E_REQUEST_NOT_HANDLED) ){
283  return $res;
284  }
285  }
286 
287  if ( isset($appdel) and method_exists($appdel, $name) ){
288  $res = $appdel->$name($record, $params);
289  if ( !PEAR::isError($res) or ($res->getCode() != DATAFACE_E_REQUEST_NOT_HANDLED) ){
290  return $res;
291  }
292  }
293  return PEAR::raiseError("No delegate method found named '$name'.", DATAFACE_E_REQUEST_NOT_HANDLED);
294  }
295 
296 
297 
298  function processRegistrationForm($values){
299 
301  $conf =& $app->_conf['_auth'];
302  $appConf =& $app->conf();
303  $table =& Dataface_Table::loadTable($conf['users_table']);
304 
305  if ( @$this->params['email_validation'] ){
306 
307  // Let's try to create the registration table if it doesn't already
308  // exist
309  $this->createRegistrationTable();
310 
311  // Now we will store the registration attempt
312 
313  // A unique code to be used as an id
314  $code = null;
315  do {
316  $code = md5(rand());
317  } while (
318  mysql_num_rows(
319  mysql_query(
320  "select registration_code
321  from dataface__registrations
322  where registration_code='".addslashes($code)."'",
323  df_db()
324  )
325  )
326  );
327 
328  // Now that we have a unique id, we can insert the value
329 
330  $sql = "insert into dataface__registrations
331  (registration_code, registration_data) values
332  ('".addslashes($code)."',
333  '".addslashes(
334  serialize(
335  $this->form->_record->getValues()
336  )
337  )."')";
338  $res = mysql_query($sql, df_db());
339  if ( !$res ) throw new Exception(mysql_error(df_db()), E_USER_ERROR);
340 
341  $activation_url = $_SERVER['HOST_URI'].DATAFACE_SITE_HREF.'?-action=activate&code='.urlencode($code);
342 
343  // Now that the registration information has been inserted, we need
344  // to send the confirmation email
345  // Let's try to send the email if possible.
346  $res = $this->_fireDelegateMethod('sendRegistrationActivationEmail', $this->form->_record, $activation_url );
347  if ( !PEAR::isError($res) or ( $res->getCode() != DATAFACE_E_REQUEST_NOT_HANDLED) ){
348  return $res;
349  }
350 
351  // If we got this far, that means that we haven't sent the email yet... Rather
352  // let's send it outselves.
353  // We use the Person Ontology to work with the users table record in a more
354  // generic way.
355  $registrant =& $this->ontology->newIndividual($this->form->_record);
356  // We now have the user's email address
357  $email = $registrant->strval('email');
358 
359  // Let's get the email info. This will return an associative array
360  // of the parameters involved in the registration email. The keys
361  // are:
362  // 1. subject
363  // 2. message
364  // 3. headers
365  // 4. parameters
366  // These are such that they can be passed directly to the mail function
367  $info = $this->_fireDelegateMethod('getRegistrationActivationEmailInfo', $this->form->_record, $activation_url);
368  if ( PEAR::isError($info) ) $info = array();
369  $info['to'] = $email;
370 
371  // Override specific parts of the message if delegate class wants it.
372  $subject = $this->_fireDelegateMethod('getRegistrationActivationEmailSubject', $this->form->_record, $activation_url);
373  if ( !PEAR::isError($subject) ) $info['subject'] = $subject;
374 
375 
376  $message = $this->_fireDelegateMethod('getRegistrationActivationEmailMessage', $this->form->_record, $activation_url);
377  if ( !PEAR::isError($message) ) $info['message'] = $message;
378 
379  $parameters = $this->_fireDelegateMethod('getRegistrationActivationEmailParameters', $this->form->_record, $activation_url);
380  if ( !PEAR::isError($parameters) ) $info['parameters'] = $parameters;
381 
382  $headers = $this->_fireDelegateMethod('getRegistrationActivationEmailHeaders', $this->form->_record, $activation_url);
383  if ( !PEAR::isError($headers) ) $info['headers'] = $headers;
384 
385 
386  // Now we fill in the missing information with defaults
387  if ( !@$info['subject'] )
388  $info['subject'] = df_translate(
389  'actions.register.MESSAGE_REGISTRATION_ACTIVATION_EMAIL_SUBJECT',
390  $app->getSiteTitle().': Activate your account',
391  array('site_title'=>$app->getSiteTitle())
392  );
393 
394  if ( !@$info['message'] ){
395  $site_title = $app->getSiteTitle();
396  if ( isset($appConf['abuse_email']) ){
397  $admin_email = $appConf['abuse_email'];
398  } else if ( isset($appConf['admin_email']) ){
399  $admin_email = $appConf['admin_email'];
400  } else {
401  $admin_email = $_SERVER['SERVER_ADMIN'];
402  }
403 
404  if ( isset( $appConf['application_name'] ) ){
405  $application_name = $appConf['application_name'];
406  } else {
407  $application_name = df_translate('actions.register.LABEL_A_DATAFACE_APPLICATION','a Dataface Application');
408  }
409 
410  if ( file_exists('version.txt') ){
411  $application_version = trim(file_get_contents('version.txt'));
412  } else {
413  $application_version = '0.1';
414  }
415 
416  if ( file_exists(DATAFACE_PATH.'/version.txt') ){
417  $dataface_version = trim(file_get_contents(DATAFACE_PATH.'/version.txt'));
418  } else {
419  $dataface_version = 'unknown';
420  }
421 
422 
423 
424 
425  $msg = <<<END
426 Thank you for registering for an account on $site_title . In order to complete your registration,
427 please visit $activation_url .
428 
429 If you have not registered for an account on this web site and believe that you have received
430 this email eroneously, please report this to $admin_email .
431 -----------------------------------------------------------
432 This message was sent by $site_title which is powered by $application_name version $application_version
433 $application_name built using Dataface version $dataface_version (http://fas.sfu.ca/dataface).
434 END;
435 
436  $info['message'] = df_translate(
437  'actions.register.MESSAGE_REGISTRATION_ACTIVATION_EMAIL_MESSAGE',
438  $msg,
439  array(
440  'site_title'=>$site_title,
441  'activation_url'=>$activation_url,
442  'admin_email'=>$admin_email,
443  'application_name'=>$application_name,
444  'application_version'=>$application_version,
445  'dataface_version'=>$dataface_version
446  )
447  );
448 
449 
450  }
451 
452  // Now that we have all of the information ready to send. Let's send
453  // the email message.
454 
455  if ( @$conf['_mail']['func'] ) $func = $conf['_mail']['func'];
456  else $func = 'mail';
457  $res = $func($info['to'],
458  $info['subject'],
459  $info['message'],
460  @$info['headers'],
461  @$info['parameters']);
462  if ( !$res ){
463  return PEAR::raiseError('Failed to send activation email. Please try again later.', DATAFACE_E_ERROR);
464  } else {
465  return true;
466  }
467 
468  } else {
469  // We aren't using email validation.. let's just pass it to the
470  // form's standard processing function.
471  return $this->form->process(array(&$this->form, 'save'), true);
472  }
473 
474  }
475 }
476 
478  function filterPermissions(&$obj, &$perms){
479  if ( @$perms['register'] ) $perms['new'] = 1;
480  }
481 }
482 
483 ?>