Error message whenever I open the index.php page - php

I'm working on a website and this is what I have for my index.php:
<?php
$p = $_GET['p'];
$pages = array('home', 'culture', 'design', 'art', 'about');
$path = 'http://localhost:8080/projects';
include('header.php');
if(!isset($p) || !in_array($p, $pages)) {
include('header.index.php');
include('content.index.php');
} else {
switch($p) {
case "home";
include('header.home.php');
include('content.home.php');
break;
case "culture";
include('content.culture.php');
break;
case "design";
include('content.design.php');
break;
case "about";
include('content.about.php');
break;
case "art";
include('content.art.php');
break;
default:
include('content.index.php');
break;
}
}
include('footer.php');
?>
I get the following error:
**Notice: Undefined index: p in C:\wamp\www\projects\index.php on line 3
Call Stack
# Time Memory Function Location
1 0.0523 680200 {main}( ) ..\index.php:0**

When you assign p initially, p is not set in $_GET
So you can do this
$p = isset($_GET['p']) ? $_GET['p'] : null;
If you don't care about notices, You can disable them in your php.ini by changing error_reporting to E_ALL & ~E_NOTICE, however I wouldn't recommend it

The switch statement you have is somewhat bogus, especially as you already have the $page array. You actually want to verify if the page exists or load the index page (probably?):
$p = isset($_GET['p']) ? (string) $_GET['p'] : NULL;
$pages = array('home', 'culture', 'design', 'art', 'about');
$path = 'http://localhost:8080/projects';
if (!in_array($p, $pages)) {
$p = 'index';
}
// include $p based on $path
However, you still have the problem with the header. So this is the lesson: make the header part of every include. You can stack as many includes as you like, just take care that every include contains it's correct header. Then you're done. And you won't see any warnings.
So the code after following what #hakre suggested should look like this:
$p = isset($_GET['p']) ? (string) $_GET['p'] : NULL;
$pages = array('home', 'culture', 'design', 'art', 'about');
$path = 'http://localhost:8080/projects';
include('header.php');
if (!in_array($p, $pages)) {
$p = 'index';
include('header.index.php');
include('content.index.php');
}
Thanks #hakre for your help..

Just a suggestion maybe try !empty()
if(!empty($p) || !in_array($p, $pages)) {
include 'header.index.php';
include 'content.index.php';
}

This is NOT an error. As the log claims this is a NOTICE. It is meant to inform you about a potential problem, but does not keep the script from being executed.
In this case the interpreter tells you that the array $_GET does not contain an element with index 'p'. It is not initialized, probably cause it has not been specified in the request in this case.
Try to test first if the element exists before you try to access it. Use isset() for this.

Related

$page =$_GET["page] (an other post)

I'm learning PHP and i block on a problem. I read posts about this issue but i still do not understand.
This is my code (from index.php):
$page = $_GET['page'];
$page = $_GET['action'];
if ($page == "operation" && $action == "liste"){
include("operationForm.php");
}
if ($page == "produits" && $action == "ajout") {
include('../Produits/AddProductForm.php');
}
When i tried to navigate i come across this message:
(404 Not Found : /Fournisseurs/index.php was not found on this
server).
I really don't see where is the problem. Do you have any tips or tutos for solving this problem ?
$page = $_GET['page'];
$page = $_GET['action'];
You are using the same variable name !
This looks better :P
$page = basename($_GET['page']);
$action = basename($_GET['action']);
As for the 404...
../ means parent folder, it seems the file you want to include is not located there. Be careful when using user input, validation / sanitization is mandatory
$page = $_GET['page'];
$page = $_GET['action'];
You set your variables with the same name. So the second $page is overwrite the first $page.

How to place include in other place

I make some function in php, but I am getting stuck
if (isset($_GET['page']) )
{
$open = __DIR__.'/../view/html/'.$_GET['page'].'.php';
if (file_exists($open)){
include $open; //<<<<can i//
}
else {
"echo "The file not found";
}
}
If true, I want to include that file in another place, but how?
I am trying to put the code in where I want, but the __DIR__ is not working as I expected. I don't know how to fix it to become right. Solution cannot be found in the tutorial.
I would use:
if( isset( $_GET['page'] ) ) {
switch( strtolower( $_GET['page') ) ) {
case 'download':
include '../download.php';
break;
case 'blog':
include '../blog.php';
break;
// ... And so on
default:
echo 'File not found';
}
} else {
echo 'No file specified';
}
This way you have full control over which files can be included!
You have to do like this.
Use file_get_contents()
if (file_exists($open)){
file_get_contents($open);
}
The answer to your question is yes, that will work. Whether or not you should use readfile(), file_get_contents() or include depends on the contents of the file. If you have php code in that file, you need either include or require. But this actually brings up another problem.
As mentioned in the comments by #anonymous, you are exposing yourself to an LFI attack. To resolve this, pages should be defined as a whitelisted array. You should then check if the page is in the whitelisted array. If it is not, do not attempt to open that file.
$pages = array(
'page1',
'page2'
);
Then you can make a reference and check if it exists.
if(in_array($_GET['page'], $pages)){
//now check for the file
$open = __DIR__.'/../view/html/'.$_GET['page'].'.php';
if(file_exists($open)){
include $open;
}
} else {
//page does not exist, redirect them elsewhere.
header('Location: http://example.com/404.php');
}

Problem with including files based on (non-defined) variable

i have a PHP site with the following code in it:
<?php
$p = $_GET['p']
include("$p.inc");
?>
Whenever I send a visitor to a page like index.php?p=contact for example I want the file contact.inc to be included. This works fine.
Now I want a certain file to be included (e.g. start.inc) when the visitor is sent to index.php without any GET variables. However, an error message is returned which tells me that $p is undefined (which it logically is).
I tried fixing this problem by using the isset function like so:
<?php
if(!isset($p)) $p = "start";
else $p = $_GET['p'];
include("$p.inc");
?>
but this doesn't work because now $p always contains the string "start" and I can't send the visitor to index.php?p=contact anymore - it will still include start.inc
Can somebody please help me with this issue?
Thanks in advance!
Explicitly specify the allowable values​​, obtained from outside.
<?php
$allowed_pages = array(
'home' => 'home.inc',
'contact' => 'contact.inc',
);
$page = #$_GET['p'];
$file = array_key_exists($page, $allowed_pages) ? $allowed_pages[$page] : $allowed_pages['home'];
include($file);
?>
You should white-list your pages anyway, for security. so:
<?php
$p = $_GET['p']
switch($p){
case 'contact':
include("contact.inc");
break;
default:
include("start.inc");
}
?>
Define your $p variable just like this:
$p = array_key_exists('p', $_GET) ? preg_replace('!\W!', '', $_GET['p']) : 'start';
you're checking $p instead of $_GET['p'] so, as $p is never set, you always land at starting page.
anyway you have to sanitize this variable first.
good practice would be like this (assuming pages stored in a "pagedata" folder and have .php extension):
if(isset($_GET['p'])) {
$p = basename($_GET['p']);
} else {
$p = "start";
}
$fileName = "pagedata/$p.inc.php";
if(is_readable($fileName)) {
include($fileName);
} else {
include("pagedata/404.html");
}
You should prefer an array-map or a switch like Nanne suggested.
At the very least use basename() if you want to keep using the $p variable directly in the include statement. And this is how you could avoid the "error" (which is a debug notice, btw):
<?php
$p = #$_GET["p"] or $p = "start";
$p = preg_replace("/\W+/", "", $p); // minimum filtering
include("./$p.inc");
?>
Thanks to you all!
I combined most of your suggestions to the following piece of code:
<?php
$pages = array(
'start'=>'Start.inc';
'contact'=>'Contact.inc';
'about'=>'About.inc';
};
$p = array_key_exists(#$_GET['p'], $pages) ? preg_replace('!\W!', '', $_GET['p'] : 'start';
$p = ucfirst($p);
$page = "./$p.inc";
if(is_readable($page)) include($page);
else include(./404.);
?>
I particularly like the array-map (as suggested by Alex and mario) for security reasons aswell as the error page idea by Col. Shrapnel.

php session strange behavior

I have a PHP website with a custom page routing system.
A php script checks the requested uri and uses a switch case to determine which page needs to be loaded. Each page has its own $page_id.
Here's a simplified version.
$page_uri = //code that extracts the relevent part of the uri
switch($page_uri){
case 'about':
$page_id = 'about';
break
case 'products':
$page_id = 'products';
break;
default:
$page_id = '404';
break;
}
include 'sessions.php'; //explanation about this after the code
include $page_id; //code that loads the page based on the $page_id
For one of the site's function, I need to know the $page_id of the previously visited page.
I am using sessions for this.
session_start();
$previous_page_id = $_SESSION['current_page_id'];
$_SESSION['current_page_id'] = $page_id;
I am therefore storing the previous $page_id which is stored in a session variable in the $previous_page_id variable before the session variable gets updated to the current $page_id.
The problem is that it doesn't work. The $previous_page_id is always equal to the default $page_id which is 404. I know the actual routing function works because the right page gets loaded and if I echo the value of the session right after storing it it's correct.
I've noticed that I can get the correct $previous_page_id if I put the following part before everything else.
session_start();
$previous_page_id = $_SESSION['current_page_id'];
What am I missing? Can you think of anything wrong with my code or logic? Is there some weird quirks I should be aware of when it comes to PHP sessions?
Thanks.
Update
It seems adding session_start(); echo $_SESSION['current_page_id']; at the top of the page makes the value stick. Otherwise by the time I get to transfering the session value to the $previous_page_id in sessions.php, the session value has changed to 404.
Can anyone make sense of that?
The problem was coming from a missing favicon.ico file which was triggering a 404 page load after each page load.
You need to put the session_start(); at the beginning of the script, that way the session is started (and available) when you need it in your big switch statement.
You have forgot to add .php extension to your include (+ some smaller things). And remember that session_start must be called at beggining, before any use of it. So you need to call it on beggining or include sessions at beggining.
So it should look like:
session_start();
$page_uri = //code that extracts the relevent part of the uri
switch($page_uri){
case 'about':
$page_id = 'about';
break;
case 'products':
$page_id = 'products';
break;
default:
$page_id = '404';
break;
}
$previous_page_id = $_SESSION['current_page_id'];
$_SESSION['current_page_id'] = $page_id;
include $page_id . '.php'; //code that loads the page based on the $page_id
session_start();
$previous_page_id = $_SESSION['current_page_id'];
$_SESSION['current_page_id'] = $page_id;
I don't really get this. $previous_page_id and $page_id are equal.
You are setting them to be equal.
You should set it after the switch statement as follows:
$page_uri = //code that extracts the relevent part of the uri
if (file_exists('sessions.php')) {
include 'sessions.php';
} else {
trigger_error("'sessions.php' not found", E_USER_ERROR);
}
switch($page_uri) {
case 'about':
$page_id = 'about';
break
case 'products':
$page_id = 'products';
break;
default:
$page_id = '404';
break;
}
if (isset($_SESSION['current_page_id'])) {
$_SESSION['current_page_id'] = $page_id;
} else {
trigger_error("'current_page_id' key not set", E_USER_ERROR);
}
if (isset($page_id)) {
include $page_id;
} else {
trigger_error("'page_id' not set", E_USER_ERROR);
}
with sessions.php being:
$ss = session_start();
if (!$ss) { trigger_error("Session couldn't be started", E_USER_ERROR);
if (isset($_SESSION['current_page_id'])) {
$previous_page_id = $_SESSION['current_page_id'];
} else {
trigger_error("'current_page_id' key not set", E_USER_ERROR);
}

Secure way to include page from GET parameter?

I'm working on a set up where the URLs will be along the lines of:
http://example.com/index.php?page=about
In reality they will rewritten to that from a simpler URL. index.php will include another page, using this code:
if ( isset( $_GET['page'] ) )
{
$page = $_SERVER['DOCUMENT_ROOT'] . '/pages/' . $_GET['page'] . '.php';
if ( is_file( $page ) )
include $page;
else
echo 'That page doesn\'t exist.';
}
Assuming everything in the pages folder is perfectly safe to be included, is this code secure? I've protected against the well-known directory hacks, i.e. using page=../../.passwd. Is there anything else I should be mindful of?
probably better to switch-case it
$page_name = $_GET['page'];
switch($page_name) {
case 'about':
$page = $_SERVER['DOCUMENT_ROOT'] . '/pages/about.php';
break;
case 'home': //fall through to default
case default:
$page = $_SERVER['DOCUMENT_ROOT'] . '/pages/home.php';
}
include $page;
This way, there isn't any injection problem.
Edit
Another solution would be to set up a class dedicated to handling the conversion of page name to address.
class Page {
static private $pages = array ("about", "home");
const DEFAULT_PAGE = "home";
static public function includePage($page_name) {
if (!in_array($page_name, self::$pages)) {
$page_name = self::DEFAULT_PAGE;
}
include ($_SERVER['DOCUMENT_ROOT'] . '/pages/'.$page_name.'.php';);
}
}
This way this is all managed inside a single class and future changes are easier to make without digging through other code
edited above to reflect request.
your code is ok, except that you should validate the parameter before use:
if(!preg_match("~^\w+$~", $_GET['page']))
die("page id must be alphanumeric!");
i won't recommend "switch" approach, because it decreases flexibility, which is the whole point of using dynamic includes.
You can also switch to a framework like CodeIgniter that will do it all for you and force you into adopting some coding standards which is always a good thing.
A very secure way to do this would be to first construct a list of directory contents, then match the user input to that list and use the value from the list for the include. Something in the lines of:
$sdir = $_SERVER['DOCUMENT_ROOT'].'/pages/';
$targetfile = $_GET['page'].'.php';
$filenames = scandir($sdir); // returns an array of directory contents
foreach ($files as $filename) {
if (($filename[0] != '.')
&& ($filename == $targetfile)
&& (is_file($sdir.$filename)) {
include $sdir.$filename;
break;
}
}
Or you could do it simply by:
$targetfile = $_GET['page'].'.php';
$sdir = $_SERVER['DOCUMENT_ROOT'].'/pages/';
$filenames = scandir($sdir);
if (in_array($targetfile,$filenames)) {
include $sdir.$filename;
}
But in the latter case you have to be really sure you get the check conditions right, and also use the regex check suggested in another answer. In the first case, you're only including from a list constructed from the directory contents, so it'll be safe even if the user manages to get some weird input through your checks.
When handling an arbitrary number of pages it might be best to ensure you have SEO friendly filenames. I would recommend alphanumeric filenames with hyphens or underscores:
define(DOCROOT, $_SERVER['DOCUMENT_ROOT']);
// assume you do not include file extensions in $_GET['page']
$page = trim(preg_replace('~[^\\pL\d]+~u', '-', $_GET['page']), '-');
if (is_file($page)) {
include DOCROOT . $page;
}

Categories