/mvc/components/account
[return to app]1
<?php
2 /**
3 * Account-related functionality
4 */
5 class accountComponent {
6 /**
7 * Keys to set/unset when logging in/out
8 *
9 * @var array
10 */
11 protected $_sessionKeys = array('_id', 'name');
12
13 /**
14 * Sets the session keys upon login
15 *
16 * @param array $row This should contain at least the keys defined in $this->_sessionKeys
17 */
18 protected function _setLoginSession(array $row) {
19 foreach ($this->_sessionKeys as $key) {
20 $_SESSION[$key] = $row[$key];
21 }
22 }
23
24 /**
25 * Attempt to log a user in
26 *
27 * @param string $email
28 * @param string $pass
29 * @return mixed
30 */
31 public function login($email, $pass) {
32 $row = get::model('account')->validateLogin(trim($email), trim($pass));
33 if ($row) {
34 $this->_setLoginSession($row);
35 if (!isset($row['initiallogin']) || !$row['initiallogin']) {
36 get::model('account')->setInitialLogin($row['_id']);
37 }
38 }
39 return $row;
40 }
41
42 /**
43 * Listens for login submission and handles it if found
44 *
45 * @param string $location Optional, if omitted user will return to the same page upon successful login
46 * @return array
47 */
48 public function checkLogin($location = null) {
49 if (isset($_POST['login_email']) && isset($_POST['login_pass'])){ //login
50 if (isset($_POST['action']) && $_POST['action'] == 'forgotPassword') {
51 $this->forgotPassword();
52 } else if (!$this->login($_POST['login_email'], $_POST['login_pass'])) {
53 $_POST['errors']['login_email'] = 'Incorrect email or password';
54 } else {
55 $redirect = true;
56 }
57 } else if (isset($_POST['logout'])) { //logout
58 $this->logout();
59 $redirect = true;
60 } else if (isset($_POST['signup_name'])) { //signup
61 if (!$this->validateRequired('simple')) {
62 $id = $this->addUser($_POST['signup_email'], array('name' => $_POST['signup_name']));
63 return array('signedup' => true);
64 }
65 } else if (isset($_GET['forgotPassword'])) { //forgotPassword
66 return $this->forgotPassword();
67 }
68 if (isset($redirect)) {
69 load::redirect(!$location ? get::url() : $location); //dump the post data
70 }
71 }
72
73 /**
74 * Log out a user
75 */
76 public function logout() {
77 foreach ($this->_sessionKeys as $key) {
78 unset($_SESSION[$key]);
79 }
80 }
81
82 /**
83 * Send password reminder
84 *
85 * @return array
86 */
87 public function forgotPassword() {
88 if (isset($_POST['login_email']) && $_POST['login_email']) {
89 $_POST = array_map('trim', $_POST);
90 if (filter_var($_POST['login_email'], FILTER_VALIDATE_EMAIL)) {
91 $pass = get::model('account')->retrievePass($_POST['login_email']);
92 if ($pass) {
93 $body = get::element('emails/retrievePass', array('email' => $_POST['login_email'],
94 'pass' => $pass));
95 $args = array('from' => 'no-reply@' . get::$config->SITE_DOMAIN,
96 'fromName' => get::$config->SITE_NAME, 'body' => $body,
97 'to' => $_POST['login_email'], 'html' => true,
98 'subject' => get::$config->SITE_NAME . ' account password');
99 get::component('email')->sendEmail($args);
100 } //no-else, no need to provide confirmation to invalid users
101 $alert = 'Your password has been emailed to you';
102 } else {
103 $alert = 'Email does not appear to be typed correctly';
104 }
105 } else {
106 $alert = 'Email is required to retrieve your password';
107 }
108 $_POST['errors']['login'] = $alert;
109 }
110
111 /**
112 * Verify typical required user data has been entered and is valid
113 *
114 * Required fields are fullname, email, address1, city, tel, country
115 * and if country is US then state and zip are also required
116 *
117 * @param string $type "simple" (name+email only) or "full" validation of fields
118 * @return array Array of errors returned; an empty array indicates no errors
119 */
120 public function validateRequired($type) {
121 $_POST = array_map('trim', $_POST);
122 if (!filter_var($_POST['signup_email'], FILTER_VALIDATE_EMAIL)) {
123 $error['signup_email'] = 'Email does not appear to be valid';
124 } else if (get::model('account')->accountExists($_POST['signup_email'])) {
125 $error['signup_email'] = 'There already is an account with that email';
126 }
127 if ($type == 'simple') {
128 if (strlen($_POST['signup_name']) < 3) {
129 $error['signup_name'] = 'Name is required';
130 }
131 } else {
132 $passLen = strlen($_POST['pass']);
133 if ($passLen < 4) {
134 $error['pass'] = 'Password is too short';
135 } else if ($passLen > 16) {
136 $error['pass'] = 'Password is too long';
137 } else if ($_POST['pass'] != $_POST['passconfirm']) {
138 $error['pass'] = 'Password and confirmation do not match, please retype both fields';
139 }
140 $requiredFields = array('signup_name' => 'Name', 'address1' => 'Address', 'city' => 'City');
141 foreach ($requiredFields as $key => $label) {
142 if (strlen($_POST[$key]) < 3) {
143 $error[$key] = $label . ' is required';
144 }
145 }
146 if (strlen(preg_replace('/\D/', '', $_POST['tel'])) < 6) {
147 $error['tel'] = 'Telephone is required';
148 }
149 if ($_POST['country'] == 'US') {
150 if (!$_POST['state']) {
151 $error['state'] = 'State is required for those in the USA';
152 }
153 $_POST['zip'] = preg_replace('/\D/', '', $_POST['zip']);
154 $zipLen = strlen($_POST['zip']);
155 if ($zipLen != 5 && $zipLen != 9) {
156 $error['zip'] = 'Zip code is required for those in the USA';
157 } else if ($zipLen == 9) {
158 $_POST['zip'] = substr($_POST['zip'], 0, 5) . '-' . substr($_POST['zip'], 5);
159 }
160 }
161 }
162 if (isset($error)) {
163 return $_POST['errors'] = $error;
164 }
165 return array();
166 }
167
168 public function generatePassword() {
169 //only letters and numbers that are easy to visually differentiate
170 $chars = array('b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'm', 'n',
171 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'y', 'z');
172 $alphanums = array_merge($chars, range(2, 9));
173 $charset = array_rand($alphanums, rand(5, 8));
174 shuffle($charset);
175 foreach ($charset as $char) {
176 $pass[] = $alphanums[$char];
177 }
178 return implode($pass);
179 }
180
181 public function addUser($email, array $cols = array()) {
182 $cols['signupTs'] = time();
183 $cols['signupDate'] = date('c');
184 $pass = $this->generatePassword();
185 $body = get::element('emails/newAccount', compact('email', 'pass'));
186 $args = array('from' => 'no-reply@' . get::$config->SITE_DOMAIN,
187 'body' => $body,
188 'to' => $email,
189 'html' => true,
190 'subject' => 'Welcome to ' . get::$config->SITE_NAME);
191 get::component('email')->sendEmail($args);
192 return get::model('account')->addUser($email, $pass, $cols);
193 }
194 }