2

So I have the below code in my .htaccess file in my local apache XAMPP server in the root directory and it works 100% correctly. However, when I try to deploy to Heroku it does not work. I have tried slightly modified versions of this found on the internet to perform the same thing, but none of them seem to work. This is supposed to remove .php file extensions and allow things like /api/products/all where the file api.php exists and the products/all are just read in with PHP $_SERVER['PATH_INFO'] and output is returned based on what they are.

Options +MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.php [NC,L]

I don't know a ton about .htaccess so any help would be appreciated.

1 Answer 1

1

This is supposed to remove .php file extensions

Well, strictly speaking, this code is intended to add the .php file extension back again (in order to route the URL). (You've already "removed" it by making a request for /api/products/all.)

However, this code isn't doing what you think it's doing. This is only working on your local server because of the MultiViews line (part of mod_negotiation). The mod_rewrite code that follows is not doing anything at all, which is possibly why this is not working for you on Heroku?

If the mod_rewrite directives were allowed to run (ie. if MultiViews was disabled) then this would rewrite a request for /api/products/all to /api/products/all.php, which is clearly not correct in this example.

I don't know what other URL formats you are trying to handle, but to specifically route a URL of the form /api/products/all to /api.php/products/all using mod_rewrite, you would need something like the following instead:

RewriteEngine On
RewriteRule ^(api)/(.+) $1.php/$2 [L]

The RewriteCond directives are not required if you are only matching this specific URL.

...and the "products/all" are just read in with php

This is called additional pathname information and is managed/collected by the server and passed onto PHP in the PATH_INFO element of the $_SERVER superglobal. Whether path info is permitted at all is dependent on the server. (If not then such URLs would result in a 404.)

UPDATE#1:

...if I also have files such as example.js.php (where I use php code, but render them as javascript files) and I would like their .php to be removed so they can be accessed via example.js how would I modify the rewrite rule?

You could add an additional rule block like the following:

RewriteCond %{DOCUMENT_ROOT}/$1.$2.php -f
RewriteRule (.+)\.(js)$ $1.$2.php [L]

This intercepts all requests for .js files and rewrites the request to the corresponding .js.php file if it exists.

Alternatively, you could specify the RewriteCond directive like this:

RewriteCond %{REQUEST_FILENAME}.php -f

Note that if your .js files are also located under a URL-path that starts /api/ then this rule will need to go before the above rule that routes your api calls, in order to avoid a conflict.

UPDATE#2: You may also need to set the correct mime-type for these resources. (Whether it works or not with the wrong mime-type is browser dependent.) Since the .js URL is being internally rewritten to a PHP script (ie. .js.php) Apache will naturally serve this with a text/html mime-type (as it does for all PHP files by default). You can either make sure you are explicitly setting the correct Content-Type header from within your script, or set this in .htaccess using the Header directive (mod_headers). For example:

<FilesMatch "\.js.php$">
    Header set Content-Type "application/javascript; charset=UTF-8"
</FilesMatch>

Note that this will only work on Apache 2.2.12+ (before this version it simply wasn't possible to set the Content-Type header with the Header directive).

Note also, that the "simpler" method of setting the mime-type using the T flag on the RewriteRule doesn't work in a per-directory/.htaccess context - it gets overwritten when the rewriting process starts over.

7
  • Appreciate the in depth explanation. But to add on to my original question, if I also have files such as example.js.php (where I use php code, but render them as javascript files) and I would like their .php to be removed so they can be accessed via example.js how would I modify the rewrite rule?
    – Apickle
    Aug 8, 2017 at 1:05
  • The updated bit does not seem to work for me (just testing locally right now). I also tried just that updated bit without the first part (aside from RewriteEngine On) and still no luck. Is it possible there is syntax error or is there something else I need to include?
    – Apickle
    Aug 8, 2017 at 1:56
  • What actually happens? What happens if you request the .js file directly? If there was a "syntax error" you would get a 500 internal server error. It's possible that your server is not responding with the correct mime-type for this resource. I've updated my answer.
    – MrWhite
    Aug 8, 2017 at 12:08
  • It gives an error 404 if I try to access example.js. If I just try to accessexample.js.php it works. I already set the content type header's to be application/javascript within the .js.php files. Do it matter that my local server is on windows, but the remote server is on linux.
    – Apickle
    Aug 9, 2017 at 0:04
  • Was this working before with the Options +MultiViews directive? Where is the .htaccess file? I'm assuming it's in the "document root" of the site? Presumably, you've tested this on both your local (Windows) server and the "live" (Linux) server, and neither work? Whether it's Windows or Linux should not matter here. (Just to clarify, you're not linking to the remote server from the local server? ie. JS files stored remotely?!)
    – MrWhite
    Aug 9, 2017 at 10:11

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .