I would like to collect all files in a specific directory (at the moment I'm using scandir) - but only those, who do not have a special pattern.
Example:
someimage.png
someimage-150x150.png
someimage-233x333.png
someotherimage.png
someotherimage-760x543.png
someotherimage-150x50.png
In this case I would like to get someimage.png and someotherimage.png as result in my array.
How can I solve this?
To get array of filenames consisting of letters only, you can use this:
$array = array();
$handle = opendir($directory);
while ($file = readdir($handle)) {
if(preg_match('/^[A-Za-z]+\.png$/',$file)){
$array[] = $file;
}
}
The OOP way could be to use a DirectoryIterator in combination with a FilterIterator:
class FilenameFilter extends FilterIterator {
protected $filePattern;
public function __construct(Iterator $iterator , $pattern) {
parent::__construct($iterator);
$this->filePattern = $pattern;
}
public function accept() {
$currentFile = $this->current();
return (1 === preg_match($this->filePattern, $currentFile));
}
}
Usage:
$myFilter = new FilenameFilter(new DirectoryIterator('path/to/your/files'), '/^[a-z-_]*\.(png|PNG|jpg|JPG)$/i');
foreach ($myFilter as $filteredFile) {
// Only files which match your specified pattern should appear here
var_dump($filteredFile);
}
It's just an idea and the code is not tested but. Hope that helps;
$files = array(
"someimage.png",
"someimage-150x150.png",
"someimage-233x333.png",
"someotherimage.png",
"someotherimage-760x543.png",
"someotherimage-150x50.png",
);
foreach ( $files as $key => $value ) {
if ( preg_match( '#\-[0-9]+x[0-9]+\.(png|jpe?g|gif)$#', $value ) ) {
unset( $files[$key] );
}
}
echo '<xmp>' . print_r( $files, 1 ) . '</xmp>';
This regex will fill $correctFiles with all png images that don't contain dimensions (42x42 for example) in their names.
<?php
// here you get the files with scandir, or any method you want
$files = array(
'someimage.png',
'someimage-150x150.png',
'someimage-233x333.png',
'someotherimage.png',
'someotherimage-760x543.png',
'someotherimage-150x50.png'
);
$correctFiles = array(); // This will contain the correct file names
foreach ($files as $file)
if (!preg_match('/^.*-\d+x\d+\.png$/', $file)) // If the file doesn't have "NUMBERxNUMBER" in their name
$correctFiles[] = $file;
print_r($correctFiles); // Here you can do what you want with those files
If you don't want to store the names in an array (faster, less memory consumption), you can use the code below.
<?php
// here you get the files with scandir, or any method you want
$files = array(
'someimage.png',
'someimage-150x150.png',
'someimage-233x333.png',
'someotherimage.png',
'someotherimage-760x543.png',
'someotherimage-150x50.png'
);
foreach ($files as $file)
if (!preg_match('/^.*-\d+x\d+\.png$/', $file)) // If the file doesn't have "NUMBERxNUMBER" in their name
{
print_r($file); // Here you can do what you want with this file
}
Related
I am yet to work on a very large project which has too many files. I am trying to find out few vaiables where it is present and list all the file names which contains the specific word or variable or string.
What I have tried so far!
$path = realpath(__DIR__); // Path to your textfiles
$fileList = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path), \RecursiveIteratorIterator::SELF_FIRST);
foreach ($fileList as $item) {
if ($item->isFile() && stripos($item->getPathName(), 'php') !== false) {
$file_contents = file_get_contents($item->getPathName());
$file_contents = strpos($file_contents,"wordtofind");
echo $file_contents;
}
}
I use the same code for replacing text which I found it on stackoverflow. But I need to find out few strings before replacing specific words in specific files. Hence this has become most important task to me.
How can I further code and get the file names?
Edit:
I want to search for a specific word, for example: word_to_find
And there are more than 200 files in a folder called abc.
When I run that code, searching for the word, then it should search in all 200 files and list all the file names which contains word_to_find word.
Then I would know, in which all files, the specific word exists and then I can work on.
Output would be:
123.php
111.php
199.php
I created you a nice function. This will return filenames (Not any paths, yield $item->getPathName() instead if you want the path, or probably better yet, just yield $item, which will return the SplFileInfo class which you can then use any of the helper functions to get info about that file.):
function findStringInPath($needle, $path = __DIR__) {
//$path = realpath(__DIR__); // Path to your textfiles
$fileList = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path), \RecursiveIteratorIterator::SELF_FIRST);
foreach ($fileList as $item) {
if ($item->isFile() && strtolower($item->getExtension()) === 'php') {
$file_contents = file_get_contents($item->getPathName());
if ( strpos($file_contents, $needle) !== false )
yield $item->getFileName();
}
}
}
foreach ( findStringInPath('stringtofind') as $file ) {
echo $file . '<br />';
}
?>
For older PHP versions:
<?php
function findStringInPath($needle, $path = __DIR__) {
//$path = realpath(__DIR__); // Path to your textfiles
$fileList = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path), \RecursiveIteratorIterator::SELF_FIRST);
$ret = array();
foreach ($fileList as $item) {
if ($item->isFile() && strtolower($item->getExtension()) === 'php') {
$file_contents = file_get_contents($item->getPathName());
if ( strpos($file_contents, $needle) !== false )
$ret[] = $item->getFileName();
}
}
return $ret;
}
foreach ( findStringInPath('stringtofind') as $file ) {
echo $file . '<br />';
}
?>
I am trying to make a recursive function to go through all of the folder path that I have given it in the parameters.
What I am trying to do is to store the folder tree into an array for example I have Folder1 and this folder contains 4 text files and another folder and I want the structure to be a multidimensional array like the following
Array 1 = Folder one
Array 1 = text.text.....So on so forth
I have the following function that I build but its not working as I want it too. I know that I need to check whether it is in the root directory or not but when it becomes recursive it becoems harder
function displayAllFolders($root)
{
$foldersArray = array();
$listFolderFile = scandir($root);
foreach($listFolderFile as $row)
{
if($row == "." || $row == "..")
{
continue;
}
elseif(is_dir("$root/$row") == true)
{
$foldersArray["$root/$row"] = "$row";
$folder = "$root/$row";
#$foldersArray[] = displayAllFolders("$root/$row");
}
else
{
$foldersArray[]= array("$root/$row") ;
}
}
var_dump($foldersArray);
}
Using RecursiveDirectoryIterator with RecursiveIteratorIterator this becomes rather easy, e.g.:
$it = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(
// root dir
'.',
// ignore dots
RecursiveDirectoryIterator::SKIP_DOTS
),
// include directories
RecursiveIteratorIterator::SELF_FIRST
// default is:
// RecursiveIteratorIterator::LEAVES_ONLY
//
// which would only list files
);
foreach ($it as $entry) {
/* #var $entry \SplFileInfo */
echo $entry->getPathname(), "\n";
}
Your approach isn't recursive at all.
It would be recursive if you called the same function again in case of a directory. You only make one sweep.
Have a look here:
http://php.net/manual/en/function.scandir.php
A few solutions are posted. I would advise you to start with the usercomment by mmda dot nl.
(function is named dirToArray, exactly what you are tryting to do.)
In case it will be removed, I pasted it here:
function dirToArray($dir) {
$result = array();
$cdir = scandir($dir);
foreach ($cdir as $key => $value) {
if (!in_array($value,array(".",".."))) {
if (is_dir($dir . DIRECTORY_SEPARATOR . $value)) {
$result[$value] = dirToArray($dir . DIRECTORY_SEPARATOR . $value);
}
else {
$result[] = $value;
}
}
}
return $result;
}
Why not using PHP itself? Just have a look at the RecursiveDirectoryIterator of the standard php library (SPL).
$folders = [];
$iterator = new RecursiveDirectoryIterator(new RecursiveDirectoryIterator($directory));
iterator_apply($iterator, 'scanFolders', array($iterator, $folders));
function scanFolders($iterator, $folders) {
while ($iterator->valid()) {
if ($iterator->hasChildren()) {
scanFolders($iterator->getChildren(), $folders);
} else {
$folders[] = $iterator->current();
}
$iterator->next();
}
}
I could use some help with this. I have to get list of files from one directory, and return them as array, but key needs to be the same as value, so output would be looking like this:
array(
'file1.png' => 'file1.png',
'file2.png' => 'file2.png',
'file3.png' => 'file3.png'
)
I found this code:
function images($directory) {
// create an array to hold directory list
$results = array();
// create a handler for the directory
$handler = opendir($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 != "..")
{
$results[] = $file;
}
}
// tidy up: close the handler
closedir($handler);
// done!
return $results;
}
It's working fine, but it returns regular array.
Can someone help me with this?
Also small note at the end, I need to list only image files (png,gif,jpeg).
Change your following line
$results[] = $file;
To
$results[$file] = $file;
To limit file extension do as below
$ext = pathinfo($file, PATHINFO_EXTENSION);
$allowed_files = array('png','gif');
if(in_array($ext,$allowed_files)){
$results[$file] = $file;
}
Something like this should to the work
$image_array = [];
foreach ($images as $image_key => $image_name) {
if ($image_key == $image_name) {
$image_array[] = $image_name;
}
return $image_array;
}
Why not using glob and array_combine ?
function images($directory) {
$files = glob("{$directory}/*.png");
return array_combine($files, $files);
}
glob() get files on your directory according to a standard pattern ( such as *.png )
array_combine() creates an associative array using an array of keys and an array of values
now do this on my script
$scan=scandir("your image directory");
$c=count($scan);
echo "<h3>found $c image.</h3>";
for($i=0; $i<=$c; $i++):
if(substr($scan[$i],-3)!=='png') continue;
echo "<img onClick=\"javascript:select('$scan[$i]');\" src='yourdirectory/$scan[$i]' />";
endfor;
this code only list png images from your directory.
I have this working function that finds folders and creates an array.
function dua_get_files($path)
{
foreach (glob($path . "/*", GLOB_ONLYDIR) as $filename)
{
$dir_paths[] = $filename;
}
return $dir_paths;
}
This function can only find the directories on the current location. I want to find the directory paths in the child folders and their children and so on.
The array should still be a flat list of directory paths.
An example of how the output array should look like
$dir_path[0] = 'path/folder1';
$dir_path[1] = 'path/folder1/child_folder1';
$dir_path[2] = 'path/folder1/child_folder2';
$dir_path[3] = 'path/folder2';
$dir_path[4] = 'path/folder2/child_folder1';
$dir_path[5] = 'path/folder2/child_folder2';
$dir_path[6] = 'path/folder2/child_folder3';
If you want to recursively work on directories, you should take a look at the RecursiveDirectoryIterator.
$path = realpath('/etc');
$objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST);
foreach($objects as $name => $object){
echo "$name\n";
}
Very strange - everybody advice recursion, but better just cycle:
$dir ='/dir';
while($dirs = glob($dir . '/*', GLOB_ONLYDIR)) {
$dir .= '/*';
if(!$result) {
$result = $dirs;
} else {
$result = array_merge($result, $dirs);
}
}
Try this instead:
function dua_get_files($path)
{
$data = array();
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST);
foreach ($files as $file)
{
if (is_dir($file) === true)
{
$data[] = strval($file);
}
}
return $data;
}
Use this function :
function dua_get_files($path)
{
$dir_paths = array();
foreach (glob($path . "/*", GLOB_ONLYDIR) as $filename)
{
$dir_paths[] = $filename;
$a = glob("$filename/*", GLOB_ONLYDIR);
if( is_array( $a ) )
{
$b = dua_get_files( "$filename/*" );
foreach( $b as $c )
{
$dir_paths[] = $c;
}
}
}
return $dir_paths;
}
You can use php GLOB function, but you must create a recursive function to scan directories at infinite level depth. Then store results in a global variable.
function dua_get_files($path) {
global $dir_paths; //global variable where to store the result
foreach ($path as $dir) { //loop the input
$dir_paths[] = $dir; //can use also "basename($dir)" or "realpath($dir)"
$subdir = glob($dir . DIRECTORY_SEPARATOR . '*', GLOB_ONLYDIR); //use DIRECTORY_SEPARATOR to be OS independent
if (!empty($subdir)) { //if subdir is not empty make function recursive
dua_get_files($subdir); //execute the function again with current subdir
}
}
}
//usage:
$path = array('galleries'); //suport absolute or relative path. support one or multiple path
dua_get_files($path);
print('<pre>'.print_r($dir_paths,true).'</pre>'); //debug
For PHP, if you are on a linux/unix, you can also use backticks (shell execution) with the unix find command. Directory searching on the filesystem can take a long time and hit a loop -- the system find command is already built for speed and to handle filesystem loops. In other words, the system exec call is likely to cost far less cpu-time than using PHP itself to search the filesystem tree.
$dirs = `find $path -type d`;
Remember to sanitize the $path input, so other users don't pass in security compromising path names (like from the url or something).
To put it into an array
$dirs = preg_split("/\s*\n+\s*/",`find $path -type d`,-1,PREG_SPLIT_NO_EMPTY);
I want to use a function to recursively scan a folder, and assign the contents of each scan to an array.
It's simple enough to recurse through each successive index in the array using either next() or foreach - but how to dynamically add a layer of depth to the array (without hard coding it into the function) is giving me problems. Here's some pseudo:
function myScanner($start){
static $files = array();
$files = scandir($start);
//do some filtering here to omit unwanted types
$next = next($files);
//recurse scan
//PROBLEM: how to increment position in array to store results
//$next_position = $files[][][].... ad infinitum
//myScanner($start.DIRECTORY_SEPARATOR.$next);
}
any ideas?
Try something like this:
// $array is a pointer to your array
// $start is a directory to start the scan
function myScanner($start, &$array){
// opening $start directory handle
$handle = opendir($start);
// now we try to read the directory contents
while (false !== ($file = readdir($handle))) {
// filtering . and .. "folders"
if ($file != "." && $file != "..") {
// a variable to test if this file is a directory
$dirtest = $start . DIRECTORY_SEPARATOR . $file;
// check it
if (is_dir($dirtest)) {
// if it is the directory then run the function again
// DIRECTORY_SEPARATOR here to not mix files and directories with the same name
myScanner($dirtest, $array[$file . DIRECTORY_SEPARATOR]);
} else {
// else we just add this file to an array
$array[$file] = '';
}
}
}
// closing directory handle
closedir($handle);
}
// test it
$mytree = array();
myScanner('/var/www', $mytree);
print "<pre>";
print_r($mytree);
print "</pre>";
Try to use this function (and edit it for your demands):
function getDirTree($dir,$p=true) {
$d = dir($dir);$x=array();
while (false !== ($r = $d->read())) {
if($r!="."&&$r!=".."&&(($p==false&&is_dir($dir.$r))||$p==true)) {
$x[$r] = (is_dir($dir.$r)?array():(is_file($dir.$r)?true:false));
}
}
foreach ($x as $key => $value) {
if (is_dir($dir.$key."/")) {
$x[$key] = getDirTree($dir.$key."/",$p);
}
}
ksort($x);
return $x;
}
It returns sorted array of directories.