80 lines
No EOL
3.1 KiB
Markdown
80 lines
No EOL
3.1 KiB
Markdown
---
|
|
date: 2025-10-30
|
|
title: Apache Slash-y
|
|
description: remove trailing /index.php from URIs with apache web server.
|
|
preview_image:
|
|
tags: programming
|
|
permalink: /blog/27/
|
|
---
|
|
|
|
gahhhhhh this was driving me crazy, putting it here so i don't lose it
|
|
|
|
basically this solves the problem where you have pages like
|
|
|
|
```
|
|
http://example.com/page2/index.php?query=true
|
|
```
|
|
|
|
and you want it to display in the browser as the much nicer
|
|
|
|
```
|
|
http://example.com/page2?query=true
|
|
```
|
|
|
|
and you can't use nginx try_files because you promised yourself you were gonna make this work in apache "for old times' sake"
|
|
|
|
basically: this takes a surprisingly large number of rewrite rules. in order:
|
|
|
|
- remove trailing slashes, `page2/` -> `page2`
|
|
- remove file extensions, `page2.php` -> `page2`
|
|
- remove index filenames, `page2/index.php` -> `page2`
|
|
- oh yeah for EACH of those last three things, I hope you remembered to preserve the query string, so `page2/?query=true` -> `page2?query=true`
|
|
- okay now you have a nice short URL in the browser. now just undo all that logic to get the actual php file to run on the server.
|
|
- if `page2` is a directory then serve from `page2/index.php`
|
|
- if `page2.php` exists then serve from `page2.php`
|
|
- if none of those things exist then fall back on static file hosting. like, `page2.html` might exist, you can serve that, sure, why not.
|
|
- oh you wanted to remove the html extension too? okay do all that again bozo.
|
|
|
|
```sh
|
|
RewriteEngine On
|
|
#LogLevel alert rewrite:trace6
|
|
|
|
# remove trailing slash
|
|
RewriteRule (\/.*)\/+(\?.*)?$ $1$2 [R]
|
|
|
|
# remove file extensions
|
|
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f
|
|
RewriteRule (.*)\.(php|html)(\?.*)?$ $1$3 [NC,R]
|
|
|
|
# remove index.php index.html etc
|
|
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-d
|
|
RewriteRule (.*)\/index(\?.*)?$ $1$2 [NC,R]
|
|
|
|
# serve php file
|
|
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.php -f
|
|
RewriteRule (\?.*)?$ fcgi://php:9000/usr/local/apache2/htdocs/%{REQUEST_URI}.php$1 [P,L]
|
|
|
|
# serve php file with index
|
|
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}/ -d
|
|
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}/index.php -f
|
|
RewriteRule (\?.*)?$ fcgi://php:9000/usr/local/apache2/htdocs/%{REQUEST_URI}/index.php$1 [P,L]
|
|
|
|
# serve html file
|
|
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.html -f
|
|
RewriteRule ([^?]*)(\?.*)?$ $1.html$2 [L]
|
|
|
|
# serve html file with index
|
|
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}/ -d
|
|
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}/index.html -f
|
|
RewriteRule ([^?]*)(\?.*)?$ $1/index.html$2 [L]
|
|
```
|
|
|
|
some useful tricks:
|
|
- [NC] can be added after any regex rule to make it Non-Case sensitive.
|
|
- [R] means "in-browser redirect" and is used when you want to fix a URI on the user's side. if you don't do this then it only affects where the server pulls data from.
|
|
- [P] means "proxy" and it allows you to have the server pull data from another machine or from a program running on a local port.
|
|
- [L] means "last one" and it skips all remaining rewrite rules, in case you were worried about matching too many of them.
|
|
|
|
all this and more can be found at [the apache2 docs](https://httpd.apache.org/docs/current/mod/mod_rewrite.html).
|
|
|
|
if there's an easy way to do all this then please please tell me, I miss try_files so much, holy cow. |