File not found at path when trying to copy - php

I'm trying to copy a file from one location to another. I'm pretty sure the location is correct, but I'm still getting the error in the title.
Here's some code:
$oDirectory = new \RecursiveDirectoryIterator($extractFolder.'/res');
$oIterator = new \RecursiveIteratorIterator($oDirectory);
foreach($oIterator as $oFile) {
if ($oFile->getFilename() == 'icon.png') {
$icons[filesize($oFile->getPath().'/icon.png')] = $oFile->getPath().'/icon.png';
}
}
asort($icons);
print_r($icons);
$icon_source = end($icons);
echo $icon_source;
$generated_icon_file = str_slug($packagename.$version).'.png';
Storage::copy($icon_source, $generated_icon_file);
The print_r returns (which means the files exist):
Array ( [19950] => /var/www/apk.land/storage/extracted_apks/res/drawable-xxhdpi-v4/icon.png [31791] => /var/www/apk.land/storage/extracted_apks/res/drawable-xxxhdpi-v4/icon.png [6979] => /var/www/apk.land/storage/extracted_apks/res/drawable-hdpi-v4/icon.png [10954] => /var/www/apk.land/storage/extracted_apks/res/drawable-xhdpi-v4/icon.png )
The echo returns:
/var/www/apk.land/storage/extracted_apks/res/drawable-xxxhdpi-v4/icon.png
And the exact error is:
File not found at path:
var/www/apk.land/storage/extracted_apks/res/drawable-xxxhdpi-v4/icon.png
P.S. PHP's copy function works just great.
I can't find the problem here.
Any suggestions?

You said that the error is like this:
File not found at path: var/www/apk.land/storage/extracted_apks/res/drawable-xxxhdpi-v4/icon.png
Here error is saying it cannot find at var/www that means it's looking for apk.land/var/www whereas your file is located somewhere at /var/www. A quick fix to this can be use file protocol. Just use it like:
file:///var/www/storage/apk.land/storage/extracted_apks/res/drawable-xxxhdpi-v4/icon.png

Try with File::copy($file, $dest) instead of Storage::copy($old, $new)
File::copy() is the wrapper on PHP's copy() function

First of all, if you are using Laravel's Storage Facade and with that the underlying Flysystem you have to know, that it is not intended to work with absolute paths like you did. The benefit of that is, that you could potentially work with different storage disks, that all have own configurations, that can be set in your config/filesystems.php file.
Assuming you did not change anythig there, the default "disk" would be local with an root of storage_path('app') ( = the path to your laravel storage folder/app )
If you want to know, why it is failing, we have to take a look at the source code you will find in the following code in the file vendor\league\flysystem\src\Filesystem.php
public function copy($path, $newpath)
{
$path = Util::normalizePath($path); // <-- this will strip leading /
$newpath = Util::normalizePath($newpath);
$this->assertPresent($path); // this will cause the error in your case, because assertion cannot be fullfilled in case of missing leading /
$this->assertAbsent($newpath);
return $this->getAdapter()->copy($path, $newpath); // calls the copy of your Adapter, assuming local in your case
}
So have a look, what would go on, if $this->getAdapter()->copy($path, $newpath) was called:
File (assuming local storage disk): vendor\league\flysystem\src\Adapter\Local.php
public function copy($path, $newpath)
{
$location = $this->applyPathPrefix($path);
$destination = $this->applyPathPrefix($newpath);
$this->ensureDirectory(dirname($destination));
return copy($location, $destination);
}
The line
$location = $this->applyPathPrefix($path);
will prepend the root path as defined in config/filesystems.php
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
],
As I can see in your code your files are are not stored in storage/app,
so i think you have to change this to 'root' => storage_path()
So if you want to use Storage::copy() you have just to provide paths relative to that folder. And as it is hard to see, how you could achieve this, take a look at that.
foreach($oIterator as $oFile) {
if ($oFile->getFilename() == 'icon.png') {
$icons[filesize($oFile->getPath().'/icon.png')] = $oIterator->getSubPath().'/icon.png';
}
}
There is RecursiveDirectoryIterator::getSubPath (Although quite undocumentated, which would return you the current subpath of your iterations. In your case relative to $extractFolder.'/res'.
Now you have to make sure you are calling
Storage::copy($icon_source, $generated_icon_file);
Where $icon_source and $generated_icon_file are relative to your defined 'root'.

Insert / before var/www/apk.land/storage/extracted_apks/res/drawable-xxxhdpi-v4/icon.png
The path is relative to current directory. Buy if you add /, the path is absolute from root directory.

you have to choose the right disk somthing like this
$file2 ='public/'.$page->thumbnail;
$destination = 'public/bundles/ttt.png';
if( Storage::disk('local')->exists($file2)){
Storage::disk('local')->copy($file2,$destination);
}

Related

I am unable to open file with \Template::instance()->render. I am getting the following error

It is giving me the following error,
[text] => Unable to open /home/mehul/www/portal.hsua.com.au/public_html/assets/templates.html
This is the part of code which is causing the problem.
$this->f3->set('const', $constants);
ob_start();
echo \Template::instance()->render('/home/mehul/www/portal.hsua.com.au/public_html/assets/templates.html');
$renderedView = ob_get_clean();
/*foreach ($variables as $varname => $variable) {
$this->f3->clear($varname);
}*/
return $renderedView;
The file might not exist
you're opening the PHP file in your webbrowser PHP file is somewhere located in /var/www delivered by Nginx / Apache. If that's the case, your webserver probably has no access to open a file within your home directory.
I recommend you put the template files next to your PHP file to make sure your webserver has access to it.
The render() methods concatenates the given template $file with all template paths stored in the UI system variable while searching for a valid file. Therefore you either have to specify a relative path or append / as workaround.
Workaround
$f3 = Base::instance();
$f3->concat('UI', ';/');
Source/Reference
The concatination $dir.$file in base.php#L2791 is the culprit. Your error is generated a few lines below.
Update / Example
$f3 = Base::instance();
$f3->concat('UI', ';/'); // Add support for absolute paths.
echo \Template::instance()
->render(__DIR__ . '/template.html');

Change save folder in burzum/cakephp-file-storage plugin

I'm using a plugin to save files in CakePHP 3: burzum/cakephp-file-storage,
everything works perfectly
but now I need to change the directory where file is being saved dynamically (through the directory where
the file is saved by parameter for example), how can I do this?
Path actual:
[htdocs]\[AppName]\tmp[FileExtension.png]
It is possibly stay with the following structure for example:
[htdocs]\[AppName-Images]\Products[FileExtension.png]
PHP Code:
public function saveFileLFS($stringSeparator, $storeName, $productName)
{
$key = $storeName . $stringSeparator . $productName . $stringSeparator .
$this->request->data['Media']['file']['name'];
if(StorageManager::adapter('Local')->write($key,
file_get_contents($this->request->data['Media']['file']['tmp_name']))){
return true;
}else
{
return false;
}
}
Github Link
The reason it ends up in TMP is that this is the default configuration that comes with the plugin. It goes to TMP because this is the only place besides logs that should be writeable in a proper application setup and the plugin should work out of the box. Maybe I'll change this in a future release (4.0) so that you have to configure it to use it, to make people aware of it.
For the local adapter change it like this:
StorageManager::config('Local', [
'adapterOptions' => [ROOT . DS . 'file_storage' . DS], // Your base path here
'adapterClass' => '\Gaufrette\Adapter\Local',
'class' => '\Gaufrette\Filesystem'
]);
This will override the default. Actually this is already documented and explained here.
I recommend you to take a look at the 1.1.0 branch (currently release is 1.1.0-RC1). Some people already use it and I'm happy to get feedback about it. The whole way paths and file names are generated has been completely rewritten and abstracted into a set of classes called "path builders".

Forcing file-creation in public directory?

Here's an idea. I'm trying to create file from PHP script. File may be created in any public place on server (in public root or in its subdirectories). Bottom of line, I want to write function like this (it must work on both unix and windows servers).
function create_file($path, $filename, $content, $overwrite=false) {
# body
...
}
Parameters:
$path - file-path (empty or ends with /)
$filename - any valid file-name (requires dot+extension)
$content - file-content (anything)
$overwrite - if set true, existing file will be overwritten (default. false).
Result:
Function returns TRUE and creates file with content, or FALSE if file-creation was not possible for any reason.
Description of problem:
I expect this function to return true and create file $filename on path $path, or false if it wasn't possible for any reason. Also if file was successfully opened for writing, need to put $content in it.
Argument $path is relative path to public directory, and $filename is any valid filename. Of course, I want to avoid creating files if path points outside of public directory. Function may be called from subdirectory-scripts like this example
# php script: /scripts/test.php
create_file('../data/', 'test.info', 'some contents');
# result file: /data/test.info
What have I tried so far?
I’ve tried doing this with fopen() and fwrite() functions and that works on some servers, and doesn’t work on some. I guess there’s problem with writing privileges and chmod() but to be honest I’m not very familiar with chmod attributes. Also I couldn't check if $path points outside of server's public directory.
In short, I want this function to create file and return TRUE if file doesn't exist, or file exists and $owerwrite=true. Otherwise, nothing happens and function returns FALSE.
Additionally, I would like to know reason why file can't be created on some path (just in theory). Incorrect path/filename is only thing I have on my mind and I'm sure there's more about this problem.
Thanks in advance for any sample/example/suggestion.
update code
So far I have this code...
function create_file($path, $filename, $content, $overwrite=false) {
$reldir = explode('/', trim(str_replace('\\', '/', dirname($_SERVER['PHP_SELF'])), '/'));
$dirdepth = sizeof($reldir);
$rpadd = $dirdepth > 0 ? '(\.\./){0,' . $dirdepth . '}' : '';
$ptpath = '#^/?' . $rpadd . '([a-z0-9]\w*/)*$#i';
$ptname = '/^[a-z]\w*\.[a-z0-9]+$/i';
if ($res = preg_match($ptpath, $path) && preg_match($ptname, $filename)) {
$res = false;
if ($overwrite === true || !file_exists($path.$filename)) {
if ($f = #fopen($path.$filename, 'w')) {
fwrite($f, $content);
fclose($f);
$res = true;
}
}
}
return $res;
}
Some suggestions:
set the owner of the web server document root: chown -R apache:apache /var/www (i suppose /var/www is your document root and that the web server apache runs with user apache). Set the privilegies of the document root like this in order to have all directories under document look with privilegies 755 (only owner which is user apache can write in folders /var/www and sub folders)
Block paths that point out of your /var/www document root: you are under the issue known as http://en.wikipedia.org/wiki/Directory_traversal_attack. What about if the $path is something like: /var/www/../../../etc/passwd?
Basename php function can help you identifying this kind of malignous paths. Look this post: php directory traversal issue
To check wheter a file already exists or not: http://php.net/manual/en/function.file-exists.php
All file functions in php will not work properly in two circumstances
If you don't have enough user privileges for applications, then
You may not used/passed the arguements/parameters correctly .

prevent /.. user input

I have a php script in a folder (I call it the root folder). The script can basically list all files in subfolders of this root folder. The user can specify which subfolder should be displayed by using GET-parameters.
script.php?foo
would display the content of
<root folder>/foo/
and
script.php?.bar
would display the content of
<root folder>/.bar/
However, users could also "cheat" and use commands like /.. to display the content of folders they souldn't be able to see.
For example with
script.php?/../..
the users could get very high in the folder hierarchy.
Do you have an idea how to prevent users of doing "cheats" like this.
For reason of simplicity, let's say the GET-parameter is stored in $searchStatement.
You could use realpath to resolve the relative path to an absolute one and then check if that path begins with your "root" folder's path:
$absolutePath = realpath(__DIR__ . '/' . trim($searchStatement, '/'));
if (strpos($absolutePath, __DIR__ .'/') !== 0) {
die('Access denied.');
}
You just should validate the input before you use it.
For example you might want to only allow the characters a-z and / to allow subdirectories. Probably you want to allow the . as well. If you make this subset small, it's easy to validate if the input is allowed or not by the allowed characters already.
At the moment you allow ., as you have noticed, you have the problem that relative paths could be created like /../../ which could be used for directory traversal attacks.
To validate if a string contains only characters of a specific range, you can validate this with a regular expression or the filter functions. If your website does not need to allow any relative path parts you can look if they exist in the path to validate the input:
$valid = !array_intersect(array('', '.', '..'), explode('/', $path));
Valid will be FALSE if there is any // or /./ or /../ part inside the path.
If you need to allow relative paths, realpath has already been suggested, so to query the input against your directory structure first. I would only use it as last resort as it is relatively expensive, but it's good to know about.
However you can resolve the string your own as well with some simple function like the following one:
/**
* resolve path to itself
*
* #param string $path
* #return string resolved path
*/
function resolvePath($path)
{
$path = trim($path, '/');
$segmentsIn = explode('/', $path);
$segmentsOut = array();
foreach ($segmentsIn as $in)
{
switch ($in)
{
case '':
$segmentsOut = array();
break;
case '.':
break;
case '..';
array_pop($segmentsOut);
break;
default:
$segmentsOut[] = $in;
}
}
return implode('/', $segmentsOut);
}
Usage:
$tests = array(
'hello',
'world/.',
'../minka',
'../../42',
'../.bar',
'../hello/path/./to/../../world',
);
foreach($tests as $path)
{
printf("%s -> %s\n", $path, resolvePath($path));
}
Output:
hello -> hello
world/. -> world
../minka -> minka
../../42 -> 42
../.bar -> .bar
../hello/path/./to/../../world -> hello/world
I can only suggest you first validate the input based on it's own data before letting touch it the filesystem, even through realpath.
Have a look at the chroot function:
bool chroot ( string $directory )
Changes the root directory of the current process to directory, and changes the current working directory to "/".
A call to that method prevents further access to files outside of the current directory.
Note however that requires root privileges.
Have you tried something with realpath, it should resolve all the /.. in your path. By testing the realpath of the arguments against your current path like:
substr($realpath, 0, strlen('/basepath/cant/go/above')) === '/basepath/cant/go/above'
you make sure that any /.. havent escaped from where you want.

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.

Categories