I need to find a file in a directory that matches a certain condition. For example, I know the file name starts with '123-', and ends with .txt, but I have no idea what is in between the two.
I've started the code to get the files in a directory and the preg_match, but am stuck. How can this be updated to find the file I need?
$id = 123;
// create a handler for the directory
$handler = opendir(DOCUMENTS_DIRECTORY);
// open directory and walk through the filenames
while ($file = readdir($handler)) {
// if file isn't this directory or its parent, add it to the results
if ($file !== "." && $file !== "..") {
preg_match("/^".preg_quote($id, '/')."\\-(.+)\\.txt$/" , $file, $name);
// $name = the file I want
}
}
// tidy up: close the handler
closedir($handler);
I wrote up a little script here for ya, Cofey. Try this out for size.
I changed the directory for my own test, so be sure to set it back to your constant.
Directory Contents:
123-banana.txt
123-extra-bananas.tpl.php
123-wow_this_is_cool.txt
no-bananas.yml
Code:
<pre>
<?php
$id = 123;
$handler = opendir(__DIR__ . '\test');
while ($file = readdir($handler))
{
if ($file !== "." && $file !== "..")
{
preg_match("/^({$id}-.*.txt)/i" , $file, $name);
echo isset($name[0]) ? $name[0] . "\n\n" : '';
}
}
closedir($handler);
?>
</pre>
Result:
123-banana.txt
123-wow_this_is_cool.txt
preg_match saves its results to $name as an array, so we need to access by it's key of 0. I do so after first checking to make sure we got a match with isset().
You must test if the match was successful.
Your code inside the loop should be this:
if ($file !== "." && $file !== "..") {
if (preg_match("/^".preg_quote($id, '/')."\\-(.+)\\.txt$/" , $file, $name)) {
// $name[0] is the file name you want.
echo $name[0];
}
}
Related
I am very inexperienced with PHP. I have a folder on a website which will receive files named with a numeric date structure. I need href links to be created for the files which are dropped into this folder. I need the link text to be formatted by with a textual month and numeric day. For example:
File name "01-02-22 BULLETIN.pdf" becomes
<href="bulletins/2022/$file">January 2</a>.
I have been messing with the code below from this post PHP to create Links for files in a folder, but I can't seem to figure it out. The links are appearing but any date formatting I attempt returns "error Call to a member function format()."
Thanks for your help!
<?php
$dir = "bulletins/2022/";
// Open a directory, and read its contents
if (is_dir($dir)){
if ($dh = opendir($dir)){
while (($file = readdir($dh)) !== false){
echo "<a href=bulletins/2022/$file>$file</a><br>";
}
closedir($dh);
}
}
?>
The html mark up is missing quotes
Here an example:
$some_path = "bulletins/2022";
$readdir=opendir($some_path);
while ($file = readdir($readdir))
{
if($file != '..' && $file !='.' && $file !='' && $file != ".htaccess")
{
echo "$file<br>"; // yours is missing the quotes which should always be escaped in php with a backslash
}
}
closedir($readdir);
You could also concider using php time(); as the filename which will give you a unix timestamp which can then be sorted and converted into a date and time.
This example will sort the files in a natural order
$some_path = "demo_track_previews";
$readdir=opendir($some_path);
while ($file = readdir($readdir))
{
if($file != '..' && $file !='.' && $file !='' && $file != ".htaccess")
{
if(!empty(file))
{
$all_files[] = $file; //put all files in array ready to sort
}
}
}
closedir($readdir);
if(!empty($all_files))
{
sort($all_files,SORT_NATURAL); //You can also try rsort($all_files,SORT_NATURAL);
foreach ($all_files as $key => $each_file)
{
echo "".$each_file."<br>";
}
}
EDIT: after comment
if you need just the date from the filename "01-02-22 BULLETIN.pdf"
then try this
foreach ($all_files as $key => $each_file)
{
$file_name_parts = explode(" ", $each_file); // seperate the filename where there is a space - $file_name_parts[0] will be 01-02-22
echo "".$file_name_parts[0]."<br>";
}
I have created a directory with some files in there:
index.php
one.txt
two.txt
three.txt
four.txt
In the index.php page, I am currently using this code to echo out all of the files within the directory:
<?php
$blacklist = array("index.php");
if ($handle = opendir('.')) {
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != ".." && !in_array($entry, $blacklist)) {
echo "$entry\n";
}
}
closedir($handle);
}
?>
Now, if anyone views the index.php page, this is what they'll see:
one.txt two.txt three.txt four.txt
As you can see from the PHP code, index.php is blacklisted so it is not echoed out.
However, I would like to go a step further than this and echo out the contents of each text file rather than the filenames. With the new PHP code (that I need help with creating), whenever someone visits the index.php page, this is what they'll now see:
(Please ignore what is in the asterisks, they are not a part of the code, they just indicate what each text file contains)
Hello ** this is what the file **one.txt** contains **
ok ** this is what the file **two.txt** contains **
goodbye ** this is what the file **three.txt** contains **
text ** this is what the file **four.txt** contains **
Overall:
I would like to echo out the contents of every file in the directory (they are all text files) aside from index.php.
You could use file_get_contents to put the file into a string.
<?php
$blacklist = array("index.php");
if ($handle = opendir('.')) {
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != ".." && !in_array($entry, $blacklist)) {
echo "$entry " . file_get_contents($entry) . "\n";
}
}
closedir($handle);
}
?>
Furthermore, you could use PHP's glob function to filter only the .txt files out, that way you do not have to blacklist files if you're going to be adding more files to that directory that need ignored.
Here is how it would be done using the glob function.
<?php
foreach (glob("*.txt") as $filename) {
echo "$filename " . file_get_contents($filename) . "\n";
}
?>
This would print the contents of the files. You can do some workaround if the path is not the current path and writing some kind of boundary between the files contents.
<?php
$blacklist = array("index.php");
if ($handle = opendir('.')) {
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != ".." && !in_array($entry, $blacklist)) {
echo file_get_contents($entry) . "\n";
}
}
closedir($handle);
}
?>
I hope this helps you.
Never reinvent the wheel. Use composer.
Require symfony/finder
use Symfony\Component\Finder\Finder;
class Foo
{
public function getTextFileContents($dir)
{
$finder = (new Finder())->files()->name('*.txt');
foreach ($finder->in($dir) as $file) {
$contents = $file->getContents();
// do something while file contents...
}
}
}
I would give a chance to some SPL filesystem iterators to accomplish such this task:
$dir = '/home/mydirectory';
$rdi = new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS);
$rdi = new \RegexIterator($rdi, '/\.txt$/i');
$iterator = new \RecursiveIteratorIterator($rdi, \RecursiveIteratorIterator::CHILD_FIRST);
foreach ($iterator as $file) {
echo 'Contents of the '.$file->getPathname().' is: ';
echo file_get_contents($file->getPathname());
}
This will recursively find & iterate all .txt files in given directory, including sub-directories.
Since each $file in iteration is a FilesystemIterator instance, you can use all related methods for additional controls like $file->isLink() (true for symbolic links), $file->isReadable() (false for unreadable files) etc..
If you don't want lookup sub-folders, just change the RecursiveDirectoryIterator in the second line from:
$rdi = new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS);
to:
$rdi = new \DirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS);
Hope it helps.
As #brock-b said, you could use glob to get the full list of files and file_get_contents to grab the contents:
$blacklist = array('index.php');
$files = glob('*.txt'); # could be *.* if needed
foreach ($files as $file) {
if (!in_array(basename($file), $blacklist)) {
echo file_get_contents($file);
}
}
Note: the blacklist wont be hit since you're seeking for *.txt files. Only useful when doing an *.* or *.php file search
I have folders on the server that contain image files. I'm trying to get those files and then upload them further, but I think I'm using the wrong function.
My code:
$dir = "../uploads/".$folderimage."/";
if ($handle = opendir($dir)) {
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != "..") {
echo "$entry\n";
$handle = fopen($entry,"wb");
$mug->images_upload(array( "AlbumID" => "#####", "File" => $handle));
}
}
closedir($handle);
}
Not sure what I am doing, all I need to do is pass the file to the class function $mug->images->upload. It works from a $_POST request but I need to move the files already uploaded to the folder.
It's a bit tricky to emulate a file upload POST request for your $mug object. You would be better off if you could refactor the code in $mug as follows:
$mug fetches the uploaded file and puts it to its destination place.
You create a new function that implements the processing you wish to use here and in $mug.
Call this function from here, and from $mug with the appropriate filename.
If $mug->images_upload is expecting the file path then pass $dir.$entry to it
<?php
$dir = "../uploads/".$folderimage."/";
if ($handle = opendir($dir)) {
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != "..") {
echo $entry.PHP_EOL;
$mug->images_upload(array( "AlbumID"=>"#####", "File"=>$dir.$entry));
}
}
closedir($handle);
}
//Or simpler way but slightly slower
foreach (glob($dir."*.{png,jpg,gif}", GLOB_BRACE) as $file) {
echo $file.PHP_EOL;
$mug->images_upload(array( "AlbumID"=>"#####", "File" =>$dir.$file));
}
?>
There are a number of apparent issues with the code that you have posted.
$dir = "../uploads/".$folderimage."/";
if ($handle = opendir($dir)) {
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != "..") {
echo "$entry\n";
$handle = fopen($entry,"wb");
$mug->images_upload(array( "AlbumID" => "#####", "File" => $handle));
}
}
closedir($handle);
}
Clashing variables.
You have used the $handle vairable to store the directory handle, only to later overwrite it with a file resource inside the loop. As soon as you overwrite it inside the loop, the next call to readdir($handle) does not make any sense are you are calling the function on a file resource. This could very easily lead to an infinite loop since when readdir() is given rubbish, it might return NULL.
Incorrect path for fopen()
Given $folderimage = "images" and $entry = "photo.jpg", then the fopen() line will try to open the image at photo.jpg rather than ../uploads/images/photo.jpg. You likely wanted to use something like $dir . $entry, but read on as you shouldn't be using fopen() at all.
Incorrect usage of the phpSmug library
The File argument must be a string containing "the path to the local file that is being uploaded" (source). You instead try to pass a file resource from fopen() to it.
opendir()/readdir() for directory iteration is ancient
There are better ways to traverse directory contents in PHP. As mentioned in Lawrence's answer, glob() might be useful.
I would also advocate using the filesystem iterator from the SPL.
$dir = "../uploads/$folderimage/";
foreach (new FilesystemIterator($dir) as $fileinfo) {
$image_pathname = $fileinfo->getPathname();
$mug->images_upload("AlbumID=#####", "File=$image_pathname");
}
I'm working on a small script and I want to list the contents of a directory, make them into hyperlinks, and then edit those hyperlinks to look pretty (I.e. not show an ugly super long path name), then limit the number files echoed back to the browser. Also, I need the most recent files echoed back only.
I was thinking about using this:
<?php
$path = "/full/path/to/files";
if ($handle = opendir($path)) {
while (false !== ($file = readdir($handle)))
{
if ($file != "." && $file != "..")
{
$files .= ''.$file.'';
}
}
closedir($handle);
}
?>
or this:
<?php
$sub = ($_GET['dir']);
$path = 'enter/your/directory/here/';
$path = $path . "$sub";
$dh = opendir($path);
$i=1;
while (($file = readdir($dh)) !== false) {
if($file != "." && $file != "..") {
if (substr($file, -4, -3) =="."){
echo "$i. $file <br />";
}else{
echo "$i. <a href='?dir=$sub/$file'>$file</a><br />";
}
$i++;
}
}
closedir($dh);
?>
But I dont want to list the files like this:
C:/example/example2/Hello.pdf
I want to edit the variable. Is that possible? To make it say something as simple as "Hello."
I want to limit the amount of files listed as well. For example: only list the first 5 files, or last 5, etc. Is there a function or some kind of parameter for that?
I appreciate any help or push in the right direction. Thanks
I'm on my phone so providing a code example will be tough. Why not iterate through the directories, storing the file name in an array, with the absolute path as the value for that key?
EDIT: You can use basename to aid you in doing this.
I'm trying to build a <ul> list with a <li> for each directory in a main folder.
here's my code :
<?php
$dir = opendir(getEnv("DOCUMENT_ROOT") . "/folder");
while(($file = readdir($dir)) !== false ){
if( is_dir($file) && $file !== "." && $file !== ".." ){
echo "<li>" . $file . "</li>";
}
}
closedir($dir);
?>
there are two directories in /home/example/folder but there are not recognized as folders (for sure they are !)
if I "echo" the files in the while loop they are printed (they well exist for the script no trouble on that side).
If I try to "filetype" them, a lstat failed error is thrown, I searched on internet the meaning of it and I end up with nothing but technically support that I pain to understand.
Your problem is that inside "folder" directory you can have two directories (a and b),then the reading retrieve "a" and "b" as file names, while is_dir receive a full path filename or a relative filename, you have two options:
pass the full path to filename to the is_dir function (see example code).
pass the relative path (depends on where you put your script).
if( is_dir($dir . "/" . $file) && $file !== "." && $file !== ".." ){ ......
Try:
while($file = readdir($dir)) {
if (...) { }
}
The !== false portion is not required. if readdir reaches the end, it returns a false, and the loop will automatically terminate. Your version is being parsed as:
$file gets the value of (readdir($file) is not false)
e.g. you're assigning the boolean result of readdir($file) !== false, not the return value from readdir.
to expand on my comment below, regarding operator precedence:
PHP's parse tree of your loop setup looks like this, expanded:
$bool = (readdir($dir) !== false);
$file = $bool;
To fix this, either remove the !== false portion entirely, or enforce your own precedence with extra brackets:
($file = readdir($dir)) !== false