I'm working on a script that essentially has tell-a-friend functionality, but I'm trying to figure out the best way to capture and process the data.
For example:
Do I display 5 pairs of fields asking for name and email, each pair being $friend_name1/$friend_email1, $friend_name2/$friend_email2, etc, which allows you to email 5 friends at a time?
Do I display one pair and use JavaScript to allow the user to keep adding more friends using the variable naming convention as #1?
Do I display them as suggested in #1 or #2, but then submit an array e.g. $friend_email[]/$friend_name[], etc.
What's the best way to capture the data?
And then what's the best way to process the data?
If you get an array, such as in #3, do you then loop through each $friend_name $_POST? Do you store it in another array? How do you ensure that the correct name/email combination stays together, if for example, the user didn't add a "name" for the third friend?
How do most people do it so they can remain flexible during the capturing and precise during the processing? I'm really looking for logic here, although sample code is much appreciated.
One of the things I'm tracking is who is referring who. For example, if A refers B and B buys something, A will benefit. So accuracy and security are very important to me.
Thanks,
Ryan
I would recommend the array. You could do javascript or otherwise, but make sure that the processing end can see how many referrals there are. To ensure the correct e-mail and name stay together, try something like
<input type="text" name="friend_name[0]" />
<input type="text" name="friend_email[0]" />
<input type="text" name="friend_name[1]" />
<input type="text" name="friend_email[1]" />
and so on. From there, your PHP script will simply match the array indices in the $_POST var. For instance, if this form was submitted (as above) with some arbitrary data, it would format like this (this is the print_r($_POST); data)
Array
(
[friend_name] => Array
(
[0] => test_name
[1] => test_name2
)
[friend_email] => Array
(
[0] => email#something.com
[1] => email#two.com
)
)
An idea on looping through these (if you implemented javascript with a potential for an "infinite" number of referrals) would be to use the count(); function. Implementation would look something like this:
for($i=0;$i<count($_POST['friend_name']);++$i)
{
if($_POST['friend_email'][$i] == NULL) continue; // Ignore NULL e-mails
// Process data blah
}
Or, if those names where entered out of order, PHP's foreach() feature is very nice and can accomplish the same thing (probably more efficiently for this type of error checking)
foreach($_POST['friend_name'] as $key => $val)
{
if($_POST['friend_email'][$key] == NULL) continue; // Ignore NULL e-mails
// Process $val and $_POST['friend_email'][$key]
}
Hope this helps! Good luck!
Dennis M.
These are UI questions, and the answer is whatever UI you think works best for your site. You might have a design where a fixed number of fields fits better, or you might have a demographic where the "add another field" button is too confusing. Either way the code that processes the form doesn't have to be related to how you present the UI.
Regarding making sure your fields stay associated if you name them as an array, specify the indexes yourself rather than using open brackets, and you won't have that problem.
<input type="text" name="name[0]" value="First Friend's Name" />
<input type="text" name="email[0]" value="First Friend's E-mail" />
<input type="text" name="name[1]" value="Second Friend's Name" />
<input type="text" name="email[1]" value="Second Friend's E-mail" />
Then in your code,
foreach ($_POST['email'] as $index => $value) {
$name = $POST['name'][$index];
$email = $_POST['email'][$index];
}
Within the loop, $name and $email will be from the same set of fields in the form, though they can still be blank.
Related
Which is the most secure way to send an array through POST?
foreach ($id as $array)
{
<input type="hidden" name="prova[]" value="<?php echo $array; ?>"/>
}
<input type="submit" name="submit"/>
or using implode() to create a single variable, pass the variable and then use explode() to get back the values into a new array?
Edit If you are asking about security, see my addendum at the bottom Edit
PHP has a serialize function provided for this specific purpose. Pass it an array, and it will give you a string representation of it. When you want to convert it back to an array, you just use the unserialize function.
$data = array('one'=>1, 'two'=>2, 'three'=>33);
$dataString = serialize($data);
//send elsewhere
$data = unserialize($dataString);
This is often used by lazy coders to save data to a database. Not recommended, but works as a quick/dirty solution.
Addendum
I was under the impression that you were looking for a way to send the data reliably, not "securely". No matter how you pass the data, if it is going through the users system, you cannot trust it at all. Generally, you should store it somewhere on the server & use a credential (cookie, session, password, etc) to look it up.
http://php.net/manual/en/reserved.variables.post.php
The first comment answers this.
<form ....>
<input name="person[0][first_name]" value="john" />
<input name="person[0][last_name]" value="smith" />
...
<input name="person[1][first_name]" value="jane" />
<input name="person[1][last_name]" value="jones" />
</form>
<?php
var_dump($_POST['person']);
array (
0 => array('first_name'=>'john','last_name'=>'smith'),
1 => array('first_name'=>'jane','last_name'=>'jones'),
)
?>
The name tag can work as an array.
You could put it in the session:
session_start();
$_SESSION['array_name'] = $array_name;
Or if you want to send it via a form you can serialize it:
<input type='hidden' name='input_name' value="<?php echo htmlentities(serialize($array_name)); ?>" />
$passed_array = unserialize($_POST['input_name']);
Note that to work with serialized arrays, you need to use POST as the form's transmission method, as GET has a size limit somewhere around 1024 characters.
I'd use sessions wherever possible.
There are two things to consider: users can modify forms, and you need to secure against Cross Site Scripting (XSS).
XSS
XSS is when a user enters HTML into their input. For example, what if a user submitted this value?:
" /><script type="text/javascript" src="http://example.com/malice.js"></script><input value="
This would be written into your form like so:
<input type="hidden" name="prova[]" value="" /><script type="text/javascript" src="http://example.com/malice.js"></script><input value=""/>
The best way to protect against this is to use htmlspecialchars() to secure your input. This encodes characters such as < into <. For example:
<input type="hidden" name="prova[]" value="<?php echo htmlspecialchars($array); ?>"/>
You can read more about XSS here: https://www.owasp.org/index.php/XSS
Form Modification
If I were on your site, I could use Chrome's developer tools or Firebug to modify the HTML of your page. Depending on what your form does, this could be used maliciously.
I could, for example, add extra values to your array, or values that don't belong in the array. If this were a file system manager, then I could add files that don't exist or files that contain sensitive information (e.g.: replace myfile.jpg with ../index.php or ../db-connect.php).
In short, you always need to check your inputs later to make sure that they make sense, and only use safe inputs in forms. A File ID (a number) is safe, because you can check to see if the number exists, then extract the filename from a database (this assumes that your database contains validated input). A File Name isn't safe, for the reasons described above. You must either re-validate the filename or else I could change it to anything.
Why are you sending it through a post if you already have it on the server (PHP) side?
Why not just save the array to s $_SESSION variable so you can use it when the form gets submitted, that might make it more "secure" since then the client cannot change the variables by editing the source.
It all depends on what you really want to do.
If it's possible, I would like a general explanation of how I should go about this so I can try to tackle the problem directly myself. As is, I'm having trouble thinking of a solution.
I'm passing values from a form containing book information (ISBN, price, condition, etc.). It's been working very well with a single book. All of this form information is placed inside a div.
I recently implemented a simple JS 'duplicate' function that duplicates all of the form data in the div so users can add another book, or multiple other books. The problem seems to be that all the name values in the original div that I duplicate aren't changing, or aren't accepting that they should now contain multiple values.
How should I go about making each 'book' have it's own values? Should the names in each input be arrays (e.g. book[0]['price']) and then every time another div is added the JS changes the name (e.g. book[1]['price'])?
I'm asking this because I'm really not sure if that would work, and I'd rather hear a more experienced opinion before changing the (already functional) way in which the form is working. If more information is needed please ask and I'll provide.
The names that you assign in html forms can be arrays. eg price[]
<input type="text" name="price[]">
Now if you have multiple form inputs with the name 'price[]', it doesn't matter. In fact this makes it useful.
Now in php you can easily access each name using
$_POST['price'][$i] //where $i is 0,1,2,3.....
Basically what this does is that it creates an array for 'price' under the $_POST array.
You can easily iterate over $i and get values for other fields too.
This answers your statement "or aren't accepting that they should now contain multiple values."
<div id="book1">
<input type="text" name="price[]" id="price1" />
<input type="text" name="isbn[]" id="isbn1" />
</div>
Duplicate this and update the IDs only, using js(since each ID should be unique),
<div id="book2">
<input type="text" name="price[]" id="price2" />
<input type="text" name="isbn[]" id="isbn2" />
</div>
Now $_POST['price'] should give you the array of prices and each corresponding element of isbn should give you the isbn of that book
server side would be like,
$price = $_POST['price'];
$isbn = $_POST['isbn'];
foreach( $price as $key => $value ) {
echo "The price is ".$value." and isbn is ".$isbn[$key];
}
This is one way I would go..
My boss set up a script to process forms through PHP and email the results. We are required to use this processor. The problem with the processor is this line of code:
foreach ($_POST as $k => $v){$$k = strip_tags($v);}
This would be fine if all values sent were just strings, but I am trying to process some checkboxes which are passed as arrays. From what I understand, the strip_tags function only works with strings. It processes everything and sends the results via email as it should, but it throws a notice every time it tries to process a series of checkboxes.
Notice: array to string conversion...
The process still works, I just get ugly notices all over the place. In order to temporarily fix the problem, I removed the strip_tags function, resulting in this:
foreach ($_POST as $k => $v){$$k = $v;}
Everything now functions properly and I get no warnings, errors or notices. However, after pointing this out to my boss he wants me to revert back to the original code and then give each checkbox its own unique name, instead of giving them all the same name with different values. I could do that, but I know that is not the proper way to process a series of checkboxes. Plus it creates all sorts of headaches. My boss simply does not understand how to work with arrays, so he comes up with stupid work-arounds like this every time he encounters one. He also claims that this is some sort of spam protection to stop people from adding recipients to our forms. I may not be an expert in PHP, but I'm pretty sure that statement is false.
So what can I do to fix this issue? I know I should be converting the checkbox arrays to strings first, then use the strip_tags function on the resulting strings, but I am still fairly new to PHP and don't entirely understand what that line of code is doing to begin with. Can anybody help at least point me in the right direction?
Point out to your boss that:
<input type="checkbox" name="valid_recipient[]" value="1" /> fred#example.com
<input type="checkbox" name="valid_recipient[]" value="x" /> nasty#badperson.com
and
<input type="checkbox" name="valid_recipient1" value="1" /> fred#example.com
<input type="checkbox" name="valid_recipient2" value="x" /> nasty#badperson.com
are the same thing, whether they get passed as an array of checkbox values, or individual checkbox/value pairs. Either way, Mr. Nasty just injected something into your checkbox list.
As well, what's a malicious user from setting
<input type="hidden" name="_POST" value="haha I wiped your post array!" />
into the form. Your PHB's handy dandy "makes us completely secure" processor has just happily nuked the $_POST array, all while being "completely secure"
Passing checkboxes as an array is kush:
<input type="checkbox" name="myarray[key1]" value="hello world" />
<input type="checkbox" name="myarray[key2]" value="well hello again" />
Will create a resultant $_POST like:
Array
(
[myarray] => Array
(
[key1] => hello world
[key2] => well hello again
)
)
While this is awesome it also means that your bosses code is doubly insecure:
First, not having the strip_tags in there makes you vulnerable to XSS attacks.
Second, naively trusting $_POST variable names and exporting them into the global namespace is a recipe for disaster. (There's a reason why register_globals is a thing of the past).
For instance, let's say you track the username of who is logged in using a simple $_SESSION variable. Something like this:
if ($_SESSION['logged_in_user'] == 'admin') {
// do administrator things
}
Well, by accepting and exporting $_POST variables and attacker could modify an HTML form element like this:
<input type="checkbox" name="myarray[key1]" value="hello world" />
And twiddle it into something like this (using Firebug or Chrome):
<input type="checkbox" name="_SESSION[logged_in_user]" value="admin" />
Tad-ah! Any anonymous user can gain administrator access to the web site.
Here is a simple script for your consideration:
<pre>
<?php
session_start();
$_SESSION['logged_in_user'] = 'pygorex1';
print_r($_SESSION);
foreach ($_POST as $k => $v) {
$$k = $v;
}
?>
</pre>
<form method="post">
<input type="checkbox" name="myarray[key1]" value="hello world" />
<input type="checkbox" name="_SESSION[logged_in_user]" value="admin" />
<input type="submit" value="go go gadget" />
</form>
<pre>
<?php
print_r($_SESSION);
print_r($myarray);
session_write_close();
if ($_SESSION['logged_in_user'] == 'admin') {
echo("OWNED\n");
}
?>
</pre>
What would be the best way to intercept multiple fields via PHP? Currently I have a login.php file which is pretty simple:
<form method="POST" action="auth.php">
Code:<br />
<input type="text" name="code" />
<input type="submit" id="submit" value="Submit" />
<br />
Pass:<br />
<input type="text" name="pass" />
<input type="submit" id="submit" value="Submit" />
</form>
Then in the auth.php I get the value via the POST:
$value = $_POST['code'];
The problem with this is that I would have a quite amount of fields, and every field would have a submit button assigned. Then I would need a if condition for every field name avaible, which I don't want to. What would be the best way to handle this?
Thanks
Just use a single submit button. There's no reason to have more than one here.
If you have multiple related fields you can use array naming:
Primary email: <input type="text" name="email[]" >
Additional email: <input type="text" name="email[]">
and access from php using
$emails = $_REQUEST['email'];
However, you should not use arrays like this for unrelated parameters just because you're too lazy to use multiple field names. If you do you're just writing terrible, unmaintainable code.
There's a couple of ways you can simplify this problem.
Here's one approach:
$fields = array('field1','field2','field3','field4','field5'); // Add all your field names to an array
$data = array();
foreach ($fields as $field) {
if (isset($_POST[$field])) {
$data[$field] = $_POST[$field];
// If you wanted it assigned to a local variable instead,
// you could do it like this, although this pattern is
// generally frowned upon:
${$field} = $_POST[$field];
}
}
The danger of assigning it as a local variable is that it can overwrite a variable that already exists. It could potentially overwrite something crucial to the rest of the application. However, because the field names are explicitly defined in the array, you do at least maintain control over this.
You would definitely NOT want to iterate through the $_POST array and assign each array key to a local variable -- doing so would leave you wide open for hackers.
You have a bad problem with HTML.
In HTML you don't need more than one submit button.
A submit does not submit a field, but a whole form.
You don't even need it, as most user-agents will submit a form if you press Enter on a textfield.
Anyway, your fields will have an attribute name, unique within the form, and shall have an id attribute unique within the document.
When they are sent, all data can be accessed in PHP as an array.
The superglobal $_POST in your case, or $_GET if that method was used to submit it.
There, you do your magic.
Assuming there are 5 inputs in web form
<input name='the_same[]' value='different' />
<input name='the_same[]' value='different' />
<input name='the_same[]' value='different' />
<input name='the_same[]' value='different' />
<input name='the_same[]' value='different' />
When server side receive the post data, i use a foreach to accept data, say
$the_same = new array();
foreach($_POST['the_same'] as $data)
$the_same[] = $data;
Will the order of data saved in server side be the same to it in web form? and cross browsers, it could be a criteria all browsers follow.
Well, the W3C recommendation on HTML forms does say:
The control names/values are listed in
the order they appear in the document.
Still, I'd consider it a bit risky to have your app depend critically on that detail.
PHP already handles converting POSTed/GETed variables into arrays when you put [] after the name. Do that instead of getting it wrong yourself.
Better way to do in html:
<input name='the_same[]' value='different' />
Then in server:
$the_same = new array();
foreach($_POST['the_same'] as $data) // or $_GET if you prefer
$the_same[] = $data;
In this way no variable will be overwrite.
if you want to have it in an order, you may use the dynamic variables or simply access the array explicitly
the_same1
the_same2
the_same3
since you know the names anyway, you can access them easily
$the_same = array();
for($i=1; ; $i++){
$tmp =$_REQUEST["the_same".$i]
if( empty($tmp) ){
// no more stuff
break;
}
$the_same[] = $tmp;
}
If you change the name of your input to the_same[] - $_REQUEST['the_same'] will become an array of those values, first to last in element order (all current browsers I believe).
You can also specify a specific order if you need, or even use string keys. For instance, an <input name='the_same[apple][2]'/> would become $_REQUEST['the_same']['apple'][2]
Without using the [] on the input names, PHP will only see the last value. The other values will be 'overwritten' by the later value when the $_REQUEST/$_GET/$_POST arrays are constructed.
An example of using that to your advantage could be with a checkbox, as the HTML checkbox only submits a value when checked, you may want to submit a "not checked" value somtime:
<input type='hidden' name='check' value='not checked' />
<input type='checkbox' name='check' value='checked' />
Most likely yes, but you should not assume this. It depends on your browser how the inputs are being send, and aditionally PHP does not guarantee that a foreach loop iterates in the same order as the elements were added.
It is a bad practise to give your inputs the same name.
You could append an index after each name value (even with javascript if you want), and then read this in PHP to be sure the order is maintained.