]> git.mxchange.org Git - friendica.git/blob - include/user.php
Merge remote-tracking branch 'upstream/develop' into more-temp-stuff
[friendica.git] / include / user.php
1 <?php
2
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');
10
11
12 function create_user($arr) {
13
14         // Required: { username, nickname, email } or { openid_url }
15
16         $a = get_app();
17         $result = array('success' => false, 'user' => null, 'password' => '', 'message' => '');
18
19         $using_invites = get_config('system','invitation_only');
20         $num_invites   = get_config('system','number_invites');
21
22
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);
34
35         $publish    = ((x($arr,'profile_publish_reg') && intval($arr['profile_publish_reg'])) ? 1 : 0);
36         $netpublish = ((strlen(get_config('system','directory'))) ? $publish : 0);
37
38         if ($password1 != $confirm) {
39                 $result['message'] .= t('Passwords do not match. Password unchanged.') . EOL;
40                 return $result;
41         } elseif ($password1 != "")
42                 $password = $password1;
43
44         $tmp_str = $openid_url;
45
46         if($using_invites) {
47                 if(! $invite_id) {
48                         $result['message'] .= t('An invitation is required.') . EOL;
49                         return $result;
50                 }
51                 $r = q("SELECT * FROM `register` WHERE `hash` = '%s' LIMIT 1", dbesc($invite_id));
52                 if(! results($r)) {
53                         $result['message'] .= t('Invitation could not be verified.') . EOL;
54                         return $result;
55                 }
56         }
57
58         if((! x($username)) || (! x($email)) || (! x($nickname))) {
59                 if($openid_url) {
60                         if(! validate_url($tmp_str)) {
61                                 $result['message'] .= t('Invalid OpenID url') . EOL;
62                                 return $result;
63                         }
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');
72                         try {
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;
76                                 return $result;
77                         }
78                         goaway($authurl);
79                         // NOTREACHED
80                 }
81
82                 notice( t('Please enter the required information.') . EOL );
83                 return;
84         }
85
86         if(! validate_url($tmp_str))
87                 $openid_url = '';
88
89
90         $err = '';
91
92         // collapse multiple spaces in name
93         $username = preg_replace('/ +/',' ',$username);
94
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;
99
100         // I don't really like having this rule, but it cuts down
101         // on the number of auto-registrations by Russian spammers
102
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' );
106
107         // So now we are just looking for a space in the full name.
108
109         $loose_reg = get_config('system','no_regfullname');
110         if(! $loose_reg) {
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;
114         }
115
116
117         if(! allowed_email($email))
118                 $result['message'] .= t('Your email domain is not among those allowed on this site.') . EOL;
119
120         if((! valid_email($email)) || (! validate_email($email)))
121                 $result['message'] .= t('Not a valid email address.') . EOL;
122
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.
125
126         $adminlist = explode(",", str_replace(" ", "", strtolower($a->config['admin_email'])));
127
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",
131                         dbesc($email)
132                 );
133                 if (dbm::is_result($r))
134                         $result['message'] .= t('Cannot use that email.') . EOL;
135         }
136
137         $nickname = $arr['nickname'] = strtolower($nickname);
138
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
142         $r = q("SELECT `uid` FROM `user`
143                 WHERE `nickname` = '%s' LIMIT 1",
144                 dbesc($nickname)
145         );
146         if (dbm::is_result($r))
147                 $result['message'] .= t('Nickname is already registered. Please choose another.') . EOL;
148
149         // Check deleted accounts that had this nickname. Doesn't matter to us,
150         // but could be a security issue for federated platforms.
151
152         $r = q("SELECT * FROM `userd`
153                 WHERE `username` = '%s' LIMIT 1",
154                 dbesc($nickname)
155         );
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;
158
159         if(strlen($result['message'])) {
160                 return $result;
161         }
162
163         $new_password = ((strlen($password)) ? $password : autoname(6) . mt_rand(100,9999));
164         $new_password_encoded = hash('whirlpool',$new_password);
165
166         $result['password'] = $new_password;
167
168         require_once('include/crypto.php');
169
170         $keys = new_keypair(4096);
171
172         if($keys === false) {
173                 $result['message'] .= t('SERIOUS ERROR: Generation of security keys failed.') . EOL;
174                 return $result;
175         }
176
177         $default_service_class = get_config('system','default_service_class');
178         if(! $default_service_class)
179                 $default_service_class = '';
180
181
182         $prvkey = $keys['prvkey'];
183         $pubkey = $keys['pubkey'];
184
185         /**
186          *
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.
193          *
194          */
195
196         $sres    = new_keypair(512);
197         $sprvkey = $sres['prvkey'];
198         $spubkey = $sres['pubkey'];
199
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()),
204                 dbesc($username),
205                 dbesc($new_password_encoded),
206                 dbesc($email),
207                 dbesc($openid_url),
208                 dbesc($nickname),
209                 dbesc($pubkey),
210                 dbesc($prvkey),
211                 dbesc($spubkey),
212                 dbesc($sprvkey),
213                 dbesc(datetime_convert()),
214                 intval($verified),
215                 intval($blocked),
216                 dbesc($default_service_class)
217         );
218
219         if ($r) {
220                 $r = q("SELECT * FROM `user`
221                         WHERE `username` = '%s' AND `password` = '%s' LIMIT 1",
222                         dbesc($username),
223                         dbesc($new_password_encoded)
224                 );
225                 if (dbm::is_result($r)) {
226                         $u = $r[0];
227                         $newuid = intval($r[0]['uid']);
228                 }
229         }
230         else {
231                 $result['message'] .=  t('An error occurred during registration. Please try again.') . EOL ;
232                 return $result;
233         }
234
235         /**
236          * if somebody clicked submit twice very quickly, they could end up with two accounts
237          * due to race condition. Remove this one.
238          */
239
240         $r = q("SELECT `uid` FROM `user`
241                 WHERE `nickname` = '%s' ",
242                 dbesc($nickname)
243         );
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",
247                         intval($newuid)
248                 );
249                 return $result;
250         }
251
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 ) ",
255                         intval($newuid),
256                         t('default'),
257                         1,
258                         dbesc($username),
259                         dbesc(z_root() . "/photo/profile/{$newuid}.jpg"),
260                         dbesc(z_root() . "/photo/avatar/{$newuid}.jpg"),
261                         intval($publish),
262                         intval($netpublish)
263
264                 );
265                 if ($r === false) {
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",
269                                 intval($newuid));
270                         return $result;
271                 }
272
273                 // Create the self contact
274                 user_create_self_contact($newuid);
275
276                 // Create a group with no members. This allows somebody to use it
277                 // right away as a default group for new contacts.
278
279                 require_once('include/group.php');
280                 group_add($newuid, t('Friends'));
281
282                 $r = q("SELECT `id` FROM `group` WHERE `uid` = %d AND `name` = '%s'",
283                         intval($newuid),
284                         dbesc(t('Friends'))
285                 );
286                 if (dbm::is_result($r)) {
287                         $def_gid = $r[0]['id'];
288
289                         q("UPDATE `user` SET `def_gid` = %d WHERE `uid` = %d",
290                                 intval($r[0]['id']),
291                                 intval($newuid)
292                         );
293                 }
294
295                 if(get_config('system', 'newuser_private') && $def_gid) {
296                         q("UPDATE `user` SET `allow_gid` = '%s' WHERE `uid` = %d",
297                                 dbesc("<" . $def_gid . ">"),
298                                 intval($newuid)
299                         );
300                 }
301
302         }
303
304         // if we have no OpenID photo try to look up an avatar
305         if(! strlen($photo))
306                 $photo = avatar_img($email);
307
308         // unless there is no avatar-plugin loaded
309         if(strlen($photo)) {
310                 require_once('include/Photo.php');
311                 $photo_failure = false;
312
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);
317
318
319                 $img = new Photo($img_str, $type);
320                 if($img->is_valid()) {
321
322                         $img->scaleImageSquare(175);
323
324                         $hash = photo_new_resource();
325
326                         $r = $img->store($newuid, 0, $hash, $filename, t('Profile Photos'), 4 );
327
328                         if ($r === false) {
329                                 $photo_failure = true;
330                         }
331
332                         $img->scaleImage(80);
333
334                         $r = $img->store($newuid, 0, $hash, $filename, t('Profile Photos'), 5 );
335
336                         if ($r === false) {
337                                 $photo_failure = true;
338                         }
339
340                         $img->scaleImage(48);
341
342                         $r = $img->store($newuid, 0, $hash, $filename, t('Profile Photos'), 6 );
343
344                         if ($r === false) {
345                                 $photo_failure = true;
346                         }
347
348                         if (! $photo_failure) {
349                                 q("UPDATE `photo` SET `profile` = 1 WHERE `resource-id` = '%s' ",
350                                         dbesc($hash)
351                                 );
352                         }
353                 }
354         }
355
356         call_hooks('register_account', $newuid);
357
358         $result['success'] = true;
359         $result['user'] = $u;
360         return $result;
361
362 }
363
364 /**
365  * @brief create the "self" contact from data from the user table
366  *
367  * @param integer $uid
368  */
369 function user_create_self_contact($uid) {
370
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)) {
374                 return;
375         }
376
377         $r = q("SELECT `uid`, `username`, `nickname` FROM `user` WHERE `uid` = %d", intval($uid));
378         if (!dbm::is_result($r)) {
379                 return;
380         }
381
382         $user = $r[0];
383
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']),
388                 datetime_convert(),
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())
405         );
406 }
407
408 /**
409  * @brief send registration confiƕmation with the intormation that reg is pending
410  *
411  * @param string $email
412  * @param string $sitename
413  * @param string $username
414  * @return NULL|boolean from notification() and email() inherited 
415  */
416 function send_register_pending_eml($email, $sitename, $username) {
417         $body = deindent(t('
418                 Dear %1$s,
419                         Thank you for registering at %2$s. Your account is pending for approval by the administrator.
420         '));
421
422         $body = sprintf($body, $username, $sitename);
423
424         return notification(array(
425                 'type' => "SYSTEM_EMAIL",
426                 'to_email' => $email,
427                 'subject'=> sprintf( t('Registration at %s'), $sitename),
428                 'body' => $body));
429 }
430
431 /*
432  * send registration confirmation.
433  * It's here as a function because the mail is sent
434  * from different parts
435  */
436 function send_register_open_eml($email, $sitename, $siteurl, $username, $password){
437         $preamble = deindent(t('
438                 Dear %1$s,
439                         Thank you for registering at %2$s. Your account has been created.
440         '));
441         $body = deindent(t('
442                 The login details are as follows:
443                         Site Location:  %3$s
444                         Login Name:     %1$s
445                         Password:       %5$s
446
447                 You may change your password from your account "Settings" page after logging
448                 in.
449
450                 Please take a few moments to review the other account settings on that page.
451
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.
454
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
458                 than that.
459
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.
463
464
465                 Thank you and welcome to %2$s.'));
466
467                 $preamble = sprintf($preamble, $username, $sitename);
468                 $body = sprintf($body, $email, $sitename, $siteurl, $username, $password);
469
470                 return notification(array(
471                         'type' => "SYSTEM_EMAIL",
472                         'to_email' => $email,
473                         'subject'=> sprintf( t('Registration details for %s'), $sitename),
474                         'preamble'=> $preamble,
475                         'body' => $body));
476 }