absolute path not working but relative path working - php

I have two files test.php and test1.php on this path http://172.16.15.11/appointment/src/
I am checking for file test1.php whether its exist or not but it does not work when i am giving absolute path :
i have the below code in test.php
//giving absolute path not working
var_dump(file_exists('http://172.16.15.11/appointment/src/test1.php')); //return false
//but when i give relative path it does work
var_dump(file_exists('test1.php')); //return true
To cross check this i tried include in my test.php
include('http://172.16.15.11/appointment/src/test1.php'); //but in this case absolute path work
If i am giving absolute path its works when i
1. include('http://172.16.15.11/appointment/src/test1.php');
2. header('location:http://172.16.15.11/appointment/src/test1.php');
But does not work when i check this file :
var_dump(file_exists('http://172.16.15.11/appointment/src/test1.php')); //return false
Note - I do not have any .htaccess file

file_exists() MAY work for some URLs, but isn't guaranteed, from the manual page...
Tip As of PHP 5.0.0, this function can also be used with some URL
wrappers. Refer to Supported Protocols and Wrappers to determine which
wrappers support stat() family of functionality.
You can try...
$file = 'http://www.examle.com/somefile.jpg';
$file_headers = #get_headers($file);
if($file_headers[0] == 'HTTP/1.1 404 Not Found') {
$exists = false;
}
else {
$exists = true;
}
( from http://www.php.net/manual/en/function.file-exists.php#75064 )
include() also supports file wrappers (from manual)...
If "URL
include wrappers" are enabled in PHP, you can specify the file to be
included using a URL (via HTTP or other supported wrapper - see
Supported Protocols and Wrappers for a list of protocols) instead of a
local pathname.
BUT as a rule, I wouldn't include anything from a URL.

Don't forget about 301 and etc... Correct only 200...
And check isset always if u don't want have Notice in error log.
$headers = #get_headers('http://www.examle.com/somefile.jpg');
if(isset($headers[0]) AND $headers[0] == 'HTTP/1.1 200 OK') {
$exists = true;
}
else {
$exists = false;
}

The problem is the file_exists works with filesystem directory path, and not with URL.
if you want to check with the absolute path you can find it using getcwd()
file_exists (getcwd() . "/test1.php");

Related

php check if file_exists() with htaccess mod_rewrite

I'm using htacces mod_rewrite to rewrite my websites URLs, for example:
/dir/file.php
/dir/file_example.php
/dir/file2.php?id=test
become
/dir/file
/dir/file-example
/dir/file2-test
All ok. Now I have a PHP script to do certain redirect, but before of the redirect I would like to check if the file (or url) exist:
if(file_exists("/dir/file2-test")){ // redirect on page
}else{ // redirect on index
But file_exists() return false in this case.
There is another way to check if these pages/url (file2-test, file-example, etc) exists via php?
PS: Due the complexity of my htaccess rules I don't have the possibility to just append ".php" at the end.
You could check, whether the URL does exist via actually calling it, but at the cost of doing a real http request with all the server load and latency caused by this.
$file = 'http://www.domain.com/dir/file2-test';
$file_headers = #get_headers($file);
if($file_headers[0] == 'HTTP/1.1 404 Not Found') {
$exists = false;
}
else {
$exists = true;
}
Source: http://www.php.net/manual/en/function.file-exists.php#75064
I would not recommend this at all.
I don't see any real chance to probe the RewriteEngine logic from php, so I suggest to integrate your whole rewrite logic either in htaccess or php.
First of all, you have to check the absolute path, then you have to add the file extension (for files):
file_exists( $_SERVER['DOCUMENT_ROOT'].'/dir/file2-test.php') // check php file
file_exists( $_SERVER['DOCUMENT_ROOT'].'/dir/file2-test') // check directory
or, maybe better:
file_exists( $_SERVER['DOCUMENT_ROOT'].$_SERVER['REQUEST_URI"].".php") // check php file
file_exists( $_SERVER['DOCUMENT_ROOT'].$_SERVER['REQUEST_URI"]) // check directory
but — to work also with segments and/or queries — you should use parse_url:
$uri = parse_url( $_SERVER['REQUEST_URI'] );
file_exists( $_SERVER['DOCUMENT_ROOT'].$uri['path'].".php") // check php file
file_exists( $_SERVER['DOCUMENT_ROOT'].$uri['path']) // check directory
Edit:
Due the complexity of my htaccess rules I don't have the possibility to just append ".php" at the end.
Try glob():
$uri = parse_url( $_SERVER['REQUEST_URI'] );
$files = glob( $_SERVER['DOCUMENT_ROOT'].$uri['path'].'*' );
Now in $files you will have all file starting with $_SERVER['DOCUMENT_ROOT'].$uri['path']
Read mored about parse_url()
Read mored about glob()

PHP Include based on REQUEST_URI

Is there any security risks involved in using $_SERVER['REQUEST_URI'] to include a file? Can you pass ../../.. through the request uri somehow?
What I'm thinking is something like this:
<?php
$path = $_SERVER['REQUEST_URI'];
$path = preg_replace('~\\.html?$~', '.php', $path);
include $path;
?>
This should substitute ".htm" or ".html" URIs for ".php" paths and render them. But I am concerned about security here.
$_SERVER['REQUEST_URI'] contains the requested URI path and query string as it appeared in the HTTP request line. So when http://example.com/foo/bar?baz=quux is requested and the server passes the request to the script file /request_handler.php, $_SERVER['REQUEST_URI'] would still be /foo/bar?baz=quux. I’ve used mod_rewrite to map any request to request_handler.php as follows:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ /request_handler.php
So for correctness, before using $_SERVER['REQUEST_URI'] in a file system path, you would need to get rid of the query string. You can use parse_url to do so:
$_SERVER['REQUEST_URI_PATH'] = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
But as this value comes directly from the HTTP request line without prior path resolution, it may still contain symbolic path segments like ...
However, path traversal is not even necessary as the requested URI path is already an absolute path reference and requesting http://example.com/etc/passwd should result in the inclusion of /etc/passwd.
So this is actually a local file inclusion vulnerability.
Now to fix this, requiring a certain root directory using the method that you, chowey, have presented is a good improvement. But you would actually need to prefix it with $basedir:
$path = realpath($basedir . $_SERVER['REQUEST_URI_PATH']);
if ($path && strpos($path, $basedir) === 0) {
include $path;
}
This solution provides several promises:
$path is either a valid, resolved path to an existing file, or false;
inclusion of that file does only happen if $basedir is a prefix path of $path.
However, this may still allow access to files which are protected using some other kind of access control like the one provided by Apache’s mod_authz_host module.
This does not actually answer the question...
Note that you can ensure the request uri points to an actual valid filepath in the current working directory. You can use the realpath function to normalize the path.
The following code would do the trick:
<?php
$basedir = getcwd();
$path = $_SERVER['REQUEST_URI'];
$path = preg_replace('~\\.html?$~', '.php', $path);
$path = realpath($path);
if ($path && strpos($path, $basedir) === 0) {
include $path;
} else {
return false;
}
?>
Here I used strpos to verify that the $path starts with $basepath. Since realpath will have removed any ../../.. funny business, this should safely keep you within the $basepath directory.
Indeed dont trust the $_SERVER['REQUEST_URI'] before checking the basepath.
And dont make a filter that removes ../ from the path attackers can craft a nieuw way to inject if they understand the filter proces.
I had the same question and chose to do the following basing myself on Gumbo's answer :
$_SERVER['REQUEST_URI_PATH'] = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$path = realpath(FOLDER_ROOT . $_SERVER['REQUEST_URI_PATH']);
$directory_white_list_array = array('/safe_folder1', '/safe_folder1/safe_folder2');
if ($path && strpos($path, FOLDER_ROOT) === 0 && (in_array(dirname($path), $directory_white_list_array) && ('php' == pathinfo($path, PATHINFO_EXTENSION)))) {
include $path;
}else{
require_once FOLDER_ROOT."/miscellaneous_functions/navigation_error.php";
navigation_error('1');
}
Summary:
Added directory whitelist and .php extension restriction.

file_exists() returns false, but the file DOES exist

I'm having a very weird issue with file_exists(). I'm using this function to check if 2 different files in the same folders do exist. I've double-checked, they BOTH do exist.
echo $relative . $url['path'] . '/' . $path['filename'] . '.jpg';
Result: ../../images/example/001-001.jpg
echo $relative . $url['path'] . '/' . $path['filename'] . '.' . $path['extension'];
Result: ../../images/example/001-001.PNG
Now let's use file_exists() on these:
var_dump(file_exists($relative . $url['path'] . '/' . $path['filename'] . '.jpg'));
Result: bool(false)
var_dump(file_exists($relative . $url['path'] . '/' . $path['filename'] . '.' . $path['extension']));
Result: bool(true)
I don't get it - both of these files do exist. I'm running Windows, so it's not related to a case-sensitive issue. Safe Mode is off.
What might be worth mentioning though is that the .png one is uploaded by a user via FTP, while the .jpg one is created using a script. But as far as I know, that shouldn't make a difference.
Any tips?
Thanks
file_exists() just doesn't work with HTTP addresses.
It only supports filesystem paths (and FTP, if you're using PHP5.)
Please note:
Works :
if (file_exists($_SERVER['DOCUMENT_ROOT']."/folder/test.txt")
echo "file exists";
Does not work:
if (file_exists("www.mysite.com/folder/test.txt")
echo "file exists";
Results of the file_exists() are cached, so try using clearstatcache(). If that not helped, recheck names - they might be similar, but not same.
I found that what works for me to check if a file exists (relative to the current php file it is being executed from) is this piece of code:
$filename = 'myfile.jpg';
$file_path_and_name = dirname(__FILE__) . DIRECTORY_SEPARATOR . "{$filename}";
if ( file_exists($file_path_and_name) ){
// file exists. Do some magic...
} else {
// file does not exists...
}
Just my $.02: I just had this problem and it was due to a space at the end of the file name. It's not always a path problem - although that is the first thing I check - always. I could cut and paste the file name into a shell window using the ls -l command and of course that locates the file because the command line will ignore the space where as file_exists does not. Very frustrating indeed and nearly impossible to locate were it not for StackOverflow.
HINT: When outputting debug statements enclose values with delimiters () or [] and that will show a space pretty clearly. And always remember to trim your input.
It's because of safe mode. You can turn it off or include the directory in safe_mode_include_dir. Or change file ownership / permissions for those files.
php.net: file_exists()
php.net: safe mode
Try using DIRECTORY_SEPARATOR instead of '/' as separator. Windows uses a different separator for file system paths (backslash) than Linux and Unix systems.
A very simple trick is here that worked for me.
When I write following line, than it returns false.
if(file_exists('/my-dreams-files/'.$_GET['article'].'.html'))
And when I write with removing URL starting slash, then it returns true.
if(file_exists('my-dreams-files/'.$_GET['article'].'.html'))
I have a new reason this happens - I am using PHP inside a Docker container with a mounted volume for the codebase which resides on my local host machine.
I was getting file_exists == FALSE (inside Composer autoload), but if I copied the filepath into terminal - it did exist! I tried the clearstatche(), checked safe-mode was OFF.
Then I remembered the Docker volume mapping: the absolute path on my local host machine certainly doesn't exist inside the Docker container - which is PHP's perspective on the world.
(I keep forgetting I'm using Docker, because I've made shell functions which wrap the docker run commands so nicely...)
It can also be a permission problem on one of the parent folders or the file itself.
Try to open a session as the user running your webserver and cd into it. The folder must be accessible by this user and the file must be readable.
If not, php will return that the file doesn't exist.
have you tried manual entry. also your two extensions seem to be in different case
var_dump(file_exists('../../images/example/001-001.jpg'));
var_dump(file_exists('../../images/example/001-001.PNG'));
A custom_file_exists() function inspired by #Timur, #Brian, #Doug and #Shahar previous answers:
function custom_file_exists($file_path=''){
$file_exists=false;
//clear cached results
//clearstatcache();
//trim path
$file_dir=trim(dirname($file_path));
//normalize path separator
$file_dir=str_replace('/',DIRECTORY_SEPARATOR,$file_dir).DIRECTORY_SEPARATOR;
//trim file name
$file_name=trim(basename($file_path));
//rebuild path
$file_path=$file_dir."{$file_name}";
//If you simply want to check that some file (not directory) exists,
//and concerned about performance, try is_file() instead.
//It seems like is_file() is almost 2x faster when a file exists
//and about the same when it doesn't.
$file_exists=is_file($file_path);
//$file_exists=file_exists($file_path);
return $file_exists;
}
This answer may be a bit hacky, but its been working for me -
$file = 'path/to/file.jpg';
$file = $_SERVER['REQUEST_SCHEME'].'://'.$_SERVER['HTTP_HOST'].'/'.$file;
$file_headers = #get_headers($file);
if($file_headers[0] == 'HTTP/1.1 404 Not Found') {
$exists = false;
}else{
$exists = true;
}
apparently $_SERVER['REQUEST_SCHEME'] is a bit dicey to use with IIS 7.0 + PHP 5.3 so you could probably look for a better way to add in the protocol.
I found this answer here http://php.net/manual/en/function.file-exists.php#75064
I spent the last two hours wondering what was wrong with my if statement: file_exists($file) was returning false, however I could call include($file) with no problem.
It turns out that I didn't realize that the php include_path value I had set in the .htaccess file didn't carry over to file_exists, is_file, etc.
Thus:
<?PHP
// .htaccess php_value include_path '/home/user/public_html/';
// includes lies in /home/user/public_html/includes/
//doesn't work, file_exists returns false
if ( file_exists('includes/config.php') )
{
include('includes/config.php');
}
//does work, file_exists returns true
if ( file_exists('/home/user/public_html/includes/config.php') )
{
include('includes/config.php');
}
?>
Just goes to show that "shortcuts for simplicity" like setting the include_path in .htaccess can just cause more grief in the long run.
In my case, the problem was a misconception of how file_exists() behaves with symbolic links and .. ("dotdot" or double period) parent dir references. In that regard, it differs from functions like require, include or even mkdir().
Given this directory structure:
/home/me/work/example/
www/
/var/www/example.local/
tmp/
public_html -> /home/me/work/example/www/
file_exists('/var/www/example.local/public_html/../tmp/'); would return FALSE even though the subdir exists as we see, because the function traversed up into /home/me/work/example/ which does not have that subdir.
For this reason, I have created this function:
/**
* Resolve any ".." ("dotdots" or double periods) in a given path.
*
* This is especially useful for avoiding the confusing behavior `file_exists()`
* shows with symbolic links.
*
* #param string $path
*
* #return string
*/
function resolve_dotdots( string $path ) {
if (empty($path)) {
return $path;
}
$source = array_reverse(explode(DIRECTORY_SEPARATOR, $path));
$balance = 0;
$parts = array();
// going backwards through the path, keep track of the dotdots and "work
// them off" by skipping a part. Only take over the respective part if the
// balance is at zero.
foreach ($source as $part) {
if ($part === '..') {
$balance++;
} else if ($balance > 0) {
$balance--;
} else {
array_push($parts, $part);
}
}
// special case: path begins with too many dotdots, references "outside
// knowledge".
if ($balance > 0) {
for ($i = 0; $i < $balance; $i++) {
array_push($parts, '..');
}
}
$parts = array_reverse($parts);
return implode(DIRECTORY_SEPARATOR, $parts);
}
I just encountered this same problem and I solved it in a mysterious way. After inserting a a filepath I copied from Windows File explorer. file_exists() keeps returning false continuously, but if I copy same path from VSCode editor it works perfectly.
After dumping variables with var_dump($path); I noticed something mysterious.
For path I copied from file explorer it shows length 94.
For path I copied from VSCode Editor it shows length 88.
Both path look same length on my code Editor.
My suggestion: if string contain hidden characters, it may fail and not work.

file_exists() does not run

$myfilepath = SITEROOT."/uploads/vaibhav_photo/thumbnail/".$user_avatar['thumbnail'];
if(file_exists($myfilepath))
{
echo "file exist";
}
else
{
echo "file does not exist";
}
It always goes to else part even though file is present.
if anybody have an alternate option for this in PHP please reply as fast as possible,
file_exists works on file paths only. http:// URLs are not supported.
$myfilepath = SITEROOT.DS.'uploads'.DS.'vaibhav_photo'.DS.'thumbnail'.DS.$user_avatar['thumbnail'];
NOTE::SITEROOT have actual root path and DS is constant DIRECTORY_SEPARATOR.
Pekka is correct that file_exists does not support http protocol.
You can however use file_get_contents
if(file_get_contents($myfilepath)) {
echo "file exist";
}
By default this pulls back the entire contents of the file. If this is not what you want you can optimise this by adding some flags:
if(file_get_contents($myfilepath, false, null, 0, 1)) {
echo "file exist";
}
This syntax will return the first character if it exists.
Check what your working directory is with getcwd().
Your path
example.com/uploads/etc/etc.jpg
is interpreted relative to the current directory. That's likely to be something like
/var/www/example.com
so you ask file_exists() about a file named
/var/www/example.com/example.com/uploads/etc/etc.jpg
You need to either figure out the correct absolute path (add the path containing all site roots in front of SITEROOT) or the correct relative path (relative to the directory your script is in, without a leading /).
tl;dr: try
$myfilepath = 'uploads/etc/etc.jpg';

Php - troubles with files paths

i can't understand one thing. In code, for example:
$filePath = 'http://wwww.server.com/file.flv';
if( file_exist($filePath) )
{
echo 'yes';
}
else
{
echo 'no';
}
Why does script return 'no', but when i copy that link to the browser it downloads?
The file_exists() function is looking for a file or directory that exists from the point of view of the server's file system. If http://www.server.com/ equates to /home/username/public_html/ then you need to make your code:
$filename = '/home/username/public_html/file.flv';
if(file_exists($filename))
{
//true branch
}
else
{
//false brach
}
See http://php.net/file_exists for more info.
GIYF.
http://sg.php.net/manual/en/function.file-exists.php#75064
use
$_SERVER["DOCUMENT_ROOT"]
to assure the right filesystem path, not dependent by development or production system for example.
in this case, it will be
$filePath = $_SERVER["DOCUMENT_ROOT"].'/file.flv';
file_exists() check for filesystem files and directories. Use fopen() too see whether that web URL is accessible. In case the respective server will return 404 Not Found for that resource, fopen() will return false and issue an warning. A much better solution would be to issue an HTTP HEAD request.
First of all the php function you need to use is file_exists() with the 's' at the end. Second of all, I think the path to the file needs to be a local file path, not a URL. Not sure though...
do:
function isExistsFileOnMyWebsite($fileName) {
return file_exist($_SERVER['DOCUMENT_ROOT'].'/'.$fileName);
}
if( isExistsFileOnMyWebsite('file.flv') )
{
echo 'yes';
}
else
{
echo 'no';
}

Categories