Among the following include methods which is the best to practice and why?
$page = $_GET['page'];
Method 1
$pages = array('home', 'blog', 'about');
if( in_array($page, $pages) )
{
include($page.'.php');
{
else
{
die('Nice Try.');
}
Method 2
if($page = 'home'){
include('home.php');
}else if($page = 'blog'){
include('blog.php');
}else if($page = 'about'){
include('about.php');
}
Method 3
if(str_replace("http://", "gth://", $page) == $page){
include_once $page;
}else{
die('Nice Try.');
}
or any other solutions? I dont prefer method 1 and 2 as it always needs to be updated everytime i add a new page.
extending/maintaining the first way is easiest, second way is worse. third way is no way to go, as it relies on user input to require pages... it is going to be a security hole
I believe that the first one is the best of the lot. You can try the second one, but it's for the freshers. And the third one is a BIG NO, because any fresher hacker could hack your "if" condition, & more loopholes will start creeping in.
As for your problem, on adding a new page to the array, every time a new page is created, for the first method, I have one solution:-
Let's say you're putting all the new pages in one folder "abc". Now just write one file code as the following, to read all the files / pages existing in that folder:-
<?php
$page = $_GET['page'];
$pages = array();
/**
* If you are using all the pages existing in the current folder you are in,
* then use the below variable as:-
* $path = ".";
*/
$path = 'abc/'; // Change the Path here, related to this Folder name
$handle = opendir($path);
while (($file = readdir($handle)) !== false) {
$pages[] = $file;
}
closedir($handle);
if( in_array($page, $pages) ) {
include($page.'.php');
}
else {
die('Nice Try.');
}
?>
So you see that the array is getting filled up dynamically, without the need to mention all the pages you create every time. And you are using the first method only. And keep the including pages in one separate folder, which you will need to include every time, in other main pages.
Hope it helps.
Related
I want to include a file with php inside of a function, but for it to be used outside of the function.
function add( $F ){
$i = 3;
while( $i > 0 ){
$i--;
try{
if( ( include $GLOBALS['_SERVER']['DOCUMENT_ROOT'] . $F ) == 2 ){
break;
}
else{
sleep( 1 );
}
}
catch( Exception $e ){ }
}
die();
}
This function is automatically included thanks to auto_prepend_file.
index.php
add( '/cat.php' );
echo 'my' . $cat;
/cat.php
$cat = 'cat';
echo '...';
return 2; //rather not exist but doesnt seem like there's a choice
When index.php is loaded: Results in my... not my...cat.
include returns 1 even if a file was included or not. Well, if Notepad++ is 50% finished uploading a file that at the same time was included, it will return 1 and it seems like it just includes a empty file. Which is why == 2 exists in add function.
If I want to include something, I don't want an answer like you got lucky or nope, better luck next time or saving was taking too long, enjoy nothing, or a bunch of code everywhere.
So is this even possible? Or is there a better alternative? Can I use include_guaranteed (sarcasm)? I know similar questions were made, but those answers were mainly alternatives to what the user was doing or "why" related.
I've placed a hit counter on my page. It reads a text file, increments the number in the file, and later in the page, I output the incremented value.
$hitsFile = "hits/exps/stats.txt";
$hits = file($hitsFile);
$hits[0]++;
$fp = fopen($hitsFile , "w");
flock($fh, LOCK_EX);
fwrite($fp , $hits[0]);
fclose($fp);
My problem is that if I reload the page, the code will increment the hits. I don't want that. I thought of using session to fix that, but with session, in order the increment the hits again, I need to exit the site and visit again. I don't want that either.
I want it to increment not when I reload the page but when I revisit the page.
For example, let's say I have two-page website, Home and Contact, and on contact page I have a hit counter. I don't want the hit counter to increment if I reload(refresh) the contact page, but if I leave the contact page and visit homepage, and later revisit the contact page, I want it to increment.
In short, I don't want it to increment on page reload. Is there a way to do that?
In each of your pages, you need to write the page name in the session.
Do something like this:
$_SESSION['page'] = 'contact';
On the pages where you need to count hits, you need to check this session key.
For example, if you were on page 'contact', then $_SESSION['page'] == 'contact'.
Now when you go to visit the 'homepage':
$page = $_SESSION['page'];
if($page != 'homepage')
{
//increment your hits counter
$_SESSION['page'] = 'homepage';
}
I suggest this method, is my preferred, create in root these folders: cnt and log... then put inside cnt folder the following files cnt.php and showcnt.php...
cnt.php
<?php
##############################################################################
# Php Counter With Advanced Technology For The Prevention Of Reloading Pages #
# Version: 1.4 - Date: 13.11.2014 - Created By Alessandro Marinuzzi [Alecos] #
##############################################################################
function cnt($file) {
session_start();
global $pagecnt;
$reloaded = isset($_SERVER['HTTP_CACHE_CONTROL']) && $_SERVER['HTTP_CACHE_CONTROL'] === 'max-age=0';
$thispage = basename($_SERVER['SCRIPT_FILENAME']);
if (!isset($_SESSION['first_go'])) {
$_SESSION['first_go'] = 1;
$first_go = TRUE;
} else {
$first_go = FALSE;
}
if (!isset($_SESSION['thispage'])) {
$_SESSION['thispage'] = $thispage;
}
if ($_SESSION['thispage'] != $thispage) {
$_SESSION['thispage'] = $thispage;
$new_page = TRUE;
} else {
$new_page = FALSE;
}
$pagecnt = rtrim(file_get_contents($file));
if ((!$reloaded) && ($new_page == TRUE) || ($first_go == TRUE)) {
$fd = fopen($file, 'w+');
flock($fd, LOCK_EX);
fwrite($fd, ++$pagecnt);
flock($fd, LOCK_UN);
fclose($fd);
}
}
?>
showcnt.php
<?php
##############################################################################
# Show Counter Results - v.1.4 - 13.11.2014 By Alessandro Marinuzzi [Alecos] #
##############################################################################
function gfxcnt($file) {
global $number;
$number = rtrim(file_get_contents($file));
$lenght = strlen($number);
$gfxcnt = "";
for ($i = 0; $i < $lenght; $i++) {
$gfxcnt .= $number[$i];
}
$gfxind = "<span class=\"counter\"><span class=\"number\">$gfxcnt</span></span>";
echo $gfxind;
}
?>
Well, then edit your index.php or other php page... and put at the beginning this piece of code:
<?php session_start(); include("cnt/cnt.php"); cnt("log/index.txt"); include("cnt/showcnt.php"); ?>
Well, then edit index.php or other php page... and use this piece of code for reading counter file:
<?php gfxcnt("log/index.txt"); ?>
It's all, I hope you'll find my answer useful :) My counter can write/read multiple php pages...
Source: my blog (https://www.alecos.it/new/101/101.php)
Add session_start(); to the top.
Now change your if to this:
if (!isset($_SESSION['lastpage']) || $_SESSION['lastpage'] != $_SERVER['QUERY_STRING') {
$hits[0]++;
}
$_SESSION['lastpage'] = $_SERVER['QUERY_STRING'];
This will basically force someone to move to another page if they want to increment the counter.
Update the hit count only if the current URL is not stored in $_SESSION['url'].
After updating the hit count, store the current URL in $_SESSION['url'].
I have 3 (.php) files/pages for a website (in a folder), I have Previous/Next Links displayed on the bottom of each. What php code on the previous/next link, would help me navigate to the next page.
For Example:
Lets say the pages are Page1.php, Page2.php, Page3.php, and I am currently on Page2.php.
If I want to click on the 'Previous' Link, I want Page1.php to be displayed.
If I click on 'Next' then I want Page3.php to be displayed.
I believe this is called 'pagination'?
Previous
Next
I dont know if this is possible. And I hope I have been clear with describing the problem.
Thanks,
babsdoc
Here is the original code #Fred
$images = "jars/"; # Location of small versions
$big = "samp2/"; # Location of big versions (assumed to be a subdir of above)
$cols = 2; # Number of columns to display
if ($handle = opendir($images)) {
while (false !== ($file = readdir($handle))) {
if ($file != "." && $file != ".." && $file != "samp2" && $file != "Thumbs.db") {
$files[] = $file;
}
}
closedir($handle);
}
foreach($files as $file)
{
$pc="Product Code:".substr($file,0,-4);
<a href=\"$images$big$file\" class=\"swap\"><img src=$images$file title=\"title\"
width=\"100\" height=\"100\">
$pc</a></li>";
}
Providing you're going to keep a sane naming convention throughout (ie pageX.php), then the following should suffice.
(might not be the ideal solution for you but gives you an idea. Can be put in a function/changes made, etc)
$strCurrentPage = basename($_SERVER['REQUEST_URI']);
$strPattern = '/\d+/';
preg_match($strPattern, $strCurrentPage, $strGetPageNumber); // extract numerical value
//set two new vars to same as page number, increment one and subtract one
$strNextPageNum = $strGetPageNumber[0];
$strPreviousPageNum = $strGetPageNumber[0];
$strNextPageNum++;
$strPreviousPageNum--;
//set full filename with new numbers
$strNextPage = 'page'.$strNextPageNum.'.php';
$strPreviousPage = 'page'.$strPreviousPageNum.'.php';
//if file is found then show link
//next page
if (file_exists($strNextPage))
{
echo 'Next Page';
}
else
{
echo "No more pages";
}
//previous page
if (file_exists($strPreviousPage))
{
echo 'Previous Page';
}
else
{
echo "No previous pages";
}
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.
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;
}