Firstly, I don't know what to call this thing :) I want to know the key, structure and example how to achieve my goal.
Example, I don't want create separate file like register.php, login.php, about.php faq.php. Here I want the register, login about, faq ,etc will handle by index.php by example, maybe something like index.php?p=register
How do I create page something like that and what this structure called in PHP programming. Let me know.
In index.php?p=register the part after ? is called "Query String". PHP will by default parse it for you and provides the superglobal $_GET. Just try it out yourself
var_dump($_GET);
To provide a more appropriate answer using Neals code, use basename to filter out non-essential file information:
$page = isset($_GET['p'])?basename($_GET['p']):'main';
include_once "$page.php";
You could also create a "white list" to ensure that only the proper files get included:
$whiteList = array('faq', 'register', 'profile');
$page = (isset($_GET['p']) && in_array($_GET['p'], $whiteList))?basename($_GET['p']):'main';
include_once "$page.php";
Both ways should be secure, obviously, the white list will be a bit more so. This tact, depending on how you do is generally referred to as "BootStrapping" IE, one entrance page to access the rest.
UPDATE
To further the security, I would set a variable, $included would be sufficient, to add to the pages that are being included. This would prevent direct access to them (assuming that register_globals is turned off like it should be, so something like:
$whiteList = array('faq', 'register', 'profile');
$page = (isset($_GET['p']) && in_array($_GET['p'], $whiteList))?basename($_GET['p']):'main';
$included = true;
include_once "$page.php";
Then on $page.php at the top you would have something like:
<?php
if (!$included)
die('Accessing the file directly is not allowed.');
Which would prevent calls to http://yoursite.com/register.php from being allowed to dish out the file. This has it's negatives to it. Instead of putting the files you are going to be including in the webroot, I would put them outside of the webroot or in an .htaccess protected directory, which would ensure that users could not access them directly and must access them through the index.php.
I'm not sure what the whole thing is called, but if you're using index.php like that, it's called a FrontController. It's how MVC frameworks work:
/index.php?q=ctrl/action
/index.php/ctrl/action
/ctrl/action
They're all handled by/in index.php using "ctrl/action"
You want to look up php templates or even html iframe. There are several ways to do this, but some are better than others. In asp.net it's called a MasterPage. Hopefully some of these terms help you out.
If you really want to do something like this, then you can use the get field, but you need to predefine your pages, so for this request: index.php?p=my_page
<?php
$page = $_GET['p'];
$pages = array(
'my_page' => 'mypage.php',
'another_page' => 'another.php',
...
);
$include = $pages[$page];
if(!empty($include)) {
include_once($include);
} else {
echo 'No such page';
}
?>
This keeps the include completely separate from what is passed on the URL so there is no chance for risky things to get passed.
Related
Supposed the page is example.com/blog/data.php. I am using file_get_contents to get the content in another script page. Now, i want to:
Forbid google search to crawl and index the data.php page.
Forbid the visitor to access it
Is there a way to achieve this?
You can redirect to another page if the request url is example.com/blog/data.php, but a far easier and more logical solution would be to move the file out of your web-root.
Edit: If you really want to keep the file inside the web-root, you can use something like this at the top of the script that you don't want to access directly:
if ($_SERVER['REQUEST_URI'] === $_SERVER['SCRIPT_NAME'])
{
header('Location: /'); // redirect to home page
}
However, this will probably not work in combination with file_get_contents (you need to remove these lines from the result), you could include the file instead.
Don't put data.php under the web root. Keep it in a parallel directory.
You can pass token via GET. Overall your way is slightly wrong. Why don't you incorporate the data.php logic in the script that is calling it.
Simply apply access restriction for authorized users only. You are able to do it in the most simple way by accessing your page using url parama as password:
example.com/blog/data.php?secret=someblah
and in the first of your file data.php do the following:
<?php
if (!isset($_GET['secret']) || $_GET['secret'] != 'someblah')) exit();
?>
However,It is recommended, don't use this from public computer becuase it is not secure but it is the primitive authentication principle.
I have the following PHP script within a file named login.php
<?php
$ref = $_SERVER['HTTP_REFERER'];
if ($ref == 'http://example.com/dir/invalid.php' || $ref == 'http://www.example.com /dir/invalid.php') {
echo '
<div id="invalid">
TESTTESTTESTTESTTESTTESTTESTTEST
</div>
';
}
?>
I have deliberately went to the invalid.php page (which redirects using header() to login.php) and this div does not show up. Does it have something to do with the referrer not really being invalid.php or is there an issue with the script?
Thanks
I don't think the HTTP_REFERER is what you think it is. Namely, it is the page from which the user followed a link to the current page. However, it's very unreliable as we rely on the browser of the user to correctly report this value.
I would suggest the option I thought you needed, except that the only one I can think of you might doesn't really makes sense... (checking if the url matches a url that's not the current script)... so I do not see what you are trying to do.
As promised several ways to do what you want to achieve:
First off, I don't like this solution at all and really consider it ugly, but it's the one closest to what you where trying to do.
invalid.php
require 'login.php'; // we include the file instead of referring to it
login.php
if ($_SERVER['SCRIPT_NAME'] == 'invalid.php')
{
// do whatever
}
The main difference between what you did and what I did for the user will be that here the url bar will show that you're at invalid.php and not somewhere else. This also means that refreshing doesn't make the message go away.
A better solution in my opinion is the following:
In your script that logs a user in (checks the database and everything):
if (!valid_login()) // pseudo-code, obviously
{
$_SESSION['invalid_login'] = true;
header('Location: login.php');
// previously, we had something like this instead of the two lines above:
// header('Location: invalid.php');
}
in login.php
if (isset($_SESSION['invalid_login']) && $_SESSION['invalid_login'])
{
$_SESSION['invalid_login'] = false;
// do whatever
}
Of course, this should be done with proper session facilities like starting up the session in both those files. Instead of using session variables, you could include the file and use normal variables or send GET variables through the header request, but both those solutions share a problem: refreshing doesn't make the message disappear. However, if you were to move the code from the top file of the two above to login.php (if it's not already there, I don't know what file that actually is...) you could once again use normal variables instead of session variables and have a solution in which refreshing does make it go away. In this case, you might argue that you are cluttering your files with bussiness logic and presentation, but there are solutions to that (like keeping it in a separate file, and including it into login.php, moving the html to another file and including that one into login.php or both.
So I made a script so that I can just use includes to get my header, pages, and then footer. And if a file doesnt exist a 404. That all works. Now my issue is how I'm supposed to get the end of the url being the page. For example,
I want to make it so that when someone goes to example.com/home/test, it will automatically just include test.php for example.
Moral of the story. How to some how get the page name. And then use it to "mask" the end of the page so that I don't need to have every URL being something.com/home/?p=home
Heres my code so far.
<?php
include($_SERVER['DOCUMENT_ROOT'].'/home/lib/php/_dc.php');
include($_SERVER['DOCUMENT_ROOT'].'/home/lib/php/_home_fns.php');
$script = $_SERVER['SCRIPT_NAME']; //This returns /home/index.php for example =/
error_reporting(E_ALL);
include($_SERVER['DOCUMENT_ROOT'].'/home/default/header.php');
if($_GET["p"] == 'home' || !isset($_GET["p"])) {
include($_SERVER['DOCUMENT_ROOT'].'/home/pages/home.php');
} else if(file_exists($_SERVER['DOCUMENT_ROOT'].'/home/pages/'.$_GET["p"].'.php')) {
include($_SERVER['DOCUMENT_ROOT'].'/home/pages/'.$_GET["p"].'.php');
} else {
include($_SERVER['DOCUMENT_ROOT'].'/home/default/404.php');
}
include($_SERVER['DOCUMENT_ROOT'].'/home/default/footer.php');
?>
PHP by itself wouldn't be the best choice here unless you want your website littered with empty "redirect" PHP files. I would recommend looking into the Apache server's mod_rewrite module. Here are a couple of guides to get you started. Hope this helps!
The simplest way would be to have an index.php file inside the /home/whatever folder. Then use something like $_SERVER['PHP_SELF'] and extract the name if you want to automate it, or since you are already writing the file yourself, hardcode it into it.
That however looks plain wrong, you should probably look into mod-rewrite if you are up to creating a more complex/serious app.
I would also recommend cakePHP framework that has the whole path-to-controller thing worked out.
What is the best way if i want do something like these;
I call it page calling.
I have an index.php which will run the config.php
And i want to have index.php as my core then do something like
index.php?customer=home or index.php?customer=viewaccount
index.php?admin=home or index.php?admin=updateproduct
then call the particular php file eg. home.php , viewaccount.php
Best regards
I really appreciate yours help.=)
It sounds like you are talking about a design pattern known as the Front Controller Pattern.
It is certainly possible to implement your own front controller, but almost every PHP framework will have this capability already. I recommend you try Zend Framework.
I wouldn't mix admin and puclic areas in the same script.
So, for the public area you can do something like
<?
if (empty($_SERVER['QUERY_STRING'])) {
$name="index";
} else {
$name=basename($_SERVER['QUERY_STRING']);
}
$file="pages/$name.htm";
if (is_readable($file)) {
include($file);
} else {
header("HTTP/1.0 404 Not Found");
readfile("404.html");
}
?>
and then address customer pages like this index.php?home, index.php?viewaccount
Best is to check the $_GET parameter against an 'whitelist' array of allowed script names. After that, you can just include the file.
if ( in_array( $_GET['admin'], array( 'home', 'updateproduct' ) ) ) {
include( $_GET['admin'] . '.php');
}
Okay I couldn't be bothered to comment all of the answers here so I'll say it to you, even though this post will probably get put down as its not a direct help.
You need to be very careful when including files from a POST or GET request. Just be aware of Remote/Local file inclusion vulnerabilities when writing code like that. index.php?page=/etc/passwd or index.php?page=www.myEvilScript.com/evil.php
Many people can get hacked this way and you don't want that to happen to you.
Always sanitize your data, so stripslashes($_GET['admin']); or whatever method you want to use.
The name for this pattern is a front controller.
You can implement the multiplexing on the webserver (e.g. using mod_rewrite) or in your PHP code.
Here's how NOT to do it:
<?php
require_once($_REQUEST['customer']);
require_once($_REQUEST['admin']);
C.
I want to make my homepage, without frames, should i just split up my design on index.php so it is header.php/footer.php, and then just include them on every page?
Yes, you can split your index.php into header.php/footer.php and then just include them on every page.
Note that your pages can be not static HTML but php scripts, to show multiple pages with one script.
I'd suggest also to have not a commonplace structure like
include 'header.php';
//do some stuff
include 'footer.php';
but another structure, much more useful:
//do some stuff, retrieve all data.
include 'header.php';
include 'page.php'; //include page template
include 'footer.php';
I suggest you use a framework. Most frameworks (if not all) have simple template systems, so you don't have to repeat code.
The problem with the suggested solution of including stuff in every page of your site is that you have to update all the pages of your site if you want to include another thing, say a sidebar.
A better idea is not to have a script--page connection at all. So you don't write a php file per page you want to show. Instead, use one front controller file, most use index.php in the root of the website. And then use Apache mod_rewrite or other server techniques to have flexibility in the URL's of your site. Then let index.php map different URL requests to serve different pages, you can then put all the pages of your site into a database or somewhere else.
This way there's only one point in your site that includes the templates for the header and footer, so that's easily changeable, and you can use the root of the site to serve AJAX requests, in which you won't want to output HTML but JSON for instance.
Afaik this is a good way of going about it.
Another idea would be to have just one single point of entry which is called with a GET parameter, e.g ?site=about. Your index.php could look like this:
<?php
// whitelist of allowed includes
$allowedIncludes = array('home', 'about', 'error404'); // etc.
// what to include if ?site is not set at all / set to an illegal include
$defaultInclude = 'home';
$errorInclude = 'error404';
// if site is not set, include default
$site = (empty($_GET['site'])) ? $defaultInclude : $_GET['site'];
// if site is illegal, include error page
$include = (in_array($site, $allowedIncludes)) ? $site : $errorInclude;
// actual includes
include 'header.php';
include $include.'.php';
include 'footer.php';
Thus you only have to include header.php and footer.php once and have full control about what is allowed and what is not (the included files could be in a directory that only php has access to). While your index.php handles the request, home.php, about.php do not have to know about header.php and footer.php (you could easily replace them at a later point in time).
If you do not like http://www.example.com/?site=about, you can look into mod_rewrite and friends.
You may want to set a session for that. A session variable exists as long as a visitor is on your website:
<?php
session_start(); // Remember that session_start(); must be the first line of your PHP and HTML-code
if($add_a_message){
$_SESSION['message'] = 'Message';
}
if($destroy_message){
$_SESSION['message'] = '';
}
// echo this message
if(isset($_SESSION['message']) && strlen($_SESSION['message']) > 0){
echo '<strong>' . $_SESSION['message'] . '</strong>';
}
?>