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_submit_url'))) ? $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 = $a->get_baseurl() . '/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",
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;
141 $r = q("SELECT `uid` FROM `user`
142 WHERE `nickname` = '%s' LIMIT 1",
146 $result['message'] .= t('Nickname is already registered. Please choose another.') . EOL;
148 // Check deleted accounts that had this nickname. Doesn't matter to us,
149 // but could be a security issue for federated platforms.
151 $r = q("SELECT * FROM `userd`
152 WHERE `username` = '%s' LIMIT 1",
156 $result['message'] .= t('Nickname was once registered here and may not be re-used. Please choose another.') . EOL;
158 if(strlen($result['message'])) {
162 $new_password = ((strlen($password)) ? $password : autoname(6) . mt_rand(100,9999));
163 $new_password_encoded = hash('whirlpool',$new_password);
165 $result['password'] = $new_password;
167 require_once('include/crypto.php');
169 $keys = new_keypair(4096);
171 if($keys === false) {
172 $result['message'] .= t('SERIOUS ERROR: Generation of security keys failed.') . EOL;
176 $default_service_class = get_config('system','default_service_class');
177 if(! $default_service_class)
178 $default_service_class = '';
181 $prvkey = $keys['prvkey'];
182 $pubkey = $keys['pubkey'];
186 * Create another keypair for signing/verifying
187 * salmon protocol messages. We have to use a slightly
188 * less robust key because this won't be using openssl
189 * but the phpseclib. Since it is PHP interpreted code
190 * it is not nearly as efficient, and the larger keys
191 * will take several minutes each to process.
195 $sres = new_keypair(512);
196 $sprvkey = $sres['prvkey'];
197 $spubkey = $sres['pubkey'];
199 $r = q("INSERT INTO `user` ( `guid`, `username`, `password`, `email`, `openid`, `nickname`,
200 `pubkey`, `prvkey`, `spubkey`, `sprvkey`, `register_date`, `verified`, `blocked`, `timezone`, `service_class`, `default-location` )
201 VALUES ( '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, 'UTC', '%s', '' )",
202 dbesc(generate_user_guid()),
204 dbesc($new_password_encoded),
212 dbesc(datetime_convert()),
215 dbesc($default_service_class)
219 $r = q("SELECT * FROM `user`
220 WHERE `username` = '%s' AND `password` = '%s' LIMIT 1",
222 dbesc($new_password_encoded)
224 if($r !== false && count($r)) {
226 $newuid = intval($r[0]['uid']);
230 $result['message'] .= t('An error occurred during registration. Please try again.') . EOL ;
235 * if somebody clicked submit twice very quickly, they could end up with two accounts
236 * due to race condition. Remove this one.
239 $r = q("SELECT `uid` FROM `user`
240 WHERE `nickname` = '%s' ",
243 if((count($r) > 1) && $newuid) {
244 $result['message'] .= t('Nickname is already registered. Please choose another.') . EOL;
245 q("DELETE FROM `user` WHERE `uid` = %d",
251 if(x($newuid) !== false) {
252 $r = q("INSERT INTO `profile` ( `uid`, `profile-name`, `is-default`, `name`, `photo`, `thumb`, `publish`, `net-publish` )
253 VALUES ( %d, '%s', %d, '%s', '%s', '%s', %d, %d ) ",
258 dbesc($a->get_baseurl() . "/photo/profile/{$newuid}.jpg"),
259 dbesc($a->get_baseurl() . "/photo/avatar/{$newuid}.jpg"),
265 $result['message'] .= t('An error occurred creating your default profile. Please try again.') . EOL;
266 // Start fresh next time.
267 $r = q("DELETE FROM `user` WHERE `uid` = %d",
271 $r = q("INSERT INTO `contact` ( `uid`, `created`, `self`, `name`, `nick`, `photo`, `thumb`, `micro`, `blocked`, `pending`, `url`, `nurl`,
272 `request`, `notify`, `poll`, `confirm`, `poco`, `name-date`, `uri-date`, `avatar-date`, `closeness` )
273 VALUES ( %d, '%s', 1, '%s', '%s', '%s', '%s', '%s', 0, 0, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', 0 ) ",
278 dbesc($a->get_baseurl() . "/photo/profile/{$newuid}.jpg"),
279 dbesc($a->get_baseurl() . "/photo/avatar/{$newuid}.jpg"),
280 dbesc($a->get_baseurl() . "/photo/micro/{$newuid}.jpg"),
281 dbesc($a->get_baseurl() . "/profile/$nickname"),
282 dbesc(normalise_link($a->get_baseurl() . "/profile/$nickname")),
283 dbesc($a->get_baseurl() . "/dfrn_request/$nickname"),
284 dbesc($a->get_baseurl() . "/dfrn_notify/$nickname"),
285 dbesc($a->get_baseurl() . "/dfrn_poll/$nickname"),
286 dbesc($a->get_baseurl() . "/dfrn_confirm/$nickname"),
287 dbesc($a->get_baseurl() . "/poco/$nickname"),
288 dbesc(datetime_convert()),
289 dbesc(datetime_convert()),
290 dbesc(datetime_convert())
293 // Create a group with no members. This allows somebody to use it
294 // right away as a default group for new contacts.
296 require_once('include/group.php');
297 group_add($newuid, t('Friends'));
299 $r = q("SELECT id FROM `group` WHERE uid = %d AND name = '%s'",
303 if($r && count($r)) {
304 $def_gid = $r[0]['id'];
306 q("UPDATE user SET def_gid = %d WHERE uid = %d",
312 if(get_config('system', 'newuser_private') && $def_gid) {
313 q("UPDATE user SET allow_gid = '%s' WHERE uid = %d",
314 dbesc("<" . $def_gid . ">"),
321 // if we have no OpenID photo try to look up an avatar
323 $photo = avatar_img($email);
325 // unless there is no avatar-plugin loaded
327 require_once('include/Photo.php');
328 $photo_failure = false;
330 $filename = basename($photo);
331 $img_str = fetch_url($photo,true);
332 // guess mimetype from headers or filename
333 $type = guess_image_type($photo,true);
336 $img = new Photo($img_str, $type);
337 if($img->is_valid()) {
339 $img->scaleImageSquare(175);
341 $hash = photo_new_resource();
343 $r = $img->store($newuid, 0, $hash, $filename, t('Profile Photos'), 4 );
346 $photo_failure = true;
348 $img->scaleImage(80);
350 $r = $img->store($newuid, 0, $hash, $filename, t('Profile Photos'), 5 );
353 $photo_failure = true;
355 $img->scaleImage(48);
357 $r = $img->store($newuid, 0, $hash, $filename, t('Profile Photos'), 6 );
360 $photo_failure = true;
362 if(! $photo_failure) {
363 q("UPDATE `photo` SET `profile` = 1 WHERE `resource-id` = '%s' ",
370 call_hooks('register_account', $newuid);
372 $result['success'] = true;
373 $result['user'] = $u;
380 * send registration confirmation.
381 * It's here as a function because the mail is sent
382 * from different parts
384 function send_register_open_eml($email, $sitename, $siteurl, $username, $password){
385 $preamble = deindent(t('
387 Thank you for registering at %2$s. Your account has been created.
390 The login details are as follows:
395 You may change your password from your account "Settings" page after logging
398 Please take a few moments to review the other account settings on that page.
400 You may also wish to add some basic information to your default profile
401 (on the "Profiles" page) so that other people can easily find you.
403 We recommend setting your full name, adding a profile photo,
404 adding some profile "keywords" (very useful in making new friends) - and
405 perhaps what country you live in; if you do not wish to be more specific
408 We fully respect your right to privacy, and none of these items are necessary.
409 If you are new and do not know anybody here, they may help
410 you to make some new and interesting friends.
413 Thank you and welcome to %2$s.'));
415 $preamble = sprintf($preamble, $username, $sitename);
416 $body = sprintf($body, $email, $sitename, $siteurl, $username, $password);
418 return notification(array(
419 'type' => "SYSTEM_EMAIL",
420 'to_email' => $email,
421 'subject'=> sprintf( t('Registration details for %s'), $sitename),
422 'preamble'=> $preamble,