3 require_once('include/config.php');
4 require_once('include/network.php');
5 require_once('include/plugin.php');
6 require_once('include/text.php');
7 require_once('include/pgettext.php');
8 require_once('include/datetime.php');
9 require_once('include/enotify.php');
12 function create_user($arr) {
14 // Required: { username, nickname, email } or { openid_url }
17 $result = array('success' => false, 'user' => null, 'password' => '', 'message' => '');
19 $using_invites = get_config('system','invitation_only');
20 $num_invites = get_config('system','number_invites');
23 $invite_id = ((x($arr,'invite_id')) ? notags(trim($arr['invite_id'])) : '');
24 $username = ((x($arr,'username')) ? notags(trim($arr['username'])) : '');
25 $nickname = ((x($arr,'nickname')) ? notags(trim($arr['nickname'])) : '');
26 $email = ((x($arr,'email')) ? notags(trim($arr['email'])) : '');
27 $openid_url = ((x($arr,'openid_url')) ? notags(trim($arr['openid_url'])) : '');
28 $photo = ((x($arr,'photo')) ? notags(trim($arr['photo'])) : '');
29 $password = ((x($arr,'password')) ? trim($arr['password']) : '');
30 $password1 = ((x($arr,'password1')) ? trim($arr['password1']) : '');
31 $confirm = ((x($arr,'confirm')) ? trim($arr['confirm']) : '');
32 $blocked = ((x($arr,'blocked')) ? intval($arr['blocked']) : 0);
33 $verified = ((x($arr,'verified')) ? intval($arr['verified']) : 0);
35 $publish = ((x($arr,'profile_publish_reg') && intval($arr['profile_publish_reg'])) ? 1 : 0);
36 $netpublish = ((strlen(get_config('system','directory'))) ? $publish : 0);
38 if ($password1 != $confirm) {
39 $result['message'] .= t('Passwords do not match. Password unchanged.') . EOL;
41 } elseif ($password1 != "")
42 $password = $password1;
44 $tmp_str = $openid_url;
48 $result['message'] .= t('An invitation is required.') . EOL;
51 $r = q("SELECT * FROM `register` WHERE `hash` = '%s' LIMIT 1", dbesc($invite_id));
53 $result['message'] .= t('Invitation could not be verified.') . EOL;
58 if((! x($username)) || (! x($email)) || (! x($nickname))) {
60 if(! validate_url($tmp_str)) {
61 $result['message'] .= t('Invalid OpenID url') . EOL;
64 $_SESSION['register'] = 1;
65 $_SESSION['openid'] = $openid_url;
66 require_once('library/openid.php');
67 $openid = new LightOpenID;
68 $openid->identity = $openid_url;
69 $openid->returnUrl = z_root() . '/openid';
70 $openid->required = array('namePerson/friendly', 'contact/email', 'namePerson');
71 $openid->optional = array('namePerson/first','media/image/aspect11','media/image/default');
73 $authurl = $openid->authUrl();
74 } catch (Exception $e){
75 $result['message'] .= t("We encountered a problem while logging in with the OpenID you provided. Please check the correct spelling of the ID."). EOL . EOL . t("The error message was:") . $e->getMessage() . EOL;
82 notice( t('Please enter the required information.') . EOL );
86 if(! validate_url($tmp_str))
92 // collapse multiple spaces in name
93 $username = preg_replace('/ +/',' ',$username);
95 if(mb_strlen($username) > 48)
96 $result['message'] .= t('Please use a shorter name.') . EOL;
97 if(mb_strlen($username) < 3)
98 $result['message'] .= t('Name too short.') . EOL;
100 // I don't really like having this rule, but it cuts down
101 // on the number of auto-registrations by Russian spammers
103 // Using preg_match was completely unreliable, due to mixed UTF-8 regex support
104 // $no_utf = get_config('system','no_utf');
105 // $pat = (($no_utf) ? '/^[a-zA-Z]* [a-zA-Z]*$/' : '/^\p{L}* \p{L}*$/u' );
107 // So now we are just looking for a space in the full name.
109 $loose_reg = get_config('system','no_regfullname');
111 $username = mb_convert_case($username,MB_CASE_TITLE,'UTF-8');
112 if(! strpos($username,' '))
113 $result['message'] .= t("That doesn't appear to be your full \x28First Last\x29 name.") . EOL;
117 if(! allowed_email($email))
118 $result['message'] .= t('Your email domain is not among those allowed on this site.') . EOL;
120 if((! valid_email($email)) || (! validate_email($email)))
121 $result['message'] .= t('Not a valid email address.') . EOL;
123 // Disallow somebody creating an account using openid that uses the admin email address,
124 // since openid bypasses email verification. We'll allow it if there is not yet an admin account.
126 $adminlist = explode(",", str_replace(" ", "", strtolower($a->config['admin_email'])));
128 //if((x($a->config,'admin_email')) && (strcasecmp($email,$a->config['admin_email']) == 0) && strlen($openid_url)) {
129 if((x($a->config,'admin_email')) && in_array(strtolower($email), $adminlist) && strlen($openid_url)) {
130 $r = q("SELECT * FROM `user` WHERE `email` = '%s' LIMIT 1",
133 if (dbm::is_result($r))
134 $result['message'] .= t('Cannot use that email.') . EOL;
137 $nickname = $arr['nickname'] = strtolower($nickname);
139 if(! preg_match("/^[a-z0-9][a-z0-9\_]*$/",$nickname))
140 $result['message'] .= t('Your "nickname" can only contain "a-z", "0-9" and "_".') . EOL;
142 $r = q("SELECT `uid` FROM `user`
143 WHERE `nickname` = '%s' LIMIT 1",
146 if (dbm::is_result($r))
147 $result['message'] .= t('Nickname is already registered. Please choose another.') . EOL;
149 // Check deleted accounts that had this nickname. Doesn't matter to us,
150 // but could be a security issue for federated platforms.
152 $r = q("SELECT * FROM `userd`
153 WHERE `username` = '%s' LIMIT 1",
156 if (dbm::is_result($r))
157 $result['message'] .= t('Nickname was once registered here and may not be re-used. Please choose another.') . EOL;
159 if(strlen($result['message'])) {
163 $new_password = ((strlen($password)) ? $password : autoname(6) . mt_rand(100,9999));
164 $new_password_encoded = hash('whirlpool',$new_password);
166 $result['password'] = $new_password;
168 require_once('include/crypto.php');
170 $keys = new_keypair(4096);
172 if($keys === false) {
173 $result['message'] .= t('SERIOUS ERROR: Generation of security keys failed.') . EOL;
177 $default_service_class = get_config('system','default_service_class');
178 if(! $default_service_class)
179 $default_service_class = '';
182 $prvkey = $keys['prvkey'];
183 $pubkey = $keys['pubkey'];
187 * Create another keypair for signing/verifying
188 * salmon protocol messages. We have to use a slightly
189 * less robust key because this won't be using openssl
190 * but the phpseclib. Since it is PHP interpreted code
191 * it is not nearly as efficient, and the larger keys
192 * will take several minutes each to process.
196 $sres = new_keypair(512);
197 $sprvkey = $sres['prvkey'];
198 $spubkey = $sres['pubkey'];
200 $r = q("INSERT INTO `user` ( `guid`, `username`, `password`, `email`, `openid`, `nickname`,
201 `pubkey`, `prvkey`, `spubkey`, `sprvkey`, `register_date`, `verified`, `blocked`, `timezone`, `service_class`, `default-location` )
202 VALUES ( '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, 'UTC', '%s', '' )",
203 dbesc(generate_user_guid()),
205 dbesc($new_password_encoded),
213 dbesc(datetime_convert()),
216 dbesc($default_service_class)
220 $r = q("SELECT * FROM `user`
221 WHERE `username` = '%s' AND `password` = '%s' LIMIT 1",
223 dbesc($new_password_encoded)
225 if (dbm::is_result($r)) {
227 $newuid = intval($r[0]['uid']);
231 $result['message'] .= t('An error occurred during registration. Please try again.') . EOL ;
236 * if somebody clicked submit twice very quickly, they could end up with two accounts
237 * due to race condition. Remove this one.
240 $r = q("SELECT `uid` FROM `user`
241 WHERE `nickname` = '%s' ",
244 if ((dbm::is_result($r)) && (count($r) > 1) && $newuid) {
245 $result['message'] .= t('Nickname is already registered. Please choose another.') . EOL;
246 q("DELETE FROM `user` WHERE `uid` = %d",
252 if(x($newuid) !== false) {
253 $r = q("INSERT INTO `profile` ( `uid`, `profile-name`, `is-default`, `name`, `photo`, `thumb`, `publish`, `net-publish` )
254 VALUES ( %d, '%s', %d, '%s', '%s', '%s', %d, %d ) ",
259 dbesc(z_root() . "/photo/profile/{$newuid}.jpg"),
260 dbesc(z_root() . "/photo/avatar/{$newuid}.jpg"),
266 $result['message'] .= t('An error occurred creating your default profile. Please try again.') . EOL;
267 // Start fresh next time.
268 $r = q("DELETE FROM `user` WHERE `uid` = %d",
273 // Create the self contact
274 user_create_self_contact($newuid);
276 // Create a group with no members. This allows somebody to use it
277 // right away as a default group for new contacts.
279 require_once('include/group.php');
280 group_add($newuid, t('Friends'));
282 $r = q("SELECT `id` FROM `group` WHERE `uid` = %d AND `name` = '%s'",
286 if (dbm::is_result($r)) {
287 $def_gid = $r[0]['id'];
289 q("UPDATE `user` SET `def_gid` = %d WHERE `uid` = %d",
295 if(get_config('system', 'newuser_private') && $def_gid) {
296 q("UPDATE `user` SET `allow_gid` = '%s' WHERE `uid` = %d",
297 dbesc("<" . $def_gid . ">"),
304 // if we have no OpenID photo try to look up an avatar
306 $photo = avatar_img($email);
308 // unless there is no avatar-plugin loaded
310 require_once('include/Photo.php');
311 $photo_failure = false;
313 $filename = basename($photo);
314 $img_str = fetch_url($photo,true);
315 // guess mimetype from headers or filename
316 $type = guess_image_type($photo,true);
319 $img = new Photo($img_str, $type);
320 if($img->is_valid()) {
322 $img->scaleImageSquare(175);
324 $hash = photo_new_resource();
326 $r = $img->store($newuid, 0, $hash, $filename, t('Profile Photos'), 4 );
329 $photo_failure = true;
332 $img->scaleImage(80);
334 $r = $img->store($newuid, 0, $hash, $filename, t('Profile Photos'), 5 );
337 $photo_failure = true;
340 $img->scaleImage(48);
342 $r = $img->store($newuid, 0, $hash, $filename, t('Profile Photos'), 6 );
345 $photo_failure = true;
348 if (! $photo_failure) {
349 q("UPDATE `photo` SET `profile` = 1 WHERE `resource-id` = '%s' ",
356 call_hooks('register_account', $newuid);
358 $result['success'] = true;
359 $result['user'] = $u;
365 * @brief create the "self" contact from data from the user table
367 * @param integer $uid
369 function user_create_self_contact($uid) {
371 // Only create the entry if it doesn't exist yet
372 $r = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `self`", intval($uid));
373 if (dbm::is_result($r)) {
377 $r = q("SELECT `uid`, `username`, `nickname` FROM `user` WHERE `uid` = %d", intval($uid));
378 if (!dbm::is_result($r)) {
384 q("INSERT INTO `contact` (`uid`, `created`, `self`, `name`, `nick`, `photo`, `thumb`, `micro`, `blocked`, `pending`, `url`, `nurl`,
385 `addr`, `request`, `notify`, `poll`, `confirm`, `poco`, `name-date`, `uri-date`, `avatar-date`, `closeness`)
386 VALUES (%d, '%s', 1, '%s', '%s', '%s', '%s', '%s', 0, 0, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', 0)",
387 intval($user['uid']),
389 dbesc($user['username']),
390 dbesc($user['nickname']),
391 dbesc(z_root()."/photo/profile/".$user['uid'].".jpg"),
392 dbesc(z_root()."/photo/avatar/".$user['uid'].".jpg"),
393 dbesc(z_root()."/photo/micro/".$user['uid'].".jpg"),
394 dbesc(z_root()."/profile/".$user['nickname']),
395 dbesc(normalise_link(z_root()."/profile/".$user['nickname'])),
396 dbesc($user['nickname'].'@'.substr(z_root(), strpos(z_root(),'://') + 3)),
397 dbesc(z_root()."/dfrn_request/".$user['nickname']),
398 dbesc(z_root()."/dfrn_notify/".$user['nickname']),
399 dbesc(z_root()."/dfrn_poll/".$user['nickname']),
400 dbesc(z_root()."/dfrn_confirm/".$user['nickname']),
401 dbesc(z_root()."/poco/".$user['nickname']),
402 dbesc(datetime_convert()),
403 dbesc(datetime_convert()),
404 dbesc(datetime_convert())
409 * @brief send registration confiĆmation with the intormation that reg is pending
411 * @param string $email
412 * @param string $sitename
413 * @param string $username
414 * @return NULL|boolean from notification() and email() inherited
416 function send_register_pending_eml($email, $sitename, $username) {
419 Thank you for registering at %2$s. Your account is pending for approval by the administrator.
422 $body = sprintf($body, $username, $sitename);
424 return notification(array(
425 'type' => "SYSTEM_EMAIL",
426 'to_email' => $email,
427 'subject'=> sprintf( t('Registration at %s'), $sitename),
432 * send registration confirmation.
433 * It's here as a function because the mail is sent
434 * from different parts
436 function send_register_open_eml($email, $sitename, $siteurl, $username, $password){
437 $preamble = deindent(t('
439 Thank you for registering at %2$s. Your account has been created.
442 The login details are as follows:
447 You may change your password from your account "Settings" page after logging
450 Please take a few moments to review the other account settings on that page.
452 You may also wish to add some basic information to your default profile
453 (on the "Profiles" page) so that other people can easily find you.
455 We recommend setting your full name, adding a profile photo,
456 adding some profile "keywords" (very useful in making new friends) - and
457 perhaps what country you live in; if you do not wish to be more specific
460 We fully respect your right to privacy, and none of these items are necessary.
461 If you are new and do not know anybody here, they may help
462 you to make some new and interesting friends.
465 Thank you and welcome to %2$s.'));
467 $preamble = sprintf($preamble, $username, $sitename);
468 $body = sprintf($body, $email, $sitename, $siteurl, $username, $password);
470 return notification(array(
471 'type' => "SYSTEM_EMAIL",
472 'to_email' => $email,
473 'subject'=> sprintf( t('Registration details for %s'), $sitename),
474 'preamble'=> $preamble,