diff --git a/README.md b/README.md index 0c0d1f3..f539ce0 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,27 @@ # hacker news clone +![](https://img.photouploads.com/file/PhotoUploads-com/SRE3.png) + a bad hacker news clone made in php +this was created on garbage free hosting so it probably works anywhere you can get php 7.3 and some new version of mysql + +(yes it breaks after php 8.0 i dont care to figure out why) + # setup -wip \ No newline at end of file +1. copy the files over to your server +2. modify `config.php` to use your database login, base url, and email +3. import `database.sql` into your database +4. go to whatever your base url is set as +5. profit i think idk + +# why you shouldn't use this + +- the account system is from some tutorial +- there's probably some vulnerability that allows code execution +- comments SUCK!!! they look so awful +- it uses mysqli instead of something more secure like pdo +- i think you can post without an account and i forgot to fix that +- the logout button is always visible even when you log out +- the navbar buttons are inconsistent \ No newline at end of file diff --git a/account/activate.php b/account/activate.php new file mode 100755 index 0000000..07fb665 --- /dev/null +++ b/account/activate.php @@ -0,0 +1,31 @@ +prepare('SELECT * FROM accounts WHERE email = ? AND activation_code = ?')) { + $stmt->bind_param('ss', $_GET['email'], $_GET['code']); + $stmt->execute(); + // Store the result so we can check if the account exists in the database. + $stmt->store_result(); + if ($stmt->num_rows > 0) { + // Account exists with the requested email and code. + if ($stmt = $con->prepare('UPDATE accounts SET activation_code = ? WHERE email = ? AND activation_code = ?')) { + // Set the new activation code to 'activated', this is how we can check if the user has activated their account. + $newcode = 'activated'; + $stmt->bind_param('sss', $newcode, $_GET['email'], $_GET['code']); + $stmt->execute(); + echo 'Your account is now activated! You can now login!'; + } + } else { + echo 'The account is already activated or doesn\'t exist!'; + } + } +} +?> \ No newline at end of file diff --git a/account/authenticate.php b/account/authenticate.php new file mode 100755 index 0000000..d12e2b2 --- /dev/null +++ b/account/authenticate.php @@ -0,0 +1,52 @@ +prepare('SELECT id, password FROM accounts WHERE username = ?')) { + // Bind parameters (s = string, i = int, b = blob, etc), in our case the username is a string so we use "s" + $stmt->bind_param('s', $_POST['username']); + $stmt->execute(); + // Store the result so we can check if the account exists in the database. + $stmt->store_result(); + + + if ($stmt->num_rows > 0) { + $stmt->bind_result($id, $password); + $stmt->fetch(); + // Account exists, now we verify the password. + // Note: remember to use password_hash in your registration file to store the hashed passwords. + if (password_verify($_POST['password'], $password)) { + // Verification success! User has logged-in! + // Create sessions, so we know the user is logged in, they basically act like cookies but remember the data on the server. + session_regenerate_id(); + $_SESSION['loggedin'] = TRUE; + $_SESSION['name'] = $_POST['username']; + $_SESSION['id'] = $id; + header('Location: home.php'); + } else { + // Incorrect password + echo 'Incorrect username and/or password!'; + } +} else { + // Incorrect username + echo 'Incorrect username and/or password!'; +} + + + $stmt->close(); +} +?> \ No newline at end of file diff --git a/account/home.php b/account/home.php new file mode 100755 index 0000000..04e7a08 --- /dev/null +++ b/account/home.php @@ -0,0 +1,37 @@ + + + + + + + Settings + + + + + +
+

Settings

+

Welcome back, !

+
+ + \ No newline at end of file diff --git a/account/index.php b/account/index.php new file mode 100755 index 0000000..e5fc3c9 --- /dev/null +++ b/account/index.php @@ -0,0 +1,34 @@ + + + + + + Login + + + + +
+

Login

+
+ + + + + +
+ +
+
+ + \ No newline at end of file diff --git a/account/logout.php b/account/logout.php new file mode 100755 index 0000000..2a16e81 --- /dev/null +++ b/account/logout.php @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/account/profile.php b/account/profile.php new file mode 100755 index 0000000..dc47073 --- /dev/null +++ b/account/profile.php @@ -0,0 +1,67 @@ +prepare('SELECT password, email FROM accounts WHERE id = ?'); +// In this case we can use the account ID to get the account info. +$stmt->bind_param('i', $_SESSION['id']); +$stmt->execute(); +$stmt->bind_result($password, $email); +$stmt->fetch(); +$stmt->close(); +?> + + + + + + Profile + + + + + +
+

Profile Page

+
+

Your account details are below:

+ + + + + + + + + + + + + +
Username:
Password:
Email:
+
+ + +
+
+
+ + \ No newline at end of file diff --git a/account/register.html b/account/register.html new file mode 100755 index 0000000..05216f7 --- /dev/null +++ b/account/register.html @@ -0,0 +1,31 @@ + + + + + Register + + + + +
+

Register

+
+ + + + + + + +
+
+
+ + + \ No newline at end of file diff --git a/account/register.php b/account/register.php new file mode 100755 index 0000000..14b815a --- /dev/null +++ b/account/register.php @@ -0,0 +1,68 @@ + 20 || strlen($_POST['password']) < 5) { + exit('Password must be between 5 and 20 characters long!'); +} +// We need to check if the account with that username exists. +if ($stmt = $con->prepare('SELECT id, password FROM accounts WHERE username = ?')) { + // Bind parameters (s = string, i = int, b = blob, etc), hash the password using the PHP password_hash function. + $stmt->bind_param('s', $_POST['username']); + $stmt->execute(); + $stmt->store_result(); + // Store the result so we can check if the account exists in the database. + if ($stmt->num_rows > 0) { + // Username already exists + echo 'Username exists, please choose another!'; + } else { + // Username doesn't exists, insert new account +if ($stmt = $con->prepare('INSERT INTO accounts (username, password, email, activation_code) VALUES (?, ?, ?, ?)')) { + // We do not want to expose passwords in our database, so hash the password and use password_verify when a user logs in. + $password = password_hash($_POST['password'], PASSWORD_DEFAULT); + $uniqid = uniqid(); + $stmt->bind_param('ssss', $_POST['username'], $password, $_POST['email'], $uniqid); + $stmt->execute(); + $from = $verifyemail; + $subject = 'Account Activation Required'; + $headers = 'From: ' . $from . "\r\n" . 'Reply-To: ' . $from . "\r\n" . 'X-Mailer: PHP/' . phpversion() . "\r\n" . 'MIME-Version: 1.0' . "\r\n" . 'Content-Type: text/html; charset=UTF-8' . "\r\n"; + // Update the activation variable below + $activate_link = $baseurl . '/account/activate.php?email=' . $_POST['email'] . '&code=' . $uniqid; + $message = '

Please click the following link to activate your account "'. $_POST['username'] . '": ' . $activate_link . '

'; + mail($_POST['email'], $subject, $message, $headers); + echo 'Please check your email to activate your account!'; +} else { + // Something is wrong with the SQL statement, so you must check to make sure your accounts table exists with all three fields. + echo 'Could not prepare statement!'; +} + } + $stmt->close(); +} else { + // Something is wrong with the SQL statement, so you must check to make sure your accounts table exists with all 3 fields. + echo 'Could not prepare statement!'; +} +$con->close(); +?> \ No newline at end of file diff --git a/account/style.css b/account/style.css new file mode 100755 index 0000000..ece0878 --- /dev/null +++ b/account/style.css @@ -0,0 +1,189 @@ +* { + box-sizing: border-box; + font-family: -apple-system, BlinkMacSystemFont, "segoe ui", roboto, oxygen, ubuntu, cantarell, "fira sans", "droid sans", "helvetica neue", Arial, sans-serif; + font-size: 16px; +} +body { + background-color: #435165; +} +.login { + width: 400px; + background-color: #ffffff; + box-shadow: 0 0 9px 0 rgba(0, 0, 0, 0.3); + margin: 100px auto; +} +.login h1 { + text-align: center; + color: #5b6574; + font-size: 24px; + padding: 20px 0 20px 0; + border-bottom: 1px solid #dee0e4; +} +.login form { + display: flex; + flex-wrap: wrap; + justify-content: center; + padding-top: 20px; +} +.login form label { + display: flex; + justify-content: center; + align-items: center; + width: 50px; + height: 50px; + background-color: #3274d6; + color: #ffffff; +} +.login form input[type="password"], .login form input[type="text"] { + width: 310px; + height: 50px; + border: 1px solid #dee0e4; + margin-bottom: 20px; + padding: 0 15px; +} +.login form input[type="submit"] { + width: 100%; + padding: 15px; + margin-top: 20px; + background-color: #3274d6; + border: 0; + cursor: pointer; + font-weight: bold; + color: #ffffff; + transition: background-color 0.2s; +} +.login form input[type="submit"]:hover { + background-color: #2868c7; + transition: background-color 0.2s; +} + + +.navtop { + background-color: #2f3947; + height: 60px; + width: 100%; + border: 0; +} +.navtop div { + display: flex; + margin: 0 auto; + width: 1000px; + height: 100%; +} +.navtop div h1, .navtop div a { + display: inline-flex; + align-items: center; +} +.navtop div h1 { + flex: 1; + font-size: 24px; + padding: 0; + margin: 0; + color: #eaebed; + font-weight: normal; +} +.navtop div a { + padding: 0 20px; + text-decoration: none; + color: #c1c4c8; + font-weight: bold; +} +.navtop div a i { + padding: 2px 8px 0 0; +} +.navtop div a:hover { + color: #eaebed; +} +body.loggedin { + background-color: #f3f4f7; +} +.content { + width: 1000px; + margin: 0 auto; +} +.content h2 { + margin: 0; + padding: 25px 0; + font-size: 22px; + border-bottom: 1px solid #e0e0e3; + color: #4a536e; +} +.content > p, .content > div { + box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.1); + margin: 25px 0; + padding: 25px; + background-color: #fff; +} +.content > p table td, .content > div table td { + padding: 5px; +} +.content > p table td:first-child, .content > div table td:first-child { + font-weight: bold; + color: #4a536e; + padding-right: 15px; +} +.content > div p { + padding: 5px; + margin: 0 0 10px 0; +} + + +* { + box-sizing: border-box; + font-family: -apple-system, BlinkMacSystemFont, "segoe ui", roboto, oxygen, ubuntu, cantarell, "fira sans", "droid sans", "helvetica neue", Arial, sans-serif; + font-size: 16px; +} +body { + background-color: #435165; + margin: 0; +} +.register { + width: 400px; + background-color: #ffffff; + box-shadow: 0 0 9px 0 rgba(0, 0, 0, 0.3); + margin: 100px auto; +} +.register h1 { + text-align: center; + color: #5b6574; + font-size: 24px; + padding: 20px 0 20px 0; + border-bottom: 1px solid #dee0e4; +} +.register form { + display: flex; + flex-wrap: wrap; + justify-content: center; + padding-top: 20px; +} +.register form label { + display: flex; + justify-content: center; + align-items: center; + width: 50px; + height: 50px; + background-color: #3274d6; + color: #ffffff; +} +.register form input[type="password"], .register form input[type="text"], .register form input[type="email"] { + width: 310px; + height: 50px; + border: 1px solid #dee0e4; + margin-bottom: 20px; + padding: 0 15px; +} +.register form input[type="submit"] { + width: 100%; + padding: 15px; + margin-top: 20px; + background-color: #3274d6; + border: 0; + cursor: pointer; + font-weight: bold; + color: #ffffff; + transition: background-color 0.2s; +} +.register form input[type="submit"]:hover { + background-color: #2868c7; + transition: background-color 0.2s; +} \ No newline at end of file diff --git a/account/updatebio.php b/account/updatebio.php new file mode 100755 index 0000000..41856fd --- /dev/null +++ b/account/updatebio.php @@ -0,0 +1,29 @@ +connect_error) { + die("Connection failed: " . $conn->connect_error); +} +// $sql = "INSERT INTO accounts (bio) +// VALUES ('". substr($_POST['bio'],0,150). "')"; + +$sql = "UPDATE accounts +SET bio = '".substr($_POST['bio'],0,150)."' +WHERE username = '".htmlspecialchars($_SESSION['name'], ENT_QUOTES)."';"; + +if ($conn->query($sql) === TRUE) { + header('Location: profile.php'); +} else { + echo "Error: " . $sql . "
" . $conn->error; +} + +$conn->close(); + +?> \ No newline at end of file diff --git a/account/userprofile.php b/account/userprofile.php new file mode 100755 index 0000000..c0525ff --- /dev/null +++ b/account/userprofile.php @@ -0,0 +1,68 @@ +query("SELECT bio FROM accounts WHERE username = '".htmlspecialchars($_GET['user'])."'"); + + +$con->query("SELECT * FROM accounts WHERE username = '".htmlspecialchars($_GET['user'])."'"); + +while($rows = mysqli_fetch_assoc($quersy)) { + $userbio = htmlspecialchars($rows['bio']); +} + +?> + + + + + + Profile + + + + + + +
+

Profile of

+
+ + + + + + + + + +
Username:
Bio:
+ +
+
+ + \ No newline at end of file diff --git a/com.php b/com.php new file mode 100755 index 0000000..03fb5c1 --- /dev/null +++ b/com.php @@ -0,0 +1,30 @@ +connect_error) { + die("Connection failed: " . $conn->connect_error); +} + +if ($_POST['comment'] == "") { + die('Empty'); +} + +$sql = "INSERT INTO comments (commenter, postid, comment) +VALUES ('". htmlspecialchars($_SESSION['name'], ENT_QUOTES). "', '". htmlspecialchars($_GET['postid']) ."', '".substr(htmlspecialchars($_POST['comment']), 0, 150)."')"; + +if ($conn->query($sql) === TRUE) { + header('Location: comments.php?postid='.htmlspecialchars($_GET['postid'])); +} else { + echo "Error: " . $sql . "
" . $conn->error; +} + +$conn->close(); + +?> \ No newline at end of file diff --git a/comments.php b/comments.php new file mode 100755 index 0000000..21dad90 --- /dev/null +++ b/comments.php @@ -0,0 +1,91 @@ + + + + + + + + + <?= $siteName; ?> + + + + + + +
+
+ + +
method="post"> + + +
+


+connect_error) { + die("Connection failed: " . $conn->connect_error); + } + + $quersy = $conn->query("SELECT * FROM comments WHERE postid = '".htmlspecialchars($_GET['postid'])."' ORDER BY id DESC"); + +// $conn->query($query) + +// $conn->query("SELECT * FROM users"); + + while($rows = mysqli_fetch_assoc($quersy)) { + print "
".htmlspecialchars($rows['commenter'])."
".htmlspecialchars($rows['comment'])."
"; + } + + +?> + + + \ No newline at end of file diff --git a/config.php b/config.php new file mode 100755 index 0000000..9b7abbc --- /dev/null +++ b/config.php @@ -0,0 +1,15 @@ + \ No newline at end of file diff --git a/database.sql b/database.sql new file mode 100644 index 0000000..5349990 --- /dev/null +++ b/database.sql @@ -0,0 +1,112 @@ +-- phpMyAdmin SQL Dump +-- version 5.2.1 +-- https://www.phpmyadmin.net/ +-- +-- Host: localhsot +-- Generation Time: Feb 23, 2024 at 08:14 PM +-- Server version: 5.7.40-log +-- PHP Version: 8.1.27 + +SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; +START TRANSACTION; +SET time_zone = "+00:00"; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8mb4 */; + +-- +-- Database: `hndatabase` +-- + +-- -------------------------------------------------------- + +-- +-- Table structure for table `accounts` +-- + +CREATE TABLE `accounts` ( + `id` int(11) NOT NULL, + `username` varchar(50) NOT NULL, + `password` varchar(255) NOT NULL, + `email` varchar(100) NOT NULL, + `activation_code` varchar(50) DEFAULT '', + `bio` text NOT NULL COMMENT 'bio' +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `comments` +-- + +CREATE TABLE `comments` ( + `id` int(11) NOT NULL, + `commenter` varchar(50) NOT NULL, + `postid` varchar(255) NOT NULL, + `comment` varchar(100) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `posts` +-- + +CREATE TABLE `posts` ( + `id` int(6) UNSIGNED NOT NULL, + `url` varchar(255) NOT NULL, + `title` varchar(30) NOT NULL, + `poster` varchar(50) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +-- +-- Indexes for dumped tables +-- + +-- +-- Indexes for table `accounts` +-- +ALTER TABLE `accounts` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `comments` +-- +ALTER TABLE `comments` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `posts` +-- +ALTER TABLE `posts` + ADD PRIMARY KEY (`id`); + +-- +-- AUTO_INCREMENT for dumped tables +-- + +-- +-- AUTO_INCREMENT for table `accounts` +-- +ALTER TABLE `accounts` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `comments` +-- +ALTER TABLE `comments` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `posts` +-- +ALTER TABLE `posts` + MODIFY `id` int(6) UNSIGNED NOT NULL AUTO_INCREMENT; +COMMIT; + +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/index.php b/index.php new file mode 100755 index 0000000..34c214c --- /dev/null +++ b/index.php @@ -0,0 +1,138 @@ + + + + + + + + + <?= $siteName; ?> + + + + + + +
+connect_error) { + die("Connection failed: " . $conn->connect_error); +} + +$quersy = $conn->query("SELECT * FROM posts ORDER BY id DESC"); + +// $conn->query($query) + +$conn->query("SELECT * FROM users"); + +print "
"; +while($rows = mysqli_fetch_assoc($quersy)) { + print ""; +} +print "
".htmlspecialchars($rows['title'])." commentsPosted by: ".htmlspecialchars($rows['poster'])."
"; + +?> + + + \ No newline at end of file diff --git a/sub.php b/sub.php new file mode 100755 index 0000000..b76dd72 --- /dev/null +++ b/sub.php @@ -0,0 +1,32 @@ +connect_error) { + die("Connection failed: " . $conn->connect_error); +} + +if ($_POST['url'] == "") { + die('Empty'); +} +if ($_POST['title'] == "") { + die('Empty'); +} +$sql = "INSERT INTO posts (url, title, poster) +VALUES ('". $_POST['url']. "', '". $_POST['title'] ."', '".htmlspecialchars($_SESSION['name'], ENT_QUOTES)."')"; + +if ($conn->query($sql) === TRUE) { + header('Location: index.php'); +} else { + echo "Error: " . $sql . "
" . $conn->error; +} + +$conn->close(); + +?> \ No newline at end of file diff --git a/submit.php b/submit.php new file mode 100755 index 0000000..bb5771c --- /dev/null +++ b/submit.php @@ -0,0 +1,116 @@ + + + + + + + + <?= $siteName; ?> + + + + + + +
+
+
+URL:

+Title:

+ +
+
+ + \ No newline at end of file diff --git a/users.php b/users.php new file mode 100755 index 0000000..61ee6d7 --- /dev/null +++ b/users.php @@ -0,0 +1,137 @@ + + + + + + + + + <?= $siteName; ?> + + + + + + +
+connect_error) { + die("Connection failed: " . $conn->connect_error); +} +$quersy = $conn->query("SELECT * FROM accounts"); + +// $conn->query($query) + +$conn->query("SELECT * FROM users"); + +print "
"; +while($rows = mysqli_fetch_assoc($quersy)) { + print ""; +} +print "
".htmlspecialchars($rows['username'])."
"; + +?> + + + \ No newline at end of file