My redirect process is showing some crazy stuff. The first part of the whole loop works just fine (if only the first element is typed in).
Possible url's look like:
www.site.com/category
www.site.com/category/product
But also:
www.site.com/cart
Using site.com/jeans works just fine. But when you click on a product, something strange happens.
The categorie.php file (used to display categories) is STILL included and after that one, the product.php file is included.
Same story with the cart page (http://www.site.com/winkelwagen/).
So my includes are wrong at some point. Winkelwagen is a folder on my site which has an index file. It should include http://www.site.com/winkelwagen/index.php and not categorie.php as well.
The route code :
<?php
$mult = Array();
if( ! empty( $_SERVER[ 'REQUEST_URI' ] ) ) {
$mult = explode ( '/', substr ( $_SERVER[ 'REQUEST_URI' ], 1 ) );
} else if( ! empty( $_SERVER[ 'ORIG_PATH_INFO' ] ) ) {
$mult = explode ( '/', substr ( $_SERVER[ 'ORIG_PATH_INFO' ], 1 ) );
} else if( ! empty( $_SERVER[ 'PATH_INFO' ] ) ) {
$mult = explode ( '/', substr ( $_SERVER[ 'PATH_INFO' ], 1 ) );
}
if(empty($mult[0]))
{
include("comingsoon/index.html");
}
if(!empty($mult[0]) && empty($mult[1]))
{
$file = "$mult[0].php";
if($mult[0] == "index2")
{
include("index2.php");
die;
}
// if file exists include file
if(file_exists($file))
{
include($file);
}
else
{
$file2 = "/$mult[0]/index.php";
// if folder index file exists include that file
if(file_exists($file2))
{
include($file2);
}
else {
// if folder index file doesn't exist, send to category page
$_GET['q'] = $mult[0];
include("categorie.php");
}
}
}
if(!empty($mult[0]) && !empty($mult[1]))
{
if($mult[0] == "add")
{
$_GET['addid'] = $mult[1];
include("addtocart.php");
}
elseif($mult[0] == "remove")
{
$_GET['removeid'] = $mult[1];
include("deletefromcart.php");
}
// check if folder exists (first part of the url)
elseif(is_dir($mult[0]))
{
// check if file .php (second part of the url) exists
$filenew = "$mult[0]/$mult[1].php";
if(file_exists($filenew))
{
// include that file
include("$mult[0]/$mult[1].php");
}
else
{
// second file does not exist, do something
}
}
else
{
// folder does not exist so redirect to product page
$_GET['c'] = $mult[0];
$_GET['p'] = $mult[1];
include("product.php");
}
}
?>
I tried removing the categorie.php file but it still shows up (like, how on earth ?!)
I'm excited for the answer - I have absolutely no idea what I'm doing wrong.
Also nice to know: when I comment out the include(categorie.php) part in the route code, the file is STILL included...
Ok... Welcome to Stack Overflow. I'll start by saying you are allowed to post links, trying to disrupt links by using "dot" actually feels more like spam, to me at least.
I'll continue by advising you to not go with your site and that code public. It has various security vulnerabilities, to which I am not going to go into detail. But, let's just say I'm curious why your user is called d284h1 and why your site/home is on a mount point /mnt/home/d284h1...
Heed my words. You just posted your routing logic and your site on a very public site.
Regarding your code. I really hope that's SO destroying your indentation and not your actual source code.
You are missing some control logic. Some of them might have been leading to the file inclusions you were experiencing. I also noticed a possible bug, where you were testing and including a file from the root directory, instead of relatively to your site path.
Update: Actually looking back at your original code, absolutely referencing the file $file2 = "/$mult[0]/index.php"; was causing categorie.php to load. And not having proper control logic, was causing multiple inclusions to occur in the file.
Took the liberty of revising your code, mildly. The below code, should not continue to include any random files. Unless included files themselves do it.
$mult = array();
if( ! empty( $_SERVER[ 'REQUEST_URI' ] ) ) {
$mult = explode ( '/', substr ( $_SERVER[ 'REQUEST_URI' ], 1 ) );
} else if( ! empty( $_SERVER[ 'ORIG_PATH_INFO' ] ) ) {
$mult = explode ( '/', substr ( $_SERVER[ 'ORIG_PATH_INFO' ], 1 ) );
} else if( ! empty( $_SERVER[ 'PATH_INFO' ] ) ) {
$mult = explode ( '/', substr ( $_SERVER[ 'PATH_INFO' ], 1 ) );
}
if (empty($mult[0])) {
include("comingsoon/index.html");
die; #missing
}
# no need to test for !empty($mult[0]), if it were empty, the above die would fire
if (empty($mult[1])) {
$file = "$mult[0].php";
if($mult[0] == "index2") {
include("index2.php");
die;
}
// if file exists include file
if (file_exists($file)) {
include($file);
die; # missing die
} # no need for else, you just die'd
# renamed $file2 to $file, don't use temporary variable names in global scope. It clutters your application
$file = "$mult[0]/index.php";# are you sure you meant to include from the root level?
// if folder index file exists include that file
if (file_exists($file)) {
include($file);
die;# missing die
} # no need for else, you just die'd
// if folder index file doesn't exist, send to category page
$_GET['q'] = $mult[0];
include("categorie.php");
die;# missing die
}
# don't do succesive if/elseif on the same variable, use a switch!
switch($mult[0]) {
case'add':
$_GET['addid'] = $mult[1];
include('addtocart.php');
break;
case'remove':
$_GET['removeid'] = $mult[1];
include('deletefromcart.php');
break;
}
if (is_dir($mult[0])) {
// check if file .php (second part of the url) exists
$filenew = "$mult[0]/$mult[1].php";
if(file_exists($filenew)) {
// include that file
include("$mult[0]/$mult[1].php");
die; # missing die
}
} else {
// folder does not exist so redirect to product page
$_GET['c'] = $mult[0];
$_GET['p'] = $mult[1];
include("product.php");
}
My updates are commented with # and this is in no way the final form it should look like. Take a look at PSR1 for a mild idea, on what coding standards are. They are meant to help and make you more proficient in your quest for the ultimate code, despite initially feeling cumbersome.
Other things I'd continue on doing are:
swapping !empty($var) with isset($var[0]), if $var is a string
swapping include($file);die; with return include $file;, if you're in the main scope
swapping if/elseif blocks with ternary operators
Actually regarding #3, here's an example:
$mult = isset($_SERVER['REQUEST_URI'][0])
? $_SERVER['REQUEST_URI']
: isset($_SERVER['ORIG_PATH_INFO'][0])
? $_SERVER['ORIG_PATH_INFO']
: isset($_SERVER['PATH_INFO'][0])
? $_SERVER['PATH_INFO']
: false
;
$mult = $mult
? explode('/', substr($mult, 1))
: array();
P.S. I did not fix the security issues you were having, as I believe the code you are using should not be used. Consider using a framework or at least learning from one. Routing is the corner stone of good MVC, you're on the right path, go one step beyond.
Can you please test this also and send your feedback, I just re-structured the code (I made the conditions more strict using if elseif else)
<?php
$mult = Array();
if( ! empty( $_SERVER[ 'REQUEST_URI' ] ) ) {
$mult = explode ( '/', substr ( $_SERVER[ 'REQUEST_URI' ], 1 ) );
} else if( ! empty( $_SERVER[ 'ORIG_PATH_INFO' ] ) ) {
$mult = explode ( '/', substr ( $_SERVER[ 'ORIG_PATH_INFO' ], 1 ) );
} else if( ! empty( $_SERVER[ 'PATH_INFO' ] ) ) {
$mult = explode ( '/', substr ( $_SERVER[ 'PATH_INFO' ], 1 ) );
}
if(empty($mult[0]))
{
include("comingsoon/index.html");
}
elseif(!empty($mult[0]) && empty($mult[1]))
{
$file = "$mult[0].php";
if($mult[0] == "index2")
{
include("index2.php");
die;
}
else{
// if file exists include file
if(file_exists($file))
{
include($file);
}
else
{
$file2 = "/$mult[0]/index.php";
// if folder index file exists include that file
if(file_exists($file2))
{
include($file2);
}
else {
// if folder index file doesn't exist, send to category page
$_GET['q'] = $mult[0];
include("categorie.php");
}
}
}
}
elseif(!empty($mult[0]) && !empty($mult[1]))
{
if($mult[0] == "add")
{
$_GET['addid'] = $mult[1];
include("addtocart.php");
}
elseif($mult[0] == "remove")
{
$_GET['removeid'] = $mult[1];
include("deletefromcart.php");
}
// check if folder exists (first part of the url)
elseif(is_dir($mult[0]))
{
// check if file .php (second part of the url) exists
$filenew = "$mult[0]/$mult[1].php";
if(file_exists($filenew))
{
// include that file
include("$mult[0]/$mult[1].php");
}
else
{
// second file does not exist, do something
}
}
else
{
// folder does not exist so redirect to product page
$_GET['c'] = $mult[0];
$_GET['p'] = $mult[1];
include("product.php");
}
}
?>
Related
Firstly, I am "new"(only been coding for a couple months) to PHP and am trying to get a file for a logged in user to display.
I have tried a few options including baseband and url but it just dosn't seem to work the way I need it to.
Here is a snippet of my code:
$personCalendar = '/folder\calendars\people';
$personFiles = scandir($personCalendars);
$personID = $_SESSION['Person_ID'];
$test = preg_grep('/'.personID.'/',$personFiles);
print_r($test);
echo basename($test);
The output from the print_r gives me Array ( [312] => s15399.ics ) which is great, but I just need the s15399.ics part and have it append to the end of the page url something like https://servername.com/index.php/calendar?s15399.ics so they can take the file and "subscribe" to their calendar.
baseband does not being anything but I am not that surprised by that.
Is this possible, if not, what would be the best way you recommend to do this?
// using \ in a file path is not going to work. Use / instead.
// $personCalendar = '/folder\calendars\people';
$personCalendar = '/folder/calendars/people';
// scandir will work but it will eventually run into problems
// if you have lots and lots of files.
$personFiles = scandir($personCalendars);
$personID = $_SESSION['Person_ID'];
function url(){
return sprintf('%s//%s%s',
isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off' ? 'https' : 'http',
$_SERVER['SERVER_NAME'],
$_SERVER['REQUEST_URI']
);
}
// shouldn't the following be $personID, not personID?
$test = preg_grep('/'.$personID.'/', $personFiles);
print_r($test);
$filename = reset($test);
if ( $filename ) {
$fullUrl = url() . $filename;
echo $fullUrl;
} else {
echo "File not found\n";
}
If you need to find a file and you know the file name, you don't need to read all the files. If the file name is the same as the person id, then:
$filename = "s{$personID}.ics";
if ( file_exists($filename) ) {
//
} else {
//
}
You can use current();
$link=current($test);
I'm nearly done with finding a way to show a .html file on certain pages only.
In this case i want test.html to be shown on http://www.example.com/categories/AnyPageThatExcistsInCategories
I figured out the following code works on /categories.
<?php if ($_SERVER['REQUEST_URI'] == '/categories/') { include 'test.html';} ?>
I only need the golden tip on how to get it also working on pages like /categories/ThisCanBeAnything and categories/ThisCanBeAnything/AndThisAlso etc etc
server config is nginx.
thank you
You could see if the request uri begins with the string '/categories/':
<?php
$request_uri = '/categories/foo';
if (strpos($request_uri, '/categories/') === 0 )
{
include 'your.html';
}
Substitute the value of $request_uri above with $_SERVER['request_uri']. Under the assumption that you have this logic in a front controller.
Further:
<?php
$request_uris = [
'/categories/foo',
'/categories/',
'/categories',
'/bar'
];
function is_category_path($request_uri) {
$match = false;
if (strpos($request_uri, '/categories/') === 0 )
{
$match = true;
}
return $match;
}
foreach ($request_uris as $request_uri) {
printf(
"%s does%s match a category path.\n",
$request_uri,
is_category_path($request_uri) ? '' : ' not'
);
}
Output:
/categories/foo does match a category path.
/categories/ does match a category path.
/categories does not match a category path.
/bar does not match a category path.
In use:
if(is_category_path($_SERVER['REQUEST_URI'])) {
include 'your.html';
exit;
}
You may want to not match the exact string '/categories/', if so you could adjust the conditional:
if(
strpos($request_uri, '/categories/') === 0
&& $request_uri !== '/categories/'
) {}
Progrock's example will work just fine, but here is another example using a regex match instead of strpos, in case you're curious!
<?php
if (preg_match("/\/categories\/.*/", $_SERVER['REQUEST_URI'])) {
include 'test.html';
}
?>
i have a question about these function: $_SERVER["REQUEST_URI"]. Can somebody tell me if it's safe to use like i use it ( these form i use for new topic in forum )?
<form name="vpid" action="<?php echo htmlspecialchars($_SERVER["REQUEST_URI"]);?>" method="post">
Thank you
The first thing I'd say is that you probably don't need REQUEST_URI in this in this context.
If you want a form to post back to the current page, the action attribute can be set to blank string or a dot; you don't need to specify the whole current URL.
In cases where you do need it, the answer is that yes, REQUEST_URI is safe.
A lot of values in $_SERVER are not safe, so it's good to be cautious, but REQUEST_URI is safe because it represents the address that was used to get to the site; if the address is invalid, then the user wouldn't have been able to get to the server in the first place.
Other $_SERVER fields can be hacked; it's trivial to spoof things like REMOTE_HOST and HTTP_REFERER, so you should never rely on them to be reliable, but REQUEST_URI ought to be safe.
The main thing here though is that you shouldn't really need it anyway.
Already an old question, but no, you cannot trust $_SERVER['REQUEST_URI'] because, it will only be available on an apache server.
Here is how Drupal handles it on the 7.x version
function request_uri() {
if (isset($_SERVER['REQUEST_URI'])) {
$uri = $_SERVER['REQUEST_URI'];
}
else {
if (isset($_SERVER['argv'])) {
$uri = $_SERVER['SCRIPT_NAME'] . '?' . $_SERVER['argv'][0];
}
elseif (isset($_SERVER['QUERY_STRING'])) {
$uri = $_SERVER['SCRIPT_NAME'] . '?' . $_SERVER['QUERY_STRING'];
}
else {
$uri = $_SERVER['SCRIPT_NAME'];
}
}
// Prevent multiple slashes to avoid cross site requests via the Form API.
$uri = '/' . ltrim($uri, '/');
return $uri;
}
And the WordPress version from v3.0.0 up to now. Its purpose is to fill in the blanks and normalize the $_SERVER variables.
function wp_fix_server_vars() {
global $PHP_SELF;
$default_server_values = array(
'SERVER_SOFTWARE' => '',
'REQUEST_URI' => '',
);
$_SERVER = array_merge( $default_server_values, $_SERVER );
// Fix for IIS when running with PHP ISAPI.
if ( empty( $_SERVER['REQUEST_URI'] ) || ( 'cgi-fcgi' !== PHP_SAPI && preg_match( '/^Microsoft-IIS\//', $_SERVER['SERVER_SOFTWARE'] ) ) ) {
if ( isset( $_SERVER['HTTP_X_ORIGINAL_URL'] ) ) {
// IIS Mod-Rewrite.
$_SERVER['REQUEST_URI'] = $_SERVER['HTTP_X_ORIGINAL_URL'];
} elseif ( isset( $_SERVER['HTTP_X_REWRITE_URL'] ) ) {
// IIS Isapi_Rewrite.
$_SERVER['REQUEST_URI'] = $_SERVER['HTTP_X_REWRITE_URL'];
} else {
// Use ORIG_PATH_INFO if there is no PATH_INFO.
if ( ! isset( $_SERVER['PATH_INFO'] ) && isset( $_SERVER['ORIG_PATH_INFO'] ) ) {
$_SERVER['PATH_INFO'] = $_SERVER['ORIG_PATH_INFO'];
}
// Some IIS + PHP configurations put the script-name in the path-info (no need to append it twice).
if ( isset( $_SERVER['PATH_INFO'] ) ) {
if ( $_SERVER['PATH_INFO'] == $_SERVER['SCRIPT_NAME'] ) {
$_SERVER['REQUEST_URI'] = $_SERVER['PATH_INFO'];
} else {
$_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME'] . $_SERVER['PATH_INFO'];
}
}
// Append the query string if it exists and isn't null.
if ( ! empty( $_SERVER['QUERY_STRING'] ) ) {
$_SERVER['REQUEST_URI'] .= '?' . $_SERVER['QUERY_STRING'];
}
}
}
// Fix for PHP as CGI hosts that set SCRIPT_FILENAME to something ending in php.cgi for all requests.
if ( isset( $_SERVER['SCRIPT_FILENAME'] ) && ( strpos( $_SERVER['SCRIPT_FILENAME'], 'php.cgi' ) == strlen( $_SERVER['SCRIPT_FILENAME'] ) - 7 ) ) {
$_SERVER['SCRIPT_FILENAME'] = $_SERVER['PATH_TRANSLATED'];
}
// Fix for Dreamhost and other PHP as CGI hosts.
if ( strpos( $_SERVER['SCRIPT_NAME'], 'php.cgi' ) !== false ) {
unset( $_SERVER['PATH_INFO'] );
}
// Fix empty PHP_SELF.
$PHP_SELF = $_SERVER['PHP_SELF'];
if ( empty( $PHP_SELF ) ) {
$_SERVER['PHP_SELF'] = preg_replace( '/(\?.*)?$/', '', $_SERVER['REQUEST_URI'] );
$PHP_SELF = $_SERVER['PHP_SELF'];
}
}
Symfony HttpFoundation method is a little bit more complex.
I'm getting all ahrefs of a page with this loop:
foreach($html->find('a[href!="#"]') as $ahref) {
$ahrefs++;
}
I want to do something like this:
foreach($html->find('a[href!="#"]') as $ahref) {
if(isexternal($ahref)) {
$external++;
}
$ahrefs++;
}
Where isexternal is a function
function isexternal($url) {
// FOO...
// Test if link is internal/external
if(/*condition is true*/) {
return true;
}
else {
return false;
}
}
Help!
Use parse_url and compare host to your local host (often but not always it's the same as $_SERVER['HTTP_HOST'])
function isexternal($url) {
$components = parse_url($url);
return !empty($components['host']) && strcasecmp($components['host'], 'example.com'); // empty host will indicate url like '/relative.php'
}
Hovewer this will treat www.example.com and example.com as different hosts. If you want all your subdomains to be treated as local links then the function will be somewhat larger:
function isexternal($url) {
$components = parse_url($url);
if ( empty($components['host']) ) return false; // we will treat url like '/relative.php' as relative
if ( strcasecmp($components['host'], 'example.com') === 0 ) return false; // url host looks exactly like the local host
return strrpos(strtolower($components['host']), '.example.com') !== strlen($components['host']) - strlen('.example.com'); // check if the url host is a subdomain
}
This is how you can simply detect external URLs:
$url = 'https://my-domain.com/demo/';
$domain = 'my-domain.com';
$internal = (
false !== stripos( $url, '//' . $domain ) || // include "//my-domain.com" and "http://my-domain.com"
stripos( $url, '.' . $domain ) || // include subdomains, like "www.my-domain.com". DANGEROUS (see below)!
(
0 !== strpos( $url, '//' ) && // exclude protocol relative URLs, like "//example.com"
0 === strpos( $url, '/' ) // include root-relative URLs, like "/demo"
)
);
The above check will treat www.my-domain.com and my-domain.com as being "internal".
Why this rule is dangerous:
The subdomain logic introduces a weakness that could be exploited: When an external URL contains your domain inside the path, for example, https://external.com/www.my-domain.com is treated as internal!
More secure code:
This problem can be eliminated by removing subdomain support (which I suggest to do):
$url = 'https://my-domain.com/demo/';
$domain = 'my-domain.com';
$internal = (
false !== stripos( $url, '//' . $domain ) || // include "//my-domain.com" and "http://my-domain.com"
(
0 !== strpos( $url, '//' ) && // exclude protocol relative URLs, like "//example.com"
0 === strpos( $url, '/' ) // include root-relative URLs, like "/demo"
)
);
function isexternal($url) {
// FOO...
// Test if link is internal/external
if(strpos($url,'domainname.com') !== false || strpos($url,"/") === '0')
{
return true;
}
else
{
return false;
}
}
I know this post is old but here my function i coded right now. Maybe some other need it too.
function IsResourceLocal($url){
if( empty( $url ) ){ return false; }
$urlParsed = parse_url( $url );
$host = $urlParsed['host'];
if( empty( $host ) ){
/* maybe we have a relative link like: /wp-content/uploads/image.jpg */
/* add absolute path to begin and check if file exists */
$doc_root = $_SERVER['DOCUMENT_ROOT'];
$maybefile = $doc_root.$url;
/* Check if file exists */
$fileexists = file_exists ( $maybefile );
if( $fileexists ){
/* maybe you want to convert to full url? */
return true;
}
}
/* strip www. if exists */
$host = str_replace('www.','',$host);
$thishost = $_SERVER['HTTP_HOST'];
/* strip www. if exists */
$thishost = str_replace('www.','',$thishost);
if( $host == $thishost ){
return true;
}
return false;
}
You probably want to check if the link is in the same domain. That will only work though if all your href attributes are absolute and contain the domain. Relative ones like /test/file.html are tricky because one can have folders that have the same name as domains.. So, if you have full url's in each link:
function isexternal($url) {
// Test if link is internal/external
if(stristr($url, "myDomain.com") || strpos($url,"/") == '0')
return true;
else
return false;
}
How do I create a dynamic PHP includes, that is secure? for example I have an index.php file with header.php and footer.php included inside of it and then grab other pages inbetween using
index.php?page=about
If possible it would need to be dynamic so using arrays and case would be time consuming and require modifications.
I also want to be able to change the title of website as well depending on what page was included.
I currently have this in place:
<?php
require_once 'includes/config.php';
//Set values for page
$page_title = 'home page';
$current_page = 'home';
require_once 'includes/header.php';
?>
CONTENT
<?php
require_once 'includes/footer.php';
?>
Thanks
Would this be a safe way to include my pages?
if( isset( $_GET[ 'page' ] ) )
{
if( strpos( $_GET[ 'page' ], "/" ) )
{
$dir = substr( str_replace( ’’, ”, $_GET[ 'page' ] ), 0, strpos( $_GET[ 'page' ], "/" ) ) . "/";
$file = substr( strrchr( $_GET['page' ], "/" ), 1 );
if( file_exists( $dir.$file.".php" ) )
{
include( $dir.$file.".php" );
} else {
include( "home.php" );
}
} else {
if( file_exists( basename( $_GET[ 'page' ] ).".php" ) )
{
include( basename( $_GET[ 'page' ] ).".php");
} else {
include( "404.php" );
}
}
} else {
include( "home.php" );
}
To prevent errors and unauthorized file access (secure) to pages outside of your web directory or invalid pages you should do the following.
Validate $_GET['page'] by checking for periods. While periods may be valid in file names, it looks like you would be constructing the filename from the value and a period could indicate a breakout attempt to gain access to a root directory.
From there I would construct the filepath for the include, and then use file_exists to make sure it exists before including it.
As for the changing title for the page include I would do something like this:
<?php
$page_title = 'Default Title';
$page_to_include = 'default';
if( strpos($_GET['page'], '.') !== false ){
//throw/display error - could be a breakout attempt
}
if( !file_exists(sprintf('page_includes/%s.php', $_GET['page'])) ){
//requested page does not exists, throw or display error
}else{
$page_to_include = sprintf('page_includes/%s.php', $_GET['page']);
}
//do page validation here with file_exists
ob_start();
include $page_to_include;
$included_page = ob_get_clean(); //gets contents and cleans the buffer and closes it
require_once 'includes/header.php';
echo $included_page;
require_once 'includes/footer.php';
?>
This way the page is included first and stored in a buffer rather that output. It allows you included page to modify $page_title, and then that modified $page_title is available to the header.php script for output within the tags.
Just to change the title? Add this to your header.php
<title>
<?php
if(isset($_GET['page']) {
echo $_GET['page'];
} else {
echo 'My Site';
}
?>
</title>