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 $blocked = ((x($arr,'blocked')) ? intval($arr['blocked']) : 0);
31 $verified = ((x($arr,'verified')) ? intval($arr['verified']) : 0);
33 $publish = ((x($arr,'profile_publish_reg') && intval($arr['profile_publish_reg'])) ? 1 : 0);
34 $netpublish = ((strlen(get_config('system','directory_submit_url'))) ? $publish : 0);
36 $tmp_str = $openid_url;
40 $result['message'] .= t('An invitation is required.') . EOL;
43 $r = q("select * from register where `hash` = '%s' limit 1", dbesc($invite_id));
45 $result['message'] .= t('Invitation could not be verified.') . EOL;
50 if((! x($username)) || (! x($email)) || (! x($nickname))) {
52 if(! validate_url($tmp_str)) {
53 $result['message'] .= t('Invalid OpenID url') . EOL;
56 $_SESSION['register'] = 1;
57 $_SESSION['openid'] = $openid_url;
58 require_once('library/openid.php');
59 $openid = new LightOpenID;
60 $openid->identity = $openid_url;
61 $openid->returnUrl = $a->get_baseurl() . '/openid';
62 $openid->required = array('namePerson/friendly', 'contact/email', 'namePerson');
63 $openid->optional = array('namePerson/first','media/image/aspect11','media/image/default');
65 $authurl = $openid->authUrl();
66 } catch (Exception $e){
67 $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;
74 notice( t('Please enter the required information.') . EOL );
78 if(! validate_url($tmp_str))
84 // collapse multiple spaces in name
85 $username = preg_replace('/ +/',' ',$username);
87 if(mb_strlen($username) > 48)
88 $result['message'] .= t('Please use a shorter name.') . EOL;
89 if(mb_strlen($username) < 3)
90 $result['message'] .= t('Name too short.') . EOL;
92 // I don't really like having this rule, but it cuts down
93 // on the number of auto-registrations by Russian spammers
95 // Using preg_match was completely unreliable, due to mixed UTF-8 regex support
96 // $no_utf = get_config('system','no_utf');
97 // $pat = (($no_utf) ? '/^[a-zA-Z]* [a-zA-Z]*$/' : '/^\p{L}* \p{L}*$/u' );
99 // So now we are just looking for a space in the full name.
101 $loose_reg = get_config('system','no_regfullname');
103 $username = mb_convert_case($username,MB_CASE_TITLE,'UTF-8');
104 if(! strpos($username,' '))
105 $result['message'] .= t("That doesn't appear to be your full \x28First Last\x29 name.") . EOL;
109 if(! allowed_email($email))
110 $result['message'] .= t('Your email domain is not among those allowed on this site.') . EOL;
112 if((! valid_email($email)) || (! validate_email($email)))
113 $result['message'] .= t('Not a valid email address.') . EOL;
115 // Disallow somebody creating an account using openid that uses the admin email address,
116 // since openid bypasses email verification. We'll allow it if there is not yet an admin account.
118 $adminlist = explode(",", str_replace(" ", "", strtolower($a->config['admin_email'])));
120 //if((x($a->config,'admin_email')) && (strcasecmp($email,$a->config['admin_email']) == 0) && strlen($openid_url)) {
121 if((x($a->config,'admin_email')) && in_array(strtolower($email), $adminlist) && strlen($openid_url)) {
122 $r = q("SELECT * FROM `user` WHERE `email` = '%s' LIMIT 1",
126 $result['message'] .= t('Cannot use that email.') . EOL;
129 $nickname = $arr['nickname'] = strtolower($nickname);
131 if(! preg_match("/^[a-z][a-z0-9\-\_]*$/",$nickname))
132 $result['message'] .= t('Your "nickname" can only contain "a-z", "0-9", "-", and "_", and must also begin with a letter.') . EOL;
133 $r = q("SELECT `uid` FROM `user`
134 WHERE `nickname` = '%s' LIMIT 1",
138 $result['message'] .= t('Nickname is already registered. Please choose another.') . EOL;
140 // Check deleted accounts that had this nickname. Doesn't matter to us,
141 // but could be a security issue for federated platforms.
143 $r = q("SELECT * FROM `userd`
144 WHERE `username` = '%s' LIMIT 1",
148 $result['message'] .= t('Nickname was once registered here and may not be re-used. Please choose another.') . EOL;
150 if(strlen($result['message'])) {
154 $new_password = ((strlen($password)) ? $password : autoname(6) . mt_rand(100,9999));
155 $new_password_encoded = hash('whirlpool',$new_password);
157 $result['password'] = $new_password;
159 require_once('include/crypto.php');
161 $keys = new_keypair(4096);
163 if($keys === false) {
164 $result['message'] .= t('SERIOUS ERROR: Generation of security keys failed.') . EOL;
168 $default_service_class = get_config('system','default_service_class');
169 if(! $default_service_class)
170 $default_service_class = '';
173 $prvkey = $keys['prvkey'];
174 $pubkey = $keys['pubkey'];
178 * Create another keypair for signing/verifying
179 * salmon protocol messages. We have to use a slightly
180 * less robust key because this won't be using openssl
181 * but the phpseclib. Since it is PHP interpreted code
182 * it is not nearly as efficient, and the larger keys
183 * will take several minutes each to process.
187 $sres = new_keypair(512);
188 $sprvkey = $sres['prvkey'];
189 $spubkey = $sres['pubkey'];
191 $r = q("INSERT INTO `user` ( `guid`, `username`, `password`, `email`, `openid`, `nickname`,
192 `pubkey`, `prvkey`, `spubkey`, `sprvkey`, `register_date`, `verified`, `blocked`, `timezone`, `service_class`, `default-location` )
193 VALUES ( '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, 'UTC', '%s', '' )",
194 dbesc(generate_user_guid()),
196 dbesc($new_password_encoded),
204 dbesc(datetime_convert()),
207 dbesc($default_service_class)
211 $r = q("SELECT * FROM `user`
212 WHERE `username` = '%s' AND `password` = '%s' LIMIT 1",
214 dbesc($new_password_encoded)
216 if($r !== false && count($r)) {
218 $newuid = intval($r[0]['uid']);
222 $result['message'] .= t('An error occurred during registration. Please try again.') . EOL ;
227 * if somebody clicked submit twice very quickly, they could end up with two accounts
228 * due to race condition. Remove this one.
231 $r = q("SELECT `uid` FROM `user`
232 WHERE `nickname` = '%s' ",
235 if((count($r) > 1) && $newuid) {
236 $result['message'] .= t('Nickname is already registered. Please choose another.') . EOL;
237 q("DELETE FROM `user` WHERE `uid` = %d",
243 if(x($newuid) !== false) {
244 $r = q("INSERT INTO `profile` ( `uid`, `profile-name`, `is-default`, `name`, `photo`, `thumb`, `publish`, `net-publish` )
245 VALUES ( %d, '%s', %d, '%s', '%s', '%s', %d, %d ) ",
250 dbesc($a->get_baseurl() . "/photo/profile/{$newuid}.jpg"),
251 dbesc($a->get_baseurl() . "/photo/avatar/{$newuid}.jpg"),
257 $result['message'] .= t('An error occurred creating your default profile. Please try again.') . EOL;
258 // Start fresh next time.
259 $r = q("DELETE FROM `user` WHERE `uid` = %d",
263 $r = q("INSERT INTO `contact` ( `uid`, `created`, `self`, `name`, `nick`, `photo`, `thumb`, `micro`, `blocked`, `pending`, `url`, `nurl`,
264 `request`, `notify`, `poll`, `confirm`, `poco`, `name-date`, `uri-date`, `avatar-date`, `closeness` )
265 VALUES ( %d, '%s', 1, '%s', '%s', '%s', '%s', '%s', 0, 0, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', 0 ) ",
270 dbesc($a->get_baseurl() . "/photo/profile/{$newuid}.jpg"),
271 dbesc($a->get_baseurl() . "/photo/avatar/{$newuid}.jpg"),
272 dbesc($a->get_baseurl() . "/photo/micro/{$newuid}.jpg"),
273 dbesc($a->get_baseurl() . "/profile/$nickname"),
274 dbesc(normalise_link($a->get_baseurl() . "/profile/$nickname")),
275 dbesc($a->get_baseurl() . "/dfrn_request/$nickname"),
276 dbesc($a->get_baseurl() . "/dfrn_notify/$nickname"),
277 dbesc($a->get_baseurl() . "/dfrn_poll/$nickname"),
278 dbesc($a->get_baseurl() . "/dfrn_confirm/$nickname"),
279 dbesc($a->get_baseurl() . "/poco/$nickname"),
280 dbesc(datetime_convert()),
281 dbesc(datetime_convert()),
282 dbesc(datetime_convert())
285 // Create a group with no members. This allows somebody to use it
286 // right away as a default group for new contacts.
288 require_once('include/group.php');
289 group_add($newuid, t('Friends'));
291 $r = q("SELECT id FROM `group` WHERE uid = %d AND name = '%s'",
295 if($r && count($r)) {
296 $def_gid = $r[0]['id'];
298 q("UPDATE user SET def_gid = %d WHERE uid = %d",
304 if(get_config('system', 'newuser_private') && $def_gid) {
305 q("UPDATE user SET allow_gid = '%s' WHERE uid = %d",
306 dbesc("<" . $def_gid . ">"),
313 // if we have no OpenID photo try to look up an avatar
315 $photo = avatar_img($email);
317 // unless there is no avatar-plugin loaded
319 require_once('include/Photo.php');
320 $photo_failure = false;
322 $filename = basename($photo);
323 $img_str = fetch_url($photo,true);
324 // guess mimetype from headers or filename
325 $type = guess_image_type($photo,true);
328 $img = new Photo($img_str, $type);
329 if($img->is_valid()) {
331 $img->scaleImageSquare(175);
333 $hash = photo_new_resource();
335 $r = $img->store($newuid, 0, $hash, $filename, t('Profile Photos'), 4 );
338 $photo_failure = true;
340 $img->scaleImage(80);
342 $r = $img->store($newuid, 0, $hash, $filename, t('Profile Photos'), 5 );
345 $photo_failure = true;
347 $img->scaleImage(48);
349 $r = $img->store($newuid, 0, $hash, $filename, t('Profile Photos'), 6 );
352 $photo_failure = true;
354 if(! $photo_failure) {
355 q("UPDATE `photo` SET `profile` = 1 WHERE `resource-id` = '%s' ",
362 call_hooks('register_account', $newuid);
364 $result['success'] = true;
365 $result['user'] = $u;
372 * send registration confirmation.
373 * It's here as a function because the mail is sent
374 * from different parts
376 function send_register_open_eml($email, $sitename, $siteurl, $username, $password){
377 $preamble = deindent(t('
379 Thank you for registering at %2$s. Your account has been created.
382 The login details are as follows:
387 You may change your password from your account "Settings" page after logging
390 Please take a few moments to review the other account settings on that page.
392 You may also wish to add some basic information to your default profile
393 (on the "Profiles" page) so that other people can easily find you.
395 We recommend setting your full name, adding a profile photo,
396 adding some profile "keywords" (very useful in making new friends) - and
397 perhaps what country you live in; if you do not wish to be more specific
400 We fully respect your right to privacy, and none of these items are necessary.
401 If you are new and do not know anybody here, they may help
402 you to make some new and interesting friends.
405 Thank you and welcome to %2$s.'));
407 $preamble = sprintf($preamble, $username, $sitename);
408 $body = sprintf($body, $email, $sitename, $siteurl, $username, $password);
410 return notification(array(
411 'type' => "SYSTEM_EMAIL",
412 'to_email' => $email,
413 'subject'=> sprintf( t('Registration details for %s'), $sitename),
414 'preamble'=> $preamble,