get entire folders/files tree and rename - php

I have a folders/files tree inside admin folder (windows, localhost).
All files are .html.
Each of them (files and folders) is starting with some numbers and middle dash, for example
32-somefolder
624-somefile.html
I need to list all of them and remove all prefixes from their names.
So the result should be:
somefolder
somefile.html
foreach(glob("admin/*") as $el) {
echo $el . '.' . filetype($el) . '<br>';
}
First problem - only folders are listed:
admin/32-somefolder.dir
How to get files too, and how to rename i.e. remove prefixes from all the names?

You can use the second choice to list files : scandir, and recursive function :
function removePrefixFiles($dir, &$results = array()){
$files = scandir($dir);
foreach ($files as $key => $value){
$path = realpath($dir . DIRECTORY_SEPARATOR . $value);
if (! is_dir($path)) {
// treat the filename
$file = pathinfo($path);
$filename = explode('-', $file['filename']);
if (count($filename) > 0) {
// '-' is found, rename file
rename($path, $file['dirname'] .'/'. $filename[1] .'.'. $file['extension'];
}
$results[] = $path;
} else if ($value != '.' && $value != '..') {
removePrefixFiles($path, $results);
$results[] = $path;
}
}
// no real need to return something here, but can log the files
return $results;
}
$dir = '/admin';
removePrefixFiles($dir);

I have created two folder inside admin/ name as
1-files and 2-abc
then inside folder 1-files i have two files
11-java.html
11-text.html
then inside folder 2-abc i have two files
22-php.html
22-sql.html
<?php
$dir = "admin/";
// Sort in ascending order - this is default
$a = scandir($dir);
echo "<pre>";
if(count($a)>0){
$newArr = array();
for($i=2;$i<count($a);$i++){
$test = array();
$folderArr = array();
$folderName = explode('-',$a[$i]);
$test['folder'] = $folderName[1];
$b = scandir($dir.'/'.$a[$i]);
for($j=2;$j<count($b);$j++){
$fileName = explode('-',$b[$j]);
$folderArr[] = substr($fileName[1], 0, strpos($fileName[1], "."));;
}
$test['files'] = $folderArr;
$newArr[] = $test;
}
}
print_r($newArr);
?>
This will be the output
Array
(
[0] => Array
(
[folder] => files
[files] => Array
(
[0] => java
[1] => text
)
)
[1] => Array
(
[folder] => abc
[files] => Array
(
[0] => php
[1] => sql
)
)
)
Hope this willl hellp you.

Related

Getting a list of sub-directories form an array of paths based on current path

I want to get an array of immediate sub-directories based on the current path from a given list of paths. Here is an example list of paths and the desired result:
$dirs = [
'/chris',
'/chris/usa',
'/david',
'/',
'/chris/canada/2022',
'/david/uk',
];
$current_path = "/chris";
// Required result:
$sub_dirs = ['/usa', '/canada'];
The current path could be anything from / to the last sub directory, in which case I would end up with an empty $sub_dirs.
My best attempt at it is this:
$dirs = [
'/chris',
'/chris/usa',
'/david',
'/',
'/chris/canada/2022',
'/david/uk',
];
$sub_dirs = [];
$current_path = "/";
foreach($dirs as $dir){
if(strstr($dir, $current_path)){
$sub_dirs[] = str_replace($current_path, '', $dir);
}
}
The above fails at two things. If the $current_path = "/" then the returned array is just paths without slashes since I strip them out with strstr() and if the $current_path = "/chris" then I still get the sub-directories.
How should I correctly solve it?
Thank you!
You can search for /chris/ to get only sub directories.
To get only the first directory of matching paths, you could use explode(), and get the first.
As of PHP8, you can use str_starts_with()
$dirs = ['/chris', '/chris/usa', '/david', '/', '/chris/canada/2022', '/david/uk'];
$current_path = "/";
$sub_dirs = [];
foreach($dirs as $dir)
{
// Ensure $dir starts with path + '/' (sub dir of $current_path)
if (!str_starts_with($dir, $current_path)) {
continue;
}
// Get the relative path from $current_path
$relPath = substr($dir, strlen($current_path));
// Get the first dir of this path
[$dir2] = explode('/', ltrim($relPath,'/'));
// skip same directory
if (empty($dir2)) {
continue;
}
// Store and add removed slash
$sub_dirs[] = '/' . $dir2;
}
var_export(array_unique($sub_dirs));
Output
array (
0 => '/usa',
1 => '/canada',
)
I like the approach of creating a tree out of the paths (adapted from this answer).
Then it's easier to get the children based on a path.
function buildTree($paths)
{
// Create a hierarchy where keys are the labels
$rootChildren = [];
foreach ($paths as $path) {
$branch = explode("/", $path);
$children = &$rootChildren;
foreach ($branch as $label) {
if ($label) {
if (!isset($children[$label])) {
$children[$label] = [];
}
$children = &$children[$label];
}
}
}
// Create target structure from that hierarchy
function recur($children)
{
$result = [];
foreach ($children as $label => $grandchildren) {
$result[$label] = recur($grandchildren);
}
return $result;
}
return recur($rootChildren);
}
function findChildren($tree, $path)
{
$branch = explode("/", $path);
$pointer = $tree;
foreach ($branch as $label) {
if ($label) {
$pointer = $pointer[$label];
}
}
return array_keys($pointer);
}
$dirs = [
'/chris',
'/chris/usa',
'/david',
'/',
'/chris/canada/2022',
'/david/uk',
];
$tree = buildTree($dirs);
print_r($tree);
$current_path = "/chris";
print_r(findChildren($tree, $current_path));
Output:
Array
(
[chris] => Array
(
[usa] => Array
(
)
[canada] => Array
(
[2022] => Array
(
)
)
)
[david] => Array
(
[uk] => Array
(
)
)
)
Array
(
[0] => usa
[1] => canada
)
I feel like I have a bit shorter answer than the previous ones, but not sure if it's the most efficient one though.
$dirs = [
'/chris',
'/chris/usa',
'/david',
'/',
'/chris/canada/2022',
'/david/uk',
];
$current_path = "/chris";
$sub_dirs = array_map(function($s) { return '/'.explode("/", $s)[2]; },array_filter($dirs, function($dir) use ($current_path) {
return substr($dir, 0, strlen($current_path) + 1) === $current_path . '/';
}));
print_r($sub_dirs); // Output: Array ( [1] => /usa [4] => /canada )

PHP: fetch file without check case sensitive

I have a image named Dark-Green.jpg but the output of function is DARK-GREEN.jpg so the image is not displaying due to case-sensitive.
So how can I fetch the image?
UPDATE
Below is my output of the array.
$output = Array
(
[WE05-5040*L] => Array
(
[qty] => 1
[stitching_category] => 2
[sku_image] => skuimages/WE05/DARK-GREEN.jpg
)
)
Then I am using this array in foreach loop like below.
foreach ($output as $ok => $op) {
$itemQty = $op['qty'];
$itemImagePath = $op['sku_image'];
echo "{$ok} has qty: {$itemQty} and the image as below.";
echo "<img src='{$itemImagePath}' width='50%' />"
}
Try this:
function getFile ($filename){
$files = glob($dir . '/*');
$filename = strtolower($filename);
foreach($files as $file) {
if (strtolower($file) == $filename){
return $file;
}
}
return false;
}

How to detect changes in directories or file inside that directory using php

I have directory structure like this:
[Products] => Array
(
[Category1] => Array
(
[product1] => Array
(
[documents] => Array
(
[0] => Attachment1.pdf
[1] => Attachment2.pdf
)
)
)
)
if there is any changes in any directory or file inside products directory
like:
product1 changed to product2
new directory added
any changes in file Attachment.pdf
new document added to directory.
What i have tried till now:
$dir="PATH TO PRODUCT DIRECTORY"
$stats = stat($dir);
but $stats['mtime'] detected change in Products children only (Like if change Category1 to Category2 or newly added directory to products) but not in grand children of products (Like if i change product1 to product2) and so on.
Can any one help me to delect any changes in product with children.
Here is my solution i have implemented. By using these function i am able to get a MD5 hash code and i can use this hash code to check if there is any changes in directory structure or in any file.
$dir="PATH TO PRODUCT DIRECTORY";
public function directoryHash($dir, $item_name){
$dirStr=$this->directoryStruture($dir, $separator= DIRECTORY_SEPARATOR, $root='');
$strHash=md5(json_encode($dirStr));
return $strHash;
}
public function directoryStruture($dir, $separator = DIRECTORY_SEPARATOR, $root = '') {
$result = array();
$cdir = scandir($dir);
$result = array();
if ($root === '') {
$root = $dir;
}
$cdir = scandir($dir);
foreach ($cdir as $key => $value) {
if (!in_array($value, array(".", ".."))) {
$current = $dir . $separator . $value;
if (is_dir($current)) {
$result['items'][] = $value;
$result[$value] = $this->directoryStruture($current, $separator, $root);
} else {
$filePath = str_replace($root, '', $current);
$result[] = $filePath.filemtime($current);
}
}
}
return $result;
}
If there is any better approach. Please let me know.
Thanks,
M.

generating array of parents paths of a URL

so if I have a string like this, e.g. "/path1/folder/fun/yay/"
How can I run that through a function to return an array of all the parent paths, looking like this:
array (
'/',
'/path1/',
'/path1/folder/',
'/path1/folder/fun/',
'/path1/folder/fun/yay/'
)
This is what I have so far, obviously it doesn't work and it's confusing to say the least...
$a = explode('/',$path); $ii = 0; $path_array = array();
for ($i = 0; $i < sizeof($a); $i++) {
if ($a[$i]) {
$path_array[$ii] = "";
for ($n = 0; $n < $i; $n++)
{
$path_array[$ii] .= $a[$n];
}
$ii++;
}
}
file_put_contents('text.txt',serialize($path_array));
Thanks!
BTW my end goal here is to be able to run an SQL query on a table of folder paths to increment a value on a folder and all of its parents.
Maybe there's some sort of SQL operator where I could select all rows whose path is a part of the path I input? Kinda like this in reverse:
mysqli_query($mysqli,'UPDATE content_folders SET size = size+'.filesize("content/$id").' WHERE path LIKE "'.$path.'%"')
As for the PHP function - something like this would work:
function returnAllPaths ( $fullPath = '/' , Array $pathHistory = array() )
{
while ( strlen($fullPath) > 1 AND $fullPath[0] === '/' )
{
array_push($pathHistory, $fullPath);
$fullPath = preg_replace('%(.*/)[^/]+(?:/)?$%is', '$1', $fullPath);
}
array_push($pathHistory, $fullPath);
return array_reverse($pathHistory);
}
You can use this
$path = '/path1/folder/fun/yay/';
$path = explode('/',$path);
$path = array_filter($path);
$iniVal = '';
$array_paths = array();
array_push($array_paths,'/');
foreach($path as $array){
$value = $iniVal.'/'.$array.'/';
array_push($array_paths,$value);
$iniVal .= '/'.$array;
}
//print_r($array_paths);
Output would display in array such as :
Array ( [0] => / [1] => /path1/ [2] => /path1/folder/ [3] => /path1/folder/fun/ [4] => /path1/folder/fun/yay/ )
same as
array (
'/',
'/path1/',
'/path1/folder/',
'/path1/folder/fun/',
'/path1/folder/fun/yay/'
)
DEMO : PHP FIDDLE

PHP recursive folder scan into multi array (subfolders and files)

I'm a little bit lost here at the moment. My goal is to recursive scan a folder with subfolders and images in each subfolder, to get it into a multidimensional array and then to be able to parse each subfolder with its containing images.
I have the following starting code which is basically scanning each subfolders containing files and just lost to get it into a multi array now.
$dir = 'data/uploads/farbmuster';
$results = array();
if(is_dir($dir)) {
$iterator = new RecursiveDirectoryIterator($dir);
foreach(new RecursiveIteratorIterator($iterator, RecursiveIteratorIterator::CHILD_FIRST) as $file) {
if($file->isFile()) {
$thispath = str_replace('\\','/',$file->getPath());
$thisfile = utf8_encode($file->getFilename());
$results[] = 'path: ' . $thispath. ', filename: ' . $thisfile;
}
}
}
Can someone help me with this?
Thanks in advance!
You can try
$dir = 'test/';
$results = array();
if (is_dir($dir)) {
$iterator = new RecursiveDirectoryIterator($dir);
foreach ( new RecursiveIteratorIterator($iterator, RecursiveIteratorIterator::CHILD_FIRST) as $file ) {
if ($file->isFile()) {
$thispath = str_replace('\\', '/', $file);
$thisfile = utf8_encode($file->getFilename());
$results = array_merge_recursive($results, pathToArray($thispath));
}
}
}
echo "<pre>";
print_r($results);
Output
Array
(
[test] => Array
(
[css] => Array
(
[0] => a.css
[1] => b.css
[2] => c.css
[3] => css.php
[4] => css.run.php
)
[CSV] => Array
(
[0] => abc.csv
)
[image] => Array
(
[0] => a.jpg
[1] => ab.jpg
[2] => a_rgb_0.jpg
[3] => a_rgb_1.jpg
[4] => a_rgb_2.jpg
[5] => f.jpg
)
[img] => Array
(
[users] => Array
(
[0] => a.jpg
[1] => a_rgb_0.jpg
)
)
)
Function Used
function pathToArray($path , $separator = '/') {
if (($pos = strpos($path, $separator)) === false) {
return array($path);
}
return array(substr($path, 0, $pos) => pathToArray(substr($path, $pos + 1)));
}
RecursiveDirectoryIterator scans recursively into a flat structure. To create a deep structure you need a recursive function (calls itself) using DirectoryIterator. And if your current file isDir() and !isDot() go deep on it by calling the function again with the new directory as arguments. And append the new array to your current set.
If you can't handle this holler and I'll dump some code here. Have to document (has ninja comments right now) it a bit so... trying my luck the lazy way, with instructions.
CODE:
/**
* List files and folders inside a directory into a deep array.
*
* #param string $Path
* #return array/null
*/
function EnumFiles($Path){
// Validate argument
if(!is_string($Path) or !strlen($Path = trim($Path))){
trigger_error('$Path must be a non-empty trimmed string.', E_USER_WARNING);
return null;
}
// If we get a file as argument, resolve its folder
if(!is_dir($Path) and is_file($Path)){
$Path = dirname($Path);
}
// Validate folder-ness
if(!is_dir($Path) or !($Path = realpath($Path))){
trigger_error('$Path must be an existing directory.', E_USER_WARNING);
return null;
}
// Store initial Path for relative Paths (second argument is reserved)
$RootPath = (func_num_args() > 1) ? func_get_arg(1) : $Path;
$RootPathLen = strlen($RootPath);
// Prepare the array of files
$Files = array();
$Iterator = new DirectoryIterator($Path);
foreach($Iterator as /** #var \SplFileInfo */ $File){
if($File->isDot()) continue; // Skip . and ..
if($File->isLink() or (!$File->isDir() and !$File->isFile())) continue; // Skip links & other stuff
$FilePath = $File->getPathname();
$RelativePath = str_replace('\\', '/', substr($FilePath, $RootPathLen));
$Files[$RelativePath] = $FilePath; // Files are string
if(!$File->isDir()) continue;
// Calls itself recursively [regardless of name :)]
$SubFiles = call_user_func(__FUNCTION__, $FilePath, $RootPath);
$Files[$RelativePath] = $SubFiles; // Folders are arrays
}
return $Files; // Return the tree
}
Test its output and figure it out :) You can do it!
If you want to get list of files with subdirectories, then use (but change the foldername)
<?php
$path = realpath('yourfold/samplefolder');
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)) as $filename)
{
echo "$filename\n";
}
?>

Categories