I'm trying to make an image gallery that scans a main directory and creates a separate album for each subdirectory.
My structure is similar to this:
-Gallery
--Subdir 1
---Image 1
---Image 2
--Subdir 2
---Image 1
---Image 2
The idea is that each album is going to be made of a div with a class of web-gallery. Then there will be a header for the album title made from the subdirectories name. After that a list is generated of each image. This is going to be a one page gallery. If possible I would like to have a variable that sets how many albums are listed that way if I have 30 subdirectories my page doesn't get too crowded.
So far I've written this but it doesn't work. I'm not getting any errors or logs though it just doesn't work.
$dirs = glob('img/gallery_temp/*', GLOB_ONLYDIR);
foreach($dirs as $val) {
echo '<div class="web-gallery">';
echo "<h3><span>ยป</span> ".basename($val). "</h3>";
echo '<ul class="web-gallery-list">';
$files = glob($val.'*.{jpg,png,gif}', GLOB_BRACE);
foreach($files as $file) {
echo "<li><a href='".$file."'><img src='" . $file . "' alt='description'></a></li> \r\n";
}
echo "</ul>";
echo "</div>";
}
Simply add a / before *.{jpg,png,gif} like this:
$files = glob($val.'/*.{jpg,png,gif}', GLOB_BRACE);
This is because $val doesn't have a final / for the directory.
You might consider using "readdir" instead of glob. Glob is to find pathnames matching a pattern, see here: http://php.net/manual/en/function.glob.php and is known to be a bit problematic.
Readdir, if your directory is entirely images might be easier to use: http://php.net/manual/en/function.readdir.php
Couple this with is_dir() http://php.net/manual/en/function.is-dir.php to resolve your directories vs files. Here is a snippet
<?php
if ($handle = opendir('/galleries')) {
while (false !== ($entry = readdir($handle))) {
// this is a subdirectory
if (is_dir($entry)) {
}
// this is a file
else {
echo $entry;
}
}
closedir($handle);
}
?>
If you make it a recursive function you could actually have it traverse a number of subdirectories creating galleries within galleries.
I also found this fantastic little snippet that is very elegant on another stack question: Get Images In Directory and Subdirectory With Glob
$rdi = new RecursiveDirectoryIterator("uploads/prevImgs/");
$it = new RecursiveIteratorIterator($rdi);
foreach($it as $oneThing)
if (is_file($oneThing))
echo '<img src="'.$oneThing.'" /><br />';
Using SPL Library (PHP >= 5)
Better solution in your case
is to use SPL library (the most cross-platform)
$directory = new RecursiveDirectoryIterator("./img/gallery_temp", FilesystemIterator::SKIP_DOTS);
// Flatten the recursive iterator, folders come before their files
$it = new RecursiveIteratorIterator($directory, RecursiveIteratorIterator::SELF_FIRST);
foreach($it as $fileinfo)
{
if($fileinfo->isDir())
{
// prevPath used to separate each directory listing and closing the bracket UL list
$prevPath = $it->getSubPath().DIRECTORY_SEPARATOR.$fileinfo->getFilename();
echo sprintf
(
"<div class='web-gallery'>
<h3><span>></span> %s</h3>
<ul>".PHP_EOL,
$fileinfo->getFilename()
);
}
if($fileinfo->isFile())
{
echo sprintf("<li><a href=''><img src='%s/%s' alt='description'></a></li>".PHP_EOL, $it->getSubPath(), $fileinfo->getFilename());
if($prevPath != $it->getSubPath())
echo("</ul>");
}
}
Note:
For more informations : SPL Documentation
DIRECTORY_SEPARATOR is a cross-platform constant, will use the
correct directory separator of the OS where are executed the code
FilesystemIterator::SKIP_DOTS, avoid to fetch the '.' and '..' dir
link level.
you can limit the depth of scanning with $it->setMaxDepth(5);
Related
is there any way for RecursiveDirectoryIterator to echo files in subfolders separately based on folder and not all together?
Here is my example. I have a folder (event), which has multiple subfolders (logo, people, bands). But subfolder names vary for certain events, so I can't simply set to look inside these three, I need a "wildcard" option.
When I use RecursiveDirectoryIterator to echo out all images from these folders, it works, but I would like to separate these based on subfolder, so it echoes out folder name and all images from within below and then repeats for the next folder and so on.
Right now I use this:
<?php
$directory = "path/to/mainfolder/";
foreach (new RecursiveIteratorIterator(new
RecursiveDirectoryIterator($directory,RecursiveDirectoryIterator::SKIP_DOTS)) as $filename)
{
echo '<img src="'.$filename.'">';
}
?>
So, how do I make this echo like:
Logo
image, image, image
People
image, image, image
...
Thanks in advance for any useful tips and ideas.
for me, code is more readable when you put objects into variables with descriptive names then pass those on when instantiating other classes. I've used the RegexIterator() over the RecursiveFilterIterator() to filter just image file extensions (didn't want to get into extending the RecursiveFilterIterator() class for example). The rest of the code is simple iterating, extracting strings and page breaking.
NOTE: there is no error handling, best to add a try/catch to manage exceptions
<?php
$directory = 'path/to/mainfolder/';
$objRecursiveDirectoryIterator = new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS);
$objRecursiveIteratorIterator = new RecursiveIteratorIterator($objRecursiveDirectoryIterator);
// use RegexIterator() to grab only image file extensions
$objRegexIterator = new RegexIterator($objRecursiveIteratorIterator, "~^.+\.(bmp|gif|jpg|jpeg|img)$~i", RecursiveRegexIterator::GET_MATCH);
$lastPath = '';
// iterate through all the results
foreach ($objRegexIterator as $arrMatches) {
$filename = $arrMatches[0];
$pos = strrpos($filename, DIRECTORY_SEPARATOR); // find position of last DIRECTORY_SEPARATOR
$path = substr($filename, 0, $pos); // path is everything before
$file = substr($filename, $pos + 1); // file is everything after
$myDir = substr($path, strrpos($path, DIRECTORY_SEPARATOR) + 1); // directory the file sits in
if ($lastPath !== $path) { // is the path the same as the last
// display page break and header
if ($lastPath !== '') {
echo "<br />\n";
echo "<br />\n";
}
echo $myDir ."<br />\n";
$lastPath = $path;
}
echo $file . " ";
}
I'm very basic when it comes to PHP.
With my website, I have a directory called "uploads"
Within "uploads" I have 3 folders "Example1" "Example2" and "Example3"
Within each of the folders, they contain images.
I need to know how to use php to create a navigation for every sub directory.
So that if I add a new folder "Example4" it will give a navigation like:
Select what section you're looking for:
Example1 | Example2 | Example3
and if I later add new folders add them to the navigation.
EX:
Example1 | Example2 | Example3 | Example4 | Example5
Then once they click the link to go into the folder, have a code that displays all the images in that folder.
So far I have:
<?php
$files = glob("uploads/*.*");
for ($i=0; $i<count($files); $i++)
{
$num = $files[$i];
echo '<img src="/'.$num.'">'."<p>";
}
?>
but it will only display the images in the upload directory, not the images in Example1 and so on.
How on earth would I go about doing this? I'm doing it for a school project and have two weeks to complete it, but I am so lost. I only have knowledge with CSS, HTML, and the only PHP I know is php includes, so any help would be appreciated.
Since it seems that you are familiar with globs a bit, here is an example using the "glob" function. You can see a basic working example of what you are looking for here:
http://newwebinnovations.com/glob-images/
Here is how I have the example set up:
There are two PHP files, one is index.php and the other is list-images.php.
There is also a folder for images two subfolders that have images inside of them.
index.php is the file that finds the folders in the images folder and places them in a list with links list-images.php which will display the images inside of the folder:
$path = 'images';
$folders = glob($path.'/*');
echo '<ul>';
foreach ($folders as $folder) {
echo '<li>'.$folder.'</li>';
}
echo '</ul>';
The links created above have a dynamic variable created that will pass in the link to the list-images.php page.
Here is the list-images.php code:
if (isset($_GET['folder'])) {
$folder = $_GET['folder'];
}
$singleImages = array();
foreach (glob($folder . '/*.{jpg,jpeg,png,gif}', GLOB_BRACE) as $image) {
$imageElements = array();
$imageElements['source'] = $image;
$singleImages[$image] = $imageElements;
}
echo '<ul>';
foreach ($singleImages as $image) {
echo '<li><img src="'.$image['source'].'" width="400" height="auto"></li>';
}
echo '</ul>';
The links created here will link you to the individual images.
To get files of every specific folder ,pass it throw a get variable that contains folder's name,an then scan this folder an show images ,url should be like this :
listImages.php?folderName=example1
To have menu like what you want :
<?php
$path = 'uploads/' ;
$results = scandir($path);
for ($i=0;$i<count($results);$i++ ) {
$result=$results[$i];
if ($result === '.' or $result === '..') continue;
if (is_dir($path . '/' . $result)) {
echo "<a href='imgs.php?folderName=$result'>$result</a> ";
}
if($i!=count($results)-1) echo '|'; //to avoid showing | in the last element
}
?>
And here is PHP page listImages that scan images of a specific folder :
<?php
if (isset($_GET['folderName'])) $folder=$_GET['folderName'];
$path = 'uploads/'.$folder.'/' ;
$images = glob($path . '*.{jpg,jpeg,png,gif}', GLOB_BRACE);
foreach ($images as $image) {
echo "<img src='$image' />";
}
?>
First of all, do read more PHP manual, for directory related: opendir, for files related: fopen
The following code is basically re-arranging the example code provided in opendir. What it does:
A scan_directory function to simply check if directory path is valid and is a directory, then proceed to do a recursive call if there's a child directory else just print out the file name.
The first if/else condition is just to ensure the base directory is valid.
I'll added ul and li to make it slightly more presentable.
$base_dir = 'upload';
if (is_dir($base_dir))
scan_directory($base_dir);
else
echo 'Invalid base directory. Please check your setting.';
// recursive function to check all dir
function scan_directory($path) {
if (is_dir($path)) {
if ($dir_handle = opendir($path)) {
echo '<ul>';
while (($file = readdir($dir_handle)) !== false) {
if ($file != '.' && $file != '..') {
if (is_dir($path . '/' . $file)) {
echo '<li>';
echo $file;
scan_directory($path . '/' . $file);
echo '</li>';
}
else
echo "<li>{$file}</li>";
}
}
echo '</ul>';
}
}
}
create image as subdirectory name with image name and save it in database
example:
subdirectory name: example2
image name: image.jpg
store image name in db as "example2/image.jpg"
I have the following which is fairly slow. How can I speed it up?
(it scans a directory and makes headers out of the foldernames and retrieves the pdf files from within and adds them to lists)
$directories= array_diff(scandir("../pdfArchive/subfolder", 0), array('..', '.'));
foreach ($directories as $v) {
echo "<h3>".$v."</h3>";
$current = array_diff(scandir("../pdfArchive/subfolder/".$v, 0), array('..', '.'));
echo "<ul style=\"list-style-image: url(/images/pdf.gif); margin-left: 20px;\">";
foreach ($current as $vone) {
echo "<li><a target=\"blank\" href=\"../pdfArchive/subfolder/".$vone."\">".str_replace(".pdf", "", $vone)."</a>";
echo "</li><br>";
}
echo "</ul>";
}
Don't use array_diff() to filter out current and parent directory, use something like DirectoryIterator or glob() and then test whether it's . or .. via an if statement
glob() has a flag that allows you to retrieve only directories for your loops
Profile your code to see exactly what lines/functions are executing slowly
I'm not sure how fast array_diff() is when the array is very large, isn't it faster to simply add a separate check and make sure that '.' and '..' is not the returned name?
Other than that, I can't see there being anything really wrong.
What did you test to consider the current approach slow?
Here is a snippet of code I use that I adapted from php.net. It is very basic and goes through a given directory and lists the files contained within.
// The # suppresses any errors, $dir is the directory path
if (($handle = #opendir($dir)) != FALSE) {
// Loop over directory contents
while (($file = readdir($handle)) !== FALSE) {
// We don't want the current directory (.) or parent (..)
if ($file != "." && $file != "..") {
var_dump($file);
if (!is_dir($dir . $file)) {
// $file is really a file
} else {
// $file is a directory
}
}
}
closedir($handle);
} else {
// Deal with it
}
You may adapt this further to recurse over subdirectories by using is_dir to identify folders as I have shown above.
This is somewhat similar to some index pages. When new file or folder is added to the directory, HTML page should display the newly created file/folder together with previous ones after it is being refreshed. (prefer in alphabatical order)
How to achieve this sort of functionality in PHP? Please provide sample coding as well. (and any references)
this is rather easy, here you go:
$files = scandir('./directory/to/list');
sort($files); // this does the sorting
foreach($files as $file){
echo''.$file.'';
}
this should give you a basic idea what to do.
Pretty much a direct rip from the manual:
<?php
$d = dir(".");
echo "Path: " . $d->path . "\n";
echo "<ul>";
while (false !== ($entry = $d->read())) {
echo "<li><a href='{$entry}'>{$entry}</a></li>";
}
echo "</ul>";
$d->close();
?>
I'm not sure how simple this would be, but I'm using a script which displays the files from a specific folder, however I'd like them to be displayed in alphabetical order, would it be hard to do this? Here's the code I'm using:
if ($handle = opendir($mainframe->getCfg( 'absolute_path' ) ."/images/store/")) {
while (false !== ($file = readdir($handle))) {
if ($file != "." && $file != "..") {
if (($file != "index.html")&&($file != "index.php")&&($file != "Thumbs.db")) {
$strExt = end(explode(".", $file));
if ($strExt == 'jpg') {
$Link = 'index.php?option=com_shop&task=deleteFile&file[]='.$file;
$thelist .= '<tr class="row0"><td nowrap="nowrap">'.$file.'</td>'."\n";
$thelist .= '<td align="center" class="order"><img src="/administrator/images/publish_x.png" width="16" height="16" alt="delete"></td></tr>'."\n";
}
}
}
}
closedir($handle);
}
echo $thelist;
:)
Instead of using readdir you could simply use scandir (documentation) which sorts alphabetically by default.
The return value of scandir is an array instead of a string, so your code would have to be adjusted slightly, to iterate over the array instead of checking for the final null return value. Also, scandir takes a string with the directory path instead of a file handle as input, the new version would look something like this:
foreach(scandir($mainframe->getCfg( 'absolute_path' ) ."/images/store/") as $file) {
// rest of the loop could remain unchanged
}
That code looks pretty messy. You can separate the directory traversing logic with the presentation. A much more concise version (in my opinion):
<?php
// Head of page
$it = new DirectoryIterator($mainframe->getCfg('absolute_path') . '/images/store/'));
foreach ($it as $file) {
if (preg_match('#\.jpe?g$#', $file->getFilename()))
$files[] = $file->getFilename();
}
sort($files);
// Further down
foreach ($files as $file)
// display links to delete file.
?>
You don't even need to worry about opening or closing the handle, and since you're checking the filename with a regular expression, you don't need any of the explode or conditional checks.
I like Glob
It makes directory reading a snap as it returns an array that's easily sortable:
<?php
$files = glob("*.txt");
sort($files);
foreach ($files as $filename) {
echo "$filename size " . filesize($filename) . "\n";
}
?>
If you're using Joomla1.5 you should be using the defined constant JPATH_BASE instead of
$mainframe->getCfg( 'absolute_path' )
If this is a Joomla extension that you will distribute, don't use scandir() as it is PHP5 only.
The best thing to do is to use the Joomla API. It has a classes for directory and file access that is layered to do this over different networks and protocols. So the file system can be over FTP for example, and the classes can be extended for any network/protocol.
jimport( 'joomla.filesystem.folder' );
$files = JFolder::files(JPATH_BASE."/images/store/");
sort($files);
foreach($files as $file) {
// do your filtering and other task
}
You can also pass a regular expression as the second parameter to JFolder::files() that filters the files you receive.
You also don't want to use URL literals like /administrator/ since they can be changed.
use the JURI methods like:
JURI::base();
If you want to make sure of the Joomla CSS classes in the tables, for:
'<tr class="row0">'
use:
'<tr class="row'.($i&1).'">'
where $i is the number of iterations. This gives you a sequence of alternating 0s and 1s.
if we have PHP built in functions, always use it, they are faster.
use glob instead of traversing folders, if it fits for your needs.
$folder_names = array();
$folder_names = glob( '*', GLOB_ONLYDIR + GLOB_MARK + GLOB_NOSORT );
returs everything in the current directory, use chdir() before calling it
remove the GLOB_ONLYDIR to include files too ( . would be only files )
GLOB_MARK is for adding a slash to folders names
Remove GLOB_NOSORT not to sort the array