I'm trying to make a notification system for my essay review website here is the basic flow of what should happen:
and here are my tables' structures(MySQL):
The problem I'm having is that I can't figure out how to update the status in the relations table securely once a user accepts or declines a review request. I could set the values of the accept/decline buttons to the id of the relationship and use ajax to update the status of that relationship, but that doesn't seem secure as a user could just change the value with inspect element.
Here is an example of what I have:
request.php
<?php
//define global variables
$dbhost = "localhost";
$dbusername = "root";
$dbpassword = "";
$dbdatabase = "test";
$conn = new mysqli($dbhost, $dbusername, $dbpassword, $dbdatabase);
?>
Click here to go to user 43's notifications<br><br>
<!--Example requests-->
<form action="request.inc.php" method="post">
op_id: 43<br>
reviewer_id: 42<br>
essay_id: 34<br>
<input type="hidden" name="op_id" value="43">
<input type="hidden" name="reviewer_id" value="42">
<input type="hidden" name="essay_id" value="34">
<input type="submit" name="submit">
</form>
<form action="request.inc.php" method="post">
op_id: 43<br>
reviewer_id: 16<br>
essay_id: 135<br>
<input type="hidden" name="op_id" value="43">
<input type="hidden" name="reviewer_id" value="16">
<input type="hidden" name="essay_id" value="135">
<input type="submit" name="submit">
</form>
<form action="request.inc.php" method="post">
op_id: 78<br>
reviewer_id: 12<br>
essay_id: 25<br>
<input type="hidden" name="op_id" value="78">
<input type="hidden" name="reviewer_id" value="12">
<input type="hidden" name="essay_id" value="25">
<input type="submit" name="submit">
</form>
request.inc.php
<?php
//define global variables
$dbhost = "localhost";
$dbusername = "root";
$dbpassword = "";
$dbdatabase = "test";
$conn = new mysqli($dbhost, $dbusername, $dbpassword, $dbdatabase);
$op = mysqli_real_escape_string($conn, $_POST['op_id']);
$reviewer = mysqli_real_escape_string($conn, $_POST['reviewer_id']);
$essay = mysqli_real_escape_string($conn, $_POST['essay_id']);
$sql = "INSERT INTO `reviewer_relations` (`reviewer_id`, `essay_id`, `status`)
VALUES ('$reviewer', '$essay', 0)";
$result=mysqli_query($conn, $sql);
if($result === TRUE){
$title = mysqli_real_escape_string($conn, $reviewer." has requested to review your essay: essay#".$essay.".");
$message = mysqli_real_escape_string($conn, '<button onclick="location.href=\'scripts/review_request.php?confirmation=accept\'" class="review-accept">Accept</button><button onclick="location.href=\'scripts/review_request.php?confirmation=decline\'" class="review-decline">Decline</button>');
$sql = "INSERT INTO `notifications` (`user_id`, `title`, `message`)
VALUES ('$op', '$title', '$message')";
$result=mysqli_query($conn, $sql);
if($result === TRUE){
echo 'notification and relation insert success';
}
else{
echo 'notification insert fail: '.mysqli_error($conn);
}
}
else{
echo 'relation insert fail: '.mysqli_error($conn);
}
?>
user43notifs.php
<?php
$dbhost = "localhost";
$dbusername = "root";
$dbpassword = "";
$dbdatabase = "test";
$conn = new mysqli($dbhost, $dbusername, $dbpassword, $dbdatabase);
$sql="SELECT *
FROM notifications
WHERE user_id = 43";
$result = mysqli_query($conn, $sql);
while($row = mysqli_fetch_assoc($result)){
echo '**********************************************<br>';
echo $row['title'].'<br>';
echo $row['message'].'<br>';
}
?>
using these two table tables setup up with PHPMyAdmin:
reviewer_relations
notifications
I need a secure way to update the status column of the reviewer_relation that is represented by the notification when the user clicks on said notification's accept or decline button.
The problem is I can't figure out a way to associate the relationship id (or the reviewer_id and essay_id that describe the relationship) to it's notification without putting it directly into the notification's HTML where it's vulnerable to be changed.
I don't often ask questions, so any critique on how the question is titled, written, or stated is greatly appreciated. If any additional information is needed please ask. Thanks!
I believe I've found a solution:
I've added a token column to the user-essay relations table so that each request can be identified with a unique, cryptographically secure token (See Scott's updated answer here for token generating code).
Then when the notification is inserted into the notification table I set the value of the accept button as the token. That way when the notifications page is loaded the token can be retrieved by using .val() and used with ajax to update the status of the appropriate request. So, while a user could change the value of the button the chances of them guessing the 100-character-long token of another request is astronomically small.
Please let me know if this is not as secure as I think it to be.
Related
so no code I was just wondering if this was possible to do before I start it. So I'm going to make one php page. So no submit form with action to another php page.
On that page it will have the user type or select login information (id, pass, name etc). Below the login info I was grab the information from the above part to figure out which database they have access to and print the list of database they have access to in a html/php table.
So would this be possible to do in one page. Or do I need to make a form (to grab their information). And then from there print the list of database the user has access to. If it is possible how hard is it I'm pretty new to programming just finished HS. Will you guys be able to guide/point me in the right direction. Much help would be appreciated
you need to connect to db at top of page (or better in another file and require it)
so you can do sth like that
db.ph:
<?php
$host = '';
$dbuser = '';
$paswrd = '';
$dbname = '';
$dns = 'mysql:host=' . $host .'; dbname=' . $dbname;
try
{
$pdo = new PDO($dns, $dbuser, $paswrd);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// echo "polaczono z mysql";
}
catch(PDOException $e)
{
// echo "nie udało się połączenie: " . $e->getMessage();
}
?>
next in login page you do:
require('db.php');
if(isset( $_POST['login']))
{
require('./config/db.php');
/*
$userName = $_POST['userName'];
$userEmail = $_POST['password'];
*/
$userName = filter_var( $_POST['userName'], FILTER_SANITIZE_STRING);
$userPassword = filter_var( $_POST['userPassword'], FILTER_SANITIZE_STRING);
$stmt = $pdo -> prepare('SELECT * FROM Users WHERE name =?');
$stmt -> execute([$userName]);
$user = $stmt ->fetch();}
and you can check if its correct for example if($user->password==$userPassword)
and in html:
<form action="login.php" method="POST">
<div class="form-group">
<label for="userName">Name</label>
<input required type="text" name="userName" ">
</div>
<div class="form-group">
<label for="userPassword">Password</label>
<input required type="password" name="userPassword"/>
</div>
<button name="login" type="submit" >Login</button>
I have been having problems with a form of an website of mine. The form values are equal to their corresponding $_POST values, which are the parameters used for updating the database.
I do not want for empty form values to be updated. However, I don't want any of the input areas to be obligatory.
That means that I would be able to update only specific content, not needing to type the values in the input areas I do not want to update. I'm having problems with this, however. Empty form values are being uploaded, so the values in the database are being changed into blank values. I've looked for tutorials in SO and over the internet, and the only (functional) ones are those which turn input boxes into obligatory. That is not how I intend it to work, so it doesn't fit.
I think the best way to do this, and I am not sure, is to change, through javaScript, the "name" attribute of the input areas into blank when the submit button is set IF the values equal empty or null. I do not know how to do this, nor do I know if this is possible, or the best way.
Here is my current code on the matter:
(first, the form an the javascript)
<script>
function validade(){
var formId = document.getElementById("configForm");
var allInputs = formId.getElementsByTagName("input");
var input, i;
for (i=0; input = allInputs[i]; i++){
if (input.value == null || input.value == "") {
input.name = "";
}
}
}
<form method="post" action="" id="configForm">
<label for="home">Home:</label>
<br>
<input type="text" id="home" name="home">
<br>
<label for="apendix">Apêndice:</label>
<br>
<input type="text" name="apendix">
<br>
<label for="about">Sobre:</label>
<br>
<input type="text" name="sobre">
<br>
<label for="contato">Contato:</label>
<br>
<input type="text" name="contato">
<br><br>
<input type="submit" value="Carregar" name="submit">
</form>
<?php require_once('editaForma.php'); ?>
(Secondly, the database query and $_POST values:)
<?php //credentials
if (isset($_POST["submit"])){
$server = 'hypotetical';
$user = 'hypotetical';
$pw = 'hypotetical';
$BD = 'hypotetical';
//estabelece a conexão
$conn = mysqli_connect($server, $user, $pw, $BD);
if (!$conn) {
die ('<span style="color: #FF0000;">"connection failed: "</span>' . mysqli_connect_error());
}
$home = $_POST["home"];
$apendix = $_POST["apendix"];
$sobre = $_POST["sobre"];
$contato = $_POST ["contato"];
$query = "UPDATE form SET
home= '$home',
apendix= '$apendix',
sobre= '$sobre',
contato= '$contato'
WHERE id='1'";
//$query = "INSERT INTO form (home, apendix, sobre, contato) VALUES ('$home', '$apendix', '$sobre', '$contato')";
if (mysqli_query($conn, $query)){
echo "Alterações feitas com sucesso";
} else {
echo "ERRO!" . $query . "<br>" . mysqli_error($conn);
}
mysqli_close($conn);
}
?>
Yes, I know the DB is prone to SQL injection. I'm trying to get everything up and running first, and once all of this is set, I'll look onto security matters before the website is online.
I've been having this problem for over a week and can't figure a way out of it.
Thank you for your time and attention, in advance.
EDIT
I wish I could select two answers for the solving ones. Both of them right down led me to the solving of the problem, each helping me to see the holes in my code. As I cannot choose both, I chose the one who helped me to solve the last issues. Thank you all so much!
Build your query dynamically, by skipping empty values
$p = &$_POST; //make $p refer to $_POST
$query = "UPDATE from SET ";
if($p['home']) $query .= " home = '$p[home]' ,";
if($p['apendix']) $query .= " apendix = '$p[apendix]' ,";
if($p['sobre']) $query .= " sobre = '$p[sobre]' ,";
if($p['contato']) $query .= " concato = '$p[contato]' ,";
$query = trim($query, ','); //remove any trailing comma
$query = "WHERE id = 1";
you can then execute the query. Oh and don't forget to check that at least 1 of the variables was available. If they're all empty, don't execute.
And yeah, your code is highly vulnerable.
Glaring security holes aside, I would usually build up a string, something like this:
$home = $_POST["home"];
$apendix = $_POST["apendix"];
$sobre = $_POST["sobre"];
$contato = $_POST ["contato"];
$query = "UPDATE form SET ";
if(!empty($home)) {
$query .= "home= '$home',";
}
if(!empty($apendix)) {
$query .= "apendix= '$apendix',";
}
if(!empty($sobre)) {
$query .= "sobre= '$sobre',";
}
if(!empty($contato)) {
$query .= "contato= '$contato',";
}
// strip off any extra commas on the end
$query = rtrim($query, ',');
$query .= "WHERE id='1'";
Building the query with the comma at the end also allows you to easily add more options later if you need to.
I did it, in a simple way using NULLIF
set potato = NULLIF(potato,'')
<? php
include_once("connection.php");
// email and password sent from form
$email = $_POST['email'];
$password = $_POST['password'];
// To protect MySQL injection (more detail about MySQL injection)
$email = stripslashes($email);
$password = stripslashes($password);
$email = mysqli_real_escape_string($connection, $_POST['email']);
$password = mysqli_real_escape_string($connection, $_POST['password']);
$sql = "SELECT * FROM users WHERE email='$email' and password='$password'";
$result = mysqli_query($connection, $sql);
// Mysql_num_row is counting table row
$count = mysqli_num_rows($connection, $result);
// If result matched $username and $password, table row must be 1 row
if ($count == 1) {
session_start();
$_SESSION['loggedin'] = true;
$_SESSION['email'] = $email;
}
?>
<div id="openModal" class="modalDialog">
<div>
X
<form class="pop" method="post" action="login.php">
<p class="login">LOGIN</p>
<div class="form-group">
<div class="left-inner-addon "><i class="fa fa-envelope-o fa-fw"></i>
<input type="email" name="email" class="form-control" id="email" placeholder="Email" required>
</div>
</div>
<div class="form-group">
<div class="left-inner-addon"><i class="fa fa-key fa-fw"></i>
<input type="password" name="password" class="form-control" id="password" placeholder="Password" required>
</div>
</div>
<p>Forgot Password?</p>
<div class="form-group">
<button class="btn btn-default" role="button" name="login" id="login">LOGIN</button>
</div>
</form>
</div>
</div>
<? php
$host = 'localhost';
$user = 'root';
$password = '';
$db = 'members';
$connection = mysqli_connect($host, $user, $password, $db);
if ($connection) {
echo "Connected Successfully";
} else {
echo "Error connecting: . mysqli_connect_error()";
}
?>
I have index.php, connection.php and login.php files. I have already created register.php for sign up it's working fine. In login.php, it is connected successfully but throwing an error in Warning: mysqli_num_rows() expects exactly 1 parameter, 2 given
One more thing I want to figure out how do I know if the users is login in my website I means I want to find out if it is stored to the database or I don't know as I'm new to SQL and after login there should valid or invalid email and password but not showing. In my database, I have created table the list of id, username, email, password. Please help in proper way and simple, don't confuse me.
The mysqli_num_rows() function returns the number of rows in a result set.
It accepts only one parameter say $result which is Required. $result is a result set identifier returned by mysqli_query(), mysqli_store_result() or mysqli_use_result(). You are passing the $connection object along with the $result which causes the issue.
For saving sessions in Database, reffer these posts
Storing Sessions in a Database
or
Saving PHP's Session data to a database
config.php
< ?php
$mysql_hostname = "hostname";
$mysql_user = "username";
$mysql_password = "password";
$mysql_database = "database";
$bd = mysql_connect($mysql_hostname, $mysql_user, $mysql_password)
or die("Opps some thing went wrong");
mysql_select_db($mysql_database, $bd) or die("Opps some thing went wrong");
?>
Login.php
include("config.php");
session_start();
if($_SERVER["REQUEST_METHOD"] == "POST")
{
// username and password sent from Form
$myemailid=addslashes($_POST['emailid']);
$mypassword=addslashes($_POST['password']);
$sql="SELECT id FROM admin WHERE username='$myemailid' and passcode='$mypassword'";
$result=mysql_query($sql);
$row=mysql_fetch_array($result);
$active=$row['active'];
$count=mysql_num_rows($result);
// If result matched $myusername and $mypassword, table row must be 1 row
Session -> variables hold information about one single user, and are available to all pages in one application
if($count==1)
{
session_register("myusername");
$_SESSION['login_user']=$myusername;
header("location: welcome.php");
}
else
{
$error="Your Login Name or Password is invalid";
}
}
?>
Logout.php
< ?php
session_start();
if(session_destroy())
{
header("Location: login.php");
}
?>
I have a form and I have been developing this website with my localhost and it is working perfect. But when I moved the files to my dedicated server it no longer gets any of the values when I submit the form. I have narrowed it down to two things. A either my server has restricted configurations on the form being submitted but I do not use global variables to get the values so that shouldnt be the problem or the php on the server is older and not allowing me to submit the values the server version i found out is <5.6. Here is my form code:
<form id="company-form" action="scripts/create-library.php" method="post" enctype="multipart/form-data">
<button id="hide-form"><img src="images/minus.png"/></button>
<h3>Add Library Item Form</h3>
<input class="c-name" type="text" name="file-display-name" placeholder="File Display Name"/>
<select class="companies-dd" name="companies">
<?php
require_once("../../scripts/connection.php");
// Select all companies and related data
$sql = "SELECT company_id, company FROM companies ORDER BY company_id";
$stmt = $conn->prepare($sql);
$stmt->execute();
$stmt->bind_result($c_id, $c);
while($stmt->fetch()){
echo "<option value='".$c_id."'>".$c."</option>";
}
?>
</select>
<select class="companies-dd" name="library-cats">
<?php
// Select all companies and related data
$sql = "SELECT library_category_id, library_category FROM library_categories ORDER BY library_category_id";
$stmt = $conn->prepare($sql);
$stmt->execute();
$stmt->bind_result($l_id, $l);
while($stmt->fetch()){
echo "<option value='".$l_id."'>".$l."</option>";
}
$conn->close();
?>
</select>
<input id="uploadFile" class="image-name" type="text" name="library-file-name" placeholder="No Logo File Chosen" disabled="disabled"/>
<input id="uploadBtn" type="file" name="library-file"/>
<input type="submit" value="Create Item"/>
</form>
This is added the page via ajax call on a button click.
Then the script that I run after the form is submitted is
<?php
session_start();
ini_set('display_errors',1);
error_reporting(-1);
$display = trim($_POST["file-display-name"]);
$company = trim($_POST["companies"]);
$lib_cat = trim($_POST["library-cats"]);
if(empty($display) || empty($company) || empty($lib_cat)){
$_SESSION["errormsg"] = "Required information is missing please fill out all required fields.";
header("Location: ../library.php");
}
else{
$file_name = $_FILES['library-file']['name'];
$tmp_name = $_FILES['library-file']['tmp_name'];
$file_size = $_FILES['library-file']['size'];
$file_type = $_FILES['library-file']['type'];
$fp = fopen($tmp_name, 'r');
$content = fread($fp, filesize($tmp_name));
$content = base64_encode($content);
fclose($fp);
if(!get_magic_quotes_gpc()){
$file_name = addslashes($file_name);
}
if(empty($content)){
$_SESSION["errormsg"] = "Required information is missing please fill out all required fields (File).";
header("Location: ../library.php");
}
else{
require_once("connection.php");
// Insert the logo into the companies photo table
$sql = "INSERT INTO library_items(filename, mime_type, file_size, file_item, display_name, company_id, library_category_id) VALUES(?,?,?,?,?,?,?)";
$stmt = $conn->prepare($sql);
$stmt->bind_param('sssssss', $file_name, $file_type, $file_size, $content, $display, $company, $lib_cat);
if(!$stmt->execute()){
$_SESSION["errormsg"] = "Failed to add library item: ".mysqli_error();
header("Location: ../library.php");
}
}
unset($_SESSION["errormsg"]);
$_SESSION["successmsg"] = "Library Item successfully added into the database.";
header("Location: ../library.php");
}
?>
It gives me the errors with the variables saying that they are undefined index's for the form names.
I have read other posts but none of them has helped me. Is there something I am not seeing or I have to change on my server for me to use this?
Well it looks like the two files I had for testing the upload and display ended up corrupt when I downloaded them. This was causing the server to throw and error saying that the text was outside the US-ASCII range. Since this was not able to be display it didnt transfer any of the forms values. That was the weirdest bug I ever had I guess I will have to start testing my pdfs for errors also.
I am using two values for 1 input box, when user selects multiple boxes the values will be submitted to submit_checkbox.php. I want to save the 2nd value i.e value after "|" sign in the php form. How can I do it ? My code is as follows :-
<form name='checkbox' method="post" action="submit_checkbox.php">
<b><h3>Select option</h3></b>
<input type="hidden" name="qq1[]" value="null">
<input type="checkbox" name="qq1[]" value="ABC|DEF"> A<br>
<input type="checkbox" name="qq1[]" value="GHI|IJK"> B<br>
<input type="checkbox" name="qq1[]" value="LMN|PQR"> C<br>
<input type="submit" value="SUBMIT" >
</form>
And in "submit_checkbox.php" the code is as follows :-
<?php
$dbhost = 'localhost';
$dbuser = 'root';
$dbpass = 'root1';
$conn = mysql_connect($dbhost, $dbuser, $dbpass);
mysql_select_db("my_db") or die(mysql_error());
list($value1,$value2)=explode('|',$_POST['qq1']);
$values=implode(',', $value2);
$sql = "INSERT INTO print_chk VALUES ('$values')";
$retval = mysql_query( $sql, $conn );
if(! $retval )
{
die('Could not enter data: ' . mysql_error());
}
else
{
echo "Success";
}
?>
However, I am unable to put the 2nd value in the sql table "print_chk".
Your $_POST['qq1'] is an array, so you have to explode every element of it and then make the string from this. Try something like this, it works for me:
//Get the second part
function GetSecond($v) {
if ($v != 'null') {
$a = explode('|',$v);
return $a[1];
}
else {
return '';
}
}
//Since $_POST['qq1'] is an array, get the second part of each item
$v = array_map('GetSecond',$_POST['qq1']);
//Filter out the empty strings
$v = array_filter($v);
//Implode the list
$values = implode(',',$v);
//Insert to DB
$sql = 'INSERT INTO print_chk VALUES ("'.mysql_real_escape_string($values).'")';