Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

345
Vistas
Can't use parentheses in RewriteCond QUERY_STRING

Moved from https://serverfault.com/questions/1013461/cant-use-parentheses-in-rewritecond-query-string because it's on topic here.


I need to capture a UID from an old url and redirect it to a new format.

example.com/?uid=123 should redirect to example.com/user/123

What should work:

RewriteCond %{QUERY_STRING} ^uid=(\d+)$
RewriteRule ^$ /user/%1? [L]

This does not redirect at all.

However, this does:

RewriteCond %{QUERY_STRING} ^uid=\d+$
RewriteRule ^$ /user/%1? [L]

It goes to example.com/user. The UID is left out, but it DOES redirect.

Notice: All I did was remove the parentheses in the second example.

Why is this?? How can I match the query AND capture the value of UID?


Updates

This is a laravel app. I've discovered that the redirects I did see may have been coming from the app, not Apache.

Self-answer coming soon...

Temporarily adding R=302 gives the desired result:

RewriteCond %{QUERY_STRING} ^uid=(\d+)$
RewriteRule ^$ /user/%1? [L,R=302]

This, of course, sends a 302 redirect to /users/123. I'd like to see if this can be done with an internal rewrite though...

Here are some rules in laravel's default .htaccess:

# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]

This catches paths that do not point to real files, and it points them to the laravel app. When this is removed, Apache responds with a 404 for /users/1234.

https://httpd.apache.org/docs/2.4/rewrite/flags.html#flag_l

Such a rewrite goes back to Apache's URL parser. Then the .htaccess is processed again (since it's still applicable to this new URL). At this point, I'd expect the above rules to pick up the non-existent path and point it to the laravel app...

Found it. Writing an answer now.

over 4 years ago · Santiago Trujillo
1 Respuestas
Responde la pregunta

0

The Answer

MrWhite was right. You have to add R=302 or R=301 to perform a redirect. An plain ol' rewrite won't work.

RewriteCond %{QUERY_STRING} ^uid=(\d+)$
RewriteRule ^$ /user/%1? [L,R=302]

The Reason

So, the way Laravel works is:

  • you request /some/file
  • .htaccess tells apache, "hey apache, if you have a request for a file that doesn't exist just pretend it's for index.php"
  • apache says, "hey php, I have a request to run index.php and the url is /some/file"
  • php runs the script which --whoah-- is a huge laravel application
  • whatever, "hey laravel, the server said /some/file is the url"
  • laravel does all it's fancy stuff, and it tries to match the url to one of your routes

Now, I added a rule to rewrite a certain URL to a virtual URL that Laravel should handle. I was matching against query parameters, but that was irrelevant. (see below for details)

When Apache's Rewrite Module hits a RewriteRule without an [R] flag, it rewrites the URL and sends it back to the URL Handler. Apache's URL Handler then processes the new URL against all the rules, including those in any applicable .htaccess files.

So all the proper rules did get applied.

Here's the key revelation: The originally requested URL never changed. So while Apache was able to pass the request to PHP with the correct file, it was also sending along the old URL.

Therefore, we have to tell Apache to send a 301 or 302 Redirect response, instead of just rewriting the request. The user will send another request with the URL that Laravel needs to resolve the route.


But what about the different behavior with/without the parentheses?

The answer lies within Laravel's default .htaccess. Let's take a look my old rules without the parentheses:

RewriteCond %{QUERY_STRING} ^uid=\d+$
RewriteRule ^$ /user/%1? [L]

Without the parenthesis to grab the uid value, %1 is empty. So we end up rewriting the URL to just /user/.

Now, we have to look at another set of Laravel rules:

RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]

This normalizes urls so that virtual paths/routes don't contain trailing slashes. Doing this makes route parsing easier.

This returns a 301 Redirect to `/users'. This is very different from the 200 we were getting with the parentheses, but it does not mean the parentheses were behaving differently. As MrWhite said in the comments, surely something else was doing it.

I hope you enjoyed the ride. And I hope even more that this will save some poor, confused soul from hours of torment. :)

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda