PHP hidden directories - Windows - php

I'm attempting to add a feature to our intranet, which will allow users to log onto the intranet, and access documents stored within a Windows network SAN.
At the moment, I've successfully retrieved all the file and folder names within a specified users 'My Documents'.
I'm having difficulty removing hidden files and folders from the array.
At the moment, I can remove all folders and files starting with ..
However on Windows, they're being marked as 'hidden' in the properties. I've googled and found lots of resources about how to mark a file as hidden, and how to hide files that start with a ., but none on how to remove hidden windows files / folders. One post on stackoverflow mentions to use DirectoryIterator, but at the moment, but haven't explained at all how to use it to check if a files marked as hidden.
We have over 1000 users, with approximately 500MB - 1GB of documents, with multiple layers of directories, so It needs to be relatively fast.
For clarification:
During a recursive iteration on a Windows system, how can I find out whether a directory is hidden or not, without relying on a prepended . symbol?

Ok, so worked it out, with help from the exec() function, so use with care!
I'm using CodeIgniter, so I've modified the directory_helper.php function slightly, as its installed on a windows box, it'll always need to check for the hidden files, but it should also work for non-codeigniter sites:
function directory_map($source_dir, $directory_depth = 0, $hidden = FALSE)
{
if ($fp = #opendir($source_dir))
{
if(!$hidden)
{
$exclude = array();
exec('dir "' . $source_dir . '" /ah /B', $exclude);
}
$filedata = array();
$new_depth = $directory_depth - 1;
$source_dir = rtrim($source_dir, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR;
while (FALSE !== ($file = readdir($fp)))
{
// Remove '.', '..', and hidden files [optional]
if ( ! trim($file, '.') OR ($hidden == FALSE && $file[0] == '.') OR ($hidden === FALSE && in_array($file, $exclude)))
{
continue;
}
if (($directory_depth < 1 OR $new_depth > 0) && #is_dir($source_dir.$file))
{
$filedata[$file] = directory_map($source_dir.$file.DIRECTORY_SEPARATOR, $new_depth, $hidden);
}
else
{
$filedata[] = $file;
}
}
closedir($fp);
return $filedata;
}
return FALSE;
}
This scanned 2207 files, and 446 folders in approx 11 seconds (Ages I know, but the best I could do). Tested it on 500 folders and 200 files, and did it in around 3 seconds.
Its a recursive function which will scan each non-hidden directory. The first thing it does is scan the current directory for all hidden files and folders using the exec('dir *directory* /ah /B') function.
It will then store the results in an array and make sure that the current file/directory being read isn't in that array.

Related

Accessing Windows Objects with PHP?

I made a tool to organize file content in a specific way. These files are located all over my pc which runs on Windows 7. The tool is made up of two parts: 1 the interface holding a form. 2 the script to do the work.
Instead of having to manually write the full path to a certain directory to the main script, I'd rather have the tool search for it and retrieve it seamlessly. I'm thinking of maybe adding a textfield and a button, in which I can enter the directory's name I'm looking for and after clicking the button, retrieve the directory's full pathname, print it to the same textfield and then pass it along to the program itself.
I've searched for several day for ways to have PHP interact with Windows (maybe with window's search object), but all I've found is very looong documentation on the COM and then on the NET. These however seem to strictly deal with accessing Office objects, since most of the available examples are about Excel or Word objects.
How can I accomplish the functionality I want to add to my interface?
To avoid further confusion, this is the image of the Window's object I'm referring to > Windows Starup Search Field
Use this handy function - just point it to the root of your filesystem and it will return an array with all the matching files - I mean, matched by the regular expression pattern you provide to the function.
// PREG_FIND_RECURSIVE - go into subdirectorys looking for more files
// PREG_FIND_DIRMATCH - return directorys that match the pattern also
// PREG_FIND_DIRONLY - return only directorys that match the pattern (no files)
// PREG_FIND_FULLPATH - search for the pattern in the full path (dir+file)
// PREG_FIND_NEGATE - return files that don't match the pattern
// PREG_FIND_RETURNASSOC - Instead of just returning a plain array of matches,
// return an associative array with file stats
// to use more than one simply seperate them with a | character
define('PREG_FIND_RECURSIVE', 1);
define('PREG_FIND_DIRMATCH', 2);
define('PREG_FIND_FULLPATH', 4);
define('PREG_FIND_NEGATE', 8);
define('PREG_FIND_DIRONLY', 16);
define('PREG_FIND_RETURNASSOC', 32);
function preg_find($pattern, $start_dir='.', $args=NULL)
{
$files_matched = array();
$fh = #opendir($start_dir);
if($fh)
{
while (($file = readdir($fh)) !== false)
{
if (strcmp($file, '.')==0 || strcmp($file, '..')==0) continue;
$filepath = $start_dir . '/' . $file;
if (preg_match($pattern, ($args & PREG_FIND_FULLPATH) ? $filepath : $file))
{
$doadd = is_file($filepath)
|| (is_dir($filepath) && ($args & PREG_FIND_DIRMATCH))
|| (is_dir($filepath) && ($args & PREG_FIND_DIRONLY));
if ($args & PREG_FIND_DIRONLY && $doadd && !is_dir($filepath)) $doadd = false;
if ($args & PREG_FIND_NEGATE) $doadd = !$doadd;
if ($doadd)
{
if ($args & PREG_FIND_RETURNASSOC) // return more than just the filenames
{
$fileres = array();
if (function_exists('stat'))
{
$fileres['stat'] = stat($filepath);
$fileres['du'] = $fileres['stat']['blocks'] * 512;
}
//if (function_exists('fileowner')) $fileres['uid'] = fileowner($filepath);
//if (function_exists('filegroup')) $fileres['gid'] = filegroup($filepath);
//if (function_exists('filetype')) $fileres['filetype'] = filetype($filepath);
//if (function_exists('mime_content_type')) $fileres['mimetype'] = mime_content_type($filepath);
if (function_exists('dirname')) $fileres['dirname'] = dirname($filepath);
if (function_exists('basename')) $fileres['basename'] = basename($filepath);
//if (isset($fileres['uid']) && function_exists('posix_getpwuid ')) $fileres['owner'] = posix_getpwuid ($fileres['uid']);
$files_matched[$filepath] = $fileres;
}
else array_push($files_matched, $filepath);
}
}
if ( is_dir($filepath) && ($args & PREG_FIND_RECURSIVE) ) $files_matched = array_merge($files_matched, preg_find($pattern, $filepath, $args));
}
closedir($fh);
}
return $files_matched;
}
Example usage:
$arr = preg_find('/./','z:\temp');
var_dump($arr);
Example output:
Another example:
$arr = preg_find('/\.tmp$/i','z:\temp',PREG_FIND_RECURSIVE | PREG_FIND_DIRMATCH);
var_dump($arr);
On the first place, thanks to #IVO GELOV for the handy script you generously shared with me.
In cases someone else needs this info.
After much searching, I found out that I only needed to use Tkinter to navigate through directories. It offers a Dialog Box with two methods: one to get the full path to a file and the other to a directory, which was what I needed. The path can be stored in a variable.
Thanks to all for the input.

Safety on 404 error doc

I am working on my 404 error doc, and I was thinking instead of just giving a sitemap, one could suggest to the user the website he might have looked for based on what actually exists on the server.
Example: if the person typed in "www.example.com/foldr/site.html", the 404 page could output:
Did you mean "www.example.com/folder/site.html"?
For this, I wrote the following code which works for me very well. My question now is: is it "safe" to use this? As basically someone could detect all files on the server by trying all kind of combinations. Or a hacker could even use a script that loops through and lists all types of valid URLs.
Should I limit the directories this script can detect and propose? With an array of "OK"-locations, or by file type?
Had anyone else already got an idea like this?
PHP:
// get incorrect URL that was entered
$script = explode("/",$_SERVER['SCRIPT_NAME']);
$query = $_SERVER['QUERY_STRING'];
// create vars
$match = array();
$matched = "../";
// loop through the given URL folder by folder to find the suggested location
foreach ($script as $dir) {
if (!$dir) {
continue;
}
if ($handle = opendir($matched)) {
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != "..") {
similar_text($dir, $entry, $perc);
if ($perc > 80) {
$match[$entry] = $perc;
}
}
}
closedir($handle);
if ($match) {
arsort($match);
reset($match);
$matched .= key($match)."/";
} else {
$matched = false;
break;
}
$match = array();
}
}
// trim and echo the result that had the highest match
$matched = trim(ltrim(rtrim($matched,"/"),"."));
echo "proposed URL: ".$_SERVER["SERVER_NAME"].$matched;
Yup, you can see it as this:
Imagine a house with only glass walls on the outside, but it's night. You're a thief (hacker) and you want to check the house for worthfull loot (files with passwords, db connections etc).
If you don't protect (certain) files, you would be putting the lights on in every part of the house. The thief would look through the windows and see that you have loot - now the only the he would have to do is get in and take it.
If you do protect the files, the thief won't even be able to know that there was any loot in the house, and thus would the thief have a higher chance of moving on to the next house.

When using readdir empty strings returned

I am using readdir in the following code to get a list of all file names of images in a directory.
while (false !== ($entry = readdir($frameDir))){
$shapeName = explode('.',$entry);
if (!empty($shapeName[0]) && $shapeName[0] != '.' && $shapeName[0] != '..' && $shapeName[0] != '/'){
$shapeName = $shapeName[0];
$shapes['frames'][] = $shapeName;
}
After this code the script appends the '.png' to make it a valid file name.
As you can see I've tried to eliminate any chances of a blank file name being passed. Though when I run the script I end up getting a blank directory "/shapes/frame/.png" . This only happens for this particular directory. When I use the code on another of the three directories I get results as expected, and the code is the same logic as what is used above.
while (false !== ($entry = readdir($frameDotDir))){
$shapeName = explode('.',$entry);
if (!empty($shapeName[0]) && $shapeName[0] != '.' && $shapeName[0] != '..' && $shapeName[0] != '/'){
$shapeName = $shapeName[0];
$shapes['frame_dots'][] = $entry;
}
}
When checking the filesystem on the server, I can't find any files with blank names.
I am wondering what could be causing my script to be reading blank file names from the diretory.
File names cannot be empty (and will not). You did something wrong in your code. It should look like:
while ($entry = readdir($frameDir)){
// skip files which names starting with a dot
// like '.', '..' or hidden files
if (strpos($entry, '.') !== 0) {
$shapes['frame_dots'][] = $entry;
}
}
You see, less is more ;)
Why don't you use glob() instead of readdir().Just give it a pattern and it will let you process the filenames with much ease instead of doing the one by one scanning work. And in your case, there is no way it will return an empty file name. Also, have a look on glob flags in the documentation, you will be amazed of it's simplicity.
glob("*.png");
Output:
Array ( [0] => shape.png, [1] => shape2.png )
I was having the same problem with blank filenames usind readdir() it turn out to be that the directory name was wrong, turns out linux is case sensitive, in code the directory name starts with "I" and in linux the directory started with "i".
I guess the error was due to not handling opendir() errors. Check your code.

listing files of subfolder issue

i have several millions files in a folder and there are several subfolders in that folder each subfolder consists of thousands of files . i am able to list all files of given folder using glob function but here in this case as its very high i am getting php fatal error . allowed memory size exhaused try to allocate more memory i know that can be done just by keeping one php.ini file in that subfolder but what i exactly want is listing all .txt extension size in descending order so the bigger file will be at the top and smaller file will be at the bottom but as i have said it is not possible to list millions of file so just like mysql can i list them in page wise or something like top 100 files will be listed in descending order when i click on next page it will show next 100-200 items but i dont want to use database if there is no other way how i can store all these details in database without causing heavy load on server.
<?php
foreach (glob("files/*") as $filename) {
echo "uploads/" . "$filename" . "\n</br>";
}
?>
use opendir insteed of glob();
Try something like this:
function printdirs($path) {
if ($handle = opendir($path)) {
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != "..") {
if(is_dir($path.'/'.$entry))
printdirs($path.'/'.$entry);
else
echo $path . "/" . $entry . "\n</br>";
}
}
closedir($handle);
}}
printdirs('uploads');

Multiple Random Includes from Directory with Sub-Directories

I have a directory containing sub directories which each contain a series of files. I'm looking for a script that will look inside the sub directories and randomly return a specified number of files.
There are a few scripts that can search a single directories (not sub folders), and other scripts that can search sub folders but only return one file.
To put a little context on the situation, the returned files will be included as li's in an rotating banner.
Thanks in advance for any help, hopefully this is possible.
I think I've got there, not exactly what I set out to achieve but works good enough, arguably better for the purpose, I'm using the following function:
<?php function RandomFile($folder='', $extensions='.*'){
// fix path:
$folder = trim($folder);
$folder = ($folder == '') ? './' : $folder;
// check folder:
if (!is_dir($folder)){ die('invalid folder given!'); }
// create files array
$files = array();
// open directory
if ($dir = #opendir($folder)){
// go trough all files:
while($file = readdir($dir)){
if (!preg_match('/^\.+$/', $file) and
preg_match('/\.('.$extensions.')$/', $file)){
// feed the array:
$files[] = $file;
}
}
// close directory
closedir($dir);
}
else {
die('Could not open the folder "'.$folder.'"');
}
if (count($files) == 0){
die('No files where found :-(');
}
// seed random function:
mt_srand((double)microtime()*1000000);
// get an random index:
$rand = mt_rand(0, count($files)-1);
// check again:
if (!isset($files[$rand])){
die('Array index was not found! very strange!');
}
// return the random file:
return $folder . "/" . $files[$rand];
}
$random1 = RandomFile('project-banners/website-design');
while (!$random2 || $random2 == $random1) {
$random2 = RandomFile('project-banners/logo-design');
}
while (!$random3 || $random3 == $random1 || $random3 == $random2) {
$random3 = RandomFile('project-banners/design-for-print');
}
?>
And echoing the results into the container (in this case the ul):
<?php include($random1) ;?>
<?php include($random2) ;?>
<?php include($random3) ;?>
Thanks to quickshiftin for his help, however it was a little above my skill level.
For info the original script which I changed an be found at:
http://randaclay.com/tips-tools/multiple-random-image-php-script/
Scrubbing the filesystem every single time to randomly select a file to display will be really slow. You should index the directory structure ahead of time. You can do this many ways, try a simple find command or if you really want to use PHP my favorite choice would be RecursiveDirectoryIterator plus RecursiveIteratorIterator.
Put all the results into one file and just read from there when you select a file to display. You can use the line numbers as an index, and the rand function to pick a line and thus a file to display. You might want to consider something more evenly distributed than rand though, you know to keep the advertisers happy :)
EDIT:
Adding a simple real-world example:
// define the location of the portfolio directory
define('PORTFOLIO_ROOT', '/Users/quickshiftin/junk-php');
// and a place where we'll store the index
define('FILE_INDEX', '/tmp/porfolio-map.txt');
// if the index doesn't exist, build it
// (this doesn't take into account changes to the portfolio files)
if(!file_exists(FILE_INDEX))
shell_exec('find ' . PORTFOLIO_ROOT . ' > ' . FILE_INDEX);
// read the index into memory (very slow but easy way to do this)
$aIndex = file(FILE_INDEX);
// randomly select an index
$iIndex = rand(0, count($aIndex) - 1);
// spit out the filename
var_dump(trim($aIndex[$iIndex]));

Categories