I'm migrating a website from an old server thats being shutdown to a new one, and in the process I'm having some trouble with Apache and mod_rewrite. I have the following .htaccess file:

RewriteEngine on
RewriteRule ^audio/(.*?)/.*?$ audio.php?id=$1
RewriteRule ^books/(.*?)/.*?$ books.php?id=$1

The audio.php and books.php are being called as expected except that the captured variables are not being passed, so in the case of the audio.php rewriterule I am being served the audio.php page but $_GET is empty.

To test what is happening I added RewriteRule (.*) test.php?a=$1 where test.php just dumped $_GET when I did that $_GET['a'] contained 'test.php'.

Nothing is showing up in the error log, and as the correct files are being served clearly the rewrite is mostly working, and the config has AllowOverride All what am I doing wrong?

I want to be clear that this htaccess file worked as is on the old server.


You should setup a RewriteLog with a high RewriteLogLevel to ensure your rules are being processed as you expect.

Keep in mind that .*? may yield an empty match, because * means 0 or more. You might at the very least want to use + (so, .+?), which means one or more.

Anyhoo. There are better ways to express what you're looking for.

To match until the next slash, this should do:

RewriteRule ^audio/([^/]+) /audio.php?id=$1

Although, if it's a numeric id, you can be more precise:

RewriteRule ^audio/(\d+) /audio.php?id=$1
  • +1 for the alternate syntax, which is almost always clearer than relying on the non-greedy flag. -1 for ".*? will always be an empty match". In Perl, .*? operates exactly as the OP is expecting it to -- just tested it in v5.8.6. The perlre page says that ? will make the "quantifier match the minimum /number/ of times possible" and I wouldn't be surprised if the behavior were actually an intentional play on the question of whether zero is a number. Perl's answer, at least in this context, seems to be "no". – Ben Dunlap Aug 15 '09 at 18:49
  • 1
    Maybe I wasn't all to clear on that part of the answer. * means 0 or more, + means one or more. *? still means zero or more, just non-greedy. So unless something else in the regular expression requires *? to perform a match of non-zero length so that the entire regex can match, it won't. In the OP's regex, though, the slash after the capture would require that anything between two slashes is matched by .*?. But for a url like /audio//, it would be an empty match between the two trailing slashes. – kch Aug 15 '09 at 22:36
  • You got me convinced anyway. It definitely doesn't add to the answer and may cause some confusion. I'll edit it out. – kch Aug 15 '09 at 22:37
  • Nice clarification, and thanks for the example. I guess Perl thinks 0 is a number after all. ;-) +1 – Ben Dunlap Aug 16 '09 at 0:14

This is really going to depends on exactly what you are after doing. What path is passed to the original request? Is it always /audio/some_id/other_stuff? What other config is there for paths with "audio" in? For a request of the form:


you will probably want a RewriteRule of:

ReWriteRule ^/audio/(.*)/.*$ /audio.php?id=$1

I think the .*? are not doing what you want. Give that a whirl, and see what it does. You may also find the Perl regular expression reference guide helpful.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.