Allowing Variable Image Extensions (Glob?)

Ah, that makes my code a little cleaner.

Here’s my revised code. (I should have been using $MyID2 instead of $IDParent.)

$Path = 'http://gs/images/sections/world/top/flower/usa/';
$names = glob($Path.$MyID2.".*");
$TopImg = $Path.$names[0];
echo $TopImg;

It displays this:

http://gs/images/sections/world/top/flower/usa/Array ( )

If I replace “Array ()” with ca.jpg and paste it into my browser, I see the image ca.jpg. So I have the right path.

The main problem with that is that I don’t think glob() will work through http. You’ll need to specify a file system path, either absolute or relative to where the php file is. For example if the php file is in the top folder, then $path might be something like “images/sections/world/top/flower/usa/”

Glob() will return the file name with the full path, so you don’t need to stick $Path on the front of it again.

Actually, I don’t normally use http. I just added that to make absolutely certain I had the correct path. I just changed it back to a relative path, but it still displays Array ():

$Path = '/images/sections/world/top/flower/usa/';

I doubt very much your file system has /images at the top of the directory. Remove the leading slash on that $Path if you’re referring to an images folder at the same level as your php file. Also you might do a var_dump($names); after the call to glob() to see what all is coming back.

I normally begin relative paths with the leading slash. However, var_dump($names) displays array(0) { } with or without the leading slash. It’s weird that nothing clicks; I guess my laptop doesn’t like glob. :wink:

We’re talking php here, an absolute file path (which is what you’ve got with the leading slash) is taken from the top of the disk drive, not from within your web site, as it would be if you specified the path within html. So it’s a critical difference.

Could you list your current code here again, I don’t see what the issue is, unless like you say your laptop just doesn’t like glob() :slight_smile:

First, here’s the code I was originally using. It correctly displays an image.

$TopImg = '<div><img src="/images/sections/world/top/'.$DesigGen.'/'.$IDParent.'/'.$MyID2.'.jpg"></div>';

Here’s how I’ve translated it into a glob script:

$Path = '/images/sections/world/top/flower/usa/';
$names = glob($Path.$MyID2.".*");
var_dump($names);
$TopImg = $Path.$names[0];
echo $TopImg;

$Path still needs to be changed to not have the leading slash, but you say the result is the same, correct? And could you echo out $MyID2 just to make sure it’s “ca”?

Please confirm this php file is in the same folder as the image folder sits.

Yes, I removed the trailing slash again, with the same results. I echoed $MyID2, and it correctly displays “ca.”

I’m a little confused by your last sentence. The full path to the file I’m working with is http://gx/2b/inc/c/child/db-values/sections/world/images.php The path to the image is http://gs/images/sections/world/top/flower/usa/ca.jpg.

In other words, I’m working on a subdomain. But I copied the image folders into gx, and the results are the same.

Presumably “ca” with no trailing dot, correct?

So your big problem is your directory path. The two paths you list here are they truly http: paths within your web directory space, or did you just put http: in front of them as you typed them here? Since they are very different and the php file is not at all in the same folder as your images folder, you will probably want to specify $Path to be the absolute FILE SYSTEM path to the images. That could be:
$Path = “/gs/images/sections/world/top/flower/usa/”;
if what you’ve written above is correct. Look at that file a file system browser and confirm that at the top of the file system (i.e. after C: for example) you have a folder named “gs”. It doesn’t seem correct to me, but I can’t see your system to look.

Yes. The full image name is ca.jpg.

I assumed that I could use the same relative path I’ve been using with glob, but it sounds like I need to change my path? I tried it with /gs/images, gs/images, /gx/images and gx/images. (I still have a copy of the image on both sites, just for test purposes.) The results are the same - an empty array.

This is too weird. I must be making some simple mistake. I have to run to work now, but I’ll play with it some more in the morning.

Thanks for all your help. I’m not a total beginner, but this is apparently just one of those weird situations where you can’t see the mistake that’s right under your nose. :wink:

I’d suggest reading up on file system paths, that’s what you need to know to get this right. I cannot figure out from what you’ve given me, what the path between your php file and your ca.jpg image is, nor why it would even work at all in your original “working” tag. So obviously I’m missing a piece of the puzzle as far as how your files are laid out.

1 Like

Try this:

Please note:

  1. Images require src to be a URL. When an image URL is prefixed with a leading slash, HTML prefixes *** ‘//’ .$_SERVER['SERVER_NAME']*** which is your serve name.
  2. glob() requires a $globDirectoryPath which is not a URL.

If you can view the image in your browser, right-click on the image and select “Copy Image Location” from the dropdown listbox. Then paste the URL to your PHP file into the following script:

$TopImg = '<div><img src="/images/sections/world/top/'.$DesigGen.'/'.$IDParent.'/'.$MyID2.'.jpg"></div>';
// URL copied from browser - "Copy Image Location"
// https://avatars.discourse.org/v2/letter/c/e8c25b/45.png

// Find path required for the directory path glob(...) parameter
echo '<br> getcwd() === ' .getcwd();

// note the current directory path
// create the $globDirectoryPath from $TopImg and getcwd();

// Test your $globDirectoryPath
   $fileExt           = '*.*';
   $globDirectoryPath = './'; //  .'i*.php';
   if( is_dir( $globDirectoryPath ) ):
      $aFiles  = glob( $globDirectoryPath .$fileExt );
      echo '<pre>'; print_r($aFiles); echo '</pre>';
   else:
      echo 'Problem: this is NOT a valid path: ' .$globDirectoryPath;
      die;
   endif;    

// ... continue

What a long conversation on a problem that can be solved in less than a minute by a simple renaming few files with non-standard extension.

3 Likes

Can you not use something like realpath() to get the actual physical location of the file? Something like

$Path = "/images/sections/world/top/flower/usa/";
$rp = realpath($Path);
$names = glob($rp . "ca.*");
var_dump($names);

Then extract the last part of it to use in your img tag? I haven’t tried this, btw.

But changing an extension is a bit of an ugly hack because:

  1. When you change the extension (like from .gif to .jpg) then the server will send it with incorrect mime type (image/jpeg instead of image/gif). Browsers may still work with incorrect mime types but nevertheless this is incorrect - and theoretically any browser at any time might reject such images and it would be right to do so.

  2. This solution is making things confusing for developers - who would expect a gif image under a jpg extension? Web browsers may be forgiving about the extension and the mime type but this could create problems when the dev is trying to edit these images in various programs. This is like making a mess.

Therefore while this will work I consider this incorrect. The OP is right in trying to figure out how to allow various file extensions. This is quite easy. I would use one of the two solutions:

  1. Store the image extension or the whole image filename in the database (along the image ID or file path - if you are getting image information from the database) - then there is no need to look for the image filename anywhere.

  2. Find the image in the directory where it is stored. Here is my alternative to glob:

    $foundImageFilename = null;

    // find first image filename in $dir:
    foreach (scandir($dir) as $filename) {
    $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));

     if ($ext == 'jpg' || $ext == 'jpeg' || $ext == 'gif' || $ext == 'png') {
         $foundImageFilename = $filename;
         break;
     }
    

    }

    if ($foundImageFilename) {
    // image file was found - do something with it
    // …
    }

Edit: this should not be used on directories with large number of files!

1 Like

Yes it is ugly hack but it works. And it will work forever, because, as it was noted above, one should never trust the mime type - so all the browsers do.

The better solution would be to convert all the images in PNG format.

While a PHP based solution, that have to read the HDD for the every request is worst of them all.

Yes, this is what I said, too. But I believe we shouldn’t use ugly hacks while proper solutions exist. I wouldn’t like to work on a project where a developer uses confusing file extensions that do not correspond to their actual types. I don’t like ugly surprises like that.

This is not always a practical solution - each format has its pros and cons and we use a specific format for a reason.

You would need to have a very busy site to see any performance impact of a reading of a small directory listing. Operating systems usually implement file system caching so in most cases this will not even tough the HDD at all. For most people this is far from being a concern unless they are accessing hundreds of files or directories with php.

1 Like

True, but in this specific case the images are all being used for the same thing by the OP - they haven’t chosen the formats specifically here. In fact I can’t think why they’d want to have the different formats.

I must admit I didn’t fully read colshrapnels post #34 earlier - I was thinking he meant to just convert the ones that aren’t jpg into jpg, not to just rename them and let the browser sort it out. While I’m sure that works it just somehow seems wrong.

This is but a theoretical musing that is inapplicable for the case in question. It’s just icons here, sharing the same purpose and obviously have to be of the same type.

With your code you don’t need a busy site, but just a directory with a lot of files. In general, searching a whole directory to find a single file is not the way to go (as long as we are talking of programming, not PHP, of course).