Add new templates for user authentication and management
- Created `unlogged-layout.php` and `unlogged.php` for the login page layout. - Implemented `main-view.php` for system update management with progress tracking. - Added `user-2fa.php` for two-factor authentication verification. - Developed `user-edit.php` for editing user details and privileges. - Introduced `users-list.php` for displaying and managing user accounts. - Added `.htaccess` configuration for URL rewriting and security settings.
This commit is contained in:
@@ -86,6 +86,24 @@ class Articles
|
||||
return true;
|
||||
}
|
||||
|
||||
static public function files_order_save( $article_id, $order )
|
||||
{
|
||||
global $mdb;
|
||||
|
||||
$order = explode( ';', $order );
|
||||
if ( is_array( $order ) and !empty( $order ) ) foreach ( $order as $file_id )
|
||||
{
|
||||
$mdb -> update( 'pp_articles_files', [
|
||||
'o' => (int)$i++
|
||||
], [
|
||||
'AND' => [
|
||||
'article_id' => $article_id,
|
||||
'id' => $file_id
|
||||
]
|
||||
] );
|
||||
}
|
||||
}
|
||||
|
||||
public static function gallery_order_save( $article_id, $order )
|
||||
{
|
||||
global $mdb;
|
||||
@@ -222,7 +240,7 @@ class Articles
|
||||
$article['languages'][ $row['lang_id'] ] = $row;
|
||||
|
||||
$article['images'] = $mdb -> select( 'pp_articles_images', '*', [ 'article_id' => (int)$article_id, 'ORDER' => [ 'o' => 'ASC', 'id' => 'ASC' ] ] );
|
||||
$article['files'] = $mdb -> select( 'pp_articles_files', '*', [ 'article_id' => (int)$article_id ] );
|
||||
$article['files'] = $mdb -> select( 'pp_articles_files', '*', [ 'article_id' => (int)$article_id, 'ORDER' => [ 'o' => 'ASC', 'id' => 'ASC' ] ] );
|
||||
$article['pages'] = $mdb -> select( 'pp_articles_pages', 'page_id', [ 'article_id' => (int)$article_id ] );
|
||||
$article['tags'] = $mdb -> select( 'pp_tags', [ '[><]pp_articles_tags' => [ 'id' => 'tag_id' ] ], 'name', [ 'article_id' => (int)$article_id ] );
|
||||
$article['params'] = $mdb -> select( 'pp_articles_additional_values', [ 'param_id', 'value', 'language_id' ], [ 'article_id' => (int)$article_id ] );
|
||||
@@ -238,7 +256,7 @@ class Articles
|
||||
}
|
||||
|
||||
public static function article_save(
|
||||
$article_id, $title, $main_image, $entry, $text, $table_of_contents, $status, $show_title, $show_date_add, $date_add, $show_date_modify, $seo_link, $meta_title, $meta_description,
|
||||
$article_id, $title, $main_image, $entry, $text, $table_of_contents, $status, $show_title, $show_table_of_contents, $show_date_add, $date_add, $show_date_modify, $date_modify, $seo_link, $meta_title, $meta_description,
|
||||
$meta_keywords, $layout_id, $pages, $noindex, $repeat_entry, $copy_from, $social_icons, $event_date, $tags, $block_direct_access, $priority,
|
||||
$password, $pixieset, $id_author, $params )
|
||||
{
|
||||
@@ -251,10 +269,11 @@ class Articles
|
||||
{
|
||||
$mdb -> insert( 'pp_articles', [
|
||||
'show_title' => $show_title == 'on' ? 1 : 0,
|
||||
'show_table_of_contents' => $show_table_of_contents == 'on' ? 1 : 0,
|
||||
'show_date_add' => $show_date_add == 'on' ? 1 : 0,
|
||||
'show_date_modify' => $show_date_modify == 'on' ? 1 : 0,
|
||||
'date_add' => $date_add ? $date_add : date( 'Y-m-d H:i:s' ),
|
||||
'date_modify' => $date_add ? $date_add : date( 'Y-m-d H:i:s' ),
|
||||
'date_add' => date( 'Y-m-d H:i:s' ),
|
||||
'date_modify' => date( 'Y-m-d H:i:s' ),
|
||||
'modify_by' => $user['id'],
|
||||
'layout_id' => $layout_id ? (int)$layout_id : null,
|
||||
'status' => $status == 'on' ? 1 : 0,
|
||||
@@ -435,9 +454,11 @@ class Articles
|
||||
{
|
||||
$mdb -> update( 'pp_articles', [
|
||||
'show_title' => $show_title == 'on' ? 1 : 0,
|
||||
'show_table_of_contents' => $show_table_of_contents == 'on' ? 1 : 0,
|
||||
'show_date_add' => $show_date_add == 'on' ? 1 : 0,
|
||||
'date_add' => $date_add,
|
||||
'show_date_modify' => $show_date_modify == 'on' ? 1 : 0,
|
||||
'date_modify' => date( 'Y-m-d H:i:s' ),
|
||||
'date_modify' => $date_modify ? $date_modify : date( 'Y-m-d H:i:s' ),
|
||||
'modify_by' => $user['id'],
|
||||
'layout_id' => $layout_id ? (int)$layout_id : null,
|
||||
'status' => $status == 'on' ? 1 : 0,
|
||||
|
||||
@@ -1,185 +1,306 @@
|
||||
<?php
|
||||
|
||||
namespace admin\factory;
|
||||
|
||||
class Users
|
||||
class Users
|
||||
{
|
||||
public static function user_delete( $user_id )
|
||||
public static function user_delete($user_id)
|
||||
{
|
||||
global $mdb;
|
||||
|
||||
return $mdb -> delete( 'pp_users', [ 'id' => (int)$user_id ] );
|
||||
|
||||
return $mdb->delete('pp_users', ['id' => (int)$user_id]);
|
||||
}
|
||||
|
||||
public static function user_details( $user_id )
|
||||
|
||||
public static function user_details($user_id)
|
||||
{
|
||||
global $mdb;
|
||||
return $mdb -> get( 'pp_users', '*', [ 'id' => (int)$user_id ] );
|
||||
return $mdb->get('pp_users', '*', ['id' => (int)$user_id]);
|
||||
}
|
||||
|
||||
public static function user_privileges( $user_id )
|
||||
|
||||
public static function user_privileges($user_id)
|
||||
{
|
||||
global $mdb;
|
||||
return $mdb -> select( 'pp_users_privileges', '*', ['id_user' => (int)$user_id]);
|
||||
return $mdb->select('pp_users_privileges', '*', ['id_user' => (int)$user_id]);
|
||||
}
|
||||
|
||||
public static function user_save( $user_id, $login, $status, $active_to, $password, $password_re, $admin, $privileges )
|
||||
|
||||
public static function user_save($user_id, $login, $status, $active_to, $password, $password_re, $admin, $privileges, $twofa_enabled = 0, $twofa_email = '' )
|
||||
{
|
||||
global $mdb, $lang;
|
||||
|
||||
$mdb -> delete( 'pp_users_privileges', [ 'id_user' => (int) $user_id ] );
|
||||
$mdb->delete('pp_users_privileges', ['id_user' => (int) $user_id]);
|
||||
|
||||
if ( !$user_id )
|
||||
if (!$user_id)
|
||||
{
|
||||
if ( strlen( $password ) < 5 )
|
||||
return $response = [ 'status' => 'error', 'msg' => 'Podane hasło jest zbyt krótkie.' ];
|
||||
if (strlen($password) < 5)
|
||||
return $response = ['status' => 'error', 'msg' => 'Podane hasło jest zbyt krótkie.'];
|
||||
|
||||
if ( $password != $password_re )
|
||||
return $response = [ 'status' => 'error', 'msg' => 'Podane hasła są różne' ];
|
||||
if ($password != $password_re)
|
||||
return $response = ['status' => 'error', 'msg' => 'Podane hasła są różne'];
|
||||
|
||||
if ( $mdb -> insert( 'pp_users',
|
||||
[
|
||||
'login' => $login,
|
||||
'status' => $status == 'on' ? 1 : 0,
|
||||
'active_to' => $active_to == '' ? NULL : $active_to,
|
||||
'admin' => $admin,
|
||||
'password' => md5( $password ),
|
||||
] ) )
|
||||
$id_user = $mdb -> get( 'pp_users', 'id', [ 'ORDER' => [ 'id' => 'DESC' ] ] );
|
||||
if ($mdb->insert(
|
||||
'pp_users',
|
||||
[
|
||||
'login' => $login,
|
||||
'status' => $status == 'on' ? 1 : 0,
|
||||
'active_to' => $active_to == '' ? NULL : $active_to,
|
||||
'admin' => $admin,
|
||||
'password' => md5($password),
|
||||
'twofa_enabled' => $twofa_enabled == 'on' ? 1 : 0,
|
||||
'twofa_email' => $twofa_email
|
||||
]
|
||||
))
|
||||
$id_user = $mdb->get('pp_users', 'id', ['ORDER' => ['id' => 'DESC']]);
|
||||
|
||||
if ( is_array( $privileges ) )
|
||||
if (is_array($privileges))
|
||||
{
|
||||
foreach ( $privileges as $pri )
|
||||
foreach ($privileges as $pri)
|
||||
{
|
||||
$mdb -> insert( 'pp_users_privileges',
|
||||
[
|
||||
'name' => $pri,
|
||||
'id_user' => $id_user
|
||||
] );
|
||||
$mdb->insert(
|
||||
'pp_users_privileges',
|
||||
[
|
||||
'name' => $pri,
|
||||
'id_user' => $id_user
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$mdb -> insert( 'pp_users_privileges',
|
||||
[
|
||||
'name' => $privileges,
|
||||
'id_user' => $id_user
|
||||
] );
|
||||
$mdb->insert(
|
||||
'pp_users_privileges',
|
||||
[
|
||||
'name' => $privileges,
|
||||
'id_user' => $id_user
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
return $response = [ 'status' => 'ok', 'msg' => 'Użytkownik został zapisany.' ];
|
||||
return $response = ['status' => 'ok', 'msg' => 'Użytkownik został zapisany.'];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if ( $password and strlen( $password ) < 5 )
|
||||
return $response = [ 'status' => 'error', 'msg' => 'Podane hasło jest zbyt krótkie.' ];
|
||||
if ($password and strlen($password) < 5)
|
||||
return $response = ['status' => 'error', 'msg' => 'Podane hasło jest zbyt krótkie.'];
|
||||
|
||||
if ( $password and $password != $password_re )
|
||||
return $response = [ 'status' => 'error', 'msg' => 'Podane hasła są różne' ];
|
||||
if ($password and $password != $password_re)
|
||||
return $response = ['status' => 'error', 'msg' => 'Podane hasła są różne'];
|
||||
|
||||
if ( $password )
|
||||
$mdb -> update( 'pp_users', [
|
||||
'password' => md5( $password )
|
||||
], [
|
||||
'id' => (int) $user_id
|
||||
] );
|
||||
if ($password)
|
||||
$mdb->update('pp_users', [
|
||||
'password' => md5($password)
|
||||
], [
|
||||
'id' => (int) $user_id
|
||||
]);
|
||||
|
||||
$mdb -> update( 'pp_users', [
|
||||
'login' => $login,
|
||||
'admin' => $admin,
|
||||
'status' => $status == 'on' ? 1 : 0,
|
||||
'active_to' => $active_to == '' ? NULL : $active_to,
|
||||
'error_logged_count' => 0
|
||||
], [
|
||||
'id' => (int) $user_id
|
||||
] );
|
||||
$mdb->update('pp_users', [
|
||||
'login' => $login,
|
||||
'admin' => $admin,
|
||||
'status' => $status == 'on' ? 1 : 0,
|
||||
'active_to' => $active_to == '' ? NULL : $active_to,
|
||||
'error_logged_count' => 0,
|
||||
'twofa_enabled' => $twofa_enabled == 'on' ? 1 : 0,
|
||||
'twofa_email' => $twofa_email
|
||||
], [
|
||||
'id' => (int) $user_id
|
||||
]);
|
||||
|
||||
if ( is_array( $privileges ) )
|
||||
if (is_array($privileges))
|
||||
{
|
||||
foreach ( $privileges as $pri )
|
||||
foreach ($privileges as $pri)
|
||||
{
|
||||
$mdb -> insert( 'pp_users_privileges', [
|
||||
'name' => $pri,
|
||||
'id_user' => $user_id
|
||||
] );
|
||||
$mdb->insert('pp_users_privileges', [
|
||||
'name' => $pri,
|
||||
'id_user' => $user_id
|
||||
]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$mdb -> insert( 'pp_users_privileges', [
|
||||
'name' => $privileges,
|
||||
'id_user' => $user_id
|
||||
] );
|
||||
$mdb->insert('pp_users_privileges', [
|
||||
'name' => $privileges,
|
||||
'id_user' => $user_id
|
||||
]);
|
||||
}
|
||||
return $response = [ 'status' => 'ok', 'msg' => 'Uzytkownik został zapisany.' ];
|
||||
return $response = ['status' => 'ok', 'msg' => 'Uzytkownik został zapisany.'];
|
||||
}
|
||||
\S::delete_cache();
|
||||
}
|
||||
|
||||
public static function check_login( $login, $user_id )
|
||||
public static function check_login($login, $user_id)
|
||||
{
|
||||
global $mdb;
|
||||
|
||||
if ( $mdb -> get( 'pp_users', 'login', [ 'AND' => [ 'login' => $login, 'id[!]' => (int)$user_id ] ] ) )
|
||||
return $response = [ 'status' => 'error', 'msg' => 'Podany login jest już zajęty.' ];
|
||||
|
||||
return $response = [ 'status' => 'ok' ];
|
||||
|
||||
if ($mdb->get('pp_users', 'login', ['AND' => ['login' => $login, 'id[!]' => (int)$user_id]]))
|
||||
return $response = ['status' => 'error', 'msg' => 'Podany login jest już zajęty.'];
|
||||
|
||||
return $response = ['status' => 'ok'];
|
||||
}
|
||||
|
||||
public static function logon( $login, $password )
|
||||
|
||||
public static function logon($login, $password)
|
||||
{
|
||||
global $mdb;
|
||||
|
||||
if ( !$mdb -> get( 'pp_users', '*', [ 'login' => $login ] ) )
|
||||
|
||||
if (!$mdb->get('pp_users', '*', ['login' => $login]))
|
||||
return 0;
|
||||
|
||||
if ( !$mdb -> get( 'pp_users', '*', [ 'AND' => [ 'login' => $login, 'status' => 1, 'error_logged_count[<]' => 5 ] ] ) )
|
||||
return -1;
|
||||
|
||||
if ( $mdb -> get( 'pp_users', '*', [
|
||||
'AND' => [
|
||||
'login' => $login, 'status' => 1, 'password' => md5( $password ),
|
||||
'OR' => [ 'active_to[>=]' => date('Y-m-d'), 'active_to' => null ]
|
||||
]
|
||||
] ) )
|
||||
|
||||
if (!$mdb->get('pp_users', '*', ['AND' => ['login' => $login, 'status' => 1, 'error_logged_count[<]' => 5]]))
|
||||
return -1;
|
||||
|
||||
if ($mdb->get('pp_users', '*', [
|
||||
'AND' => [
|
||||
'login' => $login,
|
||||
'status' => 1,
|
||||
'password' => md5($password),
|
||||
'OR' => ['active_to[>=]' => date('Y-m-d'), 'active_to' => null]
|
||||
]
|
||||
]))
|
||||
{
|
||||
$mdb -> update( 'pp_users', [ 'last_logged' => date( 'Y-m-d H:i:s' ), 'error_logged_count' => 0 ], [ 'login' => $login ] );
|
||||
$mdb->update('pp_users', ['last_logged' => date('Y-m-d H:i:s'), 'error_logged_count' => 0], ['login' => $login]);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$mdb -> update( 'pp_users', [ 'last_error_logged' => date( 'Y-m-d H:i:s' ), 'error_logged_count[+]' => 1 ], [ 'login' => $login ] );
|
||||
if ( $mdb -> get( 'pp_users', 'error_logged_count', [ 'login' => $login ] ) >= 5 )
|
||||
$mdb->update('pp_users', ['last_error_logged' => date('Y-m-d H:i:s'), 'error_logged_count[+]' => 1], ['login' => $login]);
|
||||
if ($mdb->get('pp_users', 'error_logged_count', ['login' => $login]) >= 5)
|
||||
{
|
||||
$mdb -> update( 'pp_users', [ 'status' => 0 ], [ 'login' => $login ] );
|
||||
$mdb->update('pp_users', ['status' => 0], ['login' => $login]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static function details( $login )
|
||||
|
||||
public static function details($login)
|
||||
{
|
||||
global $mdb;
|
||||
return $mdb -> get( 'pp_users', '*', [ 'login' => $login ] );
|
||||
return $mdb->get('pp_users', '*', ['login' => $login]);
|
||||
}
|
||||
|
||||
public static function check_privileges( $name, $user_id )
|
||||
|
||||
public static function check_privileges($name, $user_id)
|
||||
{
|
||||
global $mdb;
|
||||
|
||||
if ( $user_id == 1 )
|
||||
|
||||
if ($user_id == 1)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
if ( !$privilages = \Cache::fetch( "check_privileges:$user_id:$name-tmp" ) )
|
||||
{
|
||||
$privilages = $mdb -> count( 'pp_users_privileges', [ 'AND' => ['name' => $name, 'id_user' => (int)$user_id ]]);
|
||||
\Cache::store( "check_privileges:$user_id:$name", $privilages );
|
||||
}
|
||||
return $privilages;
|
||||
}
|
||||
if (!$privilages = \Cache::fetch("check_privileges:$user_id:$name-tmp"))
|
||||
{
|
||||
$privilages = $mdb->count('pp_users_privileges', ['AND' => ['name' => $name, 'id_user' => (int)$user_id]]);
|
||||
\Cache::store("check_privileges:$user_id:$name", $privilages);
|
||||
}
|
||||
return $privilages;
|
||||
}
|
||||
}
|
||||
|
||||
static public function get_by_id(int $userId): ?array
|
||||
{
|
||||
|
||||
global $mdb;
|
||||
return $mdb->get('pp_users', '*', ['id' => $userId]) ?: null;
|
||||
}
|
||||
|
||||
static public function send_twofa_code(int $userId, bool $resend = false): bool
|
||||
{
|
||||
|
||||
$user = self::get_by_id($userId);
|
||||
if (!$user)
|
||||
return false;
|
||||
|
||||
if ((int)$user['twofa_enabled'] !== 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$to = $user['twofa_email'] ?: $user['login'];
|
||||
if (!filter_var($to, FILTER_VALIDATE_EMAIL))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($resend && !empty($user['twofa_sent_at']))
|
||||
{
|
||||
$last = strtotime($user['twofa_sent_at']);
|
||||
if ($last && (time() - $last) < 30)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$code = random_int(100000, 999999);
|
||||
$hash = password_hash((string)$code, PASSWORD_DEFAULT);
|
||||
|
||||
self::update_by_id($userId, [
|
||||
'twofa_code_hash' => $hash,
|
||||
'twofa_expires_at' => date('Y-m-d H:i:s', time() + 10 * 60), // 10 minut
|
||||
'twofa_sent_at' => date('Y-m-d H:i:s'),
|
||||
'twofa_failed_attempts' => 0,
|
||||
]);
|
||||
|
||||
$subject = 'Twój kod logowania 2FA';
|
||||
$body = "Twój kod logowania do panelu administratora: {$code}. Kod jest ważny przez 10 minut. Jeśli to nie Ty inicjowałeś logowanie – zignoruj tę wiadomość i poinformuj administratora.";
|
||||
|
||||
$sent = \S::send_email($to, $subject, $body);
|
||||
|
||||
if (!$sent) {
|
||||
$headers = "MIME-Version: 1.0\r\n";
|
||||
$headers .= "Content-type: text/plain; charset=UTF-8\r\n";
|
||||
$headers .= "From: no-reply@" . ($_SERVER['HTTP_HOST'] ?? 'localhost') . "\r\n";
|
||||
$encodedSubject = mb_encode_mimeheader($subject, 'UTF-8');
|
||||
|
||||
$sent = mail($to, $encodedSubject, $body, $headers);
|
||||
}
|
||||
|
||||
return $sent;
|
||||
}
|
||||
|
||||
static public function update_by_id(int $userId, array $data): bool
|
||||
{
|
||||
global $mdb;
|
||||
return (bool)$mdb->update('pp_users', $data, ['id' => $userId]);
|
||||
}
|
||||
|
||||
static public function verify_twofa_code(int $userId, string $code): bool
|
||||
{
|
||||
$user = self::get_by_id( $userId );
|
||||
if (!$user) return false;
|
||||
|
||||
if ((int)$user['twofa_failed_attempts'] >= 5)
|
||||
{
|
||||
return false; // zbyt wiele prób
|
||||
}
|
||||
|
||||
// sprawdź ważność
|
||||
if (empty($user['twofa_expires_at']) || time() > strtotime($user['twofa_expires_at']))
|
||||
{
|
||||
// wyczyść po wygaśnięciu
|
||||
self::update_by_id($userId, [
|
||||
'twofa_code_hash' => null,
|
||||
'twofa_expires_at' => null,
|
||||
]);
|
||||
return false;
|
||||
}
|
||||
|
||||
$ok = (!empty($user['twofa_code_hash']) && password_verify($code, $user['twofa_code_hash']));
|
||||
if ($ok)
|
||||
{
|
||||
// sukces: czyścimy wszystko
|
||||
self::update_by_id($userId, [
|
||||
'twofa_code_hash' => null,
|
||||
'twofa_expires_at' => null,
|
||||
'twofa_sent_at' => null,
|
||||
'twofa_failed_attempts' => 0,
|
||||
'last_logged' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
return true;
|
||||
}
|
||||
|
||||
// zła próba — inkrementacja
|
||||
self::update_by_id($userId, [
|
||||
'twofa_failed_attempts' => (int)$user['twofa_failed_attempts'] + 1,
|
||||
'last_error_logged' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
Reference in New Issue
Block a user