1

I have a few URLs that I want to map to certain files via PHP. Currently, I am just using mod_rewrite in Apache. However, my application is getting too large for the rewriting to be done with regular expressions. So I created a file router.php that does the rewriting. I understand to do a redirect I could just send the Location: header. However, I don't always want to do a redirect. For example, I may want /api/item/ to map to the file /herp/derp.php relative to the document root. I need to preserve the HTTP method as well. "No problem," I thought. I made my .htaccess have the following snippet.

RewriteEngine On
RewriteRule ^api/item/$ /cgi-bin/router.php [L]

And my router.php file looks as follows:

<?php

$uri = parse_url($_SERVER['REQUEST_URI']);
$query = isset($uri['query']) ? $uri['query'] ? array();
// some code that modifies the query
require_once "{$_SERVER['DOCUMENT_ROOT']}/herp/derp.php?" . http_build_query($query);

?>

However, this doesn't work, because the OS is looking for a file named derp.php?some=query. How can I simulate a rewrite rule such as RewriteRule ^api/item/$ /herp/derp/ [L] in PHP. In other words, how do I tell the server to process a different URL than requested and preserve the query and HTTP method without causing a redirect?

Note: Using variables set in router.php is less than desirable and is bad structure since it's only supposed to be responsible for handling URLs. I am open to using a light-weight third party solution.

Tyler Crompton
  • 11,740
  • 12
  • 59
  • 91

2 Answers2

1

Change your .htaccess to read

RewriteEngine On
RewriteRule ^api/item/$ /cgi-bin/router.php [QSA,L]

In your php

// update your get variables
$_GET['some_var'] = 'my modifications';

// require file
require_once "{$_SERVER['DOCUMENT_ROOT']}/herp/derp.php"
cmorrissey
  • 8,187
  • 2
  • 17
  • 26
  • Is the `QSA` flag really necessary in this case if Apache isn't modifying the query? – Tyler Crompton Oct 23 '13 at 15:33
  • 1
    @TylerCrompton no its not ... but if you did update it to pass the url to determine the page requested instead of using php ... `RewriteCond %{REQUEST_URI} ^api/ RewriteRule ^(.*)$ /cgi-bin/router.php?url=$1` then you are preserving the Query ... I always like to add it – cmorrissey Oct 23 '13 at 15:42
0

Instead of require_once, try file_get_contents:

file_get_contents ((stripos($_SERVER['SERVER_PROTOCOL'],'https') === true ? 'https://' : 'http://'). "{$_SERVER['SERVER_NAME']}/herp/derp.php?" . http_build_query($query));

Be carefull with SERVER_NAME.

EDIT

For the records, if you need to work with ANY method (HTTP, HTTPS, FTP, etc.) or page infomation like cookies, you can use streams as a built-in (quicker?) alternative to cURL and PECL. In this example:

$params = array(
   'http' => array(
      'method' => 'GET',
      'content' => http_build_query($query)
   )
);

$context = stream_context_create($params);

file_get_contents (
   (stripos($_SERVER['SERVER_PROTOCOL'],'https') === true ? 'https://' : 'http://'). "{$_SERVER['SERVER_NAME']}/herp/derp.php", 
   false, 
   $context
);
Community
  • 1
  • 1
Edakos
  • 1,096
  • 7
  • 12
  • 1
    While that'd sort of work it's doubling the number of requests (and would not preserve any headers or data from the original url - i.e. no session persistence, cookie info or POST data), overall it's not a good idea to use this kind of approach – AD7six Oct 23 '13 at 15:51
  • It wouldn't work at all for the POST, PUT, or DELETE methods. If I wanted to do it that way, I would just use cURL. But again @Edakos, no additional requests is a requirement for this question. – Tyler Crompton Oct 23 '13 at 15:54
  • _this answer_ works for any method? You don't address doubling requests =) – AD7six Oct 24 '13 at 07:50