I am trying to get the last element of the request array in foreach loop that would look something like this:
array:5 [▼
0 => "files/uploads/articles/bear_PNG1183.png"
1 => "files/uploads/articles/bear_PNG1189.png"
2 => "files/uploads/articles/bear_PNG1188.png"
3 => "files/uploads/articles/bear_PNG1182 (1).png"
4 => "files/uploads/articles/bear_PNG1190.png"
]
But I can't use the end() function because then I get:
Only variables should be passed by reference
This is how foreach function looks like:
foreach ($request->get('uploadedItems') as $file) {
//make a new directory for the article and move all the uploaded files to it
$filePathArr = explode('/', $file);
$lastItem = array_pop($filePathArr);
array_push($filePathArr, $article->id, $lastItem);
$newPath = implode('/', $filePathArr);
$articleDirectory = $this->destinationPath.'/'.$article->id;
if(!File::exists($articleDirectory))
File::makeDirectory($articleDirectory, 0755, true);
File::move(public_path($file), public_path($newPath));
if(end($request->get('uploadedItems')) == $file){
dd($file);
}
Media::create(['path' => $newPath, 'article_id' => $article->id]);
}
Why call $request->get('uploadedItems') multiple times? Call it once and assign it to a variable before the loop or:
foreach ($files = $request->get('uploadedItems') as $file) {
if(end($files) == $file){
dd($file);
}
}
Related
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 )
I tried the following code but an error occurs when I run the project
$files = $request->file('files');
if($request->hasFile('files'))
{
foreach ($files as $file) {
$path = $file->store('public/gallery');
ProductGallery::create([
'products_id' => $product->id,
'url' => $path
]);
}
}
Upon using hasFile on an array it seems that it only checks the first element from the array. If the first element of your files array is empty, the result will always be false. A workaround to your problem is:
$files = $request->file('files');
if(count($request->file('files')) > 0)
{
foreach ($files as $file) {
if ($file->isValid()) {
/* Write your file upload code here */
}
}
}
How do i convert multidimensional array to file path.
I have this array :
$data = [
"users" => [
"joe" => [
"photos" => ["a.jpg","b.jpg"],
"files" => ["a.doc","b.doc"]
],
"annie" => [
"photos" => ["a.jpg","b.jpg"],
"files" => ["a.doc","b.doc"]
],
]
];
that i must convert to path example :
"users/joe/photos/a.jpg";
"users/joe/photos/b.jpg";
"users/joe/files/a.doc";
"users/joe/files/b.doc";
"users/annie/photos/a.jpg";
"users/annie/photos/b.jpg";
"users/annie/files/a.doc";
"users/annie/files/b.doc";
But i can't have the best result with this functions :
$path = "";
function iterate($data, $path)
{
echo "<br>";
foreach ($data as $key => $item){
if (is_array($item)){
$path .= $key.DIRECTORY_SEPARATOR;
iterate($item, $path);
}else{
echo $path.$item."<br>";
}
}
}
output :
users/joe/photos/a.jpg
users/joe/photos/b.jpg
users/joe/photos/files/a.doc
users/joe/photos/files/b.doc
users/joe/annie/photos/a.jpg
users/joe/annie/photos/b.jpg
users/joe/annie/photos/files/a.doc
users/joe/annie/photos/files/b.doc
Please help.
Thanks
You could make use of RecursiveIteratorIterator + RecursiveArrayIterator:
function computeFilePaths(array $fileTree): array
{
$filePaths = [];
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($fileTree));
foreach ($iterator as $fileName) {
for ($folders = [], $pos = 0, $depth = $iterator->getDepth(); $pos < $depth; $pos++) {
$folders[] = $iterator->getSubIterator($pos)->key();
}
$filePaths[] = implode('/', $folders) . '/' . $fileName;
}
return $filePaths;
}
print_r(computeFilePaths($yourArrayGoesHere));
I highly suggest this question's selected answer to understand how these iterators work.
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;
}
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";
}
?>