[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

number of images in directory

Posted on 2005-05-02
19
Medium Priority
?
329 Views
Last Modified: 2012-06-27
Hi,

I am currently using this script to create a page of thumbnail images dynamically generated from the images in a directory.

I'd like to do two things if possible.

1)  Know how many images are in the directory.  The goal being to create "next" and "previous" buttons on the page that the user arrives at when clicking on one of the thumbnails.

2)  Be able to order them in other ways besides just the default of aplhabetical.  Date created or date modified would like be preferable.



<?php
extract($_GET);
$dir = "pics";
if ($handle = opendir($dir . "/" . $gal . "/")) {
   while (false !== ($file = readdir($handle))) {
       if ($file != "." && $file != "..") {
               if (preg_match('/(jpg$|jpeg$|gif$|tif$|bmp$|png$)/', strtolower($file))) {
                  echo "<a href=\"index.php?id=photoShow&amp;d=$dir&amp;g=$gal&amp;f=$file\"><img src=\"scripts/resizer.php?d=$dir&amp;g=$gal&amp;f=$file&amp;rtype=width&amp;rval=100\" alt=\"$file\" /></a>\n\n";
            }
       }
   }
   closedir($handle);
}
?>



Thanks,


bruno
0
Comment
Question by:bruno
  • 11
  • 7
19 Comments
 
LVL 5

Expert Comment

by:dougday
ID: 13913676
First of all, extract($_GET) is quite dangerous.  Don't use it.  I could hack session variables and lots of other stuff because this line of code exists.

Also, I can hack your script quite easily like this:  
http://www.yourpage.com/script.php?gal=../../other/directory/i/shouldnt/have/access/to

$gal should be restricted.

That being said... This should solve #1.  #2 would require doing an fstat() on each file, and having a custom sort routine sort your array based on filetimes.

<?php
$dir = "pics";
$gal = basename($_GET["gal"]);
$base_dir = $dir . DIRECTORY_SEPARATOR . $gal . DIRECTORY_SEPARATOR;

$files = glob("{$base_dir}*.{jpg,jpeg,gif,tif,bmp,png}", GLOB_BRACE);
if (is_array($files)) {
    $num_files = count($files);
    foreach($files as $file) {
        echo "<a href=\"index.php?id=photoShow&d={$dir}&g={$gal}&f={$file}\"><img src=\"scripts/resizer.php?d={$dir}&g={$gal}&f={$file}&rtype=width&rval=100\" alt=\"$file\" /></a>\n\n";
    }
}

By the way, it looks like your index.php and resizer.php scripts are both wide open to be hacked as well.  What happens if I put www.yourdomain.com/scripts/resizer.php?d=/some/restricted/folder&g=&file=some_restricted_file.jpg?  This is especially dangerous if you allow them to do things other than simply *view* the file.  If, for example, you allowed them to rename or delete the file, they could potentially destroy your system!

-Doug

?>
0
 
LVL 4

Expert Comment

by:ShelfieldCollege
ID: 13916039
I used a similar script some time ago, and one way you can help tie it down a little is to check the directory they are trying to access, and split the directory up and check each element... e.g.

$dirs = split("/", "../../some/path");

foreach ($dirs as $curdir) {
  if ($curdir == "..") {
    // Hacking attempt
    die();
  }
}

Obviously this would only check for the use of ../ and not fully secure your script but it's a start at least.  There's probably a better way of doing this using regular expressions, unfortunately I haven't grasped them yet so I can't offer an alternative.

Cheers

-Matt-
0
 
LVL 5

Expert Comment

by:dougday
ID: 13918211
There are times when using ".." can be desirable and safe, even when allowing the user that kind of control.  The best way I've found is to have an absolute path that is safe to access.  Then use this:

// Make sure the real path lies somewhere within your absolute path
if (strpos(strtolower(realpath($path_to_test)), strtolower("/path/thats/okay")) !== 0) {
    // hacked
    exit();    
}

See http://us2.php.net/manual/en/function.realpath.php
and http://us2.php.net/manual/en/function.strpos.php

I make the paths lowercase so strpos() will work correctly.

-Doug
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
LVL 5

Accepted Solution

by:
dougday earned 2000 total points
ID: 13918460
brunobear,

Here's the complete code to solve both problems:

<?php

// User function to sort by last modified date
function sort_by_filetime($a, $b)
{
    $astat = stat($a);
    $bstat = stat($b);
    if ($astat['mtime'] == $bstat['mtime']) {
        // If file times are exactly the same, sort by name
        return strcasecmp($a, $b);
    }
    return ($astat['mtime'] < $bstat['mtime']) ? -1 : 1;
}

$dir = "pics";
$gal = basename($_GET["gal"]);
$base_dir = $dir . DIRECTORY_SEPARATOR . $gal . DIRECTORY_SEPARATOR;

$files = glob("{$base_dir}*.{jpg,jpeg,gif,tif,bmp,png}", GLOB_BRACE);
if (is_array($files)) {
    // The following line sorts alphabetically
    // sort($files);
    // This line sorts by file time
    usort($files, "sort_by_filetime");

    $num_files = count($files);
    foreach($files as $file) {
        echo "<a href=\"index.php?id=photoShow&d={$dir}&g={$gal}&f={$file}\"><img src=\"scripts/resizer.php?d={$dir}&g={$gal}&f={$file}&rtype=width&rval=100\" alt=\"$file\" /></a>\n\n";
    }
}

?>

Hope that helps,
-Doug
0
 
LVL 18

Author Comment

by:bruno
ID: 13968807
so sorry for the delay here, i was not on EE at all last week, let me look over your posts...thanks!
0
 
LVL 18

Author Comment

by:bruno
ID: 14029164
Hi Doug,

Again sorry for the delay here.  I have been playing with the script but having some problems.


It is currently not working because you have combined all the varialbes in these lines:


$base_dir = $dir . DIRECTORY_SEPARATOR . $gal . DIRECTORY_SEPARATOR;

$files = glob("{$base_dir}*.{jpg,jpeg,gif,tif,bmp,png}", GLOB_BRACE);


i think these lines were to help with the number of images problem, but i'm not sure i understand what is happening here.  

in this line of the script:

echo "<a href=\"index.php?id=photoShow&d={$dir}&g={$gal}&f={$file}\"><img src=\"scripts/resizer.php?d={$dir}&g={$gal}&f={$file}&rtype=width&rval=100\" alt=\"$file\" /></a>\n\n";

i need $file to just be the file name itself, not the full path.


thanks,


bruno

0
 
LVL 18

Author Comment

by:bruno
ID: 14029179
also, what is with the parens around the variables?  tks
0
 
LVL 5

Expert Comment

by:dougday
ID: 14031040
The parens around the variables means "OR".  So, in this case, it matches anything that is *.jpg OR *.jpeg OR *.gif, etc.

To fix the file problem simply put this line before your echo "<a href=...........";
$file = basename($file);

Hope that works for you,
-Doug
0
 
LVL 5

Expert Comment

by:dougday
ID: 14031053
So, do this:

    foreach($files as $file) {
        $file = basename($file);
        echo "<a href=\"index.php?id=photoShow&d={$dir}&g={$gal}&f={$file}\"><img src=\"scripts/resizer.php?d={$dir}&g={$gal}&f={$file}&rtype=width&rval=100\" alt=\"$file\" /></a>\n\n";
    }
0
 
LVL 18

Author Comment

by:bruno
ID: 14031387
i think that did it.

still don't understand the parens for OR?



<img src=\"scripts/resizer.php?d={$dir}&g={$gal}&f={$file}&rtype=width&rval=100\" alt=\"$file\" />


you have the parens around $dir, $gal, and $file

?

putting them around the other vars there and they actually write out the parens in the URL, but not for those.


thanks for sticking with a newbie here.  :-)
0
 
LVL 18

Author Comment

by:bruno
ID: 14031615
getting close


in my script i was doing this:


if (preg_match('/(jpg$|jpeg$|gif$|tif$|bmp$|png$)/', strtolower($file)))


some of the file ext are not lowercase

i assume in your script i would have to modify this line?

$files = glob("{$base_dir}*.{jpg,jpeg,gif,tif,bmp,png}", GLOB_BRACE);


not sure what to do though...


thanks.
0
 
LVL 5

Expert Comment

by:dougday
ID: 14031726
Oh, in a string the parens are to separate the variable from the string.

For example, it's acceptable to do this:

echo "$myvar";

But more correct to do this:

echo "{$myvar}";

They're both the same thing.  Using the parens allow you to use more complex objects in strings.  For example:

class myClass {
    var $myVar;
}

$var = new myClass();
$var->myVar = 10;
echo "var's myVar is {$var->myVar}";

Hope that helps,
-Doug
0
 
LVL 5

Expert Comment

by:dougday
ID: 14031738
The reason why glob("{$base_dir}*.{jpg,jpeg,gif,tif,bmp,png}", GLOB_BRACE); *might* be better than using a preg_match() (notice I'm not saying it is ;) is that the glob will only provide a list of files that end with those extensions.  You don't have to worry about filtering them out later.  :)  It's really just a matter of preference.  Given the circumstance, I thought using glob to filter was more appropriate.

-Doug
0
 
LVL 5

Expert Comment

by:dougday
ID: 14031763
And yes, the line you'd need to modify is the glob() line.

This will probably work:

// It's in *this* string where the parens mean OR.  Sorry about the confusion.
$files = glob("{$base_dir}*.{jpg,JPG,jpeg,JPEG,gif,GIF,tif,TIF,bmp,BMP,png,PNG}", GLOB_BRACE);
0
 
LVL 5

Expert Comment

by:dougday
ID: 14031771
If that doesn't work for you let me know and I can get you something that's more intuitive. :)
0
 
LVL 18

Author Comment

by:bruno
ID: 14031891
oh stupid me, they were not parens, they were brackets.  that explains why it didn't work when i tried to add parens.  lol


>>>>{jpg,JPG,jpeg,JPEG,gif,GIF,tif,TIF,bmp,BMP,png,PNG}


ok, i guess that i could have figured out that method...lol.  sometimes simplest way is really right?  :-)


what is the GLOB_BRACE on the end of that line do?
0
 
LVL 5

Expert Comment

by:dougday
ID: 14032449
The GLOB_BRACE allows that kind of method: {jpg,jpeg,gif,tif,etc}
If you did the following:

$files = glob("*.{jpg,gif,tif}");

It wouldn't work as expected -- it needs to know that you're using brackets.  This works:

$files = glob("*.{jpg,gif,tif}", GLOB_BRACE);

See the glob() function in the php manual:  http://us2.php.net/manual/en/function.glob.php
-Doug
0
 
LVL 18

Author Comment

by:bruno
ID: 14037777
thanks!  i didn't think this through all the way and i'm sure i'll be posting follow ups soon.  :-)
0
 
LVL 5

Expert Comment

by:dougday
ID: 14038333
No prob.  Glad it worked.  Thanks for the "A"
0

Featured Post

Upgrade your Question Security!

Add Premium security features to your question to ensure its privacy or anonymity. Learn more about your ability to control Question Security today.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

There are times when I have encountered the need to decompress a response from a PHP request. This is how it's done, but you must have control of the request and you can set the Accept-Encoding header.
The title says it all. Writing any type of PHP Application or API code that provides high throughput, while under a heavy load, seems to be an arcane art form (Black Magic). This article aims to provide some general guidelines for producing this typ…
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
This tutorial will teach you the core code needed to finalize the addition of a watermark to your image. The viewer will use a small PHP class to learn and create a watermark.
Suggested Courses
Course of the Month20 days, 7 hours left to enroll

868 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question