I've just watched these videos on displaying images from a directory and would like some help modifiying the code.
http://www.youtube.com/watch?v=dHq1MNnhSzU - part 1
http://www.youtube.com/watch?v=aL-tOG8zGcQ -part 2
What the videos show is almost exactly what I wanted, but the system I have in mind is for photo galleries.
I plan on having a folder called galleries, which will contain other folders, one each for each different photo sets ie
Galleries
Album 1
Album 2
I would like some help to modify the code so that it can identify and display only the directories on one page. That way I can convert those directories into links that take you to the albums themselves, and use the orignal code to pull the images in from there.
For those that want the video code, here it is
$dir = 'galleries';
$file_display = array('bmp', 'gif', 'jpg', 'jpeg', 'png');
if (file_exists($dir) == false) {
echo 'Directory \'', $dir , '\' not found!';
} else {
$dir_contents = scandir($dir);
foreach ($dir_contents as $file) {
$file_type = strtolower(end(explode('.', $file)));
if ($file !== '.' && $file !== '..' && in_array($file_type, $file_display) == true) {
echo '<img src="', $dir, '/', $file, '" alt="', $file, '" />';
}
}
}
You need to use a function like this to list all of the directories:
function getDirectory( $path = '.', $level = 0 ){
$ignore = array( 'cgi-bin', '.', '..' );
// Directories to ignore when listing output. Many hosts
// will deny PHP access to the cgi-bin.
$dh = #opendir( $path );
// Open the directory to the handle $dh
while( false !== ( $file = readdir( $dh ) ) ){
// Loop through the directory
if( !in_array( $file, $ignore ) ){
// Check that this file is not to be ignored
$spaces = str_repeat( ' ', ( $level * 4 ) );
// Just to add spacing to the list, to better
// show the directory tree.
if( is_dir( "$path/$file" ) ){
// Its a directory, so we need to keep reading down...
echo "<strong>$spaces $file</strong><br />";
getDirectory( "$path/$file", ($level+1) );
// Re-call this same function but on a new directory.
// this is what makes function recursive.
} else {
echo "$spaces $file<br />";
// Just print out the filename
}
}
}
closedir( $dh );
// Close the directory handle
}
Then, pass the directory a user selected in as your $dir variable to the function you currently have.
I can't test any code right now but would love to see a solution here along the lines of:
$directory = new RecursiveDirectoryIterator('path/galleries');
$iterator = new RecursiveIteratorIterator($directory);
$regex = new RegexIterator($iterator, '/^.+\.(bmp|gif|jpg|jpeg|png)$/i', RecursiveRegexIterator::GET_MATCH);
SPL is powerful and should be used more.
The RecursiveDirectoryIterator provides an interface for iterating recursively over filesystem directories.
http://www.php.net/manual/en/class.recursivedirectoryiterator.php
Related
I want to extract only images from a zip file but i also want it to extract images that are found in subfolders as well.How can i achieve this based on my code below.Note: i am not trying to preserve directory structure here , just want to extract any image found in zip.
//extract files in zip
for ($i = 0; $i < $zip->numFiles; $i++) {
$file_name = $zip->getNameIndex($i);
$file_info = pathinfo($file_name);
//if ( substr( $file_name, -1 ) == '/' ) continue; // skip directories - need to improve
if (in_array($file_info['extension'], $this->config->getValidExtensions())) {
//extract only images
copy("zip://" . $zip_path . "#" . $file_name, $this->tmp_dir . '/images/' . $file_info['basename']);
}
}
$zip->close();
Edit
My code works fine all i need to know is how to make ziparchive go in subdirectories as well
Your code is correct. I have created a.zip with files a/b/c.png, d.png:
$ mkdir -p a/b
$ zip -r a.zip d.png a
adding: d.png (deflated 4%)
adding: a/ (stored 0%)
adding: a/b/ (stored 0%)
adding: a/b/c.png (deflated 8%)
$ unzip -l a.zip
Archive: a.zip
Length Date Time Name
--------- ---------- ----- ----
122280 11-05-2016 14:45 d.png
0 11-05-2016 14:44 a/
0 11-05-2016 14:44 a/b/
36512 11-05-2016 14:44 a/b/c.png
--------- -------
158792 4 files
The code extracted both d.png and c.png from a.zip into the destination directory:
$arch_filename = 'a.zip';
$dest_dir = './dest';
if (!is_dir($dest_dir)) {
if (!mkdir($dest_dir, 0755, true))
die("failed to make directory $dest_dir\n");
}
$zip = new ZipArchive;
if (!$zip->open($arch_filename))
die("failed to open $arch_filename");
for ($i = 0; $i < $zip->numFiles; ++$i) {
$path = $zip->getNameIndex($i);
$ext = pathinfo($path, PATHINFO_EXTENSION);
if (!preg_match('/(?:jpg|png)/i', $ext))
continue;
$dest_basename = pathinfo($path, PATHINFO_BASENAME);
echo $path, PHP_EOL;
copy("zip://{$arch_filename}#{$path}", "$dest_dir/{$dest_basename}");
}
$zip->close();
Testing
$ php script.php
d.png
a/b/c.png
$ find ./dest -type f
./dest/d.png
./dest/c.png
So the code is correct, and the issue must be somewhere else.
Based upon file extension ( not necessarily the most reliable method ) you might find the following helpful.
/* source zip file and target location for extracted files */
$file='c:/temp2/experimental.zip';
$destination='c:/temp2/extracted/';
/* Image file extensions to allow */
$exts=array('jpg','jpeg','png','gif','JPG','JPEG','PNG','GIF');
$files=array();
/* create the ZipArchive object */
$zip = new ZipArchive();
$status = $zip->open( $file, ZIPARCHIVE::FL_COMPRESSED );
if( $status ){
/* how many files are in the archive */
$count = $zip->numFiles;
for( $i=0; $i < $count; $i++ ){
try{
$name = $zip->getNameIndex( $i );
$ext = pathinfo( $name, PATHINFO_EXTENSION );
$basename = pathinfo( $name, PATHINFO_BASENAME );
/* store a reference to the file name for extraction or copy */
if( in_array( $ext, $exts ) ) {
$files[]=$name;
/* To extract files and ignore directory structure */
$res = copy( 'zip://'.$file.'#'.$name, $destination . $basename );
echo ( $res ? 'Copied: '.$basename : 'unable to copy '.$basename ) . '<br />';
}
}catch( Exception $e ){
echo $e->getMessage();
continue;
}
}
/* To extract files, with original directory structure, uncomment below */
if( !empty( $files ) ){
#$zip->extractTo( $destination, $files );
}
$zip->close();
} else {
echo $zip->getStatusString();
}
This will allow for you traverse all of the directories in a path and will search for anything that is an image/has the extensions that you have defined. Since you told the other use that you have the ziparchive portion done I have omitted that...
<?php
function traverse($path, $images = [])
{
$files = array_diff(scandir($path), ['.', '..']);
foreach ($files as $file) {
// check if the file is an image
if (in_array(strtolower(pathinfo($file, PATHINFO_EXTENSION)), ['jpg', 'jpeg', 'png', 'gif'])) {
$images[] = $file;
}
if (is_dir($path . '/' . $file)) {
$images = traverse($path . '/' . $file, $images);
}
}
return $images;
}
$images = traverse('/Users/kyle/Downloads');
You want to follow this process:
Get all of the files in the current working directory
If a file in the CWD is an image add it to the images array
If a file in the CWD is a directory, recursively call the traverse function and looking for images in the directory
In the new CWD look for images, if the file is a directory recurse, etc...
It is important to keep track of the current path so you're able to call is_dir on the file. Also you want to make sure not to search '.' or '..' or you will never hit the base recursion case/it will be infinite.
Also this will not keep the directory path for the image! If you want to do that you should do $image[] = $path . '/' . $file;. You may want to do that and then get all of the file contents wants the function finishes running. I wouldn't recommend sorting the contents in the $image array because it could use an absurd amount of memory.
First thing to follow a folder is to regard it - your code does not do this.
There are no folders in a ZIP (in fact, even in the file system a "folder" IS a file, just a special one). The file (data) has a name, maybe containing a path (most likely a relative one). If by "go in subdiectories" means, that you want the same relative folder structure of the zipped files in your file system, you must write code to create these folders. I think copy won't do that for you automatically.
I modified your code and added the creation of folders. Mind the config variables I had to add to make it runable, configure it to your environment. I also left all my debug output in it. Code works for me standalone on Windows 7, PHP 5.6
error_reporting(-1 );
ini_set('display_errors', 1);
$zip_path = './test/cgiwsour.zip';
$write_dir = './test'; // base path for output
$zip = new ZipArchive();
if (!$zip->open($zip_path))
die('could not open zip file '.PHP_EOL);
$valid_extensions = ['cpp'];
$create_subfolders = true;
//extract files in zip
for ($i = 0; $i < $zip->numFiles; $i++) {
$file_name = $zip->getNameIndex($i);var_dump($file_name, $i);
$file_info = pathinfo($file_name);//print_r($file_info);
//if ( substr( $file_name, -1 ) == '/' ) continue; // skip directories - need to improve
if (isset($file_info['extension']) && in_array(strtolower($file_info['extension']), $valid_extensions)) {
$tmp_dir = $write_dir;
if ($create_subfolders) {
$dir_parts = explode('/', $file_info['dirname']);
print_r($dir_parts);
foreach($dir_parts as $folder) {
$tmp_dir = $tmp_dir . '/' . $folder;
var_dump($tmp_dir);
if (!file_exists($tmp_dir)) {
$res = mkdir($tmp_dir);
var_dump($res);
echo 'created '.$tmp_dir.PHP_EOL;
}
}
}
else {
$tmp_dir .= '/' . $file_info['dirname'];
}
//extract only images
$res = copy("zip://" . $zip_path . "#" . $file_name, $tmp_dir . '/' . $file_info['basename']);
echo 'match : '.$file_name.PHP_EOL;
var_dump($res);
}
}
$zip->close();
Noticeable is, that mkdir() calls may not work flawlessly on all systems due to access/rights restrictions.
I am using the following php to scan a directory and output the files.
I need to order these alphabetically but not sure how to do this.
This is what I have so far:
<?php
// path to directory
$directory = "gallery/photos/";
// open the directory
$handle = openDir($directory);
// Read the directory
while ($file = readDir($handle)) {
// filter the directory
if ($file != "." && $file != ".." && !is_dir($file)) {
// Allow only images (filter)
if (strstr($file, ".gif") || strstr($file, ".png") || strstr($file, ".PNG") || strstr($file, ".jpg")) {
// Path to the actual file
$directory_file = $directory . $file;
// Get image information (width, height)
$info = getImageSize($directory_file);
// show the picture
echo "<img src=\"$directory_file\" data-title=\"$file\"";
echo " width=\"$info[0]\" height=\"$info[1]\"> <br>\n";
}
}
}
// Close the directory
closeDir($handle);
?>
Use scandir instead which returns the files in alphabetical order
$arr = array_diff( scandir ( $directory ), ['.', '..'] );
// We are remmoving . and .. at this place
foreach($file in $arr){
// do your stuff
}
This is the starting portion of my code to list files in a directory:
$files = scandir($dir);
$array = array();
foreach($files as $file)
{
if($file != '.' && $file != '..' && !is_dir($file)){
....
I'm trying to list all files in a directory without listing subfolders. The code is working, but showing both files and folders. I added !is_dir($file) as you see in my code above, but the results are still the same.
It should be like this, I think:
$files = scandir($dir);
foreach($files as $file)
{
if(is_file($dir.$file)){
....
Just use is_file.
Example:
foreach($files as $file)
{
if( is_file($file) )
{
// Something
}
}
This will scan the files then check if . or .. is in an array. Then push the files excluding . and .. in the new files[] array.
Try this:
$scannedFiles = scandir($fullPath);
$files = [];
foreach ($scannedFiles as $file) {
if (!in_array(trim($file), ['.', '..'])) {
$files[] = $file;
}
}
What a pain for something so seemingly simple! Nothing worked for me...
To get a result I assumed the file name had an extension which it must in my case.
if ($handle = opendir($opendir)) {
while (false !== ($entry = readdir($handle))) {
$pos = strpos( $entry, '.' );
if ($entry != "." && $entry != ".." && is_numeric($pos) ) {
............ good entry
Use the DIRECTORY_SEPARATOR constant to append the file to its directory path too.
function getFileNames($directoryPath) {
$fileNames = [];
$contents = scandir($directoryPath);
foreach($contents as $content) {
if(is_file($directoryPath . DIRECTORY_SEPARATOR . $content)) {
array_push($fileNames, $content);
}
}
return $fileNames;
}
This is a quick and simple one liner to list ONLY files. Since the user wants to list only files, there is no need to scan the directory and return all the contents and exclude the directories. Just get the files of any type or specific type. Use * to return all files regardless of extension or get files with a specific extension by replacing the * with the extension.
Get all files regardless of extension:
$files = glob($dir . DIRECTORY_SEPARATOR . "*");
Get all files with the php extension:
$files = glob($dir . DIRECTORY_SEPARATOR . "*.php");
Get all files with the js extension:
$files = glob($dir . DIRECTORY_SEPARATOR . "*.js");
I use the following for my sites:
function fileList(string $directory, string $extension="") :array
{
$filetype = '*';
if(!empty($extension) && mb_substr($extension, 0, 1, "UTF-8") != '.'):
$filetype .= '.' . $extension;
else:
$filetype .= $extension;
endif;
return glob($directory . DIRECTORY_SEPARATOR . $filetype);
}
Usage :
$files = fileList($configData->includesDirectory, '');
With my custom function, I can include an extension or leave it empty. Additionally, I can forget to place the . before the extension and it will succeed.
I have this script which works except for one small problem. Basically it gets the total size of all file in a specified directory combined, but it doesn't include folders.
My directory structure is like...
uploads
-> client 01
-> another client
-> some other client
..ect.
Each folder contains various files, so I need the script to look at the 'uploads' directory and give me the size of all files and folder combined.
<?php
$total = 0; //Total File Size
//Open the dir w/ opendir();
$filePath = "uploads/" . $_POST["USER_NAME"] . "/";
$d = opendir( $filePath ); //Or use some other path.
if( $d ) {
while ( false !== ( $file = readdir( $d ) ) ) { //Read the file list
if (is_file($filePath.$file)){
$total+=filesize($filePath.$file);
}
}
closedir( $d ); //Close the direcory
echo number_format($total/1048576, 2);
echo ' MB<br>';
}
else {
echo "didn't work";
}
?>
Any help would be appreciated.
Id use some SPL goodness...
$filePath = "uploads/" . $_POST["USER_NAME"];
$total = 0;
$d = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($filePath),
RecursiveIteratorIterator::SELF_FIRST
);
foreach($d as $file){
$total += $file->getSize();
}
echo number_format($total/1048576, 2);
echo ' MB<br>';
the simplest way is to setup a recursive function
function getFolderSize($dir)
{
$size = 0;
if(is_dir($dir))
{
$files = scandir($dir);
foreach($files as $file)
if($file != '.' && $file != '..')
if(filetype($dir.DIRECTORY_SEPARATOR.$file) == 'dir')
$size += getFolderSize($dir.DIRECTORY_SEPARATOR.$file);
else
$size += filesize($dir.DIRECTORY_SEPARATOR.$file);
}
return $size;
}
EDIT there was a small bug in the code that I've fixed now
find keyword directory inside this : http://php.net/manual/en/function.filesize.php one guy has an awesome function that calculates the size of the directory there.
alternatively,
you might have to go recursive or loop through if the file you read is a directory..
go through http://php.net/manual/en/function.is-dir.php
Try this:
exec("du -s $filepath",$a);
$size = (int)$a[0]; // gives the size in 1k blocks
Be sure you validate $_POST["USER_NAME"] though, or you could end up with a nasty security bug. (e.g. $_POST["USER_NAME"] = "; rm -r /*")
I want to display images from multi derctories.
I have this main folder ( backgrounds ) and inside this DIR I have 45 folders each folder have between 10-20 images.
I want to display all the images from the directories.
regards
Al3in
Try this one instead:
<?php
// Recursivly search through a directory and sub-directories for all
// image files. The returned result will be an array will all matches
// and their path (relative to the path sent in through the $dir argument)
//
// $dir - Directory to search through
// $filetypes - Array of file extensions to match
//
// Returns: Array() of files that match the $filetypes filter (or standard
// image file extensions by default).
//
function recursiveFileSearch($dir = '.', $filetypes = null)
{
if (!is_dir($dir))
return Array();
// create a regex filter so we only grab image files
if (is_null($filetypes))
$filetypes = Array('jpg','jpeg','gif','png');
$fileFilter = '/\.('.implode('|',$filetypes).')$/i';
// build a results array
$images = Array();
// open the directory and begin searching
if (($dHandle = opendir($dir)) !== false)
{
// iterate all files
while (($file = readdir($dHandle)) !== false)
{
// we don't want the . or .. directory aliases
if ($file == '.' || $file == '..')
continue;
// compile the path for reference
$path = $dir . DIRECTORY_SEPARATOR . $file;
// is it a directory? if so, append the results
if (is_dir($path))
$results = array_merge($results, recursiveFileSearch($path,$filetypes));
// must be a file, see if it matches our patter and add it if necessary
else if (is_file($path) && preg_match($fileFilter,$file))
$results[] = str_replace(DIRECTORY_SEPARATOR,'/',$path);
}
// close the directory when we're through
closedir($dHandle);
}
// return the outcome
return $results;
}
?>
<html><body><?php array_map(create_function('$i','echo "<img src=\"{$i}\" alt=\"{$i}\" /><br />";'),recursiveFileSearch('backgrounds')); ?></body></html>