I have two folders, in one i have the videos and in the second one the configuration files for each video(3 files per video). Now if i want to delete a video i have to delete files by hand.
I found this :
<?php
$filename = 'name.of.the.video.xml';
$term = str_replace(".xml","", $filename);
$dirPath = ("D:/test/");
foreach (glob($dirPath.$term.".*") as $removeFile)
{
unlink ($removeFile);
}
?>
A echo will return:
D:/test/name.of.the.video.jpg
D:/test/name.of.the.video.srt
D:/test/name.of.the.video.xml
Is ok and it help me a lot, but i have a problem here.
Not all files are the same ex:
Name.of.The.video.jpg
Name.Of.The.Video.xml
If i echo the folder looking for that string and is not identic with the $filename will return empty.
So, my question is, how can i make that search Case insensitive?
Thank you.
You are making use of the glob function which is case sensitive. You are using the wrong function therefore to get the list of files.
You should therefore first normalize the filenames in the directory so they all share the same case (e.g. all lowercase). Or you need to use another method to get the directory listing case-insensitive. I suggest the first, however if that is not an option, why don't you glob for all files first and then filter the list of files using preg_grep which allows to specify patterns that are case-insensitive?
Which leads me to the point that it's more practicable to use DirectoryIterator with a RegexIterator:
$filename = 'name.of.the.video.xml';
$term = basename($filename, ".xml");
$files = new DirectoryIterator($dirPath);
$filesFiltered = new RegexIterator($files, sprintf('(^%s\\..*$)i', preg_quote($term)));
foreach($filesFiltered as $file)
{
printf("delete: %s\n", $file);
unlink($file->getPathname());
}
A good example of the flexibility of the Iterators code are your changed requirements: Do that for two directories at once. You just create two DirectoryIterators and append the one to the other with an AppendIterator. Job done. The rest of the code stays the same:
...
$files = new AppendIterator();
$files->append(new DirectoryIterator($dirPath1));
$files->append(new DirectoryIterator($dirPath2));
...
Voilá. Sounds good? glob is okay for some quick jobs that need just it. For everything else with directory operations start to consider the SPL. It has much more power.
Is strcasecmp() a valid function for this? Its a case insensitive str comparison function?
Surely if you know the file name and you can echo it out, you can pass this to unlink()?
Related
How to find file by name without specific extension in laravel Storage?
like this "filename.*"
Storage::get("filename.*")
I tried this but seems not to work. It searches for specific file with specific extension.
Storage::get() takes a file path as a parameter and returns the content of a single file identified by this path or throws FileNotFoundException if file can't be found.
Wildcards are not supported in the path - one reason for that could be that there might be multiple files that match the path with wildcards which would break the rule that content of a single file is returned from Storage::get(). Scanning the whole folder would also be much slower, especially with remote storages.
However, you could get what you want using other functionality that Storage facade offers. First, list the content of your storage - that will give you the list of all available files. Then filter the list yourself to get the list of matching files.
// list all filenames in given path
$allFiles = Storage::files('');
// filter the ones that match the filename.*
$matchingFiles = preg_grep('/^filename\./', $allFiles);
// iterate through files and echo their content
foreach ($matchingFiles as $path) {
echo Storage::get($path);
}
Accepted solution works. However I've found this other and I like it more:
$matchingFiles = \Illuminate\Support\Facades\File::glob("{$path}/*.log");
See reference here:
http://laravel-recipes.com/recipes/143/finding-files-matching-a-pattern
Minor change to jedrzej.kurylo's answer and combining wogsland's answer using laravel 8:
'/^filename\./' or '/filename\./' pattern does not work in my case.
// From:
$matchingFiles = preg_grep('/^filename./', $allFiles);
// To:
$allFiles = Storage::disk('yourStorageDisk')->files('folder/path');
$allowedMimeTypes = ['image/jpeg', 'image/png', 'image/webp'];
$matchingFiles = preg_grep('{'.$image.'}', $allFiles);
foreach ($matchingFiles as $path) {
// get real mime type
$contentType = image_type_to_mime_type(exif_imagetype(asset($path)));
// compare it with our allowed mime types
if (in_array($contentType, $allowedMimeTypes)) {
// do something here...
}
}
This way we can fetch files or images safely.
Dont trust what you see. Get inside and get the ext for your file
$pic = 'url/your.file';
$ext = image_type_to_mime_type(exif_imagetype($pic));
$ext = explode('/',$ext);
echo $ext[1];
I recently reworked the naming convention of some images on our website. When I uploaded the images with altered names, I ended up getting the images duplicated, one copy with the old naming convention and one with the new naming convention. The images numbered in the thousands and so I didn't want to manually delete them all.
So I decided that I needed to figure out a php script that would be capable of deleting the old images from the site. Luckily the old images were consistently named with either an ending of f.jpg or s.jpg. So all I had to do is find all the files with those endings and delete them. I thought it was a fairly straightforward thing, but for whatever reason the several different solutions I found listed online didn't work right. I ended up going back to some old code I had posted on Stackoverflow for a different purpose and reworked it for this. I'm posting that code as the answer to my problem in case it might be useful to anyone else.
Below is my solution to finding files matching a certain naming convention in a selected folder and its sub-folders and deleting them. To make it work for your situation. You'll want to place it above the directory that you want to delete, and you'll specify the specific folder by replacing the part where I have ./media/catalog/. You'll also want to replace the criteria I have selected, namely (substr($path, -5)=='f.jpg' || substr($path, -5)=='s.jpg'). Note that the 5 in the preceding code refers to how many letters are being matched in the criteria. If you wanted to simply match ".jpg" you would replace the 5 with a 4.
As always, when working with code that can effect a lot of files, be sure to make a backup in case the code doesn't work the way you expect it will.
<?php #stick ClearOldJpg.php above the folder you want to delete
function ClearOldJpg(){
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator("./media/catalog/"));
$files = iterator_to_array($iterator, true);
// iterate over the directory
foreach ($files as $path) {
if( is_file( $path ) && (substr($path, -5)=='f.jpg' || substr($path, -5)=='s.jpg')){
unlink($path);
echo "$path deleted<br/>";
}
}
}
$start = (float) array_sum(explode(' ',microtime()));
echo "*************** Deleting Selected Files ***************<br/>";
ClearOldJpg( );
$end = (float) array_sum(explode(' ',microtime()));
echo "<br/>------------------- Deleting selected files COMPLETED in:". sprintf("%.4f", ($end-$start))." seconds ------------------<br/>";
?>
One fun bonus of this code is that it will list the files being deleted and tell how long it took to run.
I have a directory that files are uploaded to, and I want to be able to display a download link if the file exists. The file however has to match a particular pattern as this is the identifier of who uploaded it.
The pattern starts with /ClientFiles/ then it needs to find all files that starts with the user ID. So for example: /ClientFiles/123-UploadData.xls
So it would need to look in the ClientFiles directory and find all files that start with '123-' no matter what comes after.
Cheers
To look for files by a certain pattern you can use glob, then use is_readable to check if you can read the files.
$files = array();
foreach(glob($dirname . DIRECTORY_SEPARATOR . $clientId . '-*' as $file) {
if(is_readable($file) {
$files[] = $file;
}
}
Simply use the file_exists() function
php has a function file_exists. Use that to make some logic about if you show a link or not.
I want to delete cache files in a directory, the directory can contain up to 50.000 files. I currently I use this function.
// Deletes all files in $type directory that start with $start
function clearCache($type,$start)
{
$open = opendir($GLOBALS['DOC_ROOT']."/cache/".$type."/");
while( ($file = readdir($open)) !== false )
{
if ( strpos($file, $start)!==false )
{
unlink($GLOBALS['DOC_ROOT']."/cache/".$type."/".$file);
}
}
closedir($open);
}
This works fine and it is fast, but is there any faster way to do this? (scan_dir seems to be slow). I can move the cache to memory obviously.
Thanks,
hamlet
You may want to take a look into the glob function, as it may be even faster... it depends on the C library's glob command to do its work.
I haven't tested this, but I think this would work::
foreach (glob($GLOBALS['DOC_ROOT']."/cache/".$type."/".$start) as $file) {
unlink($GLOBALS['DOC_ROOT']."/cache/".$type."/".$file);
}
Edit: I'm not sure if $file would be just the filename or the entire path. glob's documentation implies just the filename.
Either glob as suggested before or, if you can be certain there won't be malicious input, by issueing directly to the system via exec(sprintf('rm %s/sess*', realpath($path)));, which should be fastest.
I'm trying to design a program in PHP that would allow me to find files with specific file extensions (example .jpg, .shp etc) in a known directory which consists of multiple folders.
Sample code, documentation or information about what methods I will be required to use will be much appreciated.
glob is pretty easy:
<?php
foreach (glob("*.txt") as $filename) {
echo "$filename size " . filesize($filename) . "\n";
}
?>
There are a few suggestions for recursive descent at the readdir page.
Take a look at PHP's SPL DirectoryIterator.
I believe PHP's glob() function is exactly what you are looking for:
http://php.net/manual/en/function.glob.php
Use readdir to get a list of files, and fnmatch to work out if it matches your required filename pattern. Do all this inside a function, and call your function when you find directories. Ask another question if you get stuck implementing this (or comment if you really have no idea where to start).
glob will get you all the files in a given directory, but not the sub directories. If you need that too, you will need to: 10. get recursive, 20. goto 10.
Here's the pseudo pseudocode:
function getFiles($pattern, $dir) {
$files = glob($dir . $pattern);
$folders = glob($dir, GLOB_ONLYDIR);
foreach ($folders as $folder) {
$files = $files + getFiles($folder);
}
return $files;
}
The above will obviously need to be tweaked to get it working, but hopefully you get the idea (remember not to follow directory links to ".." or "." or you'll be in infinite loop town).