Open_basedir prevents listing symlink files in php - php

I have a function which returns the current files in a directory. Sometimes it contains symlinks which point outside of my web directory. Unfortunately, when I add a "open_basedir" restriction in my php ini file, the symlinked files are not visible anymore to PHP.
php.ini file:
[PHP]
...
open_basedir="/var/www"
...
This is partly understandable because the symlink points to a file outside the allowed directory. But I only need the filename of the symlink itself (not the original file). Why PHP cannot see/list the names of a symlinked file is a mystery for me.
I use this function to get the filelist of a directory:
function getFileList($dir)
{
// array to hold return value
$retval = array();
// add trailing slash if missing
if(substr($dir, -1) != "/") $dir .= "/";
// open pointer to directory and read list of files
$d = #dir($dir) or die("getFileList: Failed opening directory $dir for reading");
while(false !== ($entry = $d->read())) {
// skip hidden files
if($entry[0] == ".") continue;
if(is_dir("$dir$entry")) {
$retval[] = array(
"name" => "$dir$entry/",
"type" => filetype("$dir$entry"),
"size" => 0,
"lastmod" => filemtime("$dir$entry")
);
} elseif(is_readable("$dir$entry")) {
$retval[] = array(
"name" => "$dir$entry",
"type" => mime_content_type("$dir$entry"),
"size" => filesize("$dir$entry"),
"lastmod" => filemtime("$dir$entry")
);
}
}
$d->close();
return $retval;
}
Should I use another function or is this some kind of glitch in PHP?

Related

PHP and HTML to make nice interactive file display page

I've found a good demo code that I was able to make work with what I'm trying to do. But the final product is fairly ugly, and doesn't let me view the files. As far as the "nice" part goes, I have a feeling I should be looking as something more jquery oriented?
When i click on the link for a displayed file, I get a url not found error. The path to the file is incorrect...
This is incorrect and what the script currently tries to navigate to:
http://server/var/www/html/reports/1/Doe_John/2019-04-01/Run_2_Report.pdf
This is correct and works to display the file in the browser:
http://server/reports/1/Doe_John/2019-04-01/Run_2_Report.pdf
Is there a straightforward way to "subtract" out the extra file path portion that is causing the problem? I had to add the {$_SERVER['DOCUMENT_ROOT']} part to make it find the files, but that seems to be what is causing the issue now.
I'm also wanting to sort the files by date, and it's not doing that correctly. The dates are being sorted alphabetically by month. Can this be accomplished with just HTML, or should I again be looking at something like Jquery?
PHP that displays all pdf files in structure:
<?PHP
// Original PHP code by Chirp Internet: www.chirp.com.au
// Please acknowledge use of this code by including this header.
//Test User Vars
$region = "1";
$first_name = "John";
$last_name = "Doe";
function getFileList($dir, $recurse = FALSE)
{
// array to hold return value
$retval = array();
// add trailing slash if missing
if(substr($dir, -1) != "/") $dir .= "/";
// open pointer to directory and read list of files
$d = #dir($dir) or die("getFileList: Failed opening directory $dir for reading");
while(false !== ($entry = $d->read())) {
// skip hidden files
if($entry[0] == ".") continue;
if(is_dir("$dir$entry")) {
$retval[] = array(
"name" => "$dir$entry/",
"type" => filetype("$dir$entry"),
"size" => 0,
"lastmod" => filemtime("$dir$entry")
);
if($recurse && is_readable("{$dir}{$entry}/")) {
$retval = array_merge($retval, getFileList("{$dir}{$entry}/", TRUE));
}
} elseif(is_readable("$dir$entry")) {
$retval[] = array(
"name" => "$dir$entry",
"type" => mime_content_type("$dir$entry"),
"size" => filesize("$dir$entry"),
"lastmod" => filemtime("$dir$entry")
);
}
}
$d->close();
return $retval;
}
?>
<h1>List PDF files with links</h1>
<table class="collapse" border="1">
<thead>
<tr><th>Name</th><th>Type</th><th>Size</th><th>Last Modified</th></tr>
</thead>
<tbody>
<?PHP
$dirlist = getFileList("{$_SERVER['DOCUMENT_ROOT']}/reports/{$region}/{$last_name}_{$first_name}/", TRUE);
foreach($dirlist as $file) {
if($file['type'] != "application/pdf") continue;
echo "<tr>\n";
echo "<td>",basename($file['name']),"</td>\n";
echo "<td>{$file['type']}</td>\n";
echo "<td>{$file['size']}</td>\n";
echo "<td>",date('r', $file['lastmod']),"</td>\n";
echo "</tr>\n";
}
?>
</tbody>
</table>
The second link works because /var/www/html/ is probably the DocumentRoot of your server, if you are using Apache, it is kind of the root of your application.

Change folder to fetch on filemanager

I've the following problem: i'm working on a filemanager consisting in only one index.php file, that fetches all the files and folders from the actual folder there its located in.
So if i have a folder with the filemanager file on it:
Folder01
-folder-A
-folder-B
-file1.php
-image.png
-index.php
The filemanager will show: folder-A, folder-B, file1.php and image.png
The problem is I can't change the folder to fetch it's content, to be able to view, by default, the content of folder-A for example.
$file = isset($_REQUEST['file']) ? urldecode($_REQUEST['file']) : '.';
if(isset($_GET['do']) && $_GET['do'] == 'list') {
if (is_dir($file)) {
$directory = $file;
$result = array();
$files = array_diff(scandir($directory), array('.','..'));
foreach($files as $entry) if($entry !== basename(__FILE__)) {
$i = $directory . '/' . $entry;
$stat = stat($i);
$result[] = array(
'mtime' => $stat['mtime'],
'size' => $stat['size'],
'name' => basename($i),
'path' => preg_replace('#^\./#', '', $i),
'ext' => pathinfo($i, PATHINFO_EXTENSION),
'is_dir' => is_dir($i),
'is_deleteable' => (!is_dir($i) && is_writable($directory)) ||
(is_dir($i) && is_writable($directory) && is_recursively_deleteable($i)),
'is_readable' => is_readable($i),
'is_writable' => is_writable($i),
'is_executable' => is_executable($i),
);
}
} else {
err(412,"Not a Directory");
}
echo json_encode(array('success' => true, 'is_writable' => is_writable($file), 'results' =>$result));
exit;
}
This snippet is the beginning of its php code, which is in charge of fetching the files of the selected folder.
Any idea about how to change that?
try glob function, its like dir command in dos,
it will list all of the dirs and files in the current working directory and put them in an array, which is the return value of the function.

php - get sub-sub-folder and specific files name and path

I would to retrieve from a path all sub (and sub-sub) directories and all files (only with .php and .css extensions) in (last sub) it.
The structre is the following:
my_path/sub-folder1/ // I want to get the sub folder name (and check if allowed)
sub-sub-folder1/file1.php // I want to get the file name and path
sub-sub-folder1/file1.css // I want to get the file name and path
sub-sub-folder2/file2.php // ....
sub-sub-folder2/file2.css
sub-sub-folder3/file3.php
sub-sub-folder3/file3.css
my_path/sub-folder2/
sub-sub-folder1/file1.php
sub-sub-folder1/file1.css
sub-sub-folder2/file2.php
sub-sub-folder2/file2.css
sub-sub-folder3/file3.php
sub-sub-folder3/file3.css
I know the my_pathdirectory name. About sub-folder, I only want to retrieve sub-folder which have the name (sub-folder1, sub-folder2 for example). And I would like to retrieve all sub-sub-folders and inside them and get the name and path of the .css and .php files inside it. I'm not sure if I'm clear with my explanations.
My aim is to store all this information in an array like this:
$data['sub-folder-1']= array(
'sub-sub-folder1' => array(
'name' => 'file1',
'php' => 'file1.php',
'css' => 'file1.css',
),
'sub-sub-folder2' => array(
'name' => 'file2',
'php' => 'file2.php',
'css' => 'file2.css',
),
...
);
$data['sub-folder-2']= array(
'sub-sub-folder1' => array(
'name' => 'file1',
'php' => 'file1.php',
'css' => 'file1.css',
),
'sub-sub-folder2' => array(
'name' => 'file2',
'php' => 'file2.php',
'css' => 'file2.css',
),
...
);
I have started with this code but I have some difficulties to make it works (and it's not finished), I don't use this kind of functionnality a lot...
$dirname = 'my_path';
$findphp = '*.php';
$findcss = '*.css';
$types = array('sub-folder1','sub-folder2');
$sub_dirs = glob($dirname.'/*', GLOB_ONLYDIR|GLOB_NOSORT);
if(count($sub_dirs)) {
foreach($sub_dirs as $sub_dir) {
$sub_dir_name = basename($sub_dir);
if (in_array($sub_dir_name,$types)) {
$sub_sub_dirs = glob($sub_dir.'/*', GLOB_ONLYDIR|GLOB_NOSORT);
if(count($sub_sub_dirs)) {
foreach($sub_sub_dirs as $sub_sub_dir) {
$php = glob($sub_sub_dir.'/'.$findphp);
$css = glob($sub_sub_dir.'/'.$findcss);
$sub_sub_dir_name = basename($sub_sub_dir);
$data[$sub_dir_name][$sub_sub_dir_name]['type'] = $sub_dir_name;
$data[$sub_dir_name][$sub_sub_dir_name]['name'] = basename($php[0], '.php');
$data[$sub_dir_name][$sub_sub_dir_name]['html'] = $php[0];
$data[$sub_dir_name][$sub_sub_dir_name]['css'] = $css[0];
}
}
}
}
} else {
echo "Nothing was found.";
}
print_r($data);
I like using the RecursiveDirectoryIterator class. I think it's more readable. This sample allow you to read all subfolders of a given source.
$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($source)); // Top source directory
$iterator->setFlags(\FilesystemIterator::SKIP_DOTS); // Skip folders with dot
$allowedExtension = array('php', 'css'); // And other if needed
$skin = array();
while ($iterator->valid()) {
$extension = $iterator->getExtension(); // >= PHP 5.3.6
if ($iterator->isFile() && in_array($extension, $allowedExtension)) {
// Complete this part or change it following your needs
switch ($extension) {
case 'php':
// All your logic here
$skin[$iterator->getPath()]['name'] = $iterator->getFileName(); //eg
break;
default:
break;
}
}
$iterator->next();
}
You can find the whole list of available functions at Directory Iterator.
Hope it's help.

Php read directory with absolute path

I have this php script which reads mp3 files from the directory:
// Set your return content type
header('Content-type: text/xml');
//directory to read
$dir = ($_REQUEST['dir']);
$sub_dirs = isBoolean(($_REQUEST['sub_dirs']));
if(file_exists($dir)==false){
//echo $_SERVER['DOCUMENT_ROOT'];
//echo "current working directory is -> ". getcwd();
echo 'Directory \'', $dir, '\' not found!';
}else{
$temp = getFileList($dir, $sub_dirs);
echo json_encode($temp);
}
function isBoolean($value) {
if ($value && strtolower($value) !== "false") {
return true;
} else {
return false;
}
}
function getFileList($dir, $recurse){
$retval = array(); // array to hold return value
if(substr($dir, -1) != "/") // add trailing slash if missing
$dir .= "/"; // open pointer to directory and read list of files
$d = #dir($dir) or die("getFileList: Failed opening directory $dir for reading");
while(false !== ($entry = $d->read())) { // skip hidden files
if($entry[0] == "." || $entry[0] == "..") continue;
if(is_dir("$dir$entry")) {
if($recurse && is_readable("$dir$entry/")) {
$retval = array_merge($retval, getFileList("$dir$entry/", true));
}
}else if(is_readable("$dir$entry")) {
$path_info = pathinfo("$dir$entry");
if(strtolower($path_info['extension'])=='mp3'){
$retval[] = array(
"path" => "$dir$entry",
"type" => $path_info['extension'],
"size" => filesize("$dir$entry"),
"lastmod" => filemtime("$dir$entry")
);
}
}
}
$d->close();
return $retval;
}
This file sits in the same directory as the html page which executes the script. For example, I pass the relative path 'audio/mp3' or '../audio/mp3' and it all works well.
Is it possible to make this read directory with absolute path?
For example, if I would pass this: http://www.mydomain.com/someFolder/audio/mp3, and html page which executes the script and the php file would be placed in this location: http://www.mydomain.com/someFolder/
Thank you!
Web root is always just /. You'd never need the hostname or protocol part, and root can be only root of the server, not some folder or file.
If you need some path, like /testthesis/ - there are ways, but it has nothing common with web root.
If you need a filesystem directory for the webroot - it's in the $_SERVER['DOCUMENT_ROOT'] variable.

How would I scan a directory to make links to pdfs using php?

I'm really new to PHP but what I want to do is make a dynamic table of contents for some of my companies job offerings.
So if i put all the pdfs of the job descriptions in a folder called ../jobops with the php file located in root directory what would I need to do.
<?php
$directory = "/jobops";
$contents = scandir($directory);
if ($contents) {
foreach($contents as $key => $value) {
if ($value == "." || $value == "..") {
unset($key);
}
}
}
echo "<ul>";
foreach($contents as $k => $v) {
echo "<li>link text</li>";
}
echo "</ul>";
?>
Should work. Takes the directory, scans it, maps all the filenames into an array $contents removes the relative urls (the "." and "..") and then echoes them out.
Remember that foreach is relatively expensive, though; so you may wish to simply unset $contents[0] and $contents[1].
Edited in response to the following (from the OP):
Warning:
scandir(www.markonsolutions.com/jobops)
[function.scandir]: failed to open
dir: No such file or directory in
/home/content/t/i/m/timhish/html/test.php
on line 5 Warning: scandir()
[function.scandir]: (errno 2): No such
file or directory in
/home/content/t/i/m/timhish/h/i/s/h/html/test.php
on line 5 Warning: Invalid argument
supplied for foreach() in
/home/content/t/i/m/timhish/html/test.php
on line 15
I changed ti from "/jobops"
thinking it was a relative directory
thing but apparently that's not it. also
im not sure what the
/home/content....... thing is but i am
currently hosted with go daddy maybe
thats how they store things?
The $directory variable is relative to where the script is being called. In my case, this runs from the root folder so it should be, for me, $directory = "jobops" assuming the folder and script are stored in the same place. Without knowing your server's directory structure I can't really help you, but I would suggest ruling out a problem with the scandir() function.
To do this, create a folder in the same directory as your script called whatever you like, populate it with at least one image (so that the following if() doesn't unset the entire array) and see if that works. If it does then you're stuck with finding the relative path to your folder. If it doesn't then I'm stuck myself.
The SPL (PHP5) provides a nice interface to directory traversal:
// whitelist of valid file types (extension => display name)
$valid = array(
'pdf' => 'PDF',
'doc' => 'Word'
);
$files = array();
$dir = new DirectoryIterator($directory_path);
foreach($dir as $file)
{
// filter out directories
if($file->isDot() || !$file->isFile()) continue;
// Use pathinfo to get the file extension
$info = pathinfo($file->getPathname());
// Check there is an extension and it is in the whitelist
if(isset($info['extension']) && isset($valid[$info['extension']]))
{
$files[] = array(
'filename' => $file->getFilename(),
'size' => $file->getSize(),
'type' => $valid[$info['extension']], // 'PDF' or 'Word'
'created' => date('Y-m-d H:i:s', $file->getCTime())
);
}
}
take a look at fnmatch() or glob() functions.
(i'd have liked to post it as a comment, but the link would have been too long)
<?php
// open this directory
$myDirectory = opendir(".");
// get each entry
while($entryName = readdir($myDirectory)) {
$dirArray[] = $entryName;
}
// close directory
closedir($myDirectory);
// count elements in array
$indexCount = count($dirArray);
Print ("$indexCount files<br>\n");
// sort 'em
sort($dirArray);
// print 'em
print("<TABLE border=1 cellpadding=5 cellspacing=0 class=whitelinks>\n");
print("<TR><TH>Filename</TH><th>Filetype</th><th>Filesize</th></TR>\n");
// loop through the array of files and print them all
for($index=0; $index < $indexCount; $index++) {
if (substr("$dirArray[$index]", 0, 1) != "."){ // don't list hidden files
print("<TR><TD>$dirArray[$index]</td>");
print("<td>");
print(filetype($dirArray[$index]));
print("</td>");
print("<td>");
print(filesize($dirArray[$index]));
print("</td>");
print("</TR>\n");
}
}
print("</TABLE>\n");
?>
seems to be working but I need to tweak it to only search a sub dir and only *.pdf files

Categories