Before I start, I am completely new to PHP. This is probably a stupid error and I am probably doing this in the worst way possible.
I have this code:
<?php
if (!isset($_GET['p'])) {
$url .= '?p=home';
header('Location:' . $url);
exit;
}
elseif (!isset($_GET['sp'])) {
header("Location: ".$_SERVER['REQUEST_URI'].'&sp=index.php';);
die();
}
include('/Page/' . htmlspecialchars($_GET["p"]) . '/' . htmlspecialchars($_GET["sp"]));
?>
Basically the url format is www.example.com/?p=PAGE&sp=SUBPAGE.php
The internal format from this will be /Page/PAGE/SUBPAGE.php
Reasons:
Each 'Post' will have it's own folder for it's resources. (?p=) Then they can put anything within their folder and link to it with the SUBPAGE (&sp=).
This keeps everything organised and stops any internal linking to anywhere but the /page/ area.
What's wrong:
If there is no Page (p) set I need to add ?p=home as the default and if their is no SubPage (sp) set I need to add &sp=index.php by default.
If there is no Page then the SubPage will be reset to default.
If you are on a page www.example.com/?p=blog then it will add the subpage without removing the page (?p=blog to ?p=blog&sp=index.php)
However if there is no page then the subpage will be reset to default.
The question:
How can I come about this?
Thank you, in advance.
I would approach the situation differently.
Set up some variables, for page and inner page with the default values and only re-assign them if the $_GET params are set
$page = 'home';
$inner_page = 'index.php';
if( isset( $_GET['p'] ) )
{
$page = htmlspecialchars( $_GET['p'] );
}
if( isset( $_GET['sp'] ) )
{
$inner_page = htmlspecialchars( $_GET['sp'] );
}
include $_SERVER['DOCUMENT_ROOT'] . '/Page/' . $page . '/' . $inner_page;
I've added $_SERVER['DOCUMENT_ROOT'] in too because if you use /Page then it is an absolute path, probably not what you were expecting, so prepending $_SERVER['DOCUMENT_ROOT'] ensures you're looking at the path inside your web directory.
Something else worth noting; Don't assume the data is good, people could try manipulate the files that are included.
http://your.domain/index.php?p=../../../../../&sp=passwd
So it would be worth trying to sanitize the data first.
Your current code has a big security flaw.
One of the most important rule when you write an app, never trust data coming from client. Always assume, they will send you wrong or bogus data.
I would recommend you to create a configuration file defining what are the allowed routes.
By executing the following line, you just allowed anyone to access any file that would be readable by your webserver.
include('/Page/' . htmlspecialchars($_GET["p"]) . '/' . htmlspecialchars($_GET["sp"]));
What happens If you sent a valid value for $_GET['p'] and this for $_GET['sp'] :
"/../../../../../../../../../../../etc/apache2/httpd.conf"
In this example, it will output your apache configuration file (assuming that this is the right path, if not an hacker can just keep trying path until he finds it).
To avoid this, you have two solutions.
1# Quick fix - You can sanitize & filter $_GET['p'] and $_GET['sp'] to ensure that you are not getting something '/../'. Make sure to add at least a file_exists before to avoid getting unwanted warning messages.
2# More elegant fix - You can create a configuration file that would contain the routes that you are accepting. If you are using a framework, there is a very high chance that you have a routing class or a routing module that you can just use. Otherwise, if you feel like implementing your own basic routing mechanism, you could do something as simple as in your case :
<?php
/**
* Defines the different routes for the web app
* #file : config.routes.php
*/
return array(
'page1' => array(
'index.php',
'subpage2.php',
'subpage3.php',
),
);
Then, your code you would check if the $_GET['p'] and $_GET['sp'] are allowed values or not.
<?php
// Load config file containing allowed routes
$allowedRoutes = require(__DIR__ . '/config.routes.php');
$defaultPage = 'home';
$defaultSubPage = 'index.php';
$page = isset($_GET['p']) ? $_GET['p'] : defaultPage;
$subPage = isset($_GET['sp']) ? $_GET['sp'] : $defaultSubPage;
// If it is an invalid route, then reset values to default
if (!isset($allowedRoutes[$page][$subPage]))
{
$page = $defaultPage;
$subPage = $defaultSubPage;
}
include $_SERVER['DOCUMENT_ROOT'] . '/Page/' . $page . '/' . $subPage;
Related
I am trying something strange with code i just want to know weather it is possible to perform a php code like this one
<?php
$cururl= ucfirst(pathinfo($_SERVER['PHP_SELF'], PATHINFO_FILENAME));
$nexurlw = $cururl-1;
echo "$nexurlw";
?>
I have a problem in this code. My current page url is 30.php and i have a button on page "go to previous page" i want to change its url 29.php with the help of this function.
But this function echo 30 every time.
Try this :
$cururl = ucfirst(pathinfo($_SERVER['PHP_SELF'], PATHINFO_FILENAME));
$intUrl = ((int) $cururl) - 1;
$nexurlw = (string) $intUrl.'.php';
echo "$nexurlw";
Even if it happens to be true in your case (because that's the default in a raw PHP installation) there's often no direct mapping between URL locations and filesystem objects (files / directories). For instance, this question's URL is
https://stackoverflow.com/questions/68504314/how-to-get-current-webpage-name-and-echo-with-some-modification but the Stack Overflow server does not have a directory called 68504314 anywhere on its disk.
You want to build a URL from another URL, thus there's no even any benefit in having the filesystem involved, you can just gather the information about current URL from $_SERVER['REQUEST_URI']. E.g.:
$previous_page_url = null;
if (preg_match('#/blah/(\d+)\.php#', $_SERVER['REQUEST_URI'], $matches)) {
$current_page_number = (int)$matches[1];
if ($current_page_number > 1) {
$previous_page_url = sprintf('/blah/%d.php', $current_page_number - 1);
}
}
I would like to use this concept on my webshop, but how can I send variables through?
(You know index.php? Page = test & variable = 22 // variable does not work)
$page = isset($_GET['Page'])? trim(strtolower($_GET['Page'])) :"front";
$allowedPages = array(
'front' => './include/webshop_frontshop.php',
'logon' => './include/webshop_tjek_login.php',
'test' => './include/webshop_testside.php'
);
include( isset($allowedPages[$page]) ? $allowedPages[$page] : $allowedPages["front"] );
This link works fine!: nywebshop.php?Page=test
This link does not work (says the page does not exist): nywebsite.php?Page=test&item=5
Possible errors:
1) You use spaces in URL (in exemple you did)
2) In php you use $_GET['side'] - not $_GET['Page'] or $_GET['variable']
3) If you want to save variables in all pages after sending, you can use sessions:
$_SESSION['get_saved_param__Page'] = $_GET['Page'];
And it will be good to use standart
if {
// code
} else {
// code
}
As it much easier to read and you will spend most of the time in coding at reading your scripts, not writing.
I want to use the array function of PHP to translate a website. I have created PHP files with arrays in them for all the text to be translated.
<?php
//ESPANOL
$lang = array(
'work' => 'Trabajo'
'packaging' => 'Empaque'
);
And then I am calling them inside my nav.php file, and will in the content section too.
<?php include('includes/languages/es.php'); ?>
<?php echo $lang['work']; ?>
All pretty straight forward.
What I want to know is how to switch between these array files without editing the HTML, so that I don't have to link to another 'index_es.php' etc. I understand that the link would be something like this, but I don't know how this is going to work.
English
I'm guessing I need to include another file that includes the language files and then the link can choose from them but I don't know what the code would be for this.
Would it involve including a 'lang_directory' above the link and then somehow including from there??
**Also I would like to avoid using Zend/Gettext translation becuase I want to learn this inside out.
You can make another dimension containing the target language. Then pass a GET parameter to select that language. If the language isn't recognized you can fallback to English. Here's a sample.
$languages = array(
'en' => array(
'work' => 'work',
'packaging' => 'packaging'
),
'es' => array(
'work' => 'Trabajo',
'packaging' => 'Empaque'
),
);
// default language to use when the requested isn't found
$defaultLanguage = 'en';
// language requested via GET
$requested = $_GET['locale'];
// use the requested language if it exists, otherwise the default language
$language = isset($languages[$requested]) ? $requested : $defaultLanguage;
// our translations
$translation = $languages[$language];
// "work" translated based on the language
echo $translation['work'];
And the link for Español would look like this.
index.php?locale=es
I'd keep your array system, correct the links into something like index.php?lang=en and then include your file depending on the lang parameter:
if ( isset($_GET['lang']) && file_exists('includes/languages/'.$_GET['lang'].'.php') ){
include_once('includes/languages/'.$_GET['lang'].'.php');
}
And if you want to keep the language parameter in your session, do something like this:
if ( isset($_GET['lang']) && file_exists('includes/languages/'.$_GET['lang'].'.php') ){
$_SESSION['lang'] = $_GET['lang'];
}
if ( !isset($_SESSION['lang']) ){
// Default language
$_SESSION['lang'] = 'en';
}
include_once('includes/languages/'.$_SESSION['lang'].'.php');
One way to do this is by using sessions.
Make a lang.php file that will be used to change between languages.
<?php
//Start session
session_start();
//Do we get a lang variable
if (isset($_GET['lang'])) {
//Make sure we only get the lang filename
$lang = basename($_GET['lang']);
//If the file exists, then save it to session
if (file_exists('includes/languages/' . $lang . '.php'))
$_SESSION['lang'] = $lang;
}
//If the client were refered here (via hyperlink) send them back
if (isset($_SERVER['HTTP_REFERER']))
header('location: ' + $_SERVER['HTTP_REFERER']);
?>
In the header of the files you want multiple languages, insert.
<?php
//Start session
session_start();
//Default language
$lang = 'english';
//If the client have set a language, use that instead
if (isset($_SESSION['lang']))
$lang = $_SESSION['lang'];
//Load language file
include('includes/languages/' . $lang . '.php');
?>
The links to change language will then be like this:
Español|English
Out can also take the code from the lang.php file and put in a included file that will be loaded before the inclusion of language file and remove the HTTP_REFERER redirection.
The links to change language will then be like this:
Español|English
Is it secure to use the following code:
require($_SERVER['DOCUMENT_ROOT'] . "/pages/" . $_GET['page'] . ".php")
No, it is not secure. Why?
Because sequence of two dots /../ means one directory back and the attacker could potentially include anything on your system, even above $_SERVER['DOCUMENT_ROOT']. (In an unfortunate configuration that means secret/sensitive OS config files.)
You have to IF or SWITCH for the allowed values to prevent malicious input. Example:
switch($_GET['page']) {
case 'welcome': $page='welcome';
case 'shop': $page='shop';
default: $page='index';
}
require($_SERVER['DOCUMENT_ROOT'] . "/pages/" . $page . ".php")
Also check out in_array() for a little easier filtration.
StackOverflow has a useful Q&A for how to sanitize user input with PHP. It's a few years old, but the principles haven't changed at all.
The quick answer is: if you can avoid the problem in the first place, you're better off.
Show us how you're trying to use this, and we may be able to offer suggestions for improvement.
It's not secure. You can use array with allowed values.
For example
$allowed_pages = array('index', 'test', 'my_page')
if (!in_array($_GET['page'], $allowed_pages)){
echo 'good bye';
die();
} else {
//
}
If you trust all the files in the pages dir try:
if (in_array($_GET['page'],glob("/pages/*.php"))) {
require($_SERVER['DOCUMENT_ROOT'] . "/pages/" . $_GET['page'] . ".php");
} else echo "Nice try hacker!";
Here's another solution using parts of a function I use to clean uploaded filenames:
OPTION #2 thanks Daniel, Rok!
$page = preg_replace('/[^a-zA-Z0-9_ %\[\]\.\(\)%&-]/s', '', $_GET['page']);
$filename = $_SERVER['DOCUMENT_ROOT'] . "/pages/" . str_replace("/",'',$page) . ".php";
if (file_exists($filename)) {
require($filename);
} else echo "Nice try hacker!";
Note that this will only work if there are no special characters in your file names
use regExp to check your $_GET['page']!
this is my front controller
$pages = array("matches", "boards", "search", "articles", "interviews", "userlist", "teams", "servers", "awards", "gallery", "qids");
if (!$_SERVER['QUERY_STRING']) include('home_en.php');
elseif (isset($_GET['matchid'])) include('matchid.php');
elseif (isset($_GET['boardid'])) include('boardid.php');
elseif (isset($_GET['articleid'])) include('articleid.php');
elseif (isset($_GET['interviewid'])) include('interviewid.php');
elseif (isset($_GET['userid'])) include('profi.php');
elseif (isset($_GET['teamid'])) include('teamid.php');
elseif (isset($_GET['serverid'])) include('serverid.php');
elseif (isset($_GET['awardid'])) include('awardid.php');
elseif (isset($_GET['galleryid'])) include('galleryid.php');
elseif (isset($_GET['threadid'])) include('threadid.php');
elseif (isset($_GET['blogid'])) include('blogid.php');
..
elseif (in_array($_GET['content'], $pages)) include($_GET['content']);
else echo "File not found =(";
could i somehow add the identifiers to the array too? but i want the pages as index.php?matchid=9438 and for regular pages: index.php?content=matches
would really aprricate some ideas
thanks!
My Suggestion, From My Comment is this:
In order to check what type of id it is, you should use two $_GET parameters. One is the type (match, award, server, etc), one is the ID. That way you don't have to check for 500 different $_GET parameters, just the value of 2. Much more standardized.
Second, you want to make all of it under 1 file for the ID showing.
In the spirit of writing less code, not more, it would be relatively easy to change the SQL statement to grab the record based on if $_GET['type'] was match, award, team, etc. This is of course given that they will probably look the same. If they don't, instead of writing new code to grab each type, instead write code to display it differently
All Variables in this code much be validated/sanatized beforehand.
// First Get the Type
$type = $_GET['type'];
// Then the ID
$id = $_GET['id'];
// SANITIZE YOUR DATA. Replace this with your sanitization.
die("SANITIZE YOUR DATA HERE");
// Get Data Here
$sql = "SELECT * FROM table WHERE type=".$type." AND id=".$id;
$data = mysql_query($sql);
// Next, Include a template based on the data.
// Global the variable so it can be used in the file
Global $data;
include($type."-template.php");
I agree with Tom -- you should look into using a framework such as Zend, Cake, Symfony, Kohana, CodeIgniter, ez-Components, or Seagull. The advantage of using a framework is that they have already solved a lot of issues for you, including:
1) How to structure your code
2) How to interpret pretty urls (i.e. /x/1/y/2 instead of ?x=1&y=2)
3) Where to put certain types of code (html, php, configs, etc)
4) How to fix something you can't figure out (because these frameworks have communities)
and much much more...
That being said, maybe you don't want all the overhead of using a framework (it does require you to learn a lot). In that case, I recommend Rasmus Lerdorf's "No Framework PHP Framework". Rasmus is the creator of PHP, so you know he knows his stuff.
Lastly, to answer your actual question, here's how I would do it:
could i somehow add the identifiers to the array too?
i want the pages as index.php?matchid=9438
and for regular pages: index.php?content=matches
Sure, but yes, as Chacha102 said, you will need 2 parameters: $area (page) and $id.
Example: index.php?area=articles&id=2345
Then you can re-organize & simplify your 'front controller' this way:
/index.php
/areas/articles.php
/areas/boards.php
etc.
Instead of naming the templates articleid.php, just call it articles.php -- this way your area name also tells you which template to use.
$valid_areas = array("matches", "boards", "search", "articles",
"interviews", "userlist", "teams", "servers",
"awards", "gallery", "qids");
$area = strtolower(trim($_REQUEST['area'])); //if you are not posting any forms, use $_GET instead
$id = (int)$_REQUEST['id']; //if you are not posting any forms, use $_GET instead
if(!$id)
{
include('home_en.php');
}
if(!in_array($area), $valid_areas))
{
echo 'Sorry, the area you have requested does not exist: '.$area;
exit();
}
else
{
$template = '/templates/'.$area.'.php';
if(!file_exists($template))
{
echo 'Sorry, the file you have requested does not exist: '.$area.' '.$id);
}
else
{
include($template);
}
}
It might help to go ahead and use a framework such as Zend:
http://framework.zend.com/
You could do this:
<?php
$controllerDefault = 'home';
function sanitize($str)
{
return str_replace(array('.', '/', '\\'), '', $str);
}
//Prevent of Remote File Inclusion
$controller = sanitize($_GET['controller']);
$id = intval($_GET['id']);
if (empty($controller))
{
$controller = $controllerDefault;
}
if (!empty($id))
{
$controller .= 'id';
}
$controllerFile = $controller . '.php';
if (!file_exists($controllerFile)
|| $controller == 'index') //for not recursive index.php include :)
{
exit('Controller "'.$controllerFile.'" not exists');
}
include($controllerFile);
?>
Using this code you can use your application like:
http://yoursite.com/index.php //include('home.php')
http://yoursite.com/index.php?id=285230 //include('homeid.php')
http://yoursite.com/index.php?controller=matches //include('matches.php')
http://yoursite.com/index.php?controller=matches&id=28410 //include('matchesid.php')
http://yoursite.com/index.php?controller=notexists //ERROR! Controller "notexists" not exists
http://yoursite.com/index.php?controller=../../etc/passwd //ERROR! Controller "etcpasswd" not exists
I hope you like it
PD: the code is not tested, but I hope you catch my idea