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');
}
Related
I have created an index.php that serves as a template with a content box. I also have home.php, about.php, and contact.php which only contain the content to fill that content box. This is the code I use to embed pages into that content box:
<?php
if(!$_GET[page]){
include "home.php"; // Page to goto if nothing picked
} else {
include $_GET[page]."php"; // test.php?page=links would read links.php
}
?>
The home page works fine but I am not sure what code to use in the main menu to link to the other pages. I am having a very hard time getting an answer, so I think I may be searching with the wrong terms, which is why I am asking here.
On the main menu for the website, what code do I use in the links so that they get home.php, about.php, or contact.php?
I made the following test:
$page = "test.php?page=links";
$link = explode("=", $page);
echo $link[1].".php"; //gets links.php
So, your code should looks like:
<?php
if(isset($_GET[page])){
$page = $_GET[page];
$link = explode("=", $page);
include $link[1].".php"; // test.php?page=links would read links.php
} else {
include "home.php"; // Page to goto if nothing picked
}
?>
Saludos.
if(!$_GET[page]){
include "home.php"; // Page to goto if nothing picked
} else {
include $_GET[page].".php"; // test.php?page=links would read links.php
}
It was just missing the '.' before the 'php'.
You should use Quotes for arrays though to avoid a Notice (Undefined constant)
Be careful though, you should verify that $_GET['page'] only contains sites you want to make accessible. Otherwise an attacker could just read any file on your server.
if(array_key_exists('page', $_GET)) {
$page = preg_replace('~[^a-z]~', '', $_GET['page']);
include __DIR__ . '/' . $page . '.php';
} else {
include __DIR__ . '/home.php';
}
Better solution (but you have to manually add all the pages):
$page = (array_key_exists('page', $_GET) ? $_GET['page'] : 'home');
switch($page) {
case 'about':
case 'links':
case 'whatever':
include __DIR__ . '/' . $page . '.php';
break;
default:
include __DIR__ . '/home.php';
break;
}
About
?<key>=<value> in the url.
You look up a value in the $_GET-array by using the key.
Here is an example of what I am trying to do:
index.php
<ul><?php include("list.php") ?></ul>
list.php
<?php
if (PAGE_NAME is index.php) {
//Do something
}
else {
//Do something
}
?>
How can I get the name of the file that is including the list.php script (PAGE_NAME)? I have tried basename(__FILE__), but that gives me list.php.
$_SERVER["PHP_SELF"]; returns what you want
If you really need to know what file the current one has been included from - this is the solution:
$trace = debug_backtrace();
$from_index = false;
if (isset($trace[0])) {
$file = basename($trace[0]['file']);
if ($file == 'index.php') {
$from_index = true;
}
}
if ($from_index) {
// Do something
} else {
// Do something else
}
In case someone got here from search engine, the accepted answer will work only if the script is in server root directory, as PHP_SELF is filename with path relative to the server root. So the universal solution is
basename($_SERVER['PHP_SELF'])
Also keep in mind, that this returns the top script, for example if you have a script and include a file, and then in included file include another file and try this, you will get the name of the first script, not the second.
In the code including list.php, before you include, you can set a variable called $this_page and then list.php can see the test for the value of $this_page and act accordingly.
Perhaps you can do something like the following:
<ul>
<?php
$page_name = 'index';
include("list.php")
?>
</ul>
list.php
<?php
if ($pagename == 'index') {
//Do something
}
else {
//Do something
}
?>
The solution basename($_SERVER['PHP_SELF']) works but I recommend to put a strtolower(basename($_SERVER['PHP_SELF'])) to check 'Index.php' or 'index.php' mistakes.
But if you want an alternative you can do:
<?php if (strtolower(basename($_SERVER['SCRIPT_FILENAME'], '.php')) === 'index'): ?>.
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.
Is there any way to check if an included document via include('to_include.php') has returned anything?
This is how it looks:
//to_include.php
echo function_that_generates_some_html_sometimes_but_not_all_the_times();
//main_document.php
include('to_include.php');
if($the_return_of_the_include != '') {
echo $do_a_little_dance_make_a_little_love_get_down_tonight;
}
So after I've included to_include.php in my main document I would like to check if anything was generated by the included document.
I know the obvious solution would be to just use function_that_generates_some_html_sometimes_but_not_all_the_times() in the main_document.php, but that's not possible in my current setup.
make function_that_generates_some_html_sometimes_but_not_all_the_times() return something when it outputs something and set a variable:
//to_include.php
$ok=function_that_generates_some_html_sometimes_but_not_all_the_times();
//main_document.php
$ok='';
include('to_include.php');
if($ok != '') {
echo $do_a_little_dance_make_a_little_love_get_down_tonight;
}
If you are talking about generated output you can use:
ob_start();
include "MY_FILEEEZZZ.php";
function_that_generates_html_in_include();
$string = ob_get_contents();
ob_clean();
if(!empty($string)) { // Or any other check
echo $some_crap_that_makes_my_life_difficult;
}
Might have to tweak the ob_ calls... I think that's right from memory, but memory is that of a goldfish.
You could also just set the contents of variable like $GLOBALS['done'] = true; in the include file when it generates something and check for that in your main code.
Given the wording of the question, it sounds as if you want this:
//to_include.php
return function_that_generates_some_html_sometimes_but_not_all_the_times();
//main_document.php
$the_return_of_the_include = include 'to_include.php';
if (empty($the_return_of_the_include)) {
echo $do_a_little_dance_make_a_little_love_get_down_tonight;
} else {
echo $the_return_of_the_include;
}
Which should work in your situation. That way you don't have to worry about output buffering, variable creep, etc.
I'm not sure if I'm missing the point of the question but ....
function_exists();
Will return true if the function is defined.
include()
returns true if the file is inclued.
so wrap either or both in an if() and you're good to go, unless I got wrong end of the stick
if(include('file.php') && function_exists(my_function))
{
// wee
}
try
// to_include.php
$returnvalue = function_that_generates_some_html_sometimes_but_not_all_the_times();
echo $returnvalue;
//main_document.php
include('to_include.php');
if ( $returnvalue != '' ){
echo $do_a_little_dance_make_a_little_love_get_down_tonight;
}
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;
}