Check on $_GET variable fails - php

I am creating a PHP page, in one page I would like to show the main HTML based on which $_GET["action"]. However whatever which if ($action == "xxx") condition
// Action Judgement
$action = isset($_GET["action"]) ? $action : 'form';
$action = isset($action) && in_array($action, array('form', 'submit')) ? $action : 'form';
if($action == "form") { ?>
// only html <form>...</form> codes here
<?php } elseif($action == "submit") { ?>
// only php codes for processing here
<?php } ?>
If I put the URL like this abc.php?action=submit, the HTML codes are showing in the page. Is my coding wrong?

Your first line is wrong. Fix it by replacing it by
$action = isset($_GET["action"]) ? $_GET["action"] : 'form';
or you could even improve it by taking
$action = ( isset($_GET["action"]) && !empty($_GET["action"]) ) ? $_GET["action"] : 'form';
or even better (as Ben D suggested)
$action = !empty($_GET["action"]) ? $_GET["action"] : 'form';

You're confusing variables and forms.
if($action == "form") {
echo "only html <form>...</form> codes here";
} else if($action == "submit") {
only php codes for processing here
}

$action = isset($_GET["action"]) ? $_GET['action'] : 'form';
$action = isset($action) && in_array($action, array('form', 'submit')) ? $action : 'form';

Related

PHP Page password protection

I had created a simple password protection page for a PHP webpage by searching online. below is the code.
protect.php:
<?php
namespace Protect;
function with($form, $password, $scope=null) {
if( !$scope ) $scope = current_url();
$session_key = 'password_protect_'.preg_replace('/\W+/', '_', $scope);
session_start();
if( $_POST['password'] == $password ) {
$_SESSION[$session_key] = true;
redirect(current_url());
}
if( $_SESSION[$session_key] ) return;
require $form;
exit;
}
function current_url($script_only=false) {
$protocol = 'http';
$port = ':'.$_SERVER["SERVER_PORT"];
if($_SERVER["HTTPS"] === 'on') $protocol .= 's';
if($protocol === 'http' && $port === ':80') $port = '';
if($protocol === 'https' && $port === ':443') $port = '';
$path = $script_only ? $_SERVER['SCRIPT_NAME'] : $_SERVER['REQUEST_URI'];
return $protocol."://".$_SERVER[SERVER_NAME].$port.$path;
}
function redirect($url) {
header("Location: ".$url);
exit;
}
Form.php:
<html>
<body>
<form method="POST">
<?php
if( $_SERVER['REQUEST_METHOD'] === 'POST' ) {
?>
Invalid password
<?php
}
?>
<p>Enter password for access:</p>
<input type="password" name="password">
<button type="submit">Submit</button>
</form>
</body>
</html>
At the top of the php webpage which is to be protected with security password:
<?php
require_once('protect.php');
Protect\with('form.php', 'demo'); // demo is the password
?>
It's working fine but I am getting an error as
Undefined index: password in C:\xampp\htdocs\iv\admin\protect.php on line 9 and session start() is already defined.
(On top of the php page which is to be protected).
When I tried to make any changes its completely not working.
Anybody, please help and guide me where exactly the error.
You have to check first if the password has been submitted in your with function.
// this has to be checked first
// added isset to check if its existing
if( isset($_SESSION[$session_key]) && $_SESSION[$session_key] ) return;
^-------------------------------^
if( isset($_POST['password']) && $_POST['password'] == $password ) {
^--------------------------^
...
}
As noted by #Martin in several comments, your two issues can be easily solved by reading the linked questions/answers.
The first issue, which is the session already started error, can be easily solved by bringing out the session_start() from your function altogether and put it only once in the very top level php file.
The second issue is resolved by using empty() or isset().
function with($form, $password, $scope=null)
{
if(empty($scope))
$scope = current_url();
$session_key = 'password_protect_'.preg_replace('/\W+/', '_', $scope);
if(isset($_POST['password']) && ($_POST['password'] == $password)) {
$_SESSION[$session_key] = true;
redirect(current_url());
}
if(!empty($_SESSION[$session_key]))
return false;
require($form);
exit;
}
To set session:
<?php
# Just add by default, don't use an "if" clause
session_start();
# Do the rest of your script
require_once('protect.php');
$Protect->with('form.php', 'demo');
One final note; make sure your indenting correlates to hierarchy otherwise the script can get hard to read.

PHP isset equal $var1 or $var2

I'm trying to make routing system.
What I want to do:
Url: http://localhost/wiki.php?post_id=1 invoke second if
Url's: http://localhost/wiki.php?post_id=1&action=upvote
http://localhost/wiki.php?post_id=1&action=downvote invoke first if
This is routing system:
if(isset($_GET['post_id']) & ((isset($_GET['action']) ? $_GET['action'] : null) == "upvote" || "downvote")){
//Do stuff
}else if(isset($_GET['post_id'])){
//Do stuff
}
Problem:
Url's: http://localhost/wiki.php?post_id=1&action=upvote http://localhost/wiki.php?post_id=1&action=downvote work like they are supposed to.
But url: http://localhost/wiki.php?post_id=1 invokes first not second if too...
Notice: Undefined index: action in D:\xampp\htdocs\controllers\WikiController.php on line 18
Line 18: $rate = $_GET['action']; it's inside in first if.
While testing I figured out that if I change if(isset($_GET['post_id']) & ((isset($_GET['action']) ? $_GET['action'] : null) == "upvote" || "downvote")){
too
if(isset($_GET['post_id']) & ((isset($_GET['action']) ? $_GET['action'] : null) == "upvote")){
or
if(isset($_GET['post_id']) & ((isset($_GET['action']) ? $_GET['action'] : null) == "downvote")){
It works fine. But I want to learn how to do this right, not just simply made 2 different routers.
this part (exp) == "upvote" || "downvote" does not work like you suppose it does. It only tests if exp is equal to "upvote", the second part "downvote" is understood as a boolean which is true, so you stay in the first part of the alternative..
try with
if(isset($_GET['post_id']) && (($exp = (isset($_GET['action']) ? $_GET['action'] : null)) == "upvote" || $exp == "downvote")){
For clarification, a single (ampersand) & is "bitwise":
http://php.net/manual/en/language.operators.bitwise.php
Therefore, you need to change your & to &&.
From the manual:
$a & $b And Bits that are set in both $a and $b are set.
What you're after is the logical && operator:
http://php.net/manual/en/language.operators.logical.php
$a && $b And TRUE if both $a and $b are TRUE.
|| "downvote" will always return true since you're not comparing it to anything. You have to add (isset($_GET['action']) ? $_GET['action'] : null) == in front of that string too.
So your statement would be:
if(isset($_GET['post_id']) && ((isset($_GET['action']) ? $_GET['action'] : null) == "upvote" || (isset($_GET['action']) ? $_GET['action'] : null) == "downvote")){
//Do stuff
}else if(isset($_GET['post_id'])){
//Do stuff
}
$routes = [
'upvote','downvote'
];
if(isset($_GET['post_id']) && isset($_GET['action']) && in_array($_GET['action'],$routes)){
echo 'running if';
}else if(isset($_GET['post_id'])){
echo 'running else if';
}
You are missing && was the problem, i just change this for dynamic route if you need to change in future!

Get variable from link in PHP, issue

I have URL below:
session.php?action=create_program
Then I have the following piece of code:
if( isset($_GET['action']) ){ $action= $_GET['action']; $action=''; }
It returns an empty string while it should return ''create_program'
I think you were trying to set it to empty if you didn't receive anything in your get request. So either do it like this
if( isset($_GET['action']) ){
$action= $_GET['action'];
} else {
$action='';
}
Or, even simpler, give a default value that remains set if the get parameter is absent.
$action = '';
if( isset($_GET['action']) ){
$action= $_GET['action'];
}
Finally, as suggested by Cashbee in the comment below, you can use the ternary operator to check whether $_GET['action'] was set and, in case it's not, give a default value to $action.
$action = isset($_GET['action']) ? $_GET['action'] : '';
Easy is the use of the ternary operator like this:
$action = isset($_GET['action']) ? $_GET['action'] : '';
You should always check if the variable is set or empty.
$action = empty($_GET['action']) ? '' : $_GET['action'];
Or even better, use the PHP filter functions.
$action = filter_input(INPUT_GET, 'action');
This has the advantage, you can even use rules, to give the appropriate result, like described in http://php.net/manual/de/function.filter-input.php
You are setting $action to empty at last that's why it is returning an empty string
if( isset($_GET['action']) )
{
$action= $_GET['action'];
// $action=''; //Just remove this code
}
//$action will be empty if not have $_GET['action'];, just for PHP7
$action = $_GET['action'] ?? '';
hope can help you!

isset variables created using extract function

$array = explode('/', $_SERVER['REQUEST_URI']);
$count = count($array);
extract($array, EXTR_PREFIX_ALL, 'var');
can the variables (created using extract function) be isseted automatically? to avoid "Notice: Undefined variable:" errors when error_reporting(E_ALL); is enabled.
thank you
I tried doing something of this sort, still needed to isset() whenever, the variables are used next in the code (when error_reporting(E_ALL); is enabled).
if(isset($var_0))
{
$var_0 = filter_var($var_0, FILTER_SANITIZE_STRING);
}
if(isset($var_1))
{
$var_1 = filter_var($var_1, FILTER_SANITIZE_STRING);
}
if(isset($var_2))
{
$var_2 = filter_var($var_2, FILTER_SANITIZE_STRING);
}
if(isset($var_3))
{
$var_3 = filter_var($var_3, FILTER_SANITIZE_STRING);
}
==========================
Alternatively, tried the one line if condition,
$var_0 = isset($var_0) ? filter_var($var_0, FILTER_SANITIZE_STRING) : '';
$var_1 = isset($var_1) ? filter_var($var_1, FILTER_SANITIZE_STRING) : '';
$var_2 = isset($var_2) ? filter_var($var_2, FILTER_SANITIZE_STRING) : '';
$var_3 = isset($var_3) ? filter_var($var_3, FILTER_SANITIZE_STRING) : '';
while the error got subsided, but, a new problem arises i.e., variables (which are not created by extract function are getting isseted because of this one line if condition approach).
I am posting two of the routing rules (of two urls) in the website.
$pagename = "not-found.php";
//Different Routing Engine Rules follows
if ((isset($var_1)) && (($var_1 == "") || ($var_1 == "index.php"))) {
if((isset($var_2)) || (isset($var_3)) || (isset($var_4)) || (isset($var_5)) || (isset($var_6)) || (isset($var_7)))
{
$pagename = "not-found.php";
}
else
{
$pagename = "default-home.php";
}
}
if (($var_1 == "login"))
{
//echo "Login Page URL\n";
if((isset($var_2)) || (isset($var_3)) || (isset($var_4)) || (isset($var_5)) || (isset($var_6)) || (isset($var_7)))
{
$pagename = "not-found.php";
}
else
{
$pagename = "login.php";
}
}
include "code/" . $pagename;
any help will be appreciated, thank you
If I understand your question correctly then, no. It's still your responsibility to know what variables are available and act accordingly. You can simply disable these notices via error_reporting(E_ALL & ~E_NOTICE) for the portion of code in question.
Edit
Looking at your updated question, I think it would be helpful if you could explain what you're trying to achieve. Personally, I see the use of extract as a bit of a code smell and there may be a better way :)

Checking user input

I'm creating an edit page which should get called this way:
users.php?action=edit&id=5
This is my code for this:
} elseif (isset($_GET['action']) && $_GET['action'] == 'edit' && isset($_GET['id']) && is_numeric($_GET['id']) && $_GET['id'] > 0) {
As you see it's long. First a check with isset is needed. I know you can leave that out, but that way I'll get PHP notices when error reporting is set to 'E_ALL'.
I can create a function to make it shorter but that way I'll need to create too many functions as I have such code on different places in my scripts, each requiring different information.
Is there any way to make this code shorter?
Thanks!
Since action and id both are probably going to be used might as well set them at the top of the script:
$action = !empty($_GET['action'])?$_GET['action']:false;
$id = !empty($_GET['id'])?$_GET['id']:false;
switch ($action) {
case 'edit':
if ($id !== false) {
//processing here
}
break;
default:
echo 'No known action was passed through';
}
The initial variable declaration uses the ternary operator which is a shortened if/else as an fyi.
Extra Information
I prefer this method as appose to insane if/elseif/else statements, given that it is much easier to read and you do not have to think about your logic nearly as much, so it would make it less prone to errors.
You could write a function that takes an array of keys:
function check_get_params($keys) {
foreach ($keys as $key) {
if (! isset($_GET[$key]) ) {
return false;
}
}
return true;
}
Then your line above would be:
} elseif (check_get_params(array('action', 'id')) && $_GET['action'] == 'edit' && is_numeric($_GET['id'])) {
which would be cleaner as:
} elseif (check_get_params(array('action', 'id'))) {
if ($_GET['action'] == 'edit' && is_numeric($_GET['id'])) {
I would check parameters first:
$action = (isset($_GET['action']) && !empty($_GET['action'])) ? $_GET['action'] : false;
$id = (isset($_GET['id']) && !empty($_GET['id'])) ? $_GET['id'] : false;
settype($id, 'int'); // "123" became 123(int)
And then go with:
} elseif ($action && $id && $action == 'edit' && $id > 0) {
// here we are
}

Categories