I know result page that uses GET method can be bookmarked while the one using POST cannot be. I also know about the restrictions of the GET methods.
Now suppose I want to build a search engine which by default uses GET allowing users to bookmark but when the length of the search phrase exceeds the limit, switch to POST. On the server side I make use of $_GET or $_POST depending on which is set.
Is this doable?
If no, why?
If yes, please provide a brief outline.
Thanks
It is doable, no problem.
There is the $_REQUEST array that merges GET, POST, and COOKIE values but the better way would be to handle GET and POST manually in your script.
Just have your engine check both $_GET["variable"] and $_POST["variable"] and use whichever is set. If a variable is set in both methods, you need to decide which one you want to give precedence.
The only notable difference between the two methods is that a GET parameter has size limitations depending on browser and receiving web server (POST has limitations too, but they are usually in the range of several megabytes).
I think the general rule is that a GET string should never exceed 1024 characters.
Here's how you could use GET and POST in one:
<form action="myfile.php?var1=get1&var2=get2&var3=get3" method="post">
<input type="hidden" name="var1" value="post1" />
<input type="hidden" name="var2" value="post2" />
<input type="submit" />
</form>
The PHP:
print_r($_REQUEST);
// var1 = "post1"
// var2 = "post2"
// var3 = "get3"
print_r($_GET)
// var1 = "get1"
// var2 = "get2"
// var3 = "get3"
print_r($_POST);
// var1 = "post1"
// var2 = "post2"
You could use something like the following:
<?php
function getParam($key)
{
switch (true) {
case isset($_GET[$key]):
return $_GET[$key];
case isset($_POST[$key]):
return $_POST[$key];
case isset($_COOKIE[$key]):
return $_COOKIE[$key];
case isset($_SERVER[$key]):
return $_SERVER[$key];
case isset($_ENV[$key]):
return $_ENV[$key];
default:
return null;
}
}
It's also as well to be aware that using GET opens up a temptation among certain sets of users to manipulate the URL to 'see what happens' so it's absolutely necessary to ensure that your code suitably sanitises the input variables.
Of course you were doing that anyway ;-). But with get it pays to be doubly paranoid.
Myself if I'm using GET I'll generally set a cookie too and drop an ID of some sort in it, then cross-correlate that to a variable in the GET list, just to make sure there's absolutely no issues over user A manipulating the input and letting them see anything originating with user B.
Yes its doable, although (IMHO) the limit at which GET becomes cumbersome is significantly greater than the threshold at which a user interface for providing this much information becomes unusable. Also, the more complex a query you submit to a conventional search engine, the more effectively it can be resolved.
But I'm guessing you have your reasons.
The simplest way, from the information you've provided, to achieve this would be to change the form method at run time from GET to POST using javascript, e.g.
<form method='GET' id='searchform' target='search.php' onsubmit='
if (document.getElementById("searchdata")) {
if ((document.getElementById("searchdata").length >$some_threshold)
&& (document.getElementById("searchform"))) {
// 2nd if in case this moved to action for button
document.getElementById("searchform").method="POST";
}
}
return true;'>
<textarea name='searchdata' id='searchdata'>
</textarea>
<input type='submit' value='go get it'>
</form>
Which also downgrades nicely for non-javascript clients.
C.
function getQVar($key){
return isset($_GET[$key]) ? $_GET[$key] : (isset($_POST[$key]) ? $_POST[$key] : null);
}
echo getQVar("name");
Switch around $_GET and $_POST to prioritize POST over GET vars.
Related
$num = $_POST['num'];
if(filter_input(INPUT_POST,'num', FILTER_VALIDATE_INT, array("options"=>array("min_range"=>5, "max_range"=>20)))===false) {
echo "Write a valid number between 5 and 20";
} else {
echo 'Great, your number is: '.$num;
}
there are many verbs you can use to send information between your website and your app, perhaps the most commonly used are GET and POST, GET requests are the ones that you can see on the URL, usually they come after a ? symbol, POST requests on the other hand are not shown on the URL, but the data is sent "hidden", in this case you can see you're using:
$num = $_POST['num']
if it is working is because in your HTML page, or on the same PHP page you have something like
<form action="mypage.php" method="post">
so, you can get that info via _POST, not _GET, the method/verb used must match on both sides.
If you try to get the value on _GET it won't be available, so the filter will fail check on http://php.net/filter_input, it clearly states:
or NULL if the variable_name variable is not set
you are performing a === comparison that won't return false, but NULL in this case, and therefor the only available code to be executed is the else part!
i have alot of get values that define the page the user gonna see , for example for "profile" i will show the profile page and so on..
to find out what page to display i tried to do something like that:
switch ($_GET) {
case 'profile':
require_once('function/profile.php');
break;
case 'team':
require_once('function/team.php');
break;
but it shows no result..
i send the GET request like that : index.php?profile , for example..
what is the problem here and how can i can manage to do something similar that work as well. thank you in advance!
To make your example work, you could replace $_GET with key($_GET)
be aware though that key() will return the first key of an array, so if you change your URL's variable order, this line'll stop functioning.
$_GET is an array from the key value pairs found in the query string (part of the url after the script name and a question mark).
For example, the query string test=1&foo=bar will translate to:
Array(
test => 1
foo => 'bar'
)
In the OP example, index.php?profile, you will end up with a $_GET array like:
Array(
profile => null
)
Problem with doing urls like this is that it is non-standard. When you do things in a non-standard way, you have to come up with non-standard solutions to fix the problems.
Here are a few options along with issues that each has:
You can use $_SERVER['QUERY_STRING'] which will get you everything after the ? in the url. This is fine if the only thing passed in the url is just profile (or some other single value). In that case, $_SERVER['QUERY_STRING'] will have nothing but profile in it. But you also then lose the ability to pass additional parameters in the get string.
You can go with the method described by #stewe. The php key function will return the key from the current position in the array passed in. If you haven't done any looping, the current position is the first element. This will work fine with multiple get parameters as well. Your query string will just look like index.php?profile&test=1&foo=bar. The problem is that profile (or whatever page) has to be the first or else key will return whatever the key is for the first parameter passed.
Another option is to just go with the standard method of using a key and value. Regardless of page, you use the same key and just the value changes. You then have urls that look like index.php?page=profile and you can always access the page using $_GET['page'].
You can use mod_rewrite. It is simple to setup, most hosts support it (or some other similar) and there are millions of tutorials and examples on how to get it to work. You end up with the cleanest urls and it works with query string parameters. For example, /profile/ can be rewritten to point to /index.php?page=profile. The user sees /profile/ and php sees the standard. This allows you to use $_GET['page'] to get the requested page and not have to do extra parsing to get other values inside php.
$_GET is an array or variables that are populated based on the URL's query string. You need to do something like:
switch ($_GET['myVar']) { ... }
where your URL would look like:
http://www.domain.com/index.php?myVar=value
For more information, see the PHP Manual for $_GET.
$_GET by itself is not very useful to you. I suppose you are looking for a key, like 'page', right ? Remember to declare a default value as well.
so..
$page = $_GET['page'];
switch ($page) {
case 'profile':
require_once('function/profile.php');
break;
case 'team':
require_once('function/team.php');
break;
default:
require_once('function/page-not-found.php');
}
$_GET is a super global variable, where the data are sent as stored as array. So you have to
access it using Index
Assuming you page you are trying to include a page when the data are sent like this:
domain.com?page=product
Then you have to use switch like this
switch($_GET['page']) {
....
}
Note: May be I dont have to remind you how vulnerable this code towards injection.
It's an array, so you need to use a loop to iterate on the values:
foreach($_GET as $key => $val){
switch ($key) {
case 'profile':
require_once('function/profile.php');
break;
case 'team':
require_once('function/team.php');
break;
}
}
with foreach you can get the key and value pair
foreach ($_GET as $switchkey => $switchval) {
switch ($switchkey) {
case 'profile':
require_once('function/profile.php');
break;
case 'team':
require_once('function/team.php');
break;
}
}
i actually use the following after a normal get resulting in lfi/rfi vulnerabilities. the following solution was submitted to me via a bug bounty program and works great. notice the inclusion of the default attribute. very important. the following should be the only acceptable answer. Credit to the flying spaghetti monster(His Noodly Appendage)
switch($_GET['page']) {
case 'foo':
include('pages/foo.php');
break;
case 'bar':
include('pages/bar.php');
break;
default:
include('pages/home.php');
}
As mentioned before, the first thing that seems to come to mind is the non standard way of passing the information. which will generate some difficulties when you parse the values. Although, for me, the main problem is not checking/sanitazing/cleaning the data on $_GET. May be it's too obvious and since almost all the answers have been given by people who seem to know what are they doing, I'll assume they just didn't mention it because of that
But remember that if you don't check it, you are vulnerable to attacks and malfunction of your script. The extent of the damage depends on your own application, so it's not easy to predict.
In any case, this is what I'll do, including the html
<?php
// initialize variables
$variable_1 = false; // assume this is the page you want to load
$variable_2 = false;
$default = 'index.php'; // the idea is to load something controlled by you. index, error, 404, etc.
// process $_GET, check, clean and assign values
if ( isset( $_GET ) !== false ) {
foreach ( $_GET as $keys => $values ) {
// check both, $keys and $values for; character set, length, validity against a white list, content
// using an if to match the $keys garantees that regardless of the order, you will get what you want
if ( $keys === 'field_1' ) {
// do what you have to do with this, for instance ...
$variable_1 = $values;
}
if ( $keys === 'field_2' ) {
// do what you have to do with this, for instance ...
$variable_2 = $values;
}
unset( $_GET[$keys] );
}
unset ( $keys, $values );
}
// check there are no surprises on $_GET. Load and study anything here
if ( empty( $_GET ) === false ) {
// it should be empty, so log what is in here and prepare your code for that
unset( $_GET );
} else {
unset( $_GET );
}
// process the variables according to what you want to do
// if there are just a few options, and they are not going to change often
// use a switch, otherwise, use a method to check if a file/content exists
// for the request and load it. If it doesn't exist, inform the user
// with out giving away internals and suggest a new destination
// process other variables, here or before this part, wherever makes sense
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>testing get</title>
</head>
<body>
<form method="get" action="test_get_00.php" accept-charset="utf-8">
<p><label for="field_1">write something<input type="text" id="field_1" name="field_1" /></label></p>
<p><label for="field_2">write something<input type="text" id="field_2" name="field_2" /></label></p>
<p><button type="submit">send</button></p>
</form>
</body>
</html>
Of course you can do a few more things, but if you prepare your form properly, including the character set, you have less worries, or at least a few more known elements. It's not failproof, but it helps.
Also, the mechanics I mention above work on a white list mindset, that is the idea of the foreach, to check that you get what you expect and discard the rest, after logging it.
You are trying to archive SEO urls in the wrong way.
I see that index.php?profile is better then index.php?page=profile but it's the wrong way of act in this case.
You should use index.php?page=profile and then apply a rewrite rule to create SEO urls, like this one:
RewriteEngine On
RewriteRule ^(.*)$ index.php?page=$1
In this way your users will use:
http://example.com/profile
and the page displayed will be:
http://example.com/index.php?page=profile
instead of switching on the keys (as proposed by key($_GET)) you could define one variable, in $_GET (url) named for example 'action' which would containt 'profile', or 'team' or whatever you wish in the future. then your switch, simply, will be :
switch ($_GET['action'])
so whatever action you assign to this key, you can use as a case in your switch
Basically i have a form where a studentID is inputted, i then want to check id the inputted studentID is in the database, if it is post the form to the next page. If not then display an error on the page where you input studentID
Don't really know where to start
Cheers
is this what you want?
<form id = "form" action = "./?page=markandfeedback" method = "post">
<br>
Mark for:
<INPUT id="stud" onkeypress="return isNumberKey(event)" type="text" name="stud" value="Enter Student Number">
<input type="submit" value = 'Continue'>
<?
$studID = $_POST['stud'];
$module2 = $_SESSION['module'];
$ex = $_POST['exer'];
$studerr = array();
$sql = 'SELECT * FROM `student`, `modules` WHERE `studentID` = '.$studID.' AND `moduleCode` = '.$_SESSION['module'];
$result = mysql_query ($sql);
// echo $_SESSION['module'];
if ($result == NULL) { // nothing found
echo "the student id you entered is not in the database";
}
else {
$_SESSION['student'] = $studID;
Header("Location: http://www.whereever.com/"); // send the browser where you want
exit();
}
?>
EDIT:
I went over the other answers. I assume you check for mysql injection properly. I recommend implementing AJAX AFTER everything works and is secure. The idea behind my solution was to solve the problem as simple as possible. If you want to make something fancy out of it you could:
generate the whole form via php and tell the user in the input field, that the id wasn't found
tell your Javascript to present the information in some fancy way
Use AJAX. Everybody loves forms with AJAX.
You could, as suggested, assume that the user entered a valid id. You would check on the "whereever" page wether the id is actually valid. If it weren't, you would simply send the user back to the form and tell the php to output an error message (maybe via get). This possibility is not usual, I am not sure if it has any advantages.
the mysql_num_rows hint is nice, too, if you don't want any data from the user. I thought you wanted to do something with the data because of the SELECT *.
Make a seperate controller that does the checking of the username.
Use ajax to check if user input is valid or not.
So you'll have something like this:
<input id="stud" onchange="checkStudentId(this)" />
<script>
function checkStudentId(inputElement) {
var id = inputElement.value();
$.ajax({
url: "test.html",
context: {id:id}
}).done(function() {
// Check the return result
});
}
</script>
Here is a reference to jquery ajax
http://api.jquery.com/jQuery.ajax/
You actually have to connect to the server in some fashion to figure out of the student exists. What you'd normally do in this situation is submit the form to the server and do validation server-side. If the student exists, you return the "next" page. If the student doesn't exist, then you return (or redirect to using a Location header) the same form again with an error message.
Another popular method would be to use an AJAX request to check asynchronously (which I see many other people are recommending). I'd only recommend this way if you're actually doing validation right as they've finished entering the student id and are showing an error message in real-time, effectively. In this way, AJAX is a nice-to-have to provide quick user feedback, but not a real solution. Keep in mind that regardless of this, you need to check for and handle this when the form is submitted anyway, or at the least, consider what will happen when the form is submitted with an invalid id.
People can bypass this check (EVERY request from the client side is considered hostile, you can't implicitly trust anything)
Another user may have deleted the student ID between the time the check was done and the form was submitted
There could be an error in your code that causes validation to falsely pass or not to recognize a negative response
Doing AJAX onsubmit makes no sense, because effectively you're doubling the amount of work by making the server handle two separate requests in a row. It's simply the wrong answer to the problem.
The biggest trouble with this implementation is the PHP code can quickly get quite hairy and hard to follow as you have everything mixed together.
This is where you probably start to tip over using PHP like a templating language (mixed php code and html markup) and start getting into using a framework where your views (the HTML) are decoupled from your PHP code (if you're using the very-populate MVC pattern, this code is called your controller -- precisely because it controls how the server responds). This is how any professional developer will work. Kohana, CakePHP, and Zend are all examples of fairly popular MVC frameworks, all of which are used professionally.
You can do this in two different ways
AJAX - make ajax call to your server and check the ID if its exist display the error else go to the next page
PHP - put a hidden input in your form and make the action of the form to the same page and check everything their and keep the values of the input fields is the $_POST['field_name'];
And you can make the action into another page and return back variable or make a session to hold the error message
Try this:
<?
if(isset($_POST['stud'])){
$studID = $_POST['stud'];
$module2 = $_SESSION['module'];
$ex = $_POST['exer'];
$studerr = array();
$host="hostname";//your db host
$user="user";//your db user
$pass="pass";//your db pass
$conn=mysql_connect($host,$user,$pass);
$sql = 'SELECT * FROM `student`, `modules` WHERE `studentID` = '.$studID.' AND `moduleCode` = '.$_SESSION['module'];
$result = mysql_query ($sql,$conn);
if(mysql_num_rows($result)>0){//the id was found in the DB, do whatever here...
echo $_SESSION['module'];
$_SESSION['student'] = $studID;
Header("Location: http://www.whereever.com/");//redirect to wherever
$error=false;
}
else{//id was not found
$error=true;}
}//end of isset
?>
<? if($error===true){?> <div> The id was not found.... </div> <?}?>
<form id = "form" action = "<? echo $_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI']; ?>" method = "post">
<br>
Mark for:
<INPUT id="stud" onkeypress="return isNumberKey(event)" type="text" name="stud" value="Enter Student Number">
<input type="submit" value = 'Continue'>
So what this does is: When the user hits submit, conects to the DB, and checks if the ID exists...if it does, then it redirects it to wherever.com (see comments) and if it don't an error messege will show up. Be sure to change the db variable values to your own ($host, $user, $pass).
Basically I have several big forms (lot of fields submitted) that need to be processed, which are very similar but may differ by one or two fields. Firstly all fields get escaped and assigned to a variable of their original name (thus $_POST['f_name'] will be $f_name).
Then I need to validate the data, things like certain obligatory fields must be present, certain fields much match (confirming password/email), certain fields must pass regex check. I do this via a long if/else statement, where each failure has it's own error message.
Now of course I would like to avoid this repetition of the clumsy code, and replace it with some looping function, which will be easier to edit and maintain.
However this poses a bit of a problem, especially performing the checks and assigning individual error messages.
I would be keen to hear suggestions as how would you approach developing such validation/error reporting function.
Here is a short version of what the code looks like:
$name = mysqli_real_escape_string($mysqli, $_POST['name']);
$password = mysqli_real_escape_string($mysqli, $_POST['password']);
$password_re = mysqli_real_escape_string($mysqli, $_POST['password_re']);
if ($name == '') :
$data = "Please enter name";
elseif ($password != $password_re) :
$data = "Passwords don't match";
endif;
First off I would make a function to clean your post array.
$clean_post = sanitize($_POST);
function sanitize($input) {
if (is_array($input)) {
foreach($input as $var=>$val) {
$output[$var] = sanitize($val);
}
}
else {
if (get_magic_quotes_gpc()) {
$input = stripslashes($input);
}
$input = cleanInput($input);
$output = mysql_real_escape_string($input);
}
return $output;
}
Next I would add divs with the same name as the field and set error variable within the $data array and remove the ifs in between them, personally I hate being spoon fed my form errors.
if ($name == '')
$data['name'] = "Please enter name";
if ($password != $password_re)
$data['password] = "Passwords don't match";
Finally, I would set the content of the divs to the $data array value.
<div><?=$data[name];?></div>
<input type="text" name="name" value="<?=$clean_post[name];?>">
<div><?=$data[password];?></div>
<input type="password" name="password" value="<?=$clean_post[password];?>">
<input type="password" name="password_re" value="<?=$clean_post[password_re];?>">
Hope this helps
I'm not sure that there's one cut-and-dried approach to this problem. Here's how my company has addressed this problem:
1) Front side validation. Yes, can be bypassed. However, if you're only using it as the first line of defense it's a great solution (and acceptable to some of my biggest clients including an international banking group) I love the simplicity of Cedric Dugas' inline validation script because it's basically just a few extra characters per field. Another HUGE benefit to the inline validation--it allows us to use one centralized alert area for server-side validation errors along with a simple alert trigger via css on individual elements, while the majority are caught inline and alerted which is FAR more user friendly.
2) A class that deals with "stuff" We refer to it as the "garbage in, garbage out" It takes an array of post data, sets fields based on element names, and deals accordingly. This includes data sanitizing, validations, etc. The problem with validations is that unless you have generic types data to validate, you can get into a lot of specifics which can really gum up code in a hurry. Also, this can make you actually have to do MORE work on the front end because your field names have to line up accordingly. In our case, we deal with external webform responses from clients a lot who don't necessarily appreciate the need for standardized naming of fields, and that can get to be a headache.
3) "Chunking" sections. On huge form scenarios, we've resorted to "chunking" submits in phases via Ajax to minimize the damage to the server done in one big submit. So, user updates profile information, submit happens. User does background info section, update happens...etc. It's not right for all situations, but is some it can work well...and it allows progressive validation as you move from start to finish. I certainly wouldn't ever recommend this approach for each individual question, though.
4) "Forced Sanitation" Sounds evil, huh? In cases such as zip codes, addresses, etc you can simply fix information for the client. Rather than barking about a missing Zip Code, you can get it automatically, correct 100% of the time. That's the beauty of Google and the USPS--they're free and smarter than the average user.
I'd say it's better to do this on the client side using a javascript form validator, before anything gets submitted. Do a search for javascript form validation. It'll save you a page load and force your users to correct errors before even submitting. Here's a simple example of one way, taken from the first google hit for "javascript form validation":
<form name="myForm" action="demo_form.asp" onsubmit="return validateForm()" method="post">
First name: <input type="text" name="fname">
<input type="submit" value="Submit">
</form>
<script language="javascript">
function validateForm()
{
var x=document.forms["myForm"]["fname"].value
if (x==null || x=="")
{
alert("First name must be filled out");
return false;
}
}
</script>
Hey, I'm programming a feedback form on a website for a client, however, there are over 100 inputs (all uniquely named). I was wondering if there was a loop I could run to get all of the variables, do you have to call them like this:
$variable = $_REQUEST['variable'];
EDIT:
I'm going with $_POST as recommended by everyone here - thanks for the input! I'll just manually go through and write a line for each $_POST I have.
You can loop over all veriables in the $_PREQUEST array:
foreach($_REQUEST as $key=>$value){
//doStuff
}
However this will include all send parameters, not only the input. Also you should not use $_REQUEST but $_POST or $_GET
If you don't want to have hundreds of uniquely named variables and want to have arrays of data turn up client side, there is a handy form trick you may want to try.
<form>
<input name="foo[a]" type="text" />
<input name="foo[b]" type="text" />
<input name="bar[]" type="text" />
<input name="bar[]" type="text" />
Client Side:
<?php
$_POST['foo']['a'];
$_POST['foo']['b'];
$_POST['bar'][0];
$_POST['bar'][1];
?>
echo "<pre>";
print_r($_POST); // or $_GET
echo "</pre>";
If you are dealing with items that you possibly won't know the name of but need the values then you are dealing with a much larger problem than you think.
But the above snippet should show you all variables set and their values when you submit the form
I think you should start out with a list of all variables that you expect, and loop only over those. If you don't, hackers can inject any variable name... In fact, you're reemplementing the old, terribly bad idea of Register Globals. So, don't do that...
In fact, why not keep the input in an associative array, just like $_POST? You might still want to remove those values that you didn't expect.
As in my comment above, don't use REQUEST, use POST. I'd probably write a line for each one so that I was aware of what was happening. You don't want people to post extra variables that still get parsed.
You can write simple code to algorithmically obtain all inputs from a posted form, but this is a dangerous business, one that is ripe for exploitation.
The $_GET and $_POST array variables contain every parameter passed via URL or POST method respectively. You should rather use that variables instead of extracting every item like the register_globals option or extract function does. See Using Register Globals for the reasons.
I can't add a comment on Pim Jager's post, but here's an example code:
foreach($_POST as $key=>$value) {
echo($key.' > '.$value.'<br />');
}
Use an array with the fields you want copied from POST and store the data in an array. It's a lot easier to maintain.
$fields = array("name","email","addr","bla","bla2");
$form = array();
foreach($fields as $field){
$form[$field] = $_POST[$field];
}
Now you've got all the data inside $form.
You could also make a similar thing when creating the form. (Although it's trickier..)
Cheers!
foreach($_POST as $key=>$value) {
${$key} = $value;
}
but this does the same thing as extract()