62

I have a website where all requests are redirected silently (via .htaccess) to index.php and then PHP is used to show the correct page (by parsing the REQUEST_URI).

I was wondering if it's possible to submit POST data to a fake address too?

I've currently got my form like so...

<form action="/send-mail" method="post">

And my .htaccess rule is...

# redirect mail posting to index
RewriteRule send-mail index.php?send-mail [NC,L] 

My index.php checks isset($_GET['send-mail']) which works fine.

This however seems to drop off all the POST data that should be sent to it.

Is there a way to keep the post data? I don't want to use GET because it can't send as much information, though it might not be an issue with a simple inquiry form.

Here is my .htaccess for redirecting to index.php

# serve files and dirs if they exist please, otherwise send to index
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . index.php
alex
  • 479,566
  • 201
  • 878
  • 984

6 Answers6

70

Try this:

# redirect mail posting to index
RewriteRule send-mail index.php?send-mail [NC,P]

"P" acts like "L" in that it stops processing rules but it also tells the module that the request should be passed off to the proxy module intact (meaning POST data is preserved).

Giacomo1968
  • 25,759
  • 11
  • 71
  • 103
Tautologistics
  • 1,488
  • 12
  • 12
  • 16
    Note that you need to enable the proxy module, and the proxy_http_module in the config files for this to work. Also, you might need to set the absolute path to the rewrite rule. That is, in the example above, you would use `RewriteRule send-mail /path/to/index/index.php?send-mail [NC,P]` (or at the very least a `/` before index) – Marius Jan 29 '10 at 14:31
  • 2
    If you want the Host header to be preserved, you'll also want to enable `ProxyPreserveHost On` in apache config. – Artem Russakovskii Aug 12 '12 at 05:15
  • It seems that in the meantime proxying also works for URLs as pointed out in the documentation: https://httpd.apache.org/docs/2.4/rewrite/proxy.html – Kjell Apr 23 '17 at 13:49
  • I spent 3 days trying to figure out why the POST data was not forwarded. The [P] made the job. Thank you. – Jean-François Aug 26 '21 at 14:40
9

You should be able to simply redirect to index.php, and then in that script, access $_SERVER['REQUEST_URI'] to see the original request, with "send-mail" intact.

By the way, "can't send as much information" is not the reason to use POST. The reason to use POST is that the request will modify data on your site, instead of simply retrieving data.

Suppose you put a hyperlink on your page with a GET request like "/delete_user?id=1234," and then some search engine innocently follows the link as it's indexing your site. That's why GET requests are not good for requests that modify data.

Bill Karwin
  • 538,548
  • 86
  • 673
  • 828
  • 3
    Theres a small limitation in that, once you hit some arbitrary limit ( i think its 1024 characters ), data following it gets stripped from the request. Especially problematic if it happens to be a user input field. – Kent Fredric Dec 11 '08 at 06:24
  • 3
    (NB: Limit is server *and* browser specific, RFC says its unbounded, but we know how often some companys read that ) – Kent Fredric Dec 11 '08 at 06:28
  • 3
    +1 I'm a bit more enlightened since I asked this question and now fully understand all modification of data should be POST – alex Aug 14 '09 at 01:57
6

I've found the most reliable way is to use the 307 status code.

RewriteRule send-mail index.php?send-mail [R=307,L]

Status code 307 indicates that the request should be repeated with the same HTTP method and data. So your POST request will be repeated along with its data if you use this status code.

You may detect if the request is a POST request as well in case you need to support standard 301 redirects for non POST requests.

# POST requests.
RewriteCond %{REQUEST_METHOD} POST
RewriteRule send-mail index.php?send-mail [R=307,L]

# Standard GET requests.
RewriteRule send-mail index.php?send-mail [R=301,L]
Giacomo1968
  • 25,759
  • 11
  • 71
  • 103
Mat Lipe
  • 725
  • 8
  • 14
  • It´s exactly as you say. Thanks for the tip. (detailled at https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.8) – Kadaiser Dec 20 '21 at 11:28
1

I want to redirect user_login.php to seo friendly url like /user-login with post form data and this worked for me.

RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s/user_login\.php [NC]
RewriteRule ^ user-login [QSA,R=301]
RewriteRule ^user-login$ user_login.php [QSA,L]

In view file

<form action="<?php $siteurl;?>/user-login" method="post" id="user_login">
Kamal Kumar
  • 3,393
  • 2
  • 19
  • 15
1

To avoid issues with some proxies and Apache rewrites, pass in POST data or set the Content-Length: 0 header for requests with an empty body.

I recently had issues with Apache converting my request to a GET when doing a POST with an empty body. So, instead of this:

curl -X POST https://example.com/api/user/123456789

pass the Content-Length header:

curl -X POST https://example.com/api/user/123456789 -H 'Content-Length: 0'

or pass something in the body:

curl -X POST https://example.com/api/user/123456789 -d ''
Giacomo1968
  • 25,759
  • 11
  • 71
  • 103
Alex Pop
  • 168
  • 1
  • 6
0

As long as you are only using an internal rewrite, not an HTTP redirect, you should not lose POST data. Here is the rule I use on my site:

RewriteRule ^(.*)$ index.php/$1 [L]

Try using the HTTPLiveHeaders extension for Firefox (or something similar) and track the entire page request. Make sure you are not getting an HTTP redirect. If you get a HTTP/1.1 3xx response and Location: http://address header, that is the problem. Your rewrite rule that you posted should not cause that to happen. If you are being redirected, there is probably either an error in your PHP code or another rewrite rule that is being applied.

mcrumley
  • 5,682
  • 3
  • 25
  • 33