I have a huge ammount of photos that need sorting through. I need to know the dimensions of each photo in order to know or it needs re-sizing. As a programmer I'm convinced there must be a quicker way of doing this.
I got quite far. The following code reads the dir and all the sub dirs. But the moment I try to extract the dimensions the loop halts at 8% of all the pictures that need checking. Could it be PHP is not allowed to do more calculations? What is going on!?
This is how far I got:
checkDir('dir2Check');
function checkDir($dir, $level = 0) {
if ($handle = opendir($dir)) {
while (false !== ($entry = readdir($handle))) {
if (!preg_match('/\./i', $entry)) {
echo echoEntry("DIR\\", $entry, $level);
checkDir($dir.'/'.$entry, $level+1);
} else {
if ($entry != "." && $entry != ".." && $entry != ".DS_Store") {
// if I comment the next line. It loops through all the files in the directory
checkFile($entry, $dir.'/'.$entry, $level);
// this line echoes so I can check or it really read all the files in case I comment the proceeding line
//echo echoEntry("FILE", $entry, $level);
}
}
}
$level--;
closedir($handle);
}
}
// Checks the file type and lets me know what is happening
function checkFile($fileName, $fullPath, $level) {
if (preg_match('/\.gif$/i', $fullPath)) {
$info = getImgInfo(imagecreatefromgif($fullPath));
} else if (preg_match('/\.png$/i', $fullPath)) {
$info = getImgInfo(imagecreatefrompng($fullPath));
} else if (preg_match('/\.jpe?g$/i', $fullPath)){
$info = getImgInfo(imagecreatefromjpeg($fullPath));
} else {
echo "XXX____file is not an image [$fileName]<br />";
}
if ($info) {
echo echoEntry("FILE", $fileName, $level, $info);
}
}
// get's the info I need from the image and frees up the cache
function getImgInfo($srcImg) {
$width = imagesx($srcImg);
$height = imagesy($srcImg);
$info = "Dimensions:".$width."X".$height;
imagedestroy($srcImg);
return $info;
}
// this file formats the findings of my dir-reader in a readable way
function echoEntry($type, $entry, $level, $info = false) {
$output = $type;
$i = -1;
while ($i < $level) {
$output .= "____";
$i++;
}
$output .= $entry;
if ($info) {
$output .= "IMG_INFO[".$info."]";
}
return $output."<br />";
}
The following does similar to what you do, only it's using php's DirectoryIterator which in my humble opinion is cleaner and more OOP-y
<?php
function walkDir($path = null) {
if(empty($path)) {
$d = new DirectoryIterator(dirname(__FILE__));
} else {
$d = new DirectoryIterator($path);
}
foreach($d as $f) {
if(
$f->isFile() &&
preg_match("/(\.gif|\.png|\.jpe?g)$/", $f->getFilename())
) {
list($w, $h) = getimagesize($f->getPathname());
echo $f->getFilename() . " Dimensions: " . $w . ' ' . $h . "\n";
} elseif($f->isDir() && $f->getFilename() != '.' && $f->getFilename() != '..') {
walkDir($f->getPathname());
}
}
}
walkDir();
You can simply use getimagesize()
list($width, $height) = getimagesize($imgFile);
Related
I want to ask - How can I return/make array with-in a foreach loop?
Here is my code
function getAllUsers() {
$dir = "users/";
$fl = scandir($dir);
$cnt = 0;
foreach (scandir($dir) as $fl) {
if ($fl !== '.') {
if ($fl !== '..') {
if ($fl !== 'index.php') {
$pr = $fl;
$fl1 = scandir($dir . '/' . $fl);
$cnt++;
return $fl1[3]; //Here I want a array for file inside 'users\'.
}
}
}
}
}
Thanks for giving answer.
Basically: you can not.
upon using return, the current function returns the value and stops execution.
return is by definition the end of the function.
but you can save the data you want to return in an array and then return the whole thing:
function getAllUsers() {
$dir = "users/";
$fl = scandir($dir);
$cnt = 0;
$result = []; //initiating the array
foreach (scandir($dir) as $fl) {
if ($fl !== '.') {
if ($fl !== '..') {
if ($fl !== 'index.php') {
$pr = $fl;
$fl1 = scandir($dir . '/' . $fl);
$cnt++;
$result[] = $fl1[3]; //adding your value to the array
}
}
}
}
return $result;
}
Edit: If your PHP-Version mucks about the $result = []; you can use the "old" style $result = array(); instead
Generators: Solution for PHP >= 5.5.
If you want the function to return a value for each element in the loop back from the function use a generator:
/**
* #return Generator|Iterator
*/
function getAllUsers() {
$dir = "users/";
$fl = scandir($dir);
$cnt = 0;
foreach (scandir($dir) as $fl) {
if ($fl !== '.') {
if ($fl !== '..') {
if ($fl !== 'index.php') {
$pr = $fl;
$fl1 = scandir($dir . '/' . $fl);
$cnt++;
yield $fl1[3]; //Here I want a array for file inside 'users\'.
}
}
}
}
}
// Loop over
foreach (getAllUsers() as $file) {
}
// Or one at a time
$generator = getAllUsers();
$file1 = $generator->current();
The other solutions here are more feasible however, this solution is mostly useful for implementing the IteratorAggregate interface, or creating co-routines.
You can achieve this by using an array. like below..
function getAllUsers() {
$dir = "users/";
$fl = scandir($dir);
$cnt = 0;
$array = array();
foreach (scandir($dir) as $fl) {
if ($fl !== '.') {
if ($fl !== '..') {
if ($fl !== 'index.php') {
$pr = $fl;
$fl1 = scandir($dir . '/' . $fl);
$cnt++;
$array[$fl] = $fl1[3]; //Push values in array for each user.
}
}
}
}
return $array;
}
Hope this will help
I've a simple problem of copying a a php folder to some directories, bu the problem is I can't the solution for that, the idea is that I've an Online Manga Viewer script, and what I want to do is I want to add comments page to every chapter, the I dea that I came with, is, I create a separate comments page file and once a new chapter added the the comments file will be copied to the folder of the chapter :
Description Image:
http://i.stack.imgur.com/4wYE0.png
What I to know is how can I do it knowing that I will use Disqus commenting System.
Functions used in the script:
function omv_get_mangas() {
$mangas = array();
$dirname = "mangas/";
$dir = #opendir($dirname);
if ($dir) {
while (($file = #readdir($dir)) !== false) {
if (is_dir($dirname . $file . '/') && ($file != ".") && ($file != "..")) {
$mangas[] = $file;
}
}
#closedir($dir);
}
sort($mangas);
return $mangas;
}
function omv_get_chapters($manga) {
global $omv_chapters_sorting;
$chapters = array();
$chapters_id = array();
$dirname = "mangas/$manga/";
$dir = #opendir($dirname);
if ($dir) {
while (($file = #readdir($dir)) !== false) {
if (is_dir($dirname . $file . '/') && ($file != ".") && ($file != "..")) {
$chapter = array();
$chapter["folder"] = $file;
$pos = strpos($file, '-');
if ($pos === false) {
$chapter["number"] = $file;
} else {
$chapter["number"] = trim(substr($file, 0, $pos - 1));
$chapter["title"] = trim(substr($file, $pos + 1));
}
$chapters_id[] = $chapter["number"];
$chapters[] = $chapter;
}
}
#closedir($dir);
}
array_multisort($chapters_id, $omv_chapters_sorting, $chapters);
return $chapters;
}
function omv_get_chapter_index($chapters, $chapter_number) {
$i = 0;
while (($i < count($chapters)) && ($chapters[$i]["number"] != $chapter_number)) $i++;
return ($i < count($chapters)) ? $i : -1;
}
function omv_get_pages($manga, $chapter) {
global $omv_img_types;
$pages = array();
$dirname = "mangas/$manga/$chapter/";
$dir = #opendir($dirname);
if ($dir) {
while (($file = #readdir($dir)) !== false) {
if (!is_dir($dirname . $file . '/')) {
$file_extension = strtolower(substr($file, strrpos($file, ".") + 1));
if (in_array($file_extension, $omv_img_types)) {
$pages[] = $file;
}
}
}
#closedir($dir);
}
sort($pages);
return $pages;
}
/*function add_chapter_comment($dirname){
$filename = $dirname.'comments.php';
if (file_exists($filename)) {
} else {
copy('comments.php', .$dirname.'comments.php');
}
}*/
function omv_get_previous_page($manga_e, $chapter_number_e, $current_page, $previous_chapter) {
if ($current_page > 1) {
return $manga_e . '/' . $chapter_number_e . '/' . ($current_page - 1);
} else if ($previous_chapter) {
$pages = omv_get_pages(omv_decode($manga_e), $previous_chapter["folder"]);
return $manga_e . '/' . omv_encode($previous_chapter["number"]) . '/' . count($pages);
} else {
return null;
}
}
function omv_get_next_page($manga_e, $chapter_number_e, $current_page, $nb_pages, $next_chapter) {
if ($current_page < $nb_pages) {
return $manga_e . '/' . $chapter_number_e . '/' . ($current_page + 1);
} else if ($next_chapter) {
return $manga_e . '/' . omv_encode($next_chapter["number"]);
} else {
return null;
}
}
function omv_get_image_size($img) {
global $omv_img_resize, $omv_preferred_width;
$size = array();
$imginfo = getimagesize($img);
$size["width"] = intval($imginfo[0]);
$size["height"] = intval($imginfo[1]);
if ($omv_img_resize) {
if ($size["width"] > $omv_preferred_width) {
$size["height"] = intval($size["height"] * ($omv_preferred_width / $size["width"]));
$size["width"] = $omv_preferred_width;
}
}
return $size;
}
And thanks for all of you!
Include the following line in all of your pages in a small php statement, if it covers two folder paths, use this. Which I think in your case it does.
<?php
include('../../header.php');
?>
And then save this in the main root directory. Which in your diagram is called "Main Folder"
I was looking at RecursiveDirectoryIterator and glob to say
"return me a list of files (in an array) based on the extension (for example) .less. Oh and look in all child, grandchild and so on and so forth, excluding . and .. until you find all files matching."
But I am not sure the best approach to create a recursive function that keeps going well beyond the grand child.
What I have is a mess, its worked for two years - but now I need to refactor and change it up:
public function get_directory_of_files($path, $filename, $extension) {
if (!is_dir($path)) {
throw new AisisCore_FileHandling_FileException("Could not find said path: " . $path);
}
if (file_exists($filename)) {
$handler = opendir($path);
while ($file = readdir($handler)) {
if ($file != "." && $file != "..") {
$this->package_files [] = $file;
$count = count($this->package_files);
for ($i = 0; $i < $count; $i++) {
if (substr(strrchr($this->package_files [$i], '.'), 1) == $extension) {
if ($this->package_files [$i] == $filename) {
$this->files_got_back = $this->package_files [$i];
}
}
}
}
}
}
return $this->_files_got_back;
}
This requires a file name to be passed in and thats not really my thing to do any more. So how can I re-write this function to do the above "pseudo code"
This function recursively finds files with a matching ending string
function getDirectoryContents($directory, $extension)
{
$extension = strtolower($extension);
$files = array();
$it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory));
while($it->valid())
{
if (!$it->isDot() && endsWith(strtolower($it->key()), $extension))
{
array_push($files, $it->key());
}
$it->next();
}
return $files;
}
function endsWith($haystack, $needle)
{
return $needle === "" || substr($haystack, -strlen($needle)) === $needle;
}
Used like so
print_r(getDirectoryContents('folder/', '.php'));
It converts the extension to lowercase to compare against
Take a look at this code:
<?php
class ex{
private function get_files_array($path,$ext, &$results){ //&to ensure it's a reference... but in php obj are passed by ref.
if (!is_dir($path)) {
//throw new AisisCore_FileHandling_FileException("Could not find said path: " . $path);
}
if ($dir = opendir($path)) {
$extLength = strlen($ext);
while (false !== ($file = readdir($dir))) {
if ($file != '.' && $file != '..'){
if (is_file($path.'/'.$file) && substr($file,-$extLength) == $ext){
$results[] = $path . '/' . $file; //it's a file and the correct extension
}
elseif (is_dir($path . '/'. $file)){
$this->get_files_array($path.'/'.$file, $ext, $results); //it's a dir
}
}
}
}else{
//unable to open dir
}
}
public function get_files_deep($path,$ext){
$results = array();
$this->get_files_array($path,$ext,$results);
return $results;
}
}
$ex = new ex();
var_dump($ex->get_files_deep('_some_path','.less'));
?>
It will retrieve all the files with the matching extension in the path and it's sub directories.
I hope it's what you need.
What is the best way to get the size of a directory in PHP? I'm looking for a lightweight way to do this since the directories I'll use this for are pretty huge.
There already was a question about this on SO, but it's three years old and the solutions are outdated.(Nowadays fopen is disabled for security reasons.)
Is the RecursiveDirectoryIterator available to you?
$bytes = 0;
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir));
foreach ($iterator as $i)
{
$bytes += $i->getSize();
}
You could try the execution operator with the unix command du:
$output = du -s $folder;
FROM: http://www.darian-brown.com/get-php-directory-size/
Or write a custom function to total the filesize of all the files in the directory:
function getDirectorySize($path)
{
$totalsize = 0;
$totalcount = 0;
$dircount = 0;
if($handle = opendir($path))
{
while (false !== ($file = readdir($handle)))
{
$nextpath = $path . '/' . $file;
if($file != '.' && $file != '..' && !is_link ($nextpath))
{
if(is_dir($nextpath))
{
$dircount++;
$result = getDirectorySize($nextpath);
$totalsize += $result['size'];
$totalcount += $result['count'];
$dircount += $result['dircount'];
}
else if(is_file ($nextpath))
{
$totalsize += filesize ($nextpath);
$totalcount++;
}
}
}
}
closedir($handle);
$total['size'] = $totalsize;
$total['count'] = $totalcount;
$total['dircount'] = $dircount;
return $total;
}
I'd like to randomly load images from a directory and have a button somewhere that refreshes the entire page. Here's the current code I have now:
<?php
$a = array();
$dir = '../public/wp-content/uploads/2012/01';
if ($handle = opendir($dir)) {
while (false !== ($file = readdir($handle))) {
if (preg_match("/\.png$/", $file)) $a[] = $file;
elseif (preg_match("/\.jpg$/", $file)) $a[] = $file;
elseif (preg_match("/\.jpeg$/", $file)) $a[] = $file;
}
closedir($handle);
}
foreach ($a as $i) {
echo "<img src='" . $dir . '/' . $i . "' />";
}
?>
The problem is it loads all 400,000 images at once. I only want 30 to load. 30 random images from the directory. I tried looking up some code such as modifying the above to this:
<?php
$a = array();
$dir = '../public/wp-content/uploads/2012/01';
if ($handle = opendir($dir)) {
while (false !== ($file = readdir($handle))) {
if (preg_match("/\.png$/", $file)) $a[] = $file;
elseif (preg_match("/\.jpg$/", $file)) $a[] = $file;
elseif (preg_match("/\.jpeg$/", $file)) $a[] = $file;
}
closedir($handle);
}
foreach ($a as $i) {
echo "<img src='" . $dir . '/' . $i . "' />";
if (++$i == 2) break;
}
?>
But it seems to do absolutely nothing.. So if someone can help me get 30 random photos from that directory to load and have some type of reload button, that would be of great help.
Thank you in advance
Here is my solution with a cache:
<?php
define('CACHE_FILE', 'mycache.tmp');
define('CACHE_TIME', 20); // 20 seconds (for testing!)
define('IMG_COUNT', 30);
define('IMG_DIR', '../public/wp-content/uploads/2012/01');
/**
* Loads the list (an array) from the cache
* Returns FALSE if the file couldn't be opened or the cache was expired, otherwise the list (as an array) will be returned.
*/
function LoadListFromCache($cacheFile, $cacheTime)
{
if ( file_exists($cacheFile) )
{
$fileHandle = fopen($cacheFile, 'r');
if ( !$fileHandle )
return false;
// Read timestamp (separated by "\n" from the content)
$timestamp = intval( fgets($fileHandle) );
fclose($fileHandle);
// Expired?
if ( $timestamp+$cacheTime > time() )
return false;
else
{
// Unserialize the content!
$content = file_get_contents($cacheFile);
$content = substr( $content, strpos($content, "\n") );
$list = unserialize($content);
return $list;
}
}
return false;
}
/**
* Caches the passed array
* Returns FALSE if the file couldn't be opened, otherwise TRUE.
*/
function SaveListToCache($cacheFile, $list)
{
$fileHandle = fopen($cacheFile, 'w');
if ( $fileHandle === FALSE ) return false;
fwrite($fileHandle, time());
fwrite($fileHandle, "\n");
fwrite($fileHandle, serialize($list));
fclose($fileHandle);
return true;
}
/**
* Generates the list of all image files (png, jpg, jpeg) and caches it.
* Returns the list as an array.
*/
function GenerateList()
{
$a = array();
$dir = IMG_DIR;
if ($handle = opendir($dir))
{
while (false !== ($file = readdir($handle)))
{
if (preg_match("/\.png$/", $file)) $a[] = $file;
elseif (preg_match("/\.jpg$/", $file)) $a[] = $file;
elseif (preg_match("/\.jpeg$/", $file)) $a[] = $file;
}
closedir($handle);
}
SaveListToCache(CACHE_FILE, $a);
return $a;
}
function GetRandomImages($list, $count)
{
$listCount = count($list);
$randomEntries = array();
for ($i=0; $i<$count; $i++)
{
$randomEntries[] = $list[ rand(0, $listCount) ];
}
return $randomEntries;
}
// This code will execute the other functions!
$list = LoadListFromCache(CACHE_FILE, CACHE_TIME);
if ( $list === FALSE )
{
$list = GenerateList();
}
$images = GetRandomImages($list, IMG_COUNT);
foreach ($images as $image)
{
echo '<img src="', IMG_DIR.DIRECTORY_SEPARATOR.$image, '" />';
}
If you have 400,000 images then I think reading the entire directory everytime is going to be an expensive means of showing random images. I would use a database instead and store the file paths in it.
If you want to use your existing code then think of it this way. You have an array of length n containing image names. You want to generate thirty random numbers between 0 and n-1. Then display the image associated with that position in the array. I'm not a php expert, but here is some pseudocode:
$a = array();
$dir = '../public/wp-content/uploads/2012/01';
if (preg_match("/\.png$/", $file)) $a[] = $file;
elseif (preg_match("/\.jpg$/", $file)) $a[] = $file;
elseif (preg_match("/\.jpeg$/", $file)) $a[] = $file;
for ( i=0; i < 30; i++) {
//generate a random number between 0 and N-1
random = rand(0, $a.length - 1);
//display that image in the array
echo "<img src='" . $dir . '/' . $a[random] . "' />";
}
You need to create a new variable for the counter instead of using $i
For example, you can do this instead
$j = 0;
foreach ($a as $i) {
echo "<img src='" . $dir . '/' . $i . "' />";
$j++;
if ($j >= 30)
{
break;
}
}
EDIT: Perhaps for the random part you can first generate a random number between 0 and n-1 where n is the total number of the images and then just echo out the image from the array with the index number.
Instead of using foreach, I think you'll need a for loop instead.
$totalImgs = count($a);
$imgUsed = array();
for ($j = 0; $j < 30; $j++)
{
do
{
$randIndex = mt_rand(0, $totalImgs);
}
while ($imgUsed[$randIndex] === TRUE);
$imgUsed[$randIndex] = TRUE;
echo "<img src='" . $dir . '/' . $a[$randIndex] . "' />";
}
You should maybe only read 30 file from your directory. Stop looking in the directory when readdir return false or your array's length is 30.
This should work
$a = array();
$dir = '../public/wp-content/uploads/2012/01';
if ($handle = opendir($dir)) {
while (false !== ($file = readdir($handle)) && (count($a) <= 30) {
if (preg_match("/\.png$/", $file)) $a[] = $file;
elseif (preg_match("/\.jpg$/", $file)) $a[] = $file;
elseif (preg_match("/\.jpeg$/", $file)) $a[] = $file;
}
closedir($handle);
}
It may not execute (I didn't try). But the idea is here
For randomize the image: shuffle($a) should do the trick
in simplest way ,
you can use
find , sort , head
commands in linux,in conjuction with PHP's built in
exec()
function to get 30 random image links easily , the folowing snippet lists how to do it
(How to get random 30 image links in an array.)
<?php
$picdir = "directory/containing/pictures"; // directory containing only pictures
exec("find " . $picdir . " | sort -R | head -30 ",$links);
while(list($index,$val) = each($links) ) {
echo "<img src =" .$val . "> <br/>"; // shows image
}
?>
Here $links array contain random 30 image names(from folder) with complete path . This is used with img tag in echo to generate images
Here $picdir has the path of the directory having images and it is assumed that dirrectory is having only image files . in other case its only matter of modifying find command to exclude non image files(such as using grep command to exclude )