• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Rzuci ktoś okiem na prostą aplikację PHP?

Aruba Cloud - Virtual Private Server VPS
0 głosów
350 wizyt
pytanie zadane 30 stycznia 2024 w PHP przez whiteman808 Gaduła (3,460 p.)

Hej, napisałem taką prostą witrynę w PHP, będę wdzięczny za code review :-)

lib/app_init.php

<?php
declare(strict_types=1);

require_once 'config/db.php';

try {
    $db_conn = new PDO(PDO_DSN, DB_USER, DB_PASS);

    $db_conn->query('ALTER TABLE IF EXISTS author DROP FOREIGN KEY fk_author_role_id');
    $db_conn->query('ALTER TABLE IF EXISTS post DROP FOREIGN KEY fk_post_author_id');
    foreach (['author_role', 'author', 'post'] as $db_table) {
        $db_conn->query("DROP TABLE IF EXISTS $db_table");
    }
    $stmt = 'CREATE TABLE IF NOT EXISTS author_role (' .
        'id int NOT NULL PRIMARY KEY AUTO_INCREMENT, ' .
        'role_name varchar(100) UNIQUE NOT NULL)';
    $db_conn->query($stmt);
    $stmt = 'INSERT INTO author_role (role_name) VALUES ' .
        "('Administrator'), ('Moderator'), ('User')";
    $db_conn->query($stmt);
    $stmt = 'CREATE TABLE IF NOT EXISTS author (' .
        'id int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT, ' .
        'username varchar(255) UNIQUE NOT NULL, ' .
        'passwd varchar(255) NOT NULL, ' .
        'email varchar(255) UNIQUE NOT NULL, ' .
        'created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, ' .
        'role_id int(11) NOT NULL, ' .
        'FOREIGN KEY fk_author_role_id (role_id) REFERENCES author_role (id))';
    $db_conn->query($stmt);
    $stmt = 'INSERT INTO author (username, passwd, email, role_id) ' .
        "VALUES ('lester29', 'test', 'lester29@lester29.org', 1)";
    $db_conn->query($stmt);
    $stmt = 'CREATE TABLE IF NOT EXISTS post ( ' .
        'id int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT, ' .
        'title varchar(255) UNIQUE NOT NULL, ' .
        'content text NOT NULL, ' .
        'author_id int(11) NOT NULL, ' .
        'created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, ' .
        'updated_at DATETIME NOT NULL ON UPDATE CURRENT_TIMESTAMP, ' .
        'FOREIGN KEY fk_post_author_id (author_id) REFERENCES author (id))';
    $db_conn->query($stmt);

    echo 'Successfully created required tables.';
} catch (PDOException $ex) {
    echo "An error occurred while initializing database: " . $ex->getMessage();
}

lib/user.php

<?php
declare(strict_types=1);

require_once 'config/db.php';

function userExists(string $username, string $password): bool
{
    try {
        $db_conn = new PDO(PDO_DSN, DB_USER, DB_PASS);
        $stmt = 'SELECT username, passwd ' .
            'FROM author ' .
            "WHERE username = ? " .
            "AND passwd = ?";
        $query = $db_conn->prepare($stmt);
        $query->execute([$username, $password]);
        return $query->rowCount() > 0;
    } catch (PDOException $ex) {
        die('An error occurred at auth_user function: ' . $ex->getMessage());
    }
}

footer.php

<footer>
    <p>This website is owned by lester29</p>
</footer>
</body>
</html>

header.php

<?php
session_start();

if (!isset($_SESSION['auth_user'])) {
    $_SESSION['auth_user'] = false;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>lester29</title>
</head>
<body>
    <header>
        <h1>lester29</h1>
        <p>My first website :-)</p>
        <?php if ($_SESSION['auth_user']): ?>
            <p>You're logged as <?php echo $_SESSION['username']; ?>.</p>
        <?php endif; ?>
    </header>
    <section>
        <nav>
            <ul>
                <li><a href="index.php">Home</a></li>
                <?php if ($_SESSION['auth_user']): ?>
                    <li><a href="transact_user.php?action=logout">Log out</a></li>
                <?php else: ?>
                    <li><a href="login.php">Login</a></li>
                <?php endif; ?>
            </ul>
        </nav>
    </section>
    <main>

index.php

<?php
require_once 'lib/user.php';
require_once 'header.php';
?>
    <section>
        <h2>Posts</h2>
        <?php
        try {
            $db_conn = new PDO(PDO_DSN, DB_USER, DB_PASS);
            $stmt = 'SELECT post.title AS post_title, ' .
                'author.username AS post_author, ' .
                'post.created_at AS post_created, ' .
                'post.content AS post_content ' .
                'FROM post ' .
                'LEFT JOIN author ' .
                'ON post.author_id = author.id';
            /** @var PDOStatement $posts */
            $posts = $db_conn->query($stmt);
            while ($post = $posts->fetch(PDO::FETCH_ASSOC)) {
                ?>
                <article>
                    <h3><?php echo $post['post_title']; ?></h3>
                    <p>Created at <?php echo $post['post_author']; ?> by <?php echo $post['$post_author']; ?></p>
                    <p>
                        <?php echo htmlspecialchars(nl2br($post['post_content'])); ?>
                    </p>
                </article>
                <?php
            }

            if ($posts->rowCount() == 0) {
                echo '<p>No such any posts.</p>';
            }
        } catch (PDOException $ex) {
            echo '<p>An error occurred during retrieving posts: ';
            echo $ex->getMessage();
            echo '</p>';
        }
        ?>
    </section>
<?php
require_once 'footer.php';

login.php

<?php
require_once 'header.php';
?>
    <section>
        <?php if ($_SESSION['auth_user']): ?>
            <h2>Information</h2>
            <p>
                It seems like you're already logged in.
                Do you want to <a href="transact_user.php?action=logout">log out</a>?
            </p>
        <?php else: ?>
            <h2>Sign in</h2>
            <form action="transact_user.php?action=login" method="post">
                <p>
                    <label for="username">Username</label>
                    <input type="text" name="username" id="username">
                </p>
                <p>
                    <label for="password">Password</label>
                    <input type="password" name="password" id="password">
                </p>
                <p>
                    <input type="submit" name="submit_login" value="Login">
                </p>
            </form>
        <?php endif; ?>
    </section>
<?php
require_once 'footer.php';

transact_user.php

<?php
require_once 'header.php';
require_once 'config/db.php';
require_once 'lib/user.php';
?>
    <section>
        <?php
        if (!isset($_GET['action'])) {
            ?>
            <h2>Error</h2>
            <p>No action chosen for user.</p>
            <?php
        } else {
            switch ($_GET['action']) {
                case 'login':
                    if (isset($_POST['submit_login'])) {
                        $username = $_POST['username'];
                        $password = $_POST['password'];
                        if (userExists($username, $password)) {
                            $_SESSION['username'] = $username;
                            $_SESSION['auth_user'] = true;
                            ?>
                            <h2>Success</h2>
                            <p>You're logged in.</p>
                            <?php
                        } else {
                            $_SESSION['auth_user'] = false;
                            ?>
                            <h2>Login failed</h2>
                            <p>Incorrect login or password. <a href="login.php">Try again</a></p>
                            <?php
                        }
                    }
                    break;
                case 'logout':
                    if ($_SESSION['auth_user']) {
                        $_SESSION['auth_user'] = false;
                        ?>
                        <h2>Success</h2>
                        <p>You're successfully log out!</p>
                        <?php
                    } else {
                        ?>
                        <h2>Information</h2>
                        <p>
                            It seems you're not logged in. Do you want to
                            <a href="login.php">log in</a> again?
                        </p>
                        <?php
                    }
                    break;
                default:
                    ?>
                    <h2>Error</h2>
                    <p>Invalid action <code><?php echo $_GET['action']; ?></code>.</p>
                <?php
            }
        }
        ?>
    </section>
<?php
require_once 'footer.php';

 

komentarz 30 stycznia 2024 przez Velta Maniak (52,830 p.)

Jak dla mnie:

  • W przypadku wielu zapytań bez parametrów, preferowałbym utworzenie tablicy z ich treścią i wywołanie podczas iteracji – a przynajmniej dla mnie byłoby to czytelniejsze.
  • Choć prawdopodobnie piszesz aplikację (na razie) na użytek własny, należy pamiętać, że wszelkie produkcyjne systemy implementujące strukturę przechowania informacji o użytkownikach powinny (wręcz: muszą, ze względu na obowiązujące prawo) jednostronnie ukrywać ich hasła, czego można dokonać operacją hashowania – warto o tym wiedzieć i się tym zainteresować.
    • Wypróbuj algorytm bcrypt – został wystarczająco dobrze przetestowany na przestrzeni lat. W PHP można utworzyć wartość funkcji skrótu przez funkcję password_hash, a domyślnie używanym algorytmem jest właśnie bcrypt.
    • W przypadku ukrywanych haseł, porównujesz ze sobą wersje utajnione, zamiast jawnych – w PHP odpowiada za to funkcja password_verify.
  • Nazwy tabel powinny być określone w liczbie mnogiej. Przechowujesz nie rolę (author_role), tylko wiele ról (authors_roles; swoją drogą plus za utworzenie tej tablicy pomocniczej, zapewniającej właściwą integralność), nie autora (author), a autorów (authors) – i tak dalej.
  • Dla logiki sprawdzania istnienia użytkownika w bazie, warto użyć operatora podzapytania EXISTS, ponieważ takie zapytanie jest w stanie zatrzymać się w przypadku odnalezienia pożądanego rekordu, a COUNT przeszuka tak czy tak całą tabelę, pogorszając wydajność tej operacji.
    EXISTS zwróci całkowitoliczbowy odpowiednik wartości logicznej.
$stmt = 'SELECT EXISTS(SELECT *' .
    'FROM author ' .
    "WHERE username = ? " .
    "AND passwd = ?)";
$query = $db_conn->prepare($stmt);
$query->execute([$username, $password]);
return boolval($query->fetchColumn());

 

komentarz 31 stycznia 2024 przez Ehlert Ekspert (214,940 p.)
  •  - jest też argon

Zaloguj lub zarejestruj się, aby odpowiedzieć na to pytanie.

Podobne pytania

0 głosów
4 odpowiedzi 564 wizyt
pytanie zadane 23 października 2018 w Java przez niezalogowany
0 głosów
1 odpowiedź 228 wizyt
pytanie zadane 3 marca 2018 w PHP przez fipooo Bywalec (2,880 p.)
–1 głos
1 odpowiedź 230 wizyt
pytanie zadane 8 stycznia 2020 w C i C++ przez Nabuchadonozor Gaduła (3,120 p.)

93,336 zapytań

142,332 odpowiedzi

322,418 komentarzy

62,672 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj

Wprowadzenie do ITsec, tom 1 Wprowadzenie do ITsec, tom 2

Można już zamawiać dwa tomy książek o ITsec pt. "Wprowadzenie do bezpieczeństwa IT" - mamy dla Was kod: pasja (użyjcie go w koszyku), dzięki któremu uzyskamy aż 15% zniżki! Dziękujemy ekipie Sekuraka za fajny rabat dla naszej Społeczności!

...