Link to home
Start Free TrialLog in
Avatar of Wanda Marston
Wanda MarstonFlag for Canada

asked on

PHP Forms - passing information to a Database.

PHP - two separate forms on two pages. I want to combine them into one form on one page.

Form No. 1 - uploading three images -

<form enctype="multipart/form-data" action="add_file2.php" method="post">

	<fieldset><legend>Fill out the form to upload a file:</legend>
    <input type="hidden" name="MAX_FILE_SIZE" value="524288">
	
	<?php // Create the inputs.
	for ($i = 0; $i < $counter; $i++) {
		echo '<p><b>File:</b> <input type="file" name="upload' . $i . '" /></p>';
	}
	?>
	</fieldset>
	
    <input type="hidden" name="submitted" value="TRUE" />
	
    
    //<div align="center"><input type="submit" name="submit" value="Submit" /></div>

Open in new window


Form No 2. - general information

    <form action="PostANoticeYE.php" method="POST" accept-charset="utf-8">
        
         <p><label for="description" class="SmallHeading"><strong>Description</strong></label>
Please enter a brief description. You have up to 300 characters.
      <div id="div1">Characters Left = 300</div>
<?php create_form_input('description', "textarea", $PostANoticeYE_errors,"maxlength='300' onkeyup='return chlimit(this)' "); ?>


<br />

		<label for="amount" class="SmallHeading"><strong>Amount</strong></label>
        <p class="noticeType">Less than 20 characters please.
		<?php create_form_input('amount', 'text', $PostANoticeYE_errors); ?><br />

		<label for="currency" class="SmallHeading"><strong>Currency</strong></label>
        <p class="noticeType">Enter the currency that you used to pay the organization or individual.
        For example – CAD$, US$, Yen, Pesos, Franc, Pound</small>
        <?php create_form_input('currency', 'text', $PostANoticeYE_errors); ?><br />
        
        <p><label for="location" class="SmallHeading"><strong>Location</strong></label>
        <p>Where did this occur? e.g. town, city or geographical area
		<?php create_form_input('location', 'text', $PostANoticeYE_errors); ?><br />
       
       <br />  
    
    <button class="button" style="vertical-align:center"><span>Submit Your Notice &rarr;</span></button>
	<input type="hidden" name="id" value="' . $_SESSION['user_id'] . '" />
</form>

Open in new window

Avatar of Chris Stanyon
Chris Stanyon
Flag of United Kingdom of Great Britain and Northern Ireland image

Any fields that exist in a form and have the name attribute set, will be submitted along with the form, and accessible in the request's array - either POST or GET (usually POST).

You would need to create one form containing all your fields (including the File inputs), and when that form was submitted, you would need to process the $_FILES array to handle the uploads and the $_POST array to handle the rest of the information.

Given our previous conversations - now would be a really, really good time to upgrade from the deprecated mysql function and start using the modern replacements. I would personally suggest going with PDO - it's just cleaner to use. As you're taking input from a user (filling in a form), you should absolutely use a Prepared statement to insert the data into a database - not doing so just leaves you wide open to SQL Injection attacks.

If you'd like some code hints, let me know and I can post up a simple example.
Avatar of Wanda Marston

ASKER

Yes, I understand what you are saying above and agree that I should update my website and coding. So PDO is a form of PHP? I had asked my web hosting company awhile ago about the coding and they had said that if I was not getting any error messages to not worry about it. Anyway, I think they have upgraded their system to be using PHP 7.

Yes, I am interested in receiving some code hints.
Not great advice from your Hosting Company - by the time you do get errors, your whole application will have fatally collapsed. They should be advising you to update ... NOW!

PDO is a Database Library. Years ago, when we wanted to work with the MySQL database in PHP we used a collection of functions that all started with mysql_. These came from the mysql DB Library. That library has now been retired (deprecated and removed), so we don't have it as an option anymore. Instead we have a choice of 2 newer database libraries - mySQLi and PDO. Both are capable of talking to your MySQL Database, and it's largely a personal choice as to which one you use. As I said, I prefer the PDO library for several reasons.

Now when you're inserting your data into the database, you need to make sure it's safe to do so. A user could enter anything they want into your form, and a malicious user could actually enter code that would break your database - this is known as a SQL Injection attack. There are several ways to prevent it, but one of the more effective measures is to use Prepared Statements. The idea is that you send a query to your database that doesn't contain the data - it just contains placeholders for the data. Then in a separate process, you just send the data. Both PDO and mySQLi are capable of running prepared statements, but I think the PDO way is cleaner and simpler.

First off, you will need to create a connection to your database. The best way to do this is to create a separate file that only contains the code needed to connect to your database (it's easier to reuse this way). Create a file and call it something like db.php, with the following content:

<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);

$username = 'username';
$password = 'password';
$dsn      = 'mysql:host=localhost;dbname=yourDb;charset=utf8mb4'; 
$options  = [
    PDO::ATTR_EMULATE_PREPARES   => false,
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ,
];

try {
    $db = new PDO($dsn, $username, $password, $options);
} catch(PDOException $e) {
    die( $e->getMessage() );
}

Open in new window

Change the username and password to match your own. Also change yourDb in the DSN to match the name of the database you want to connect to.

Now to create your main form page. Take a look at this very simple example:

<?php require_once 'db.php'; ?>
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Chris Stanyon // EE - 29118007</title>
   </head>
    <body>

        <?php
        if ( ! empty($_POST) ):
            try {
                
                $insert = $db->prepare("INSERT INTO myTable (firstName, lastName, emailAddress) VALUES (:first, :last, :email)");
                $insert->execute([
                    'first'     => $_POST['firstname'],
                    'last'      => $_POST['lastname'],
                    'email'     => $_POST['email'],
                ]);

            } catch (PDOException $e) {
                printf( "<p>Error: %s</p>", $e->getMessage() );
            }
        endif;
        ?>

        <form method="post">
            <input type="text" name="firstname" placeholder="Enter your first name">
            <input type="text" name="lastname" placeholder="Enter you last name">
            <input type="email" name="email" placeholder="Enter your email address">

            <input type="submit" value="Go">
        </form>

    </body>
</html>

Open in new window

It's not a production-ready script by any means, as there's no error checking or data valdaition in there, but it's a good simple starting point, and something for you have a go at. It should help you see the basic moving parts.

Right at the top of the script, we're including the db.php script we created earlier. This will create a new connection to the Database, and store that connection in a variable called $db.

Then we check to make sure the POST array is not empty. If the form hasn't been submitted, then it will be empty. We then create a Prepared Statement and store it in a variable called $insert (you can call this whatever you like, but keep it meaningful). This statement looks very much like a normal query, except that we use named placeholders where we would normally put our data. A placeholder is a simple name preceded by a colon, and you can call them whatever you like (you can also use anonymous placeholders, but more on that later). Also note that we DO NOT wrap these placeholder in quotes.

Once we've prepared the statement, we then need to run it. You do this by calling the execute() method on the statement. This is where you actually send the information to be stored. You pass an array into the execute() method containing key / value pairs. The key must match the name of a placeholder, and the value is the data to be stored. That's the basics of using Prepared Statements with PDO - Prepare the statement, and execute it. Simple!

The whole process is wrapped in a try/catch block, which is a modern, object-oriented way of handling errors. If an error happens, an Exception is thrown. This exception is caught in the catch() block, and the error message is echoed out to the screen.

Have a read through and try creating it on your own system. Once you've got your head around it, we can build it up to be more robust.
I am working on this and seem to be making a database connection but now the code for the counter is not working. I have tried several variations on this and getting many different kinds of error messages, depending on what I have done. This code is at the very bottom of my index page.

This is the latest error message -  line 117:
mysqli_query() expects parameter 1 to be mysqli, object given


$q = "UPDATE `counter` SET `counter` = `counter` + 1";
$r = mysqli_query ($conect, $q);
$connect = ($db);
$q = "SELECT counter FROM counter";
$r = mysqli_query($connect, $q);
if (mysqli_num_rows($r) > 0) {
while ($count = mysqli_fetch_array($r, MYSQLI_NUM)) {
echo "<p>Hello Visitor Number $count[0]!<br />
Thanks for visiting!</p>" ;		
}
}
?>

Open in new window

Hey Wanda,

I don't know what line 117 is, but the code above looks like it has a typo on line 2 - $conect.

Also, I don't understand what you're doing with line 3 - you seem to setting one variable to another for no apparent reason. You've decided to go with mysqli instead of pdo, so just make sure your connection is set up correctly. If you store the connection in a varable called $db, then just use that variable. If you call it $connect, then just use $connect.

Finally, if your count table just has one record, then there's no point in looping through it. Just select it and move on.

One final piece of advice - name your variables using something more meaningful than $q and $r. It'll make it more intelligible:

mysqli_query($db, "UPDATE counter SET counter = counter + 1");

$countResult = mysqli_query($db, "SELECT counter FROM counter LIMIT 1");

if ($count = mysqli_fetch_object($countResult)) {
    echo "<p>Hello Visitor Number {$count->counter}!<br />Thanks for visiting!</p>";     
};

Open in new window

I just noticed that there is a typo with my code for the counter. However, I amended the word "connect" and it still does not work.
OK. Let's look at the error:

mysqli_query() expects parameter 1 to be mysqli, object given

It's telling you that the first parameter (argument) to use when you call mysqli_query() has to be an instance of the mysqli class (a valid connection to your database). So if we look at your code:

$r = mysqli_query ($connect, $q);

The 1st parameter is called $connect, and the error is indicating that $connect is NOT an instance of the mysqli class (it's something else!). The way you create an instance of that class is with the new keyword, so to connect to your database you do something like this:

$connect = new mysqli(.....);

That is what makes $connect an instance of the mysqli class. You could also use the mysqli_connect() function, but I would advise you stick to the new keyword.

You haven't posted up the code that shows your connection, so I can't tell whether you've got that right or wrong.

Generally speaking, you assign the mysqli instance to a variable and either catch an exception if it failed, or explicitly check whether the connection was successful. If it wasn't successful, then you report an error and exit.

Post up your connection code (remove any passwords!) and I'll take a look
Thanks. Following is the connection code that I have in a separate file. I thought that I was using the PDO code as you suggested.

<?php

error_reporting(E_ALL);
ini_set('display_errors', 1);

$username = 'xxx';
$password = 'xxx';
$dsn      = 'mysql:host=xxxxxxxxxxxxxxmysql.com;dbname=yarnextras;charset=utf8mb4'; 
$options  = [
    PDO::ATTR_EMULATE_PREPARES   => false,
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ,
];

try {
    $db = new PDO($dsn, $username, $password, $options);
} catch(PDOException $e) {
    die( $e->getMessage() );
}


$connect = ($db);

function escape_data ($data) { 

	global $connect; // Database connection.
	
	// Strip the slashes if Magic Quotes is on:
	if (get_magic_quotes_gpc()) $data = stripslashes($data);
	
	// Apply trim() and mysqli_real_escape_string():
	return mysqli_real_escape_string ($connect, trim ($data));
	
} // End of the escape_data() function.

function get_password_hash($password) {
	
	// Need the database connection:
	global $connect;
	
	// Return the escaped password:
	return mysqli_real_escape_string ($connect, hash_hmac('sha256', $password, 'c#haRl891', true));
	
} // End of get_password_hash() function.

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of Chris Stanyon
Chris Stanyon
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
The counter works now with the code that you have supplied.

It appears that anything that I thought I knew before is now completely redundant. The only reference I have now is what I find on the web and I have to completely redo my website - although for experienced people like yourself, would be considered simple.

Just saw this on the web which looks like the password is out there in the open for anyone to see.
$password = "asdf123";
$secret = password_hash($password, PASSWORD_BCRYPT);
//Store $secret in database

Open in new window


SO, I guess the learning never stops.
Hey Wanda,

Good news on the Counter code.

and Nope - the learning never stops. The technology keeps moving forward, so it's a constant battle to keep up to date with it all - no matter how experienced you are!

The code you posted regarding the password is just an example to show the idea. Your code obviously has to know the password in order to hash it and store it in the database. Once it's stored in the database, then it becomes unreadable (as much as is possible), so it's secure. If for example, someone on your site wants to create a new account, they will often enter a username and password in a form. You would then take that password value from the form and hash it. It's the hashed value that you store in the DB, so it's never exposed in plain-text.

As for re-doing your entire site - sometimes that's necessary - particularly if it's a few years old. The best advice I can give is to do it in a logical, structured way. Think about your application, and all the moving parts of it, and try and keep those moving parts as separate as you can. Keep your CSS in their own files, Keep your JS in their own files. For the PHP part, keep as much as you can out of the HTML, and where that's not possible, structure your HTML / PHP in a way so that it's well structured.

Don't let it overwhelm you - if you learn a few key concepts (reading up / asking here on EE etc), then actually your website will become much easier to code and manage than what you currently have.
Thank you very much for all your help. I had thought I had done this part of the process earlier. Sorry that it took so long.
No worries Wanda :)