I have a form in dashboard.php to create invoice and this is submitted to invoice.php
Now my invoice.php inserts the Invoice and the customer into the database and then shows me a invoice order filling form.
if i refresh this page, it inserts a new invoice for the same customer, how do i avoid this.
I was reading that we could avoid it by redirection, but in my case how do i use it. Some thing like a PRG(post/redirect/get) how to use it?
Do i need to make an intermediate page before going to insert items to invoice
The pattern you've heard about is this: Post/Redirect/Get.
In general, POST is for actions, GET is for views. So you never show a user a page on a POST request. Instead, you redirect them to a page they'll request with GET, which will not cause any changes in your database.
after successful form submission do a redirect to the same page and optionally indicate that the submission was successful
Example: invoice.php
if (count($_POST)) {
if (/*post data is valid*/) {
/*do whatever is needed*/
header('Location: invoice.php?success');
}
} else if (isset($_GET['success'])) {
echo "Form successfuly submitted";
}
Let dashboard.php post the form data to insert.php, which will process the data and then forward to invoice.php. Use sessions to transport the data from one file to another. Here is insert.php:
<?php
session_start();
if (session_is_registered("invoiceVars"))
session_unregister("invoiceVars");
if (!session_is_registered("errors"))
session_register("errors");
$errors = array();
if (!session_is_registered("formVars"))
session_register("formVars");
foreach($_POST as $f_varname => $f_value)
$formVars[$varname] = trim(EscapeShellCmd(stripslashes($value)));
// process your data and write it to the database or return to dashboard.php with errors, then:
session_unregister("errors");
session_register("invoiceVars");
$invoiceVars = array();
foreach ($formVars as $i_varname => $i_value)
$invoiceVars[$i_varname] = $i_value;
session_unregister("formVars");
// add additional variables
$invoiceVars["coupon"] = 'unique_coupon_code';
// invoice.php will process the data and display it
// it has session_start(); at the top, to have $invoiceVars available
header('Location: invoice.php');
exit();
?>
header(); and exit(); will flush $_POST, so it is no longer available when the user hits back on his browser.
Here is an example code for you:
# database.php
$db = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
session_start();
# dashboard.php
require_once("database.php");
function getSavedValue() {
global $db;
$sql = "SELECT input_text FROM temp_table WHERE sess_key='?'";
$query = $db->prepare($sql);
$query->bindParam(session_id());
$query->execute();
if ($query->rowCount() == 1)
return $query->fetch();
else
return " ";
}
<form action="invoice.php" method="POST">
<input type="text" name="getThisInfo" value="<?php echo getSavedValue(); ?>"/>
<input type="submit" value="Send"/>
</form>
# invoice.php
if (isset($_POST["getThisInfo"]) && /* validation check */ 1) {
require_once("database.php");
$textInput = $_POST["getThisInfo"];
$sql = "INSERT INTO perm_table(invoice_info) VALUES('?');";
$query = $db->prepare($sql);
$query->bindParam($textInput);
$query->execute();
$rows = $query->rowCount();
echo "$rows invoices were inserted.";
unset($_POST["getThisInfo"]);
header("success.php");
} else {
header("dashboard.php");
}
Related
I have a PDO prepared statement that I use on a single-image page where a user is going to be able to download that specific image. I currently have a counter that increments each time the download button is clicked which updates a counter value in a MySQL database. I'd like to transfer and use the download counter from the single-image page onto an index page that shows multiple images.
Because the form element is inside a while loop when you click the download button, the current functionality updates the counter for all of the images on this page (i.e. everything inside the loop).
Obviously I don't think I can move it outside of the loop because it then won't update anything at all?
How do I get it so the when the download button is clicked for a particular instance of the form, it only updates that specific form elements details?
PHP
<?php
// get username from URL parameter
isset($_GET['username']) ? $username = $_GET['username'] : header("Location: index.php");
// fetch filename details from database
$stmt = $connection->prepare("SELECT * FROM imageposts WHERE username = :username");
$stmt->execute([':username' => $username]);
while ($row = $stmt->fetch()) {
$db_image_filename = htmlspecialchars($row['filename']);
// -- HTML that shows the image file goes here --
// update counter for number of downloads of an image
if (isset($_POST['download'])) {
try {
$sql = "UPDATE imageposts SET downloads = downloads +1 WHERE filename = :filename";
$stmt = $connection->prepare($sql);
$stmt->execute([
':filename' => $db_image_filename
]);
} catch (PDOException $e) {
echo "Error: " . $e->getMessage();
}
}
?>
// download button that updates the counter
<form method="post">
<button type="submit" name="download">Download</button>
</form>
<?php } ?>
One way to approach this is to add some PHP outside of your loop, that references a value from a hidden <form> element inside the loop - in this case you have a $db_image_filename value you could use.
<form method="post">
<button type="submit" name="download">Download</button>
<input type="hidden" name="hidden-filename" value="<?php echo $db_image_filename; ?>">
</form>
Then reference this value in PHP:
<?php
if (isset($_POST['download'])) {
// value from hidden form element
$hidden_filename = $_POST['hidden-filename'];
try {
$sql = "UPDATE imageposts SET downloads = downloads +1 WHERE filename = :filename";
$stmt = $connection->prepare($sql);
$stmt->execute([
':filename' => $hidden_filename
]);
header("location: " . $_SERVER['PHP_SELF']);
} catch (PDOException $e) {
echo "Error: " . $e->getMessage();
}
}
?>
After doing my SQL Schema (Different types of users redirected to same page (index.php) with different content), I'm starting to make my login system.
I now have this:
function login($email,$password){
$mysqli = $this ->dbConnect();
if($mysqli){
$strQuery = "SELECT USERS.ID, USERS.EMAIL, TYPES.NAME FROM `USERS` LEFT JOIN `TYPES` ON USERS.TYPEID = TYPES.ID WHERE `EMAIL` = '$email' AND `PASSWORD` = '$password'";
$recordSet = $mysqli->query($strQuery);
$row = $recordset->fetch_assoc();
if($recordset->num_rows>0){
$_SESSION['auth'] = $row['ID'];
$_SESSION['username'] = $row['EMAIL'];
$_SESSION['type'] = $row['NAME'];
header ("location:"index.php");
return true;
}
//....
}
}
Does this look good? Is the query right? Any suggestions for improvement?
UPDATE
I have my login working now. And it's redirecting to index.php. But in index php I don't have acess to the $_SESSIONS variables i have stored on my function login. Is there any problem with the attribuitions? Placing the header inside the function not good?
Thanks :)
I summarized the previous comments.
1. Issue: you didn't used the same variables
function login($email,$password){ and $strQuery = " ... WHERE EMAIL = '$email' AND PASSWORD = '$password'";
2. Recomendation: use the same namming convention
On your SQL request you used two way to use fields: USERS.EMAIL and EMAIL = (with ` arround).
Use the same. This will be easier for later & debugging.
i.e.: of course, you should not use table.field each time. Not mandatory for example if you have only one table OR if the fields are not shared between them. For my perosnnal usage, I always use this table.field. This will prevent any future issue :)
3. Protect your data from any injection
Example:
$post_email = isset($_POST['email']) ? htmlspecialchars($_POST['email']) : null;
Alter call
$this->login($post_email, ...)
And finally use something like this to protect your data:
$email = $mysqli->real_escape_string($email);
and you are ready for your request:
" SELECT [..] FROM users as u [...] WHERE u.email = '$email' "
4. Or use specific functions
Example (real_escape_string not needed anymore):
$stmt = $dbConnection->prepare('SELECT * FROM users WHERE email = ? AND password = ?');
$stmt->bind_param('s', $email);
$stmt->bind_param('s', $password);
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
// do something with $row
}
http://php.net/manual/fr/class.mysqli.php
5. Sessions
If you want to activate sessions on a spacific page, the first code (at the first line) should be session_start().
Calling this method will activate the sessions and load the $_SESSION variable with content.
<?php // index.php
session_start(); // first line
// ... code
var_dump($_SESSION);
?>
&
<?php // page.php
session_start(); // first line
// ... code
$_SESSION['test'] = time();
Header('Location: index.php');
?>
Visit index.php -> nothing on the debug
Visit page.php -> you will be redirected on index.php
On index.php -> you will have data
Enjoy session :p
6. Handle specific data
To begin with, you should coose a way to store the credential access (ACL) for each user. For example, store on the database some values as 100001, and each number is a yes/no access for a specific action (binary access mode) ; another system is to store the level '1,2,3,4,5' ... or 'member,customer,admin, ...'. So many ways :)
I will choose the USER.ACCESS = member|customer|admin solution
On the login page
// is user successfully logged
$_SESSION['access'] = $row['access']; // member|customer|admin
// Header('Location: index.php');
On any page of your site:
if( in_array($_SESSION['access'], ['member', 'admin']) ) {
echo 'You are a member, you can see this part';
}
if( in_array($_SESSION['access'], ['customer', 'admin']) ) {
echo 'You are a customer, you can see this part';
}
Or
if( checkAccess() ) {
echo 'Welcome user !';
if( checkAccess(['member', 'customer']) ) {
echo 'This is a section for member, customer or admin :)';
}
if( checkAccess('member') ) {
echo 'You are a member, you can see this part';
}
if( checkAccess('customer') ) {
echo 'You are a customer, you can see this part';
}
}
function checkAccess($types = null) {
if( !isset($_SESSION['access']) )
return false; // not logged
if( is_null($types) )
retun true; // if empty, provide info about loggin.
// admin has always access to all sections of the website
$hasAccess = in_array($_SESSION['access'], ((array) $types) + ['admin']);
return $hasAccess; // user is logged + has accessor not ?
}
Of course, you can also use includes
if( checkAccess('member') ) {
include 'secret_page_for_member.php';
}
Or, at the begening of the included page:
<?php
if( !checkAccess('admin') ) {
return '403 - Not authorized';
// die('403');
// throw new Exception('403');
}
// your code
?>
Recently I built a form using HTML, CSS, and JavaScript. I then entered the PHP required to send the data that is inputted in the form, to my database. After I finished, what I thought was necessary for it to work, I ended up with a blank page when I executed the code. The form and everything disappeared. This is my PHP code:
<?php
require("$_SERVER[DOCUMENT_ROOT]/connect.php");
$email = $username = $type = $question = "";
if ($_SERVER["REQUEST_METHOD"] == "POST")
{
if(!empty($_POST))
{
if(isset($_POST["email"], $_POST["username"], $_POST["type"], $_POST["question"])
{
$email = test_input($_POST["email"]);
$username = test_input($_POST["username"]);
$type = test_input($_POST["type"]);
$question = test_input($_POST["question"]);
$premium = ($_POST["premium"]);
$member = $_POST["member"];
$terms = $_POST["terms"];
if ($member != "NO")
{
$member = "YES";
}
}
if(!empty($email) && !empty($username) && !empty($type) && !empty($question) && !empty($terms))
{
$insert = $db->prepare("INSERT INTO QuestionSubmission (Email, Username, Type, Question, Member, Premium, Date) VALUES (?, ?, ?, ?, ?, ?, NOW())");
$insert->bind_param("ssssss", $email, $username, $type, $question, $member, $premium);
if($insert->execute())
{
header("Location: landing.php");
die();
}
}
}
}
function test_input($data)
{
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
return $data;
}
?>
The "member" part is a check box where the user can optionally select to become a member. It is unchecked initially, and i've set a value of "NO" for that. Also, there is a hidden check box that is already checked with a value of NO...this is the "premium" check box. Lastly, there is a check box for agreeing to the terms. This is initially unchecked, but the user has to check it so it won't be empty and for the form to process.
Could you please explain what I have to do in order for my form to work properly?
Also, the " require("$_SERVER[DOCUMENT_ROOT]/connect.php"); " part is where my connection to the database code is located. This code and the form code is located in the same page.
Replace require("$_SERVER[DOCUMENT_ROOT]/connect.php"); with require_once $_SERVER[DOCUMENT_ROOT]."/connect.php");, you're not using a variable - the $_SERVER can't be used like you're using it. This is why you're getting a "blank page of death", if you check your error_log you'd see that it has a syntax-error because of it.
Furthermore, you're checking if(!empty($_POST)) - this could really be any POST-form. You should remove this code
if ($_SERVER["REQUEST_METHOD"] == "POST")
{
if(!empty($_POST))
{
as you're checking if the inputs are set just below the above code.
As a final note, when you're using die();, you should use exit; instead. They really do the same thing, but usage of die() is more for error-checking, like "Script can't run any further - die now!", while exit; is more like "I would like to stop the script from running now, I'm done - thanks!".
Normally it’s easier to include the processing code inside the form page. That way, if you encounter errors, you can:
allow the code to fall through to the form again
persist old values by using the value="…" attribute
Roughly it looks like this:
<?php
$email=$username=''; // etc
if(isset($_POST['submit'])) { // or whatever you name the submit button
// validate data
if(!$errors) {
// process
// new location
}
// retain values from above
}
?>
<form>
<label>Name: <input type="text" name="username" value="<?php print $username; ?>"></label>
<label>Email: <input type="text" name="email" value="<?php print $email; ?>"></label>
<!-- etc -->
<button type="submit" name="submit">Send Message</button>
</form>
For ease and management, you can put the PHP code above into a separate file to be included.
The problem your sample above is that although you do redirect to a new page on success, you don’t go anywhere otherwise.
If you want to do it with a separate processing script, you will need to conclude by redirecting back to the original form on failure. However, you will find that persisting old data is more difficult that way.
I am trying to allow users to upload a profile image for my site. The file upload part works fine (although there is nothing deterring them form uploading a non-image file). However I can't get it to update the "profile" row in the mysql database. I think it has something to do with the $_SESSION['user_id'] but I'm not sure. Any ideas why it wont update the row?
<?php
if(isset($_POST['submit'])){
$temp = explode(".",$_FILES["file"]["name"]);
$newfilename = ('ProfileImage') . rand(1,99999) . '.' .end($temp);
move_uploaded_file($_FILES['file']['tmp_name'],"images/profile/" . $newfilename);
$con = mysqli_connect("localhost","root","","testsite");
$q = mysqli_query($con,"UPDATE user SET profile = '".$newfilename."' WHERE username = '".$_SESSION['user_id']."'");
}
?>
<form action="" method="post" enctype="multipart/form-data" name="">
<input type="file" name="file" required>
<input type="submit" name="submit" value="Update Image">
</form>
Just in case you need to see this, this is the "functions.php" page where $_SESSION['user_id'] is defined:
<?php
#session_start();
function loggedin(){
if(isset($_SESSION['user_id']) && !empty($_SESSION['user_id'])){
return true;
} else {
return false;
}
}
function getuser($id, $field){
$query = mysql_query("SELECT $field FROM user WHERE UserID='$id'");
$run = mysql_fetch_array($query);
return $run[$field];
}
?>
I am assuming your error is here:
$q = mysqli_query($con,"UPDATE user SET profile = '".$newfilename."' WHERE username = '".$_SESSION['user_id']."'");
And that it should be like this:
$q = mysqli_query($con,"UPDATE user SET profile = '".$newfilename."' WHERE UserID = '".$_SESSION['user_id']."'");
Looks like you switched out UserId with username.
When it comes to the page where you supposedly is setting $_SESSION['user_id'], the code you displayed here does no such thing.
It defines two functions, but does not call them, and does not assign a value to user_id.
So first, update the query as shown above, then do a var_dump of $_SESSION, to see if you have stored anything in it. If not you need to go back a few steps, and make sure you actually set the session variables.
What I want is to show the error (message), only if the user do a false action. For example, if the field is empty, it will show (Please fill all the fields). I've already done that, but the problem that I have is that it shows also if the user enter to the page for the first time, meaning it does NOT respects the (if condition) that I have written !
The question :
How to show the message only if one of the fields is empty ?
Any ideas on how I can solve it ?
Here is my code :
<?
$conn = mysqli_connect('localhost', 'db', 'db_pass', 'db_name') or die("Error " . mysqli_error($conn));
$email = filter_var(trim($_POST['email']), FILTER_VALIDATE_EMAIL);
$old_password = trim($_POST['old_pass']);
$new_password = trim($_POST['new_pass']);
$email = mysqli_real_escape_string($conn,$email);
$old_password = mysqli_real_escape_string($conn,$old_password);
$new_password = mysqli_real_escape_string($conn,$new_password);
if(empty($email) || empty($old_password) || empty($new_password)){
echo 'Please fill all the fields !<br>';
}
else{
$sql="UPDATE users SET pass='$new_password' WHERE email='$email' AND pass='$old_password'" or die("Error " . mysqli_error($conn));
$result = mysqli_query($conn,$sql);
mysqli_close($conn);
}
if($result){
echo'Password changed successfully !';
}
elseif(!$result) {
echo 'The email/password you provided is false !';
}
?>
Validation of any form happens in the "action" file within a condition i.e. the validation should be subjected to the event of user clicking the submit button. For this to work you should check that
1. Your form has a submit button with a name property set to say submit (can be anything)
eg: <input type="submit" name="submit" id="someid" value="Submit" />
2. The form must have action property pointing to a processor file
eg: <form action = "somefile.php" method = "post">
3. In the somefile.php file the validation code must be within a condition which checks for the event of form been submited
eg://somefile.php
<?php
if(isset($_POST['submit']{
//all the validation code goes here
}else{
//for a single page form and validation
// the code for displaying the form can go here
?>
I suggest you to do this:
First define a variable with plain $_POST[] for eg $name = $_POST['name'];
Then, check if all the vatiables you've define are empty or not.
Lastly, Use escape_string() or whatever you want.
The solution is to check for a variable that you know will always be set if the form is submitted, usually the submit button.
For example, if your form ends like this:
...
<input type="submit" name="change_password" value="Change password" />
</form>
then in the PHP code you could check
if(isset($_POST['change_password'])) {
// The submit button was in the POSTed data, so this is a form submit
} else {
// This is a new page load
}
Alternatively, if you are POSTing the data, you can check which HTTP method was used to call the form:
if($_SERVER['REQUEST_METHOD'] == 'POST') {
// Form was posted
} else {
// $_SERVER['REQUEST_METHOD'] == 'GET'
}
The pattern I commonly use is:
$showForm = true;
if( is_form_postback() ) {
if( data_is_valid() ) {
redirect_to_thank_you_page();
} else {
show_validation_errors();
$showForm = false;
}
}
if($showForm) {
// Print the form, making sure to set the value of each input to the $_POSTed value when available.
}