Forum Moderators: phranque

Message Too Old, No Replies

RewriteRule to catch one file -- not being caught

         

jboy

2:48 pm on Dec 6, 2010 (gmt 0)

10+ Year Member



Hello,

One line isn't working in the below. This is my .htaccess file at the moment:



RewriteEngine on

RewriteRule /?shortname\.pdf /Long\ Full\ Name\ To\ Use.pdf [L,R=301]
# the problematic one:
RewriteRule /?Long\ Full\ Name\ To\ Use\.pdf /Long\ Full\ Name\ To\ Use.pdf [L]

RewriteCond %{REQUEST_URI} !^(.*for-all-requests\.php) [NC]
RewriteRule ^(.*)$ /for-all-requests.php [L]



The last two RewriteCond and RewriteRule lines redirect all requests to one particular file. That works OK.

The first RewriteRule redirects externally from a short PDF file name to a long one. That works OK.

The second RewriteRule is intended to allow "mydomain.com/Long Full Name To Use.pdf" requests to get through, not be caught by the last two RewriteCond and RewriteRule lines, but this isn't working. Why? I've tried both slash spaces and %20's in various combinations but can't get it to work.

Thanks.

g1smd

2:58 pm on Dec 6, 2010 (gmt 0)

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



The last two RewriteCond and RewriteRule lines redirect all requests to one particular file. That works OK.

Be aware that there is no redirect here. The rule rewrites all incoming requests to a single fixed internal filepath and script.


The second rule creates a loop, as it rewrites to itself. It's the wrong method.

The correct way to do this, is to add a preceding negative match RewriteCond exclusion to the final ruleset. Are you aware that your final rule, as coded, means that all requests for images, scripts and robots.txt are also rewritten to your script for it to handle. Can it handle those requests? If not, they should also be excluded by adding their extensions to an additional negative match RewriteCond.

One major tip here. Do not ever use spaces in URLs or filenames. Change the spaces in the physical filename to hyphens and adjust all of the rules to suit.

jboy

3:06 pm on Dec 6, 2010 (gmt 0)

10+ Year Member



I just tried a different tact which I really thought was going to work but it didn't:


RewriteEngine on

RewriteRule /?shortname\.pdf /Long\ Full\ Name\ To\ Use.pdf [L,R=301]

RewriteCond %{REQUEST_URI} !^(.*for-all-requests\.php) [NC,OR]
RewriteCond %{REQUEST_URI} !^(.*Long\ Full\ Name\ To\ Use\.pdf) # << causes internal server error
RewriteRule ^(.*)$ /for-all-requests.php [L]


That's probably a better tact, apart from the fact it doesn't work. Any ideas why?

Thanks.

jboy

3:26 pm on Dec 6, 2010 (gmt 0)

10+ Year Member



(posted my last post after I saw your reply, again, thanks for the reply)

>> The last two RewriteCond and RewriteRule lines redirect all requests to one particular file. That works OK.
> Be aware that there is no redirect here. The rule rewrites all incoming requests to a single fixed internal filepath and script.

Yup, I meant to say internal redirect there. That's fine, thanks.

> Are you aware that your final rule, as coded, means that all requests for images, scripts and robots.txt are also rewritten to your script for it to handle. Can it handle those requests?

Ah, I've got all that covered apart for robots.txt -- thanks very much for pointing that out. I'm using a subdomain for all the css and image and javascript files, so there aren't any of those on this main domain.

> The correct way to do this, is to add a preceding negative match RewriteCond exclusion to the final ruleset.

Right, I thought of that after my first post.

> One major tip here. Do not ever use spaces in URLs or filenames. Change the spaces in the physical filename to hyphens and adjust all of the rules to suit.

I'd really like to have spaces in this pdf file if possible. It worked fine when I was using a Redirect instead. Like so:


Redirect /shortname.pdf http://www.mydomain.com/Full%20Name%20To%20Use.pdf


But I wasn't using the rule which catches all files then. But anyway, without spaces and hyphens instead, have just tried this:


RewriteEngine on

RewriteRule /?shortname\.pdf /Long-Full-Name-To-Use.pdf [L,R=301]

RewriteCond %{REQUEST_URI} !^(.*for-all-requests\.php) [NC,OR]
RewriteCond %{REQUEST_URI} !^(.*Long-Full-Name-To-Use\.pdf)
RewriteRule ^(.*)$ /for-all-requests.php [L]


and have changed the actual pdf filename to include hyphens, and I still get an internal server error. Any ideas what I'm doing wrong?

Thanks.

jboy

6:12 pm on Dec 6, 2010 (gmt 0)

10+ Year Member



ignore, sorry

jboy

7:48 pm on Dec 6, 2010 (gmt 0)

10+ Year Member



Got it. So far as the internal error goes from the very last .htaccess code I posted, it's the OR bit. Removing ',OR' from it makes it OK. Thanks.

g1smd

8:10 pm on Dec 6, 2010 (gmt 0)

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



The two RewriteCond lines simplify to one:

RewriteCond %{REQUEST_URI} !/([^/]+/)*(for-all-requests|Long-Full-Name-To-Use)\.pdf$


I'm not so sure the ([^/]+/)* part is required, but it replaces your (.*) part and will parse very much faster.

jdMorgan

8:55 pm on Dec 6, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



The following "well-known URL-paths" should be considered for exclusion, unless properly handled/generated by your script:

  • /robots.txt
  • /sitemap.xml
  • /labels.rdf
  • /w3c/p3p.xml
  • All custom error pages (500-Server errors, in particular, should not be handled by any script)

    If you need no exclusions whatsoever, then the single RewriteCond suggested above can be eliminated by moving its pattern to the RewriteRule. Remove the leading slash from the RewriteRule pattern for use in .htaccess, though.

    Jim
  • jboy

    9:11 pm on Dec 6, 2010 (gmt 0)

    10+ Year Member



    Thanks for that.

    Contrary to my previous post, I haven't got it. This is driving me absolutely potty now.

    First, I don't think

    RewriteCond %{REQUEST_URI} !/([^/]+/)*(for-all-requests|Long-Full-Name-To-Use)\.pdf$

    will work because the for-all-requests.php file is not a pdf. The for-all-requests.php bit is actually working (although just about every time I say that it turns out not to be working in some way but so far that part really does look like it's working properly) so I don't want to touch that with a barge pole.

    The bit that isn't working now is the line which is supposed to stop the for-all-requests.php RewriteRule from kicking in when the Long-Full-Name-To-Use.pdf file is accessed. I've tried many different things. Here's one version of my full .htaccess file:


    RewriteEngine on

    RewriteRule /?shortname\.pdf/Long-Full-Name-To-Use.pdf [L,R=301]

    RewriteCond %{REQUEST_URI} !^(.*for-all-requests\.php) [NC]
    RewriteCond %{REQUEST_URI} !^(.*Long-Full-Name-To-Use\.pdf) #not working
    RewriteRule ^(.*)$ /for-all-requests.php [L]

    And I've also tried it with $ signs on the end:
    ....-Use\.pdf)$
    and
    ....-Use\.pdf$)

    It doesn't work like this: I click the link for the pdf on a webpage which is the shortname.pdf link. The browser gets redirected to the long name version but then my /for-all-requests.php page is accessed (which means the line marked '#not working' isn't working). At the moment /for-all-requests.php doesn't go anywhere, just outputs some stuff.. So I'm left with the output of the /for-all-requests.php and the browser is showing the /Long-Full-Name-To-Use.pdf URL in its address bar. Here's the rediculous bit: I click reload and then it downloads the PDF fine. Unbelievable.

    I think what I need to do is just not use Apache at all (apart from the external redirect from short pdf filename to long, and the internal redirect to for-all-requests.php).

    When I was trying to get this to work with spaces I started to use a PHP method which I got from another forum, quoted here:

    <?php
    $filename = "brochure.pdf";

    header("Content-Length: " . filesize($filename));
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename=brochure.pdf');

    readfile($filename);
    ?>


    It worked with spaces in Safari but in Firefox the file came down as just 'Long' (so the filename got cut off when it came across the first space). So I gave up with that. But now I can go back to using that because it will work without spaces I'm sure. That PHP can go in the for-all-requests.php file.

    Phew. Absolute hell this stuff. But thanks for the replies g1smd.

    g1smd

    10:12 pm on Dec 6, 2010 (gmt 0)

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



    I didn't notice one URL was a pdf and one a php.

    The general principle still holds true, a one line condition can do both.

    RewriteCond %{REQUEST_URI} !/([^/]+/)*(for-all-requests\.php|Long-Full-Name-To-Use\.pdf)$

    However, do take on board everything that jdMorgan posted. If any of it disagrees with anything I posted, then go with his answer.

    Clear your browser cache before each test, otherwise you're not testing your current server code, merely looking at the cached result of a previous test.

    jdMorgan

    4:13 am on Dec 7, 2010 (gmt 0)

    WebmasterWorld Senior Member 10+ Year Member



    ...and do not try to "guess" your way through this, unless you have a couple of years to find the answer and want to use up all two years. If you don't understand the syntax of an Apache directive, look it up at Apache.org. If you don't understand regular expressions, then look up the correct syntax (a tutorial is cited in our Apache Forum Charter here.)

    Looking up the answers from authoritative sources (not forums) is tens to thousands of times faster than "guessing" or "inferring." Apache mod_rewrite and regular expressions are utterly unforgiving; one tiny deviation from 'perfect' changes everything. It is not at all something to be guessed at.

    Jim