2018-12-27 20:50:55 -05:00
< ? php
2020-02-09 09:45:36 -05:00
/**
2021-03-29 02:40:20 -04:00
* @ copyright Copyright ( C ) 2010 - 2021 , the Friendica project
2020-02-09 09:45:36 -05:00
*
* @ license GNU AGPL version 3 or any later version
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation , either version 3 of the
* License , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Affero General Public License for more details .
*
* You should have received a copy of the GNU Affero General Public License
* along with this program . If not , see < https :// www . gnu . org / licenses />.
*
*/
2018-12-27 20:50:55 -05:00
namespace Friendica\Module ;
use Friendica\BaseModule ;
use Friendica\Content\Text\BBCode ;
use Friendica\Core\Hook ;
use Friendica\Core\L10n ;
use Friendica\Core\Logger ;
use Friendica\Core\Renderer ;
use Friendica\Core\Worker ;
use Friendica\Database\DBA ;
2019-12-15 16:34:11 -05:00
use Friendica\DI ;
2018-12-27 20:50:55 -05:00
use Friendica\Model ;
2021-09-17 14:36:20 -04:00
use Friendica\Model\User ;
use Friendica\Util\Proxy ;
2018-12-27 20:50:55 -05:00
use Friendica\Util\Strings ;
/**
* @ author Hypolite Petovan < hypolite @ mrpetovan . com >
*/
2019-05-01 15:29:04 -04:00
class Register extends BaseModule
2018-12-27 20:50:55 -05:00
{
const CLOSED = 0 ;
const APPROVE = 1 ;
const OPEN = 2 ;
/**
2020-01-19 01:05:23 -05:00
* Module GET method to display any content
2018-12-27 20:50:55 -05:00
*
* Extend this method if the module is supposed to return any display
* through a GET request . It can be an HTML page through templating or a
* XML feed or a JSON output .
*
* @ return string
*/
2019-11-05 16:48:54 -05:00
public static function content ( array $parameters = [])
2018-12-27 20:50:55 -05:00
{
// logged in users can register others (people/pages/groups)
// even with closed registrations, unless specifically prohibited by site policy.
// 'block_extended_register' blocks all registrations, period.
2020-01-19 15:21:13 -05:00
$block = DI :: config () -> get ( 'system' , 'block_extended_register' );
2018-12-27 20:50:55 -05:00
2020-01-17 02:02:59 -05:00
if ( local_user () && $block ) {
2020-01-18 14:52:34 -05:00
notice ( DI :: l10n () -> t ( 'Permission denied.' ));
2018-12-27 20:50:55 -05:00
return '' ;
}
2020-01-17 02:02:59 -05:00
if ( local_user ()) {
$user = DBA :: selectFirst ( 'user' , [ 'parent-uid' ], [ 'uid' => local_user ()]);
if ( ! empty ( $user [ 'parent-uid' ])) {
2020-01-18 14:52:34 -05:00
notice ( DI :: l10n () -> t ( 'Only parent users can create additional accounts.' ));
2020-01-17 02:02:59 -05:00
return '' ;
}
}
2020-01-19 15:21:13 -05:00
if ( ! local_user () && ( intval ( DI :: config () -> get ( 'config' , 'register_policy' )) === self :: CLOSED )) {
2020-01-18 14:52:34 -05:00
notice ( DI :: l10n () -> t ( 'Permission denied.' ));
2018-12-27 20:50:55 -05:00
return '' ;
}
2020-01-19 15:21:13 -05:00
$max_dailies = intval ( DI :: config () -> get ( 'system' , 'max_daily_registrations' ));
2018-12-27 20:50:55 -05:00
if ( $max_dailies ) {
$count = DBA :: count ( 'user' , [ '`register_date` > UTC_TIMESTAMP - INTERVAL 1 day' ]);
if ( $count >= $max_dailies ) {
Logger :: log ( 'max daily registrations exceeded.' );
2020-01-18 14:52:34 -05:00
notice ( DI :: l10n () -> t ( 'This site has exceeded the number of allowed daily account registrations. Please try again tomorrow.' ));
2018-12-27 20:50:55 -05:00
return '' ;
}
}
2019-10-15 09:20:32 -04:00
$username = $_REQUEST [ 'username' ] ? ? '' ;
$email = $_REQUEST [ 'email' ] ? ? '' ;
$openid_url = $_REQUEST [ 'openid_url' ] ? ? '' ;
$nickname = $_REQUEST [ 'nickname' ] ? ? '' ;
$photo = $_REQUEST [ 'photo' ] ? ? '' ;
$invite_id = $_REQUEST [ 'invite_id' ] ? ? '' ;
2018-12-27 20:50:55 -05:00
2020-01-19 15:21:13 -05:00
if ( local_user () || DI :: config () -> get ( 'system' , 'no_openid' )) {
2018-12-27 20:50:55 -05:00
$fillwith = '' ;
$fillext = '' ;
$oidlabel = '' ;
} else {
2020-01-18 14:52:34 -05:00
$fillwith = DI :: l10n () -> t ( 'You may (optionally) fill in this form via OpenID by supplying your OpenID and clicking "Register".' );
$fillext = DI :: l10n () -> t ( 'If you are not familiar with OpenID, please leave that field blank and fill in the rest of the items.' );
$oidlabel = DI :: l10n () -> t ( 'Your OpenID (optional): ' );
2018-12-27 20:50:55 -05:00
}
2020-01-19 15:21:13 -05:00
if ( DI :: config () -> get ( 'system' , 'publish_all' )) {
2018-12-27 20:50:55 -05:00
$profile_publish = '<input type="hidden" name="profile_publish_reg" value="1" />' ;
} else {
2019-10-27 10:09:00 -04:00
$publish_tpl = Renderer :: getMarkupTemplate ( 'profile/publish.tpl' );
2018-12-27 20:50:55 -05:00
$profile_publish = Renderer :: replaceMacros ( $publish_tpl , [
'$instance' => 'reg' ,
2020-01-18 14:52:34 -05:00
'$pubdesc' => DI :: l10n () -> t ( 'Include your profile in member directory?' ),
2018-12-27 20:50:55 -05:00
'$yes_selected' => '' ,
'$no_selected' => ' checked="checked"' ,
2020-01-18 14:52:34 -05:00
'$str_yes' => DI :: l10n () -> t ( 'Yes' ),
'$str_no' => DI :: l10n () -> t ( 'No' ),
2018-12-27 20:50:55 -05:00
]);
}
2020-01-17 02:02:59 -05:00
$ask_password = ! DBA :: count ( 'contact' );
2018-12-27 20:50:55 -05:00
$tpl = Renderer :: getMarkupTemplate ( 'register.tpl' );
$arr = [ 'template' => $tpl ];
Hook :: callAll ( 'register_form' , $arr );
$tpl = $arr [ 'template' ];
$tos = new Tos ();
$o = Renderer :: replaceMacros ( $tpl , [
2020-01-19 15:21:13 -05:00
'$invitations' => DI :: config () -> get ( 'system' , 'invitation_only' ),
'$permonly' => intval ( DI :: config () -> get ( 'config' , 'register_policy' )) === self :: APPROVE ,
2020-12-19 22:41:42 -05:00
'$permonlybox' => [ 'permonlybox' , DI :: l10n () -> t ( 'Note for the admin' ), '' , DI :: l10n () -> t ( 'Leave a message for the admin, why you want to join this node' ), DI :: l10n () -> t ( 'Required' )],
2020-01-18 14:52:34 -05:00
'$invite_desc' => DI :: l10n () -> t ( 'Membership on this site is by invitation only.' ),
'$invite_label' => DI :: l10n () -> t ( 'Your invitation code: ' ),
2018-12-27 20:50:55 -05:00
'$invite_id' => $invite_id ,
2020-01-18 14:52:34 -05:00
'$regtitle' => DI :: l10n () -> t ( 'Registration' ),
2020-01-19 15:21:13 -05:00
'$registertext' => BBCode :: convert ( DI :: config () -> get ( 'config' , 'register_text' , '' )),
2018-12-27 20:50:55 -05:00
'$fillwith' => $fillwith ,
'$fillext' => $fillext ,
'$oidlabel' => $oidlabel ,
'$openid' => $openid_url ,
2020-01-18 14:52:34 -05:00
'$namelabel' => DI :: l10n () -> t ( 'Your Full Name (e.g. Joe Smith, real or real-looking): ' ),
'$addrlabel' => DI :: l10n () -> t ( 'Your Email Address: (Initial information will be send there, so this has to be an existing address.)' ),
'$addrlabel2' => DI :: l10n () -> t ( 'Please repeat your e-mail address:' ),
2018-12-27 20:50:55 -05:00
'$ask_password' => $ask_password ,
2020-01-18 14:52:34 -05:00
'$password1' => [ 'password1' , DI :: l10n () -> t ( 'New Password:' ), '' , DI :: l10n () -> t ( 'Leave empty for an auto generated password.' )],
'$password2' => [ 'confirm' , DI :: l10n () -> t ( 'Confirm:' ), '' , '' ],
'$nickdesc' => DI :: l10n () -> t ( 'Choose a profile nickname. This must begin with a text character. Your profile address on this site will then be "<strong>nickname@%s</strong>".' , DI :: baseUrl () -> getHostname ()),
'$nicklabel' => DI :: l10n () -> t ( 'Choose a nickname: ' ),
2018-12-27 20:50:55 -05:00
'$photo' => $photo ,
'$publish' => $profile_publish ,
2020-01-18 14:52:34 -05:00
'$regbutt' => DI :: l10n () -> t ( 'Register' ),
2018-12-27 20:50:55 -05:00
'$username' => $username ,
'$email' => $email ,
'$nickname' => $nickname ,
2019-12-29 20:17:16 -05:00
'$sitename' => DI :: baseUrl () -> getHostname (),
2020-01-18 14:52:34 -05:00
'$importh' => DI :: l10n () -> t ( 'Import' ),
'$importt' => DI :: l10n () -> t ( 'Import your profile to this friendica instance' ),
2020-01-19 15:21:13 -05:00
'$showtoslink' => DI :: config () -> get ( 'system' , 'tosdisplay' ),
2020-01-18 14:52:34 -05:00
'$tostext' => DI :: l10n () -> t ( 'Terms of Service' ),
2020-01-19 15:21:13 -05:00
'$showprivstatement' => DI :: config () -> get ( 'system' , 'tosprivstatement' ),
2018-12-27 20:50:55 -05:00
'$privstatement' => $tos -> privacy_complete ,
'$form_security_token' => BaseModule :: getFormSecurityToken ( 'register' ),
2020-01-19 15:21:13 -05:00
'$explicit_content' => DI :: config () -> get ( 'system' , 'explicit_content' , false ),
2020-01-18 14:52:34 -05:00
'$explicit_content_note' => DI :: l10n () -> t ( 'Note: This node explicitly contains adult content' ),
2020-01-17 02:02:59 -05:00
'$additional' => ! empty ( local_user ()),
2020-01-18 14:52:34 -05:00
'$parent_password' => [ 'parent_password' , DI :: l10n () -> t ( 'Parent Password:' ), '' , DI :: l10n () -> t ( 'Please enter the password of the parent account to legitimize your request.' )]
2020-01-17 02:02:59 -05:00
2018-12-27 20:50:55 -05:00
]);
return $o ;
}
/**
2020-01-19 01:05:23 -05:00
* Module POST method to process submitted data
2018-12-27 20:50:55 -05:00
*
* Extend this method if the module is supposed to process POST requests .
* Doesn ' t display any content
*/
2019-11-05 16:48:54 -05:00
public static function post ( array $parameters = [])
2018-12-27 20:50:55 -05:00
{
BaseModule :: checkFormSecurityTokenRedirectOnError ( '/register' , 'register' );
$arr = [ 'post' => $_POST ];
Hook :: callAll ( 'register_post' , $arr );
2020-01-17 02:02:59 -05:00
$additional_account = false ;
if ( ! local_user () && ! empty ( $arr [ 'post' ][ 'parent_password' ])) {
2020-01-18 14:52:34 -05:00
notice ( DI :: l10n () -> t ( 'Permission denied.' ));
2020-01-17 02:02:59 -05:00
return ;
} elseif ( local_user () && ! empty ( $arr [ 'post' ][ 'parent_password' ])) {
try {
Model\User :: getIdFromPasswordAuthentication ( local_user (), $arr [ 'post' ][ 'parent_password' ]);
} catch ( \Exception $ex ) {
2020-01-18 14:52:34 -05:00
notice ( DI :: l10n () -> t ( " Password doesn't match. " ));
2020-01-17 02:02:59 -05:00
$regdata = [ 'nickname' => $arr [ 'post' ][ 'nickname' ], 'username' => $arr [ 'post' ][ 'username' ]];
DI :: baseUrl () -> redirect ( 'register?' . http_build_query ( $regdata ));
}
$additional_account = true ;
} elseif ( local_user ()) {
2020-01-18 14:52:34 -05:00
notice ( DI :: l10n () -> t ( 'Please enter your password.' ));
2020-01-17 02:02:59 -05:00
$regdata = [ 'nickname' => $arr [ 'post' ][ 'nickname' ], 'username' => $arr [ 'post' ][ 'username' ]];
DI :: baseUrl () -> redirect ( 'register?' . http_build_query ( $regdata ));
}
2020-01-19 15:21:13 -05:00
$max_dailies = intval ( DI :: config () -> get ( 'system' , 'max_daily_registrations' ));
2018-12-27 20:50:55 -05:00
if ( $max_dailies ) {
$count = DBA :: count ( 'user' , [ '`register_date` > UTC_TIMESTAMP - INTERVAL 1 day' ]);
if ( $count >= $max_dailies ) {
return ;
}
}
2020-01-19 15:21:13 -05:00
switch ( DI :: config () -> get ( 'config' , 'register_policy' )) {
2018-12-27 20:50:55 -05:00
case self :: OPEN :
$blocked = 0 ;
$verified = 1 ;
break ;
case self :: APPROVE :
$blocked = 1 ;
$verified = 0 ;
break ;
case self :: CLOSED :
default :
if ( empty ( $_SESSION [ 'authenticated' ]) && empty ( $_SESSION [ 'administrator' ])) {
2020-01-18 14:52:34 -05:00
notice ( DI :: l10n () -> t ( 'Permission denied.' ));
2018-12-27 20:50:55 -05:00
return ;
}
$blocked = 1 ;
$verified = 0 ;
break ;
}
$netpublish = ! empty ( $_POST [ 'profile_publish_reg' ]);
$arr = $_POST ;
2020-01-15 12:55:32 -05:00
// Is there text in the tar pit?
if ( ! empty ( $arr [ 'email' ])) {
Logger :: info ( 'Tar pit' , $arr );
2020-01-18 14:52:34 -05:00
notice ( DI :: l10n () -> t ( 'You have entered too much information.' ));
2020-01-15 12:55:32 -05:00
DI :: baseUrl () -> redirect ( 'register/' );
}
2020-01-17 02:02:59 -05:00
if ( $additional_account ) {
$user = DBA :: selectFirst ( 'user' , [ 'email' ], [ 'uid' => local_user ()]);
if ( ! DBA :: isResult ( $user )) {
2020-01-18 14:52:34 -05:00
notice ( DI :: l10n () -> t ( 'User not found.' ));
2020-01-17 02:02:59 -05:00
DI :: baseUrl () -> redirect ( 'register' );
}
$blocked = 0 ;
$verified = 1 ;
$arr [ 'password1' ] = $arr [ 'confirm' ] = $arr [ 'parent_password' ];
$arr [ 'repeat' ] = $arr [ 'email' ] = $user [ 'email' ];
2021-06-30 15:13:27 -04:00
} else {
// Overwriting the "tar pit" field with the real one
$arr [ 'email' ] = $arr [ 'field1' ];
2020-01-17 02:02:59 -05:00
}
2020-01-15 12:55:32 -05:00
if ( $arr [ 'email' ] != $arr [ 'repeat' ]) {
Logger :: info ( 'Mail mismatch' , $arr );
2020-01-18 14:52:34 -05:00
notice ( DI :: l10n () -> t ( 'Please enter the identical mail address in the second field.' ));
2020-01-15 12:55:32 -05:00
$regdata = [ 'email' => $arr [ 'email' ], 'nickname' => $arr [ 'nickname' ], 'username' => $arr [ 'username' ]];
DI :: baseUrl () -> redirect ( 'register?' . http_build_query ( $regdata ));
}
2018-12-27 20:50:55 -05:00
$arr [ 'blocked' ] = $blocked ;
$arr [ 'verified' ] = $verified ;
2020-01-18 16:07:07 -05:00
$arr [ 'language' ] = L10n :: detectLanguage ( $_SERVER , $_GET , DI :: config () -> get ( 'system' , 'language' ));
2018-12-27 20:50:55 -05:00
try {
$result = Model\User :: create ( $arr );
} catch ( \Exception $e ) {
2020-01-17 02:29:22 -05:00
notice ( $e -> getMessage ());
2018-12-27 20:50:55 -05:00
return ;
}
$user = $result [ 'user' ];
2019-12-15 17:28:01 -05:00
$base_url = DI :: baseUrl () -> get ();
2019-10-10 13:13:23 -04:00
2020-01-19 15:21:13 -05:00
if ( $netpublish && intval ( DI :: config () -> get ( 'config' , 'register_policy' )) !== self :: APPROVE ) {
2019-10-10 13:13:23 -04:00
$url = $base_url . '/profile/' . $user [ 'nickname' ];
2018-12-27 20:50:55 -05:00
Worker :: add ( PRIORITY_LOW , 'Directory' , $url );
}
2020-01-17 02:02:59 -05:00
if ( $additional_account ) {
DBA :: update ( 'user' , [ 'parent-uid' => local_user ()], [ 'uid' => $user [ 'uid' ]]);
2020-01-18 14:52:34 -05:00
info ( DI :: l10n () -> t ( 'The additional account was created.' ));
2020-01-17 02:02:59 -05:00
DI :: baseUrl () -> redirect ( 'delegation' );
}
2020-01-19 15:21:13 -05:00
$using_invites = DI :: config () -> get ( 'system' , 'invitation_only' );
$num_invites = DI :: config () -> get ( 'system' , 'number_invites' );
2018-12-27 20:50:55 -05:00
$invite_id = ( ! empty ( $_POST [ 'invite_id' ]) ? Strings :: escapeTags ( trim ( $_POST [ 'invite_id' ])) : '' );
2020-01-19 15:21:13 -05:00
if ( intval ( DI :: config () -> get ( 'config' , 'register_policy' )) === self :: OPEN ) {
2018-12-27 20:50:55 -05:00
if ( $using_invites && $invite_id ) {
Model\Register :: deleteByHash ( $invite_id );
2020-01-18 10:54:50 -05:00
DI :: pConfig () -> set ( $user [ 'uid' ], 'system' , 'invites_remaining' , $num_invites );
2018-12-27 20:50:55 -05:00
}
// Only send a password mail when the password wasn't manually provided
if ( empty ( $_POST [ 'password1' ]) || empty ( $_POST [ 'confirm' ])) {
$res = Model\User :: sendRegisterOpenEmail (
2020-01-18 14:54:15 -05:00
DI :: l10n () -> withLang ( $arr [ 'language' ]),
2018-12-27 20:50:55 -05:00
$user ,
2020-01-19 15:21:13 -05:00
DI :: config () -> get ( 'config' , 'sitename' ),
2019-10-10 13:13:23 -04:00
$base_url ,
2018-12-27 20:50:55 -05:00
$result [ 'password' ]
);
if ( $res ) {
2020-01-18 14:52:34 -05:00
info ( DI :: l10n () -> t ( 'Registration successful. Please check your email for further instructions.' ));
2019-12-15 18:28:31 -05:00
DI :: baseUrl () -> redirect ();
2018-12-27 20:50:55 -05:00
} else {
2020-01-17 02:29:22 -05:00
notice (
2020-01-18 14:52:34 -05:00
DI :: l10n () -> t ( 'Failed to send email message. Here your accout details:<br> login: %s<br> password: %s<br><br>You can change your password after login.' ,
2018-12-27 20:50:55 -05:00
$user [ 'email' ],
$result [ 'password' ])
);
}
} else {
2020-01-18 14:52:34 -05:00
info ( DI :: l10n () -> t ( 'Registration successful.' ));
2019-12-15 18:28:31 -05:00
DI :: baseUrl () -> redirect ();
2018-12-27 20:50:55 -05:00
}
2020-01-19 15:21:13 -05:00
} elseif ( intval ( DI :: config () -> get ( 'config' , 'register_policy' )) === self :: APPROVE ) {
if ( ! strlen ( DI :: config () -> get ( 'config' , 'admin_email' ))) {
2020-01-18 14:52:34 -05:00
notice ( DI :: l10n () -> t ( 'Your registration can not be processed.' ));
2019-12-15 18:28:31 -05:00
DI :: baseUrl () -> redirect ();
2018-12-27 20:50:55 -05:00
}
2019-10-06 05:57:43 -04:00
// Check if the note to the admin is actually filled out
if ( empty ( $_POST [ 'permonlybox' ])) {
2020-01-18 14:52:34 -05:00
notice ( DI :: l10n () -> t ( 'You have to leave a request note for the admin.' )
. DI :: l10n () -> t ( 'Your registration can not be processed.' ));
2019-10-06 05:57:43 -04:00
2019-12-15 18:28:31 -05:00
DI :: baseUrl () -> redirect ( 'register/' );
2019-10-06 05:57:43 -04:00
}
2020-01-19 15:21:13 -05:00
Model\Register :: createForApproval ( $user [ 'uid' ], DI :: config () -> get ( 'system' , 'language' ), $_POST [ 'permonlybox' ]);
2018-12-27 20:50:55 -05:00
// invite system
if ( $using_invites && $invite_id ) {
Model\Register :: deleteByHash ( $invite_id );
2020-01-18 10:54:50 -05:00
DI :: pConfig () -> set ( $user [ 'uid' ], 'system' , 'invites_remaining' , $num_invites );
2018-12-27 20:50:55 -05:00
}
// send email to admins
$admins_stmt = DBA :: select (
'user' ,
[ 'uid' , 'language' , 'email' ],
2020-01-19 15:21:13 -05:00
[ 'email' => explode ( ',' , str_replace ( ' ' , '' , DI :: config () -> get ( 'config' , 'admin_email' )))]
2018-12-27 20:50:55 -05:00
);
// send notification to admins
while ( $admin = DBA :: fetch ( $admins_stmt )) {
2021-10-19 15:45:36 -04:00
DI :: notify () -> createFromArray ([
2021-01-23 04:53:44 -05:00
'type' => Model\Notification\Type :: SYSTEM ,
2018-12-27 20:50:55 -05:00
'event' => 'SYSTEM_REGISTER_REQUEST' ,
2020-11-25 14:56:39 -05:00
'uid' => $admin [ 'uid' ],
'link' => $base_url . '/admin/users/' ,
2018-12-27 20:50:55 -05:00
'source_name' => $user [ 'username' ],
'source_mail' => $user [ 'email' ],
'source_nick' => $user [ 'nickname' ],
2019-10-10 13:13:23 -04:00
'source_link' => $base_url . '/admin/users/' ,
2021-10-02 17:28:29 -04:00
'source_photo' => User :: getAvatarUrl ( $user , Proxy :: SIZE_THUMB ),
2018-12-27 20:50:55 -05:00
'show_in_notification_page' => false
]);
}
DBA :: close ( $admins_stmt );
// send notification to the user, that the registration is pending
Model\User :: sendRegisterPendingEmail (
$user ,
2020-01-19 15:21:13 -05:00
DI :: config () -> get ( 'config' , 'sitename' ),
2019-10-10 13:13:23 -04:00
$base_url ,
2018-12-27 20:50:55 -05:00
$result [ 'password' ]
);
2020-01-18 14:52:34 -05:00
info ( DI :: l10n () -> t ( 'Your registration is pending approval by the site owner.' ));
2019-12-15 18:28:31 -05:00
DI :: baseUrl () -> redirect ();
2018-12-27 20:50:55 -05:00
}
return ;
}
}