Forum Moderators: phranque

Message Too Old, No Replies

RewriteRule causing some images to not load

         

okgo

11:30 am on Aug 11, 2014 (gmt 0)

10+ Year Member



Hello everyone, nice to meet you all. My first post here.

I've tried to get help at a couple of places with no luck.

I have a php page that loads a thumbnail at the top, and a group of thumbnails at the bottom. All images share the same path/directory.

I will post as much detail as I can re my php code. I have stripped it down and removed as much as possible (including security) just to narrow down this problem:

if (!isset($_GET['id'])) {
$group = array();
while ($row = mysqli_fetch_assoc($result)) {
$group[ $row['company-name'] ][] = $row;
}
foreach ($group as $company_name => $models) {
foreach ($models as $model) {
echo "<a href='$model[id]/'>$model[model-abbreviation]</a>";
}
}
}

if (isset($_GET['id'])) {
$top_thumb = "$image_directory_name" . "top.jpg";
echo "<img src='$top_thumb'>";
echo '</br>';
$images = glob($image_directory_name."*_thumb*");
if (!$images) {
echo 'No images to display.';
}
else {
foreach ($images as $image) {
$full = str_replace('thumb','full',$image);
echo '<a href="'.$full.'" target="_blank"><img src="'.$image.'"></a>';
}
}


So this works fine, UNTIL I turn this rewrite rule on.

^products/(.*)/$ /products/index.php?id=$1


It works and gives me nice directories, ala www.example.com/products/55/

But none of my images show anymore.

HOWEVER, in the page source I can see that it is TRYING to display the images (though I get no error from my script, just a blank page), just with the wrong path - it looks like this:

<img src='Company Name/Model Name (Model Version)/top.jpg'></br><a href="Company Name/Model Name (Model Version)/A_full.jpg"><img src="Company Name/Model Name (Model Version)/A_thumb.jpg"></a>


so I tried adding /products/ to this line, to change my $image_directory_name variable:

if ($row['model-version'] == NULL) { $image_directory_name = "/products/$company_name/$model_abbreviation/"; } else $image_directory_name = "/products/$company_name/$model_abbreviation (" . $row['model-version'] . ")/";


This is where things get weird.

Now the top thumb (top.jpg) shows up, yet the bottom thumbs do not (I get my 'No images to display' error on those now. Yet they all share the same path!

I'm thinking it's got to do with my rewrite, so here's my whole rewrite file:

RewriteEngine On
^products/(.*)/$ /products/index.php?id=$1


That's it. sorry for the huge post there, hopefully someone can save me from this...it is destroying me at the moment.

not2easy

2:40 pm on Aug 11, 2014 (gmt 0)

WebmasterWorld Administrator 10+ Year Member Top Contributors Of The Month



Hello okgo and welcome to the Forums. It may be possible that your rewrite is having unintended consequences. If you can clear up what the rule is intended to accomplish, there may be hope of limiting it to that task only.

What is this rule supposed to be doing?
RewriteEngine On
^products/(.*)/$ /products/index.php?id=$1

lucy24

3:31 pm on Aug 11, 2014 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



So this works fine, UNTIL I turn this rewrite rule on.

^products/(.*)/$ /products/index.php?id=$1

Urk. Under what circumstances would there be a request for
www.example.com/products//

with no content between the slashes?

Well, never mind that. The slash-plus-closing-anchor means that image requests as such aren't being rewritten, because they'll never match the pattern. That's one possibility to cross off. But presumably all page requests are being rewritten. This in turn means there should never be relative links
<img src='Company Name/Model Name (Model Version)/top.jpg'>

anywhere in your html, because the browser "thinks" it is in a different location than it really is, and will then look for images in the wrong place. You have to code it so all image links are site-absolute (leading slash).

so I tried adding /products/ to this line, to change my $image_directory_name variable

Yes, exactly. But where are the non-top_thumbs getting set?

okgo

8:22 pm on Aug 11, 2014 (gmt 0)

10+ Year Member



Thanks for the reply. In hurrying before going to sleep for the night I forgot to post some of my php.

Hello okgo and welcome to the Forums. It may be possible that your rewrite is having unintended consequences. If you can clear up what the rule is intended to accomplish, there may be hope of limiting it to that task only.

What is this rule supposed to be doing?
RewriteEngine On
^products/(.*)/$ /products/index.php?id=$1


If someone goes to www.example.com/products/30/, that will actually run www.example.com/products/index.php?id=30, and my script looks up that item numbers details.

Yes, exactly. But where are the non-top_thumbs getting set?


Here is where the thumb path is being set.

if (isset($_GET['id'])) {
$id = $_GET['id'];
$get_item_info = mysqli_query($link, "SELECT products.*, company.company-name FROM products INNER JOIN company ON products.company-id=company.id WHERE products.id='$id'");
$row = mysqli_fetch_assoc($get_item_info);
if (!$row) {
echo 'Error';
exit();
}
$company_name = $row['company-name'];
$model_abbreviation = $row['model-abbreviation'];
if ($row['model-version'] == NULL) { $image_directory_name = "/products/$company_name/$model_abbreviation/"; } else $image_directory_name = "/products/$company_name/$model_abbreviation (" . $row['model-version'] . ")/";
}


So this line specifically sets the image path for the product.

if ($row['model-version'] == NULL) { $image_directory_name = "/products/$company_name/$model_abbreviation/"; } else $image_directory_name = "/products/$company_name/$model_abbreviation (" . $row['model-version'] . ")/";


$image_directory_name will either equal /products/company_name/product_name or /products/company_name/product_name (product_version)/

And that variable is then used here:

if (isset($_GET['id'])) {
$top_thumb = "$image_directory_name" . "top.jpg"; // top thumb set here
echo "<img src='$top_thumb'>";
echo '</br>';
$images = glob($image_directory_name."*_thumb*"); // attempting to find all bottom thumbs here
if (!$images) {
echo 'No images to display.';
}
else {
foreach ($images as $image) {
$full = str_replace('thumb','full',$image);
echo '<a href="'.$full.'" target="_blank"><img src="'.$image.'"></a>';
}
}

All images are in the same folder. The top thumb, and the bottom thumbs. They both use the same $image_directory_name variable to set their path. The only difference is in my php, is how they are accessed. The top thumb has a direct path to one image (top.jpg), which might be why it is not being rewritten...

okgo

9:48 pm on Aug 11, 2014 (gmt 0)

10+ Year Member



A bit more information... I just found something interesting, I'm not sure if it means anything.

If I change the $image_directory_name variable back to no longer have /products/ in it, and I view the source of the product page, it is at least attempting to load the images from:

<img src="Company/Product/file1.jpg">

and if I click on that link in the source, it attempts to find the image at:

The requested URL /products/ID/Company/Product/file1.jpg was not found on this server.

When I put /products/ back in the $image_directory_name variable it just doesn't find or even attempt to load any images.

lucy24

12:39 am on Aug 12, 2014 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



and if I click on that link in the source, it attempts to find the image at:

The requested URL /products/ID/Company/Product/file1.jpg was not found on this server.

Wait, wait, wait, I just realized I read something backward in your first post.

Attempting to find a file at
/products/ID/Company/Product/file1.jpg

when the page HTML reads
Company/Product/file1.jpg

(no leading slash)
is what happens when the browser thinks the current page is
/products/ID/pagename.xtn

and/or
/products/ID/


Backtracking:
RewriteEngine On
^products/(.*)/$ /products/index.php?id=$1

That can't literally be the whole RewriteRule. I've been assuming the line reads in full
RewriteRule ^products/(.*)/$ /products/index.php?id=$1 [L]

with an internal rewrite. Is that right?

What is the actual structure of the part of the URL after /products/ ? Is it always the same number of directories? (In this case, pseudo-directories in the URL path, but the browser doesn't know that.)

okgo

12:55 am on Aug 12, 2014 (gmt 0)

10+ Year Member



is what happens when the browser thinks the current page is
/products/ID/pagename.xtn
and/or
/products/ID/


Yup right. When I am at the page localhost/products/ID/ in my browser I get that attempt in the source (if my $image_directory_name does not contain /products/ at its base). It attempts to display the correct amount of images in the directory too.

And sorry, yes, my .htaccess looks exactly like that:

RewriteEngine On
RewriteRule ^products/(.*)/$ /products/index.php?id=$1 [L]

Hard to think straight, I've been battling this issue for 3 days now and it's wearing my brain down.

The real, physical /products/ contains one index.php and a whole bunch of directories (company names) -> (product names).

/products/index.php

/products/company 1/
/products/company 2/
/products/company 3/

And within those, product names

/products/company 1/product 1/
/products/company 1/product 2/
/products/company 1/product 3 (version x)/

And so on.

In the product directories are nothing but images for each product.

lucy24

2:19 am on Aug 12, 2014 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



What do the URLs look like? The part after /products/

okgo

4:14 am on Aug 12, 2014 (gmt 0)

10+ Year Member



What do the URLs look like? The part after /products/


Without rewriting, the only thing in there (aside from the image directories explained above) is /products/index.php

This displays ALL products in the database, and to see a single product it calls /products/index.php?id=ID

With the rewriting, going to /products/30/ is the equivalent of going to /products/index.php?id=30

Is that what you mean?

okgo

11:06 pm on Aug 13, 2014 (gmt 0)

10+ Year Member



Removing the trailing slash from my rule fixed everything.

I have to use /products/30 instead of /products/30/, but all my images load.

lucy24

9:57 pm on Aug 14, 2014 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Bingo. See, that's why I kept asking what the URLs look like. (The visible address-bar URL, nothing to do with physical location of content.)

/products/30/
>>
browser thinks it is on page
/products/30/blahblah.html
within directory
/products/30/
and it will interpret relative links accordingly.

/products/30
>>
browser thinks it is on page
/products/30.html
within directory
/products/
and will, again, interpret relative links accordingly.

It's important to remember that the browser does not know it has been rewritten. So it will interpret any relative links based on where it "thinks" it is.

okgo

1:58 am on Aug 15, 2014 (gmt 0)

10+ Year Member



yeah, it's a shame I can't have the trailing slash (I personally much prefer the look of it), but I'll take what I can get :)

It's important to remember that the browser does not know it has been rewritten. So it will interpret any relative links based on where it "thinks" it is.


Very good quote, it will definitely help to keep that in mind when thinking of rewrite rules in the future.

okgo

6:21 am on Aug 16, 2014 (gmt 0)

10+ Year Member



So I'm glad to have it working, and I actually like the no trailing slash now. But I'm trying to change it up a little bit.

I've implemented another few rules that work great...here is my current .htaccess file:

RewriteRule ^products/all/$ /products/index.php?company=all&sort_style=all [L]

when I go to /products/all/, all products are listed.

RewriteRule ^products/([a-z0-9-]+)$ /products/index.php?product_slug=$1 [L]

when I select a single product, that one products specs are shown.

#RewriteRule ^products/([a-z0-9-]+)/([a-z0-9-]+)$ /products/index.php?company_slug=$1&product_slug=$2 [L]

This is the one I was testing for my new desired 'single product' page

RewriteRule ^products/(.+)/$ /products/index.php?company=$1&sort_style=all [L]

when I go to /products/pick-a-company/ it shows all products from that company only.


But now I'm trying to change the 'single product' page url, but I'm having trouble getting the images to show up again

The one that is working for me:

RewriteRule ^products/([a-z0-9-]+)$ /products/index.php?product_slug=$1 [L]


Which makes this work beautifully:

localhost/products/product-name-here (no trailing slash)


my images are linked as:
'companyname/productname/'


Everything works fine.

But I really, really want to have:

localhost/products/company-name/product-name (no trailing slash)

yet I'm running into the same issue, top thumb loads, bottom thumbs don't.

I tried using this RewriteRule:

RewriteRule ^products/([a-z0-9-]+)/([a-z0-9-]+)$ /products/index.php?company_slug=$1&product_slug=$2 [L]


Am I just completely out of luck and not able to do that, for the same reason I couldn't do the previous method I was trying (that I fixed by removing the trailing slash)?

Just isn't very uniform to be able to go to /products/company-name/ to see all products from a company, but a single product is /products/product - doesn't flow very well.

lucy24

7:59 pm on Aug 16, 2014 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Quick note: The locution
(.+)/$
can mean
([a-z0-9-]+)/$
but it can also mean
([a-z0-9-]+)/([a-z0-9-]+)/$
([a-z0-9-]+)/([a-z0-9-]+)/([a-z0-9-]+)/$
([a-z0-9-]+)/([a-z0-9-]+)/([a-z0-9-]+)/([a-z0-9-]+)/$
et cetera. I would recommend spelling it out, so you never get directory slashes hiding in the middle of a capture.

You may need to backtrack and fine-tune your php-- the part that generates the <img blahblah> links on your pages. The simplest approach is to use absolute links for all <img blahblah> tags. Once there's a leading slash, it will make no difference what the URL is, because everything is relative to the root.

Remember, a form such as
<img src = "blahblah">
is not a direct file request. It's a message sent to the browser: "Ask for the file located at 'blahblah'", where the full path of "blahblah" is based on what the browser knows, thinks or believes about the current page URL. That means the visible URL, NOT the physical location of the content.

Do all images live in the same uber-directory, or are there a bunch of sub-sub-directories like
foobar/images
widget/images
thisway/images
et cetera?

Trailing slash = browser thinks it is on the index page of a directory
/foobar/products/ = /foobar/products/index.php
No trailing slash = browser thinks it is on a page
/foobar/products = /foobar/products.php
That's a bit of a simplification-- but browsers are simple-minded critters.

okgo

7:39 am on Aug 17, 2014 (gmt 0)

10+ Year Member



Thanks I will change my rules to be more specific, definitely. I think I'm supposed to make the 'old' links no longer work as well, so if someone goes to for example index.php?get=1&blah=2 it doesn't work or points to the rewritten version...I haven't read that far on SEO stuff yet. Putting final touches on the site then looking that up.

As far as images, all images are in each productname directory, sorted under company directories, under /products/:

/products/companyname/productname

I think it must be something to do with the php. Since when I set an absolute path of /products/companyname/productname/ as the $image_directory_name variable php uses to set the link to the top thumb and to search for the bottom thumbs, the top thumb works! It just doesn't find the bottom ones using the same variable...it is utterly confusing. But it is using a different method:

top thumb = static image tag with the $image_directory_name as href.

bottom thumbs: php glob() function to search directory ($image_directory_name)... there's got to be something I'm overlooking. I don't know :)

lucy24

8:32 am on Aug 17, 2014 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



You may want to step next door to the php ("server-side scripting") subforum. I don't speak more than three words of php, but there are people who will know where to point you.

okgo

9:10 am on Aug 17, 2014 (gmt 0)

10+ Year Member



Will do. Thank you lucy, you've helped me a great deal :)