I searched this site and found a very useful snippet of code that i've been able to use.
$counter = 0;
foreach (glob("images/gallery/photo_gallery/resized/*.jpg") as $pathToThumb)
{
$filename = basename($pathToThumb);
$pathToLarge = 'images/gallery/photo_gallery/' . $filename;
echo ('<img src="'.$pathToThumb.'" />');
$counter++;
}
But for some reason this will only return the first 30 images in my directory. (there are 81) Can anyone think why this is happening?
Thanks.
As I have said above
$path = 'images/gallery/photo_gallery/resized/*';
would be enough. or, if you stubbornly wants only jpg only,
$path = 'images/gallery/photo_gallery/resized/*.[Jj][Pg][Gg]';
as manual suggests
Thanks to everyone for input.
Here's the answer - file extensions are CASE-SENSITIVE when used in glob() (something I was un-aware of)
30 of my files end in .jpg whilst the remaining files have been auto renamed through a resizing program to .JPG
So this means glob("imagesPath/*.jpg") only returned the lower-case matches.
Another lesson learnt :)
Hopefully this answer can help someone else too. :)
Related
I have a PHP program which scans a folder named output (which contains all image files in any format) for images. The image files are the screenshots of the output in terminal (I'm using Linux) of various Java programs. The image files are named according to the class name in which the main() function resides. So for example if the main() function resides inside the public Example class, then the output screenshot will be named Example with the extension of either .jpg, .jpeg, .png or .gif. The PHP program has a front page which scans for Java files and lists them in an unordered list with links the user can click to go on the next page. The next page reads the particular file and displays the source code along with the output screenshot. Now since I'm using Fedora and Fedora takes screenshots in png format, that is quite easy like:
echo '<img src="' . $file_name . '".png>'
But what if someone uploads a Java program with the output screenshot in any format? (jpg, jpeg, png, gif). How to then load the appropriate image file since I don't know what the extension will be?
I have an answer to use foreach loop and read through every image file there is within the output folder and then use an if condition for checking the appropriate file names with the various extensions but I think it will not be a very good programming practice.
I generally try to avoid conditions while programming and use more mathematical approach cause that gives me the challenge I need and I feel my code looks different and unique compared to others' but I don't seem to make it work this time.
I'm feeling that this can be done using regular expressions but I don't know how to do it. I know regular expressions but I'm clueless to even how to use them for this. Any answer to not use regular will be appreciated but I want to make this work using regular expressions because in that way I'll also add a little bit of knowledge to my regular expression concepts.
Thanks.
Here's an alternative to MM's that uses RegEx:
function getImageFilename ($basename, $directory) {
$filenames = scandir($directory);
$pattern = "/^" . $basename . "\.(jpeg|png|jpg|gif)$/";
foreach($filenames as $filename) {
preg_match($pattern, $filename, $matches);
if($matches) {
return $filename;
}
}
return false;
}
You can't avoid using a loop. You either loop through the possible file names and check for their existence, or you get a list of all the files in the directory and loop through them whilst performing a pattern match.
If there aren't a lot of files in the directory then this function might perform better because it only needs to call the OS once (to get a list of the files in the directory), whereas asking the OS to check for file existence multiple times requires multiple system calls. (I think that's right...)
One possible solution, you could check if the file exists with that extension (assuming you won't have multiple images with the same name but different extensions):
function get_image($file_name) {
if (file_exists($file_name . '.png')) {
return $file_name . '.png';
} elseif (file_exists($file_name . '.jpg')) {
return $file_name . '.jpg';
} elseif (file_exists($file_name . '.gif')) {
return $file_name . '.gif';
}
return false;
}
echo '<img src="' . get_image($file_name) . '">';
You define the pattern as an or list of the various extensions:
$pattern = '/\.(jpg|png|gif)$/i';
We are also making sure this is an extension by including the match with a dot (escaped) and making sure it's at the end of the string ($). The "i" at the end of that enables case-insensitive matching, so that the regex still picks up GIF or JPG in filenames.
After that, the test is fairly simple:
if (preg_match($pattern, $filename)) {
echo "File $filename is an image";
}
Putting it together in an example, you can see:
$filename = 'test.png';
$pattern = '/\.(jpg|png|gif)$/i';
if (preg_match($pattern, $filename)) {
echo "File $filename is an image";
}
https://eval.in/618651
Whether you want to wrap that in a function, is up to you, as you would have to decide what to return in case the filename does not match one of the extensions provided.
Also note that the test is based on the extension only and not on the content.
I want to create a piece of code that will remove images based on set parameters and a wildcard.
The number of images and naming will vary, though the first two parameters will remain as a constant.
// Example of images to be deleted / removed.
/images/1-50-variablename-A.jpg
/images/1-50-variablename-B.jpg
/images/1-50-variablename-C.jpg
/images/1-50-variablename-D.jpg
/images/1-50-variablename-E.jpg
Essentially I am after a loop to make this happen though I am not too sure on the best logic to make this happen.
$menuid = "1";
$imageid = "50"
$fileName = "images/".$menuid."-".$imageid."-*.jpg";
if (file_exists ($fileName)) {
unlink ($fileName);
}
You can use the php glob function (http://php.net/manual/fr/function.glob.php). Feed it with your pattern (it supports wildcards) and then iterate over the result and unlink each file.
Hope it helped
Solution presented itself in Glob form.
$menuid ="9999";
$imageid="5";
array_map('unlink', glob("../images/".$menuid."-".$imageid."-*.jpg"));
All images are uploaded into image folder under my php project while reference goes into mysql table, but my confusion is, what if there are two images have the same name, are there better way to avoid duplicate naming happen? i know i cant control how will user naming their image file.
I usually do a combination of timestamp and a big random value (just in case):
So for example:
$filename = time() . rand(1000000,9999999) . strtolower($ext);
Where $ext is the extension (whether it's jpg, png or whatever).
This is also more secure than accepting filenames from user.
And the reason for strtolower, is because sometimes someone will upload something like IMAGE.JPG, so rather on counting that your server and all your scripts will be case insensitive, you can simply make sure that all extensions are in lowercase.
Like VMai said before. Primary key is a good solution. But if You just wan`t to know solution with same name problem:
$filename = 'myfilename'; // without extension!
$extension = '.jpg';
$dir = '/directory/';
$fullPath = $dir.$filename.$extension;
$i=1;
$newFilename = filename;
while(file_exists($fullPath))
{
$newFilename = $filename.'_'.$i;
$i++;
$fullPath = $dir.$newFilename.$extension;
}
Not tested, but You got the concept
For security and yes to avoid duplicate you could change the filename to your own format,
example. formats
$filename = sha1(time().$original_filename) or $filename = md5(time().$originalfilename) it is up to you.
One advantage of changing the filename is that if an attacker uploads something, you are sure he will not find it because of a different name,other than the already security validations you have provided.
I'm trying to learn PHP programming through trial, error and lots and lots of practice.
I've been working on a directory bases image gallery for the last few days and it seems to work fine. I can upload pictures and create new albums. Plus whenever I see a full size picture I have links to the previous and next pictures in the directory.
Now this is where I ran into problems. Once you got to the end of the directory the code would start an infinite loop while it searches for the next file, which isn't there.
So I altered my code and it now looks something like this:
$x = 1;
$dir = opendir($base.'/'.$get_album);
while ((($file = readdir($dir)) !== FALSE) && ($x == 1)) {
while ($img < $file) {
$img++;
$image_exists = file_exists($base.'/'.$get_album.'/'.$img);
if ($image_exists) {
echo "<a href='member.php?album=$get_album&imgID=$img'>
<img src='$base/$get_album/$img' width='70' align='right'>
</a>";
break;
}
$x++;
}
}
This works when I get to the last picture in the directory. So I thought I'd do the same for when I get to the first picture and just invert the operators like so:
$x = 1;
$dir = opendir($base.'/'.$get_album);
while ((($file = readdir($dir)) !== FALSE) && ($x == 1)) {
while ($img > $file) {
$img--;
$image_exists = file_exists($base.'/'.$get_album.'/'.$img);
if ($image_exists) {
echo "<a href='member.php?album=$get_album&imgID=$img'>
<img src='$base/$get_album/$img' width='70' align='right'>
</a>";
break;
}
$x++;
}
}
This however DOES NOT work. I can't understand why that would be the case and I've tried to change things around a few dozen times but I cant seem to make it stop looping.
What am I doing wrong?
Thanks in advance for your help (and for reading through all this).
The issue could likely be related to the fact that readdir returns a string, and you are treating it as if you know its a number. You might find that it is returning you something at the start or end, such as the parent directory '..' as a string or the current directory as a string '.'.
If you want to iterate over the directories, you should check that the return value from readdir is not '.' or '..' specifically.
Please use a better format to your code (it's really painful read it), for instance, in netbeans you can use shiftalt F to format automatically.
I want address your attention to this line:
$image_exists= file_exists($base.'/'.$get_album.'/'.$img);
That is a possible source of errors. If only $base.'/'.$get_album.'/' exists then:
$image_exists= file_exists($base.'/'.$get_album.'/'.$img); // is true even if $img is empty!!!
But moreover:
What is $img? You treat it as a number when do $img++ and then as a string. That is not good for your health.
A good start it should be initialize your vars at the beginning of your code. And then use them in consonance.
I think there is something fundamentally wrong with the design, you are comparing $img, an uninitialized integer, to $file, a string.
It also seems needlessly complicated, as you are reading files from a directory, then check if they exist and break out of your loop if they do.
Perhaps with a clear view of the directory structure and what you are trying to do, I could provide a more detailed answer, but I think you need to go back to the drawing board.
The issue was saving file uploads locally, and trying to find a nice way to handle duplicate file names.
This algorithm is not scalable. Uploading n files with the same name will cause O(n) behavior in this algorithm, leading to O(n²) total running time, including O(n²) filesystem accesses. That's not pretty for a server app. It also can't be fixed because of how filesystems work.
Better solutions:
Store filenames that have already been used in a DB table, mapping them to their use count.
Put a high-granularity timestamp in the filename.
Use the SHA1 (or MD5) hash of the contents as the filename. This also prevents duplicate files being uploaded, if that's important.
Use a database to map filenames back to human-readable names, if necessary.
Best solution is just attach Time Stamp in form of YYYYDDMMHHMMSS , You won't get conflicts throughout your whole life ;)
Also its Time complexity is very less.
Another thing you can do .. you might skip name check directly and instead with file's name ex.
"1.jpg" if you are uploading
just attach 1(timestamp).jpg , so that you don't even need to iterate through file system. hope it helps
ex. in PHP
$timestamp=date("YmdGis");
it will generate something like
20111122193631
;)
I've made my own solution. Here it is:
function recursive_increment_filename ($path, $filename)
{
$test = "{$path}/{$filename}";
if (!is_file($test)) return $test;
$file_info = pathinfo($filename);
$part_filename = $file_info['filename'];
if (preg_match ('/(.*)_(\d+)$/', $part_filename, $matches))
{
$num = (int)$matches[2] +1;
$part_filename = $matches[1];
}
else
{
$num = 1;
}
$filename = $part_filename.'_'.$num;
if (array_key_exists('extension', $file_info))
{
$filename .= '.'.$file_info['extension'];
}
return recursive_increment_filename($path, $filename);
}
$url = realpath(dirname(__FILE__));
$file = 'test.html';
$fn = recursive_increment_filename($url, $file);
echo $fn;