I thought about this other solution:
RewriteEngine On RewriteBase / # Hide the "pages" directory and all PHP files from direct access. RewriteRule ^pages\b|\.php$ - [R=404] # Rewrite clean-URL pages to the PHP files inside the "pages" directory: # If the request isn't a file. RewriteCond %{REQUEST_FILENAME} !-f # If the request isn't a folder. RewriteCond %{REQUEST_FILENAME} !-d # If the PHP page file exists. RewriteCond %{DOCUMENT_ROOT}/pages/$0.php -f # /your-page?param=foo is rewritten to /pages/your-page.php?param=foo # The L flag isn't suffisient because the rewrite rule to protect PHP files # above will take over in the second loop over all the rewrite rules. To stop # here we can use the newly END flag which stops completely the rewrite engine. RewriteRule ^.*$ pages/$0.php [END,QSA]
You wanted to hide index.php. This can be done with a 404 error. So you could just do:
RewriteRule ^index\.php - [R=404]
But you'll probably want to avoid also someone requesting /pages to list all the PHP files or to directly access /pages/your-page.php. So I used a regex that matches both the directory and PHP file extensions (only lowercase here, but you could use \.(?i)php where (?i) enables the case insensitive flag).
Then, for the rewrite itself, I would capture the URL with ^.*$ which will be available in the $0 backreference which can then be used in the rewrite rule itself and in the rewrite conditions.
If the request is not a directory or an existing file then we have to check that the resulting rewritten URL is effectively an existing PHP file in the pages directory.
I used the QSA flag so that you keep the query parameters in the resulting URL. The PHP script can then access them easily via $_GET. I expect you could also get them by checking some other environment variables if you don't use this flag. I also had to use the END flag which is similar to the L for Last flag but completely stops the rewrite rules to execute. If you use the L flag instead the problem is that you'll get the 404 error due to the fact that /pages/your-page.php will match the rewrite rule to hide PHP files since the whole process of rewrite rules is run a second time. The rewrite engine loop only stops when the input URL doesn't get changed anymore by rewrite rules. Yes, this took me ages to understand that rewrite rules are not just run once like they are displayed in the config file!
index.phpin the document root or/pages/index.php?