PHP - select ONLY file in folder without foreach()? - php

I have a script that places a CSV file into a temporary folder where it will remain until another script picks it up for import into my DB. This is a separated script and for various reasons cannot do both the placement into the temp folder AND the consecutive database import.
Since I now have a separated import script, I first need to scan the temp folder and look for the import-file, which is the ONLY file in the folder anyway, but has a constantly changing filename that I cannot pre-define. My question now is, how can I get the filename of said file, assign it to a variable and use this later for the database import?
When using a foreach() loop I end up with an array, but rather would like a string for further usage.
PHP
if(file_exists('./'.$temp)) {
$files = scandir('./'.$temp.'/');
foreach ($files as $attachment) {
if (in_array($attachment, array(".",".."))) continue;
$import_file = $attachment;
}
} else {
die("Temp Folder for $temp could not be found, hence no files exist for import. Operation cancelled.");
}

Since scandir is ordered alphabetically (http://php.net/manual/en/function.scandir.php), you file will always be at the end of the scandir array (on non-unix systems it is the only file, on unix systems it comes after . and ..).
Thus, you just need to get the last item of the array, like so:
$s = scandir("./".$temp."/");
$import_file = $s[count($s)-1];
This code automatically retrieves the name of the third file in the temp folder, so as long as there are no other files in there it should work perfectly.

Related

How to create increment folder name in php

I have an HTML form with three inputs:
name
consultant id (number)
picture upload
After the user submits the form, a php script would:
Create folder with the submitted name
Inside the folder create a txt file with: name + consultant id (given number)
Inside the folder, store the image uploaded by user
The most important thing I want is that folders created by the php file should be increased by 1. What I mean: folder1 (txt file + image), folder2 (txt file + image), folder3 (txtfile + image) and so on...
There are a few different methods for accomplishing what you describe. One option would be look at all existing folders(directories) when you attempt to create a new one and determine the next highest number.
You can accomplish this by using scandir on your parent output directory to find existing files.
Example:
$max=0;
$files=scandir("/path/to/your/output-directory");
$matches=[];
foreach($files as $file){
if(preg_match("/folder(\d+)/", $file, $matches){
$number=intval($matches[1]);
if($number>$max)
$max=$number;
}
}
$newNumber=$max+1;
That is a simple example to get you the next number. There are many other factors to consider. For instance, what happens if two users submit the form concurrently? You would need some synchronization metaphor(such as semaphore or file lock) to ensure only insert can occur at a time.
You could use a separate lock file to store the current number and function as a synchronization method.
I would highly encourage finding a different way to store the data. Using a database to store this data may be a better option.
If you need to store the files on disk, locally, you may consider other options for generating the directory name. You could use a timestamp, a hash of the data, or a combination thereof, for instance. You may also be able to get by with something like uniqid. Any filesystem option will require some form of synchronization to address race conditions.
Here is a more complete example for sequentially creating directories using a lock file for the sequence and synchronization. This omits some error handling that should be added for production code, but should provide the core functionality.
define("LOCK_FILE", "/some/file/path"); //A file for synchronization and to store the counter
define("OUTPUT_DIRECTORY", "/some/directory"); //The directory where you want to write your folders
//Open the lock file
$file=fopen(LOCK_FILE, "r+");
if(flock($file, LOCK_EX)){
//Read the current value of the file, if empty, default to 0
$last=fgets($file);
if(empty($last))
$last=0;
//Increment to get the current ID
$current=$last+1;
//Write over the existing value(a larger number will always completely overwrite a smaller number written from the same position)
rewind($file);
fwrite($file, (string)$current);
fflush($file);
//Determine the path for the next directory
$dir=OUTPUT_DIRECTORY."/folder$current";
if(file_exists($dir))
die("Directory $dir already exists. Lock may have been reset");
//Create the next directory
mkdir($dir);
//TODO: Write your content to $dir (You'll need to provide this piece)
//Release the lock
flock($file, LOCK_UN);
}
else{
die("Unable to acquire lock");
}
//Always close the file handle
fclose($file);

get a unknown file name in different dir, php

Here is my directory structure,
C:\xampp\htdocs\..
C:\download\20150923abc.xls //abc is a random value
how can I attach the file 20150923abc.xls in php?
Also, how to change the filename after I got it?
Thanks.
Use the glob ability to find references all files of type .xls and then you can use the file name references as you wish. This sidesteps the issue of you not knowing the specific file name.
$files = glob("c:/download/*.xls");
This will produce an array of all .xls files with their full filepath. If you wish to rename or attach these files then you can do this using the glob reference:
rename($files[0], "c:/download/somenewname.xls");
etc. Read more at:
PHP Glob Function
EDIT:
From Comment below:
foreach (glob( $old_folder."*.xls") as $filename)
{
$names = explode('/', $filename);
$just_file_name = end($names);
echo $just_file_name . "----\n";
$new_folder = dirname(FILE)."\\prm\\att\\";
//rename_win($old_folder, $new_folder);
rename($filename, $new_folder.$just_file_name); <== this line changed.
}
unset($filename);
To fix the above code in your comment, you need to change the incorrect variables referenced (there was no array $files[0]) to the ones used in the foreach loop.

PHP load CSV without filename

I am in index.php, and at the same directory level I have a CSV file which I load using
$reader = new CSV\CSVReader('mycsv.csv');
This is the only CSV in the folder. After it is read, I want to delete it from my FTP and replace it with a different CSV. However, if possible, I don't want to have to edit the PHP file each time to change the filename.
Knowing that the root will only ever have one CSV file in it at any time, is there any way to load this without using the filename?
You could get all the files with a .csv extension using glob(). Then just use the first file in the result array since there's only one. Something like this:
$csvFiles = glob('*.csv');
if (!count($csvFiles)) die('Error: No CSV file to read');
$reader = new CSV\CSVReader($csvFiles[0]);
// Optionally, if you want to automatically delete the file:
unlink($csvFiles[0]);
Try this
$files = scandir('/path/to/directory');
$filename = $files[2]; // avoid dots elements

PHP Script for Monitoring Folder Creation

I want to write one PHP script that will tell me how many folders getting created today( not modified one !! ).
Ex. Suppose if gave the path ( like c:\Data ) so my script must be continuously checking that
give path for if it is new entry of any folder. I have used http://php.net/manual/en/function.date-diff.php. But getting result for modified folders as well.
Quote from #Alin Purcaru:
Use filectime. For Windows it will return the creation time, and for Unix the change time which is the best you can get because on Unix there is no creation time (in most filesystems).
Using a reference file to compare the files age allows you to detect new files whidout using a database.
// Path to the reference file.
// All files newer than this will be treated as new
$referenceFile="c:\Data\ref";
// Location to search for new folders
$dirsLocation="c:\Data\*";
// Get modification date of reference file
if (file_exists($referenceFile))
$referenceTime = fileatime($referenceFile);
else
$referenceTime = 0;
// Compare each directory with the reference file
foreach(glob($dirsLocation, GLOB_ONLYDIR) as $dir) {
if (filectime($dir) > $referenceTime)
echo $dir . " is new!";
}
// Update modification date of the reference file
touch($referenceFile);
Another solution could be to use a database. Any folders that are not in the database are new. This ensures to not catch modified folders.
You might want to try getting your script launched with cron like every one minute and check the difference between directory lists (from before and current I mean), not the dates. It's not a perfect solution, but it will work.
Check directories arays with:
$dirs = array_filter(glob('*'), 'is_dir');
Compare them later with array_diff

Select file(s) in a directory based upon complex filename

I have audio files in var/
This is the file name
2-3109999999-3246758493-1271129518-1271129505.6.wav
Format
2=campaign id
3109999999=caller id
3246758493=number called
1271129518=timestamp call ended
1271129505=timestamp call started
6=call id
If I were to pass just the number called which was 3246758493, how can I find all the files without defining all the other variables(such as timestamp, etc) and just the files that have that number in the filename?
You would need to loop though the folder: http://php.net/manual/en/function.readdir.php
Then for each of the files in the folder, try and match it to the file that was requested using regex I guess?
http://www.txt2re.com/index-php.php3?s=2-3109999999-3246758493-1271129518-1271129505.6.wav&8
You could also use a DirectoryIterator to scan the folder and a RegexIterator to filter the files based on a pattern.
$id = '3246758493';
$files = new RegexIterator(new DirectoryIterator('var/'),
"#^\d-\d{10}-$id-\d{10}-\d{10}\.\d\.wav$#D");
foreach ($files as $fileinfo) {
echo $fileinfo . PHP_EOL;
}

Categories