I'm working on a project to learn PHP, and I'm realizing I have a ways to go.
I'm creating a basic site that allows traditional account creation for a user to go in and build email lists. They can then send out an email that it personalizes and makes a form letter. At the end of this letter I am including a link that the reader can go to (unique to each person) where they can select and fill out a short form that I would like to be able to process back into another table in my database. All the while keeping track of who said what.
I have everything working perfectly right now, but I didn't realize until just barely that the only reason it works is because I was already authenticated as the main user (when I was opening up test emails and saving my responses). So when I open an email and go to the link and fill out the form on a computer that doesn't have any cookies or session variables cached, I can't save because I have no access to the database.
My question
The URL that shows up in each person's email has a guid at the end that is made up of a combination of things that uniquely identifies that person. I'd really prefer not to make the email recipients make an account with me, but I need to be able to process their responses.
How can I give them access to writing to the database even though they don't have full login credentials? I know that they are legitimate based on their URL, can that somehow be made to work?
EDIT: Some code
Here is an example of a URL in the email:
mysite.com/process.php?guid=abcdefghijklmnopqrstuvwxyz
When clicked, I pull the guid out of the $_GET and look up some information about it. Now that I think about it, it doesn't really make sense that I can look up stuff in the database off the bat, but that's another issue. After the form is filled out, and the save button pressed, this is what is going on:
<?php
drequire("library/database.inc.php");
require("library/check-user.inc.php");
include("library/head1.inc.php"); // Load meta data
include("library/head2.inc.php"); // Load scripts
include("library/header.inc.php"); // Load header
$email = $_POST['email'];
$eqp = $_POST['eqp'];
$month = $_POST['month'];
$sqlDel = "DELETE FROM results WHERE eqp = $eqp AND month = '$month' AND email = '$email'";
mysql_query($sqlDel) or die('Error, could not delete.');
$sqlIns = "INSERT INTO results (month, email, eqp) VALUES ('$month', '$email', $eqp);";
mysql_query($sqlIns) or die('Error, could not insert.');
echo'Success! Keep up the good work!';
?>
But the insert doesn't occur. I am assuming it is because I really don't have a connection to the database.
You need to post some code, but as a pseducode answer
function post_for_user_to_write($special_user_ID_in_email)
{
if ($special_user_ID_in_email == valid_special_ID())
{
// Connect to database
// Post data to database
}
}
Related
I'm not familiar with PHP / MySQL and Emails. And I'm pretty sure this question has been asked somewhere already, but I cannot find it. So I apologise if this is troubling and thank you in advance!
Is it possible to do something that user has to click on a link in email first before the user is added into database???
And you know how, for some websites, they have a unique web address for each email validation (Shown in red on the picture)? How do they create a webpage that's unique in for every email ?
Picture credited: https://kayako.atlassian.net/wiki/download/attachments/5734920/subs-validation.png?version=1&modificationDate=1291956283000&api=v2
Thank you a lot for the attention! If it's possible, I prefer not having straight scripts that I can copy and paste because I like to find out myself :P But please do give me some hints because I'm totally lost.
If there's anything that's not clear, please tell me, I'll try my best to clarify it!
The Registration process
User fills out a form online with basic details including an email and password, and submits the form to register.php
register.php adds user info to a temporary location, such as a pending_users table which has all the fields the user submitted along with an expiration and an activation_code fields. This code can be any random, impossible to guess value. eg: hash('sha1', mt_rand(10000,99999).md_rand(10000,99999)). Just don't do anything predictable such as hash the current time, or the username
register.php sends an email to the user with a URL that will link to activate.php and that includes the activation code. eg: example.com/activate.php?code=a2ef24... The email should also inform the user of the expiration (1 to 12hrs validity seems ok to me)
When user clicks the link, she triggers a GET request to activate.php. In doing so, the user proves ownership of the email address
activate.php gets the code from the request parameters, eg: $code=$_GET['code']. With that code, the script queries the pending_users table for the record matching that code.
If the code is found, check that it hasn't expired before proceeding. Expiration prevents someone else much later who gets in the user's account from completing the registration.
If the code is valid, capture the user details from the matching record and delete that record from pending_users table.
Write a matching record in the regular users table. Until this is done, the user could not log in because login script only checks the users table, and ignores the pending_users table.
Registration complete.
Security Note I:
For your users' protection, never store passwords in cleartext. When you receive it from the registration form (eg: $_POST['pwd'], do:
$pwd = $_POST['pwd'];
//first validate; it should meet minimum requirements
$pwd_hash = password_hash($pwd, PASSWORD_DEFAULT); // <- the hash gets stored
Later, to verify the password, do:
password_verify($cleartext_pwd, $pwd_hash);
It will return true if the password is correct; false otherwise.
Security Note II:
For your protection, never insert user supplied values directly in your DB queries. This means any value that arrives from the outside. Not just usernames, emails, passwords... but also values that you're getting back from the user such as activation_code above or cookie values or headers (eg User-Agent). Instead, learn to use prepared statements. This will protect you from SQL injection.
Not sure if it's possible to add datas in database after the validation...
When I want to do something like that, I create a data in the users table (or metas users table) like "validate".
If this data is "true", then the user already did the validation and he can use his account. If it's still set on "false", the user didn't validate his account : he can't use it.
With that, you have to make sure the account is validate when the user tries to log in, but it's not a big deal ^^
Hope it's usefull.
Those are not a unique websites, there is only one script validating the registration finalization. The incoming requests (when the user has clicked the link) are routed all to the same script by means of server side "request rewriting", so that the random token value is available as an argument (parameter) to the script execution.
What the script does: it checks if that random token value does exist in the database where it has been generated and stored before when the user actually registered.
The only thing left to do for that script is to remove the confirmation random token and/or set a flag indicating that the registered use has actually confirmed his identify (email address) by clicking the link.
Easy and straight forward. Hard to bypass, since you cannot guess what random token value has been generated for what registered user without receiving the email. However take into consideration that it is trivial for an attacking script to use anonymous email services (one time email addresses) to receive and evaluate such a confirmation request, if the process is known to the attacker.
I want to create a system so a User can Signup / Login, and when they go on they are directed to a page of custom like blahurl.com/nations/customid, each ID is already generated when they sign up called UserID, and I want to be able to go blahurl.com/nations/92 and that person will pop up and their SQL info will be displayed.
I want so when they register they can already access these pages, I don't want to have to make a page for each person that signs up. How would I go about doing this? And then searching for them by their MySQL UserName?
The table in my MySQL is called users
The ID us called UserID
The Username is called UserName
The password is called Password
The registration date is called RegDate
When people register they are automatically put to my submit-form.php which is this:
<?php
$username=$_POST['UserName'];
$password=$_POST['Password'];
$leadername=$_POST['LeaderName'];
$nationname=$_POST['NationName'];
$email=$_POST['Email'];
//Database connection
require_once("config.php");
require_once("checkregister.php");
//mysql query to insert value to database
$query=mysql_query("INSERT INTO users (UserName, Password, LeaderName, NationName, Email)
VALUES ('$username', '$password', '$leadername', '$nationname', '$email')");
//if value inserted successyully disply success message
if($query)
{
echo '<div style="color:#008000; font-weight:bold;">Your Account has been Created! <del>Check your Email for Verification Code!</del> in the future you will need to Verify your Account, for right now just go back to the Website!</div>';
} else
{
//error message
echo '<div style="color:#c24f00; font-weight:bold;">Registration Failed: Could not INSERT to Query! (Could not Connect to Database)<br>Back to Website</div>';
}
?>
config.php connects to the Database
checkregister.php checks to make sure that the Username / Leader Name
does not yet exist and that no spaces are left empty.
You've asked how to link to a non-fancy URL, which is fairly easy. You just need to get the primary key, which will have been created from your auto-increment column:
submit-form.php
// Create user
// #todo Fix injection vuln
$query=mysql_query( ... );
// If successful...
if($query)
{
// Get the inserted primary key
$userId = mysql_insert_id();
?>
<div style="color:#008000; font-weight:bold;">
Your account has been created,
<a
href="nations.php?userId=<?php echo $userId ?>"
>go back to the website!</a>
</div>
<?php
}
You can then read it in the other page:
nations.php
<?php
// Read it only if it exists
$userId = isset($_GET['userId']) ? $_GET['userId'] : null;
// Escape any apostrophes in the ID, to avoid SQL injection
$cleanUserId = mysql_real_escape_string($userId);
// Always check if it exists, the user may have tampered with the URL
$sql = "SELECT * FROM users WHERE UserID = '$cleanUserId'";
$query = mysql_query($sql);
// Do something with the result...
Some general notes now follow. These are probably too much to absorb in one go, but if you do some reading around them, they will help in the long term:
When you do a POST operation, you should generally follow it up with a redirect, unless it has failed (and you need to render validation/error messages). This is because browsers don't like to render content in a post method, and if you then refresh the screen, browsers will ask you to confirm if you wish to re-submit the operation. In most cases you do not, since it will repeat what happened in the post (in this case, creating a user)
To carry information over a POST-redirect, often the session is used. Some frameworks offer "flash messages", which are just session values that are cleared after one page view. Alternatively the query string can be used. Either way, this would be useful to carry your user ID from the post page to a result page, so that refreshing the screen does not result in re-submission.
Logic and presentation is intermingled here, which will make for an app that is rather hard to maintain. When you get chance, try to move all your logic (e.g. database calls) to the top of the page, and put your presentation HTML at the bottom of the script. Tiny pieces of PHP can be used where dynamic content is required.
You may find using a web framework helpful to give further structure and modularity to your code. There is no "best" PHP framework, so choose from Slim, Laravel, Aura, Symfony, Zend, Cake, CodeIgniter, and several others. It's worth trying a few to see what you prefer.
Swap to a newer database library - the mysql_ calls are no longer maintained. They will throw notices in PHP 5.5+.
As per the comments, use parameter binding and password hashing for security. Don't go live until these are both fixed.
If you are not using version control, it's worth getting into the habit. Git is pretty simple to use, and integrates automatically with a number of IDE applications (e.g. NetBeans).
I have a problem with an online study I'm conducting, which is structured as a multi-page form. A processing file sends the data from each page to the database and assigns a unique ID based on user IP addresses. Subsequent pages use separate processing files and retrieve the ID from the first table by matching the IP address with the unique ID, using this php code:
$result = mysql_query("SELECT * FROM $table0 WHERE IP='$ipstr'");
$row = mysql_fetch_array( $result );
$id = $row['ID'];
I got a group of students to do the survey in a campus computer lab, but little did I realise, that all the computers were on one IP address. Consequently, a whole lot of valuable data did not get stored to the database.
While I've learned an important lesson about campus networking and the embarrassing implications of neglecting to consider the possibility of shared IP addresses in my code, I thought I should ask if there is any way to retrieve the data from the form submits that weren't inserted into the database. Any ideas?
No way to retrieve the data again.
As of now you cannot do anything as it is lost. But in future you can use logs. you can retrieve your data if you create logs for form submitted data. You can then check this apache logs for each submitted form data and put a log for the sql results if it was successful you do not need to worry but if the query failed you can read that data from logs.
I'm developing a website where in it will list names from database as links. I'm already up to the point that when one user clicks on the name, it will pass the name's details to another page to view the email format etc. I just need a suggestion on how I can do this as I'm not an expert with php yet. I'm still studying more advanced codes. So,
clicks on the name,
views the details as an email and a confirmation button,
send the mail. I just need suggestions on how to make this easy. I am getting to know the script for mail(). Thanks
EDIT :
Since, there are a lot who think it's confusing. I just need advice on how I will pass data from one page to another then email.
What do you mean by getting the names as links?. do you have the link field in the database which is retrieved along with the name?
This is the solution based on what I understand from your vague question:
You have names which are retrieved from the database. Also retrive the id from the database. Display these names as links pointing to a different PHP page. lets name the php page as user.php. so the link will be:
$name = "You go this name from USER TABLE";
$id = "YOU GOT THIS ID FROM USER TABLE";
$name
Now in your user.php, retrive the id
$name = $_GET["userID"]; // make sure you do some parsing to avoid sql injection
// Retrieve all the information about this guy like email address etc from the database
// put everything into a form with a Confirm button which when clicked will mail it to the individual
// I think you should be able to figure out the mail part.
i've just made a sign script for my website. The form posts the data to itself and then checks to see if all the data is correct. if so it then loads a payment page. To load this payment page i use:
header(location: payment.php);
So i want to send data over to the page that im loading, i though i could use:
$userid = mysql_insert_id();
to get the last id added to the database but its not working, maybe im using it wrong though. Anyway, i know what in my database the email address on every record with be unique as well as the id, so i thought maybe i'd change the header to:
header(location: payment.php?email=$email);
This way it would put the email address into the URL and i'd be able to find the user again on the next page by using:
$email = $_GET['email'];
Now this works fine and from that i can get the users details from the database. However i thought that putting someones email address into the URL wasn't best practice but i can't for the life of me think of another way around it.
Any suggestions or good ways of doing this?
Thanks for the time.
Use persistent data to be associated with client
Use $_SESSION to associate data with the current client, don't forget to call session_start (); before you actually append data to the array.
Note: This will require the use of cookies in the client
Include functionality into one file
Though if the only purpose of the page where the data is posted is to validate data, do that and then you could include ("payment.php");, no redirects required.
Or put the functionality of the form-landing page in payment.php instead.
Use a GET-parameter sent to payment.php
You could also redirect to payment.php?id=<val> where <val> is the id of the transaction, though you should not expose the real id since this will decrease security.
Unless you check to see so that a user can only access ids who actually belongs to them.
A hash of the payment info can be used instead since this value will not easily, or at all, be guessed.
I think you should go back and check why mysql_insert_id() isn't working. That'll be the best way to get the data across.
Just start a session before doing anything in the two pages.
<?php session_start()
and on the verification page do something like
$_SESSION['email'] = $email;
and finally on the payment page you can get the email then via
$email = $_SESSION['email'];
Once you update your payment, create/ get your GUID or your unique id from your DB, and redirect to your success page with your guid or unique id, exposing this id will not harm anyway.