PHP Securely include files + handle invalid parameters - php

I'm having a little problem. I want to securely include files based on the $_GET Parameter from a subdirectory + handle if the parameter is not valid.
<?php
if(isset($_GET['p']) && $_GET['p'] == 'fahrzeuge'){
include 'includes/cars.php';
}
if(isset($_GET['p']) && $_GET['p'] == 'impressum'){
include 'includes/impressum.php';
}
if(isset($_GET['p']) && $_GET['p'] == 'home'){
include 'includes/home.php';
}
if(isset($_GET['p']) && $_GET['p'] == 'anfahrt'){
include 'includes/anfahrt.php';
}
if(isset($_GET['p']) && $_GET['p'] == 'about'){
include 'includes/about.php';
}
?>
This is my Code. Sorry I know it is a noob way of solving this. How can I improve it? Any Suggestions/Help would be highly appreciated

This is the fastes and best way, i am a fan of short codes
and found this from (HACKBUGZ PHP).
You have an array with array keys and array values.
EXAMPLE 1
<?php
$PAGES = array();
$PAGES = [
'home' => 'home.html'
,'about' => 'about.php'
,'contact' => 'somedir/contact.php'
];
#include(substr($PAGES[$_GET['p']] ?? ('home'), 0, 255));
exit;
?>
You can have different query names, filenames, filetypes and directorys.
the # catch the include error if file not exists.
substr($PAGES, 0, 255) cuts the uri to 255 chars(if you dont like that
just do it without)
($PAGES[$_GET['p']] ?? ('home')) checks if query (array_key) exists in array if not 'home' will be the default
EXAMPLE 2(without substr)
<?php
$PAGES = array();
$PAGES = [
'home' => 'home.html'
,'about' => 'about.php'
,'contact' => 'somedir/contact.php'
];
#include($PAGES[$_GET['p']] ?? ('home'));
exit;
?>

Set an array of legit pages. Check once if $_GET['p'] is set and if so assign its value (after escaping it) to a variable $p.
Then check if the requested page ($p) is defined in your pages array, if so - include it.
$pages = array('about','contact','home');
$p = 'home'; //Default page
if(isset($_GET['p'])) {
$p = $_GET['p']; //no need to escape as we compare it to predefined values as #Yoshi suggested
}
if(in_array($p, $pages)){
include 'includes/'.$p.'.php';
} else {
include 'includes/home.php';
}

I would use a ternary to set a variable that tells the page what to include.
This is very similar to Ofir Baruch's answer, except much shorter.
$pages = array('about','contact','home');
$p = isset($_GET['p']) && in_array($_GET['p'], $pages)? $_GET['p'] : 'home';
include "includes/{$p}.php";
Basically, you have an array of pages that are possible. In the ternary, we check if $_GET['p'] is set (isset()), AND we check if the value it contains is in the array. If it is, we use $_GET['p'] as $p, if it is not, we set $p to home, this means that home will always be the default if $_GET['p'] is not set, or not a valid page as per the array.

Related

if statement and isset($_GET if statement error with the ifelse

<?php if (isset($_GET['p'])) { $variable = $_GET['p']; ?>
<?php if ($variable == '1'): ?>
<?php include('pages/home.php');?>
<?php endif;?>
<?php };?>
<?php if (isset($_GET['p'])) { $variable = $_GET['p']; ?>
<?php if ($variable == '2'):
include('pages/about.php');
else: include('pages/home.php'); endif; };?>
The above is what I have used to try and fix it, but if I don't put it, errors show up. For example if I used "ifelse", and it tells me to change it to else, or endif. But when I use endif, it tells me to use ifelse. I'm trying to make it so http://localhost/?p=PAGE_ID just simply shows the page using an include(FILE_PATH) statement.
Does anyone know where I went wrong? Or how I can fix it :)
You seem to have thoroughly tied yourself in knots. To my mind, this is a much cleanrer and more flexible and maintainable way to approach the whole thing:
$pages = [
"1" => "pages/home.php",
"2" => "pages/about.php"
];
if (isset($_GET['p'])) {
if (isset($pages[$_GET['p']]))
{
$page = $pages[$_GET['p']];
}
else
{
$page = $pages["1"];
}
}
else
{
$page = $pages["1"];
}
include($page);
This way, you have a list of pages, and the system simply looks up the required page in the array by its index number (as passed in via the GET parameter). If it can't find that index, it just uses the default page.
You can now easily add pages by just adding items to the array, without needing to write more if/else logic. You could even store the array data in a database instead of it being hard-coded.
You dont need or want an elseif in this flow, simple do
<?php
if (isset($_GET['p'])) {
if ($_GET['p'] == '1') {
include('pages/home.php');
}
if ($_GET['p'] == '2') {
include('pages/about.php');
}
}
If the value of $_GET['p'] can only be 1 or 2 you could do
<?php
if (isset($_GET['p'])) {
if ($_GET['p'] == '1') {
include('pages/home.php');
} else {
include('pages/about.php');
}
}
Or if $_GET['p'] could be multiple values a switch may be more useful
<?php
if (isset($_GET['p'])) {
switch($_GET['p']) {
case 1:
include('pages/home.php');
break;
case 2:
include('pages/about.php');
break;
default:
include('pages/somethingelse.php');
}
}
Note I also left out the intermediate variable, as its not needed. The $_GET and $_POST arrays are, once filled by PHP all yours to use as you want. There is no need to waste CPU cycles and memory creating unnecessary variables

Keeping array from POST when using pagination link

I am having a litte issue with my searchengine.
It outputs the searchresult just fine, but when I am clicking a pagination link it fails, of course because it no longer have the $_POST array. I am using this piece of code:
if(empty($_POST) == false) {
$res = $search->search_ads($_POST);
if($res == false) {
$view->setData('numres', 0);
} else {
$view->setData('numres',$res[2]);
$view->setData('adverts', $res[0]);
}
$app->view()->setData('paginate', $res[1]);
$app->render('search.tpl');
} else {
$app->render('404.tpl');
}
When I click on f.x. "Page 2" it will render the 404 template.
Is there a way I can keep the $_POST array and reuse it in the search_ads function?
"paginate" contains the HTML for the pagination
<li><a class=\"paginate\" href=\"$target?page=$next_page&ipp=$this->items_per_page\">«</a></li>":"<li><span class=\"inactive\" href=\"#\">«</span></li>
use sessions.
session_start(); //on the top of your php file.
...
if(!empty($_POST))
$_SESSION['post_data']= $_POST;
...
if(empty($_SESSION['post_data']) == false) {
$res = $search->search_ads($_SESSION['post_data']);
...
}
Store the post array in a variable and use that elsewhere?
$post_array = $_POST;
$res = $search->search_ads($post_array);
You want to check for $_GET rather than $_POST on subsequent pages, as that's the method your using to pass the data:
href=\"$target?page=$next_page&ipp=$this->items_per_page\"
Will provide you with a $_GET array containing key value pairs:
$_GET['page'] = value of $next_page
$_GET['ipp'] = value of $this->items_per_page

Pagination Problems(PHP superglobal variable issue, undefined index)

i am trying to implement pagination somewhere and i have this issue:
I have this part to change links:
echo " <a href='$_SERVER[SCRIPT_NAME]?Page=$Prev_Page'><< Back</a> ";
which gives this error for this part:
$Page = $_GET["Page"];
if(!$_GET["Page"])
{
It says undefined index..
Why do I get this Error?
Thanks
You should quote the array index. also use html entities.
Like this
echo " <a href='{$_SERVER['SCRIPT_NAME']}?Page=$Prev_Page'><< Back</a> ";
And its safe to check if $_GET["Page"] exists.
$Page = isset($_GET["Page"]) ? $_GET["Page"]: false;
This happens because you are missing an index in the array. $_GET is just an array, so you should check if the key exists first.
$Page = (array_key_exists('page', $_GET)) ? $_GET["page"] : false;
if($Page===false)
{
//no page
return;
}
// empty() works even if the variable doesn't exist, kind of like isset()
if(!empty($_GET['Page']) !== false) {
// Do stuff
$page = $_GET['Page'];
}

Idea with php logic using operators

I am new to PHP and find it very hard to explain.
I have a PHP navigation script with 5 categories and two variables relevant to my question:
$catname = 'used-cars'; // the same value for all categories
$currentpage; // pages 1 to 5
index.php of my site has $currentpage == '1'
The issue is that I need a logic that will say:
If $catname IS NOT 'used-cars', do something, BUT, IF $currentpage is equal to 1, even if $catname is 'used-cats' do it anyway
I am thinking of something like this:
if($catname != 'used-cars' && !($currentpage > '1')):
endif;
Hope you can help!
This is merely a single or condition. On the right side, $currentpage === 1 will evaluate to TRUE without regard to the value of $catname. If either part of the condition is TRUE, you'll enter the if () block to execute your code there.
if ($catname !== "used-cars" || $currentpage === 1) {
// do your thing
}
This is just:
if (strcmp($catname, 'used-cars') != 0 || $currentpage == 1)
(Careful with the string comparison.)
Alternatively, you could declare it as a boolean first:
$proceed = false;
if($catname != 'used-cars')
$proceed = true;
if($currentpage == 1)
$proceed = true;
if($proceed){
// whatever you want
}
$doflag = 0;
if($catname != 'used-cars')
{
$doflag = 1;
} else if($currentpage == 1) {
$doflag = 1;
}
if($doflag == 1) {
//do something
}
Basically instead of trying to do everything with the block, use the block to set a flag and use the flag to do something.

Dynamic include

<?php
// Default page
if (!$_SERVER['QUERY_STRING']) $Page = "news";
// View
elseif (isset($_GET['newsID'])) $Page = "newsView";
elseif (isset($_GET['userID'])) $Page = "profile";
elseif (isset($_GET['messageID'])) $Page = "message";
elseif (isset($_GET['threadID'])) $Page = "thread";
elseif (isset($_GET['forumID'])) $Page = "forum";
elseif (isset($_GET['imgID'])) $Page = "imageView";
// Pages
elseif ($_GET['content'] == "search") $Page = "search";
elseif ($_GET['content'] == "gallery") $Page = "gallery";
elseif ($_GET['content'] == "forums") $Page = "forums";
elseif ($_GET['content'] == "messages") $Page = "messages";
many more...
// If page don't exist
else $Page = "error";
// Output page
include($config['PAGE_PATH'].$Page.'.php');
include($config['TEMPLATE_PATH'].$Page.'.html');
?>
This is some code my friend wrote years ago...
I'm wondering how safe this is and if I could make it a little cleaner?
Thanks.
As it is you who defines what pages are allowed to be included (white list), I cannot see any way to poison the $Page variable. So this seems pretty safe.
But you could clean it up using arrays such as:
$argToPage = array(
'newsID' => 'newsView',
'userID' => 'profile',
'messageID' => 'message',
'threadID' => 'thread',
'forumID' => 'forum',
'imgID' => 'imageView'
);
$contents = array(
'search',
'gallery',
'forums',
'messages'
);
$Page = null;
if (trim($_SERVER['QUERY_STRING']) == '') {
$Page = 'news';
} else {
foreach ($_GET as $key => $val) {
if (isset($argToPage[$key])) {
$Page = $argToPage[$key];
break;
}
}
}
if (is_null($Page) && isset($_GET['content']) && in_array($_GET['content'], $contents)) {
$Page = $contents[$_GET['content']];
} else {
$Page = 'error';
}
But that’s not much cleaner.
Well it's safe in the sense that the code sanitizes the parameter. People often do that (to disastrous results usually).
I'm not a big fan of this pattern however. By that I mean a single controller that includes files passed on a parameter. I much prefer to have a script per page and just include what's needed. Structurally I think it's better.
That being said, there's nothing fundamentally wrong with the above approach.
Just make sure you treat any data that comes from the user with extreme paranoia.
I'd be very cautious about cleaning this up any more than it is. Using a variable provided by user input in an include is a major security flaw. I would leave this as it is.
You could make an array with GET options as key and pages as values.. then use switch() statement. This should make the code cleaner. But as Cletus said, this isn't the best way to make a controller.

Categories