Mod rewrite rule help

Hi

I have the following mod rewrite rule which works perfectly on one server:
RewriteRule ^/?image/([^/])/([^/])?$ image.php?product_type_id=$1&image=$2&%{QUERY_STRING} [L]

However on a different server it seems to break (on occasion). Eg:
image/card/hsbc-card_visa.png
^ this matches/works on the original server for the above rule, but on this new server it breaks.

I worked out with trial and error that it MAY be something to do with the combinition of “hs” together which is making it fail on the new server.
image/card/hbc-card_visa.png
image/card/sbc-card_visa.png
image/card/hsbsc-card_visa.png
^ All these match/work for the above rule on this new server.

Any ideas? I’m really baffled by this.

Thanks

Hm. There’s certainly nothing in your regex that could possibly match/notmatch based on the letters hs.
What do your Apache error logs say when you try to request image/card/hsbc-card_visa.png ? If it works when requesting directly, what do your error logs say when the request is part of a whole normal page?

Lucky,

I agree with Mallory about your mod_rewrite code but have two comments on that and one other consideration.

  1. ^/? is the code for EITHER Apache 1 or Apache 2. By now, I believe that there are not likely to be any Apache 1 installations in the wild so ^ should be fine.

  2. Why use &%{QUERY_STRING} when (a) it’s also likely to be adding only a & at the end of your URI (no previous query string) AND (b) Apache has a flag which will do the same job without the possibility of (a): QSA.

I don’t believe that your second server has Options +Multiviews (enabled) but that will cause a problem because the image/ in the path WILL trigger image.php which would have to parse the path for the query string information. Be sure that Options -MultiViews is selected.

Regards,

DK

Thanks guys.

I’ve removed the query string and it still is broken for this hsbc case.
This is what I have now:
RewriteEngine On
Options -MultiViews
RewriteRule ^/?image/([^/])/([^/])?$ image.php?product_type_id=$1&image=$2 [L]

Not sure if I did the MultiViews correct. I tried it before the “RewriteEngine” line as well, both didn’t work.

image/card/hsbc-card_visa.png
^ this matches/works on the original server for the above rule, but on this new server it breaks.

Thanks

Curious: what version of Apache was your original server? Where there possibly other settings? A different php script?
And what version Apache you have now?

btw, the mutliviews goes in your directory settings…

Example of a directory setting; I dunno if this is in your .htaccess but it’s in my config file:


     <Directory "/usr/share/doc/">
         Options Indexes MultiViews FollowSymLinks
         AllowOverride None
         Order deny,allow
         Deny from all
         Allow from 127.0.0.0/255.0.0.0 ::1/128
     </Directory>

You should have <Directory> statements in some file or other. In my config they are before any RewriteEngine On stuff. Multiviews is not a part of the rewrite module. You can just grep through the file for anything looking like Multi, and if you have it without a minus, change to -Multiviews and see if nothing breaks : )

Off Topic:

You might as well also go ahead and try what DK suggested about the ^/? in the beginning… not because it’s causing the problem here, but because if you don’t need it, it’s extra junk you don’t need.
With .htaccess you just use ^
With my Apache, because I write directly in the config, I need the / (which is mapped to DocumentRoot, or /var/www/ in my case).

Problem server:
Apache version 	2.2.17

Working server (different host):
Apache version 	2.2.21


RewriteEngine On
RewriteRule /?image/([^/]*)/([^/]*)?$ image.php?product_type_id=$1&image=$2 [L]

# BEGIN WordPress
&lt;IfModule mod_rewrite.c&gt;
....
&lt;/IfModule&gt;

# END WordPress

This is just a shared host, using WHM and Cpanel, not sure how I can find the multiview file.

Is this multiview the likely reason why this rule is breaking for this 1 particular image URL match/rewrite?

Any other ways I can re-do this rule not to have such a problem?

Yes, MultiViews is most likely the reason this is screwing up. Just put this at the top of your .htaccess:


Options -MultiViews

To disable that ‘feature’.

@Mallory: you can put MultiViews in the .htaccess also (if allowed by the server config in httpd.conf of course, which it usually is through AllowOverride All).

Also, once you’ve established that mod_rewrite works, there is no need to ask Apache again and again and again and … i.e. when you’ve established it works, remove <IfModule mod_rewrite.c> and </IfModule> from your .htaccess

Lucky,

The Options -MultiViews can be in the .htaccess file (typically, though, it’s put before the mod_rewrite code as it’s part of Apache’s core and, thus, is handled before mod_rewrite).

Four more comments:

RewriteEngine On
RewriteRule /?image/([^/]*)/([^/]*)?$ image.php?product_type_id=$1&image=$2 [L]

# BEGIN WordPress
<IfModule mod_rewrite.c>
....
</IfModule>

# END WordPress
  1. You don’t need the ^/? or /? at the start of your RewriteRule; ^ is fine.

  2. ([^/]*)/ will allow NULL values for $1 and $2. Replacing * with + will require at least one character.

  3. You can retain the pre-existing query string with the QSA flag, i.e., replace [L] with [QSA,L].

  4. Finally, you’ve displayed code relating to my standard rant #4, the inappropriate use of <IfModule> (any) use in .htaccess:

[rant #4][indent]The definition of an idiot is someone who repeatedly does the same thing expecting a different result. Asking Apache to confirm the existence of ANY module with an <IfModule> … </IfModule> wrapper is the same thing in the webmaster world. DON’T BE AN IDIOT! If you don’t know whether a module is enabled, run the test ONCE then REMOVE the wrapper as it is EXTREMELY wasteful of Apache’s resources (and should NEVER be allowed on a shared server).[/indent][/rant 4]

Regards,

DK

Thanks all, most of all that IF stuff was added by wordpress I believe, or some WP plugin.

Anyway I have trimmed my .htaccess file to the following:

Options -MultiViews

RewriteEngine On
RewriteBase /

RewriteRule ^image/([^/]+)/([^/]+)?$ image.php?product_type_id=$1&image=$2 [QSA,L]
RewriteRule ^index\\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

I don’t understand half the rules as I didn’t create them - I only added the image one.

Unfortunately the image rewrite is still failing for this one particular image.

Lucky,

Hey! Now we’re getting somewhere!

Options -MultiViews

RewriteEngine On
[COLOR="#FF0000"]RewriteBase /[/COLOR]

RewriteRule ^image/([^/]+)/([^/]+)?$ image.php?product_type_id=$1&image=$2 [QSA,L]
[COLOR="#FF0000"]RewriteRule ^index\\.php$ - [L][/COLOR]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .[COLOR="#0000FF"]?[/COLOR] /index.php [L]
  1. RewriteBase is designed to UNDO a mod_alias redirection for mod_rewrite. If you have no Redirect statements, get rid of it because it can cause some weird problems (with the location of the files).

  2. The RewriteRule ^index\.php$ - [L] is useless (it’s handled by the first RewriteCond statement as index.php does exist).

  3. It’s a personal thing but if domain.com/ were requested, there would be nothing for . to match in the last (WP) RewriteRule so I’d recommend making the dot optional, i.e., .?.

Finally, IMHO, you MUST understand what all your code is doing before you dare to use it. Not to know/understand makes you susceptable to illegitimate code and unexpected consequences. In the <IfModule> case, it is extremely abusive of the server and should be cause to remove you from a shared host. In other words, if you want to be considered a (professional) webmaster, you must learn to act like one. Please know that this is not a personal attack but a repeated comment which has been made altogether too often (and continues to be required).

Now, back to the image problem. Does a direct call to image.php with the query string display the image? If not, please look into the MIME type sent by the script as PHP files are of a text application type, not an image type. Also, if anything is output by the script before the MIME type, that header will not be accepted by the browser.

Regards,

DK

Ok, got it down to this:

Options -MultiViews

RewriteEngine On

RewriteRule ^image/([^/]+)/([^/]+)?$ image.php?product_type_id=$1&image=$2 [QSA,L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .? /index.php [L]

Interesting question about accessing the image.php directly. If I do this, I get the following results:
image.php?product_type_id=card&image=hsbc-card_visa.png <- 404 error
image.php?product_type_id=card&image=some-other-valid-card_visa.png <- IT WORKS (card image displays in browser)!

No idea, how, why this is happening.

Again if I change:
image.php?product_type_id=card&image=hsbc-card_visa.png to
image.php?product_type_id=card&image=hbc-card_visa.png
It works (the image.php script loads and throws an error as the card doesn’t exists, but at least the script loads)

This is BAFFLING me :slight_smile:

So… image.php is really the one fetching these?

This may be a PHP problem somehow.

The image that actually shows up on the other/old server: this image absolutely fer sure exists on the new one?

LB,

Well, at least with “perfect code,” we now understand that this IS a PHP problem (as Mallory just stated). Thus, this thread should be relocated to the PHP board for their expertise - unless you’d care to display your PHP code here so we can take a look at it (now that we know where the problem resides).

As for your 404, there is no reason for that (within Apache - we don’t know what your script is trying to call from within).

If you need to take your own look first, I’ve already noted the buffering (NO output) and MIME headers above but you’ll also need to add the fetch (and validation) of the two GET variables and how they’re handled in the script. I’m not sure what product_type_id is supposed to do for the script (the image’s subdirectory?) but the image (filename) handling must check that the file exists (which you now understand for your “throws an error” comment) before any attempt to serve an image file. IMHO, image.php should have a default “file not found” image which can be replaced with the image filename if … and only if … the filename image exists.

Regards,

DK

Hi guys

I am not sure if it is a PHP problem, as early on, I did an

echo "hello world";exit;

as the very first line in the image.php code.

The following was the result:
image.php?product_type_id=card&image=hsbc-card_visa.png <- 404 error
image.php?product_type_id=card&image=some-other-valid-card_visa.png <- “Hello world”

Any more ideas?

image.php?product_type_id=card&image=hsbc-card_visa.png <- 404 error

I’m still suspecting the image.php script is looking for the image and not finding it. It may be telling Apache later on that it’s not found and Apache uses DocumentError to send the 404 header, but I still feel this is deep inside the PHP somewhere. Either because something in the script changed, or something in the image file changed so the script can’t match/find it anymore.

I think you should go to the PHP section, link to this thread, explain that image.php isn’t finding a file and that it’s likely to be something in PHP… and then post that code. If you need to sanitise names or something from the file first that’s fine.

LB,

“early on” means absolutely nothing. Either it’s before ANYTHING else in the file or it’s a useless test.

Rémon, please send this to the PHP board.

Regards,

DK

Ok moved to the PHP forum.

LuckyB, could you please post the image.php script?

Hi David

Yes, I agree. This is exactly what I did!

The:

echo "hello world";exit;  

was on the FIRST LINE (right after the opening <?php tag)

So I do not see how this could be a PHP error as I get the following results from visiting the pages:
image.php?product_type_id=card&image=hsbc-card_visa.png <- 404 error (Does not even print “Hello World” the first thing in the PHP)
image.php?product_type_id=card&image=some-other-valid-card_visa.png <- “Hello world”

Not sure if this can be the case, I did an echo and exit on the very first line of the PHP and it didn’t even get to do that.