Can someone explain this strange mod_rewrite regex behavior - php

I've been working on a script for debugging mod_rewrite, and when testing their regex system I've had some strange results. I'm wondering if this is normal behavior for the mod_rewrite regex engine or if some part in my code is causing it.
Requested URL: http://myurl.com/path/to/something
.htaccess has: RewriteRule to where
Using my debugging system, the following is what happens when that RewriteRule is used:
path/to/something -> where/to/something
Shouldn't it be path/where/something???
Here's the full .htaccess file
RewriteEngine On
RewriteBase /ModRewriteTester
RewriteRule .* - [E=ORIG:$0]
RewriteRule to where
RewriteRule .* - [E=MODD:$0]
RewriteRule .* index.php
Then I've got a php script that's reading in the environmental variables $_SERVER['REDIRECT_ORIG'] and $_SERVER['REDIRECT_MODD'], that's where I'm getting the previously stated paths.
If anyone knows a better way to explicitly show how mod_rewrite's regex engine works I'm open to it. The initial question still stands though...

Your rule:
RewriteRule to where
...will rewrite a URL that matches to and replace it with the URL representing what would be a request to /where. It's possible in certain circumstances for mod_rewrite to try and re-add what Apache believes to be PATH_INFO, which could create a situation like the following:
path/to/somewhere -> PATH_INFO = /to/somewhere
path/to/somewhere -> /where
(append PATH_INFO) -> /where/to/somewhere
To check if this is the case in your scenario, you can add the DPI flag to the RewriteRule to discard the PATH_INFO if it exists. This would look like this:
RewriteRule to where [DPI]
In this case, you would end up with just the URL /where. If you wanted to replace to with where while retaining the rest of the URL, you would need a rule more like this:
RewriteRule (.*?/)?to(/.*)? $1where$2
As far as debugging your rule set goes, if you have access to the Apache configuration you're much better off using the RewriteLog directive with a sufficiently high RewriteLogLevel. If you don't have access to the configuration, you're pretty much limited to doing something similar to what you're trying to do now.

Related

Generic way to rewrite external /api/entity/1 URL to internal /api/entity.php/1 (or /api/entity.php?id=1)

With a API I'm trying to make in PHP I currently have these rewrite rules setup in the .htaccess file for the root directory of the API:
# Remove the php extension from the filename
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
This is so that requests to the API appear more "RESTful" - so instead of api/entity.php?id=5 it would be api/entity?id=5 - I'd like to go a step further though, and allow a request URL like api/entity/5 to successfully rewrite to api/entity.php/5 or api/entity.php?id=5.
I was experimenting with an apache rewrite rule something like this, where it has regex to detect a path like entity/{any number here}
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.php [NC]
RewriteRule ^(.+)(\/\d+)$ $1.php$2 [NC,L]
Where it would match entity/5 in two captures with entity and /5 and would then internally direct that to entity.php/5 - at which point in the php file I could do an explode on the request URI or something similar to that to get the value from the path.
But I don't really know enough about apache rewrites to fully implement this, as this rule doesn't work for whichever reason. I'm aware I could write hardcoded rewrite rules for each directory I would like to behave like this, but I'd really rather keep this generic.
If there is no real way to achieve what I want to here, then I'd rather just stick to paths like api/entity?id=5 than need to write a whole bunch of rewrite rules.
I was thinking as well, if there is a way to detect when a request doesn't match a directory (which would be what happens by default with a path like api/entity/5?) - it runs a different rewrite in this case - without running the first and causing it to try and write the now internally pointed URL, but again, I'm not sure how to go about implementing this.
Can someone with more experience point me in the right direction?
As Chris Hass highlighted, in this case implementing a PHP router of some variation probably makes more sense and is just easier.
Here are links to some examples I found for anyone in the future who stumbles onto this:
https://medium.com/the-andela-way/how-to-build-a-basic-server-side-routing-system-in-php-e52e613cf241
https://www.taniarascia.com/the-simplest-php-router/
https://www.educative.io/edpresso/how-to-create-a-basic-php-router
Obviously, if you're not intentionally using just PHP on its own like me, there's no reason you couldn't use a library or do this with Laravel etc to make your life even easier, why reinvent the wheel after all?

htaccess setup for rest api to handle directories that do not exist

I'm having a terrible time and not sure if I'm overthinking it. I'm trying to create a rest API in php (may not matter). I want to have the uri in the format /api/research/data/2020. I created the directory "research" but nothing below that. In the htaccess file, I have
Options +FollowSymLinks
RewriteEngine On
RewriteRule ^/api/research/data/$ /api/research/index.php [NC,L]
I keep getting results that /api/research/ does not exist (it's true, it doesn't). I have tried to be literal and I have tried various pattern matching. I have googled around and tried a lot of things but nothing seems to be getting me what I need.
Main question: does /api/research/ need to exist? Does /api/research/data/ ? Or if not, what might I be doing wrong?
Thank you!
UPDATE May 26, 2020: I finally got this working:
Options +FollowSymLinks
RewriteEngine On
RewriteRule ^mobile/list/?$ RestController.php?view=all [nc,qsa]
RewriteRule ^mobile/list/([0-9])+/? RestController.php?view=single&id=$1 [nc,qsa]
1) The main issue I was having was starting off with ^/ instead of just ^. As soon as I made that change, it cleared right up. I do NOT need to create any of these directories.
2) The .htaccess file needs to be at the public_html level. I had it in a subdirectory trying to match the target.
I would recommend to rewrite using wildcards and then filter the endpoints of the API in PHP:
# .htaccess
RewriteEngine On
RewriteRule ^(.*)/(.*)/?$ index.php [nc,qsa]

Unlimited paired variables through .htaccess

This may be asked already but I'm struggling on here and can't figure it out,
I'm not really good with .htaccess
I'm working on an API and would like to accept multiple variables such as
http://www.website.com/api/CONTROLLER/person/id/1/sort/name/limit/2
and would like to obtain something like
$_REQUEST['CONTROLLER']=person;
$_REQUEST['id']=1;
$_REQUEST['sort']=name;
$_REQUEST['limit']=2;
I'm currently doing this through php using $_SERVER[REQUEST_URI] and explode, but would like to find out if there is a way to do it on .htaccess directly
If you know which one will perform best would be glad to hear it out!
Try:
RewriteEngine On
RewriteRule ^api/([^/]+)/([^/]+)(/.*)? /api/$3?$1=$2 [L,QSA]
Assuming that your php script is the index.php file in your /api/ directory. Otherwise, you'd need to also include (at the end):
RewriteCond %{QUERY_STRING} .+
RewriteRule ^api/$ /path/to/your/script.php [L,QSA]
Note that this relies on the mod_rewrite engine looping internally. There's a server setting which limits the maximum number of internal redirects, and if the URL is really long, it'll hit the internal recursion limit and return a 500. You can change this using the LimitInternalRecursion directive.

How to have a PHP file be used for multiple URLs

I want to have a single PHP file that takes care of multiple URLs in a subdirectory.
For example, my site is http://www.startingtofeelit.com/. I want one php file, say, called playlist.php which would handle when a user goes to http://www.startingtofeelit.com/playlist/101 or if they go to http://www.startingtofeelit.com/playlist/142 etc. I want to be able to strip the number (101, 142 in my example urls above) to use as a variable (the playlist ID), so I can display the correct playlist.
I know that I can create an index.php in my playlist subdirectory and use GET variables like http://www.startingtofeelit.com/playlist?id=102 and get the ID that way, but this is much sloppier looking and I'd like to be able to know how to do it the other way.
My site is built on WordPress, but I don't think this should make a difference in any way.
Well, you cannot achieve this with PHP alone.
If you use Apache, you can use .htaccess
If you use IIS, you can use URL Rewrite
The basic idea behind those modules is to mapping from one URL to another URL. For example: you would want to map from
http://www.startingtofeelit.com/playlist/142 =>
http://www.startingtofeelit.com/playlist.php?id=142
You can express the URL mapping in regular expression. For example, in .htaccess (Apache). You can write like this
RewriteRule ^playlist/([0-9]+)/?$ playlist.php?id=$1
Noted that, you need to have .htaccess file in your website directory. Since, you are using Wordpress, chance that you have existed .htaccess is high. You can simply append that line of code to existed .htaccess
The following is an explanation of the regular expression:
^playlist/ # any URL start with playlist/
([0+9]+) # following by number, and store it as $1
/?$ # end with or without /
Mapping to
playlist.php?id=$1 # where $1 is taken from the matched number from our pattern.
This is usually handled in a way similar to what you already tried. However, it's common to use a re-writing script so that your application will accept a clean URL such as:
http://www.startingtofeelit.com/playlist/142
...and re-write it for your application as such:
http://www.startingtofeelit.com/playlist?id=142
For example, if you're using an Apache web server and have the mod_rewrite module installed and enabled, you can use the following snippet in an .htaccess file and use your GET parameter as you indicated you already know how to do. Other popular web servers have unique URL re-writing modules that will let you do the same.
<IfModule mod_rewrite.c>
RewriteEngine On
# Rewrite this:
# http://www.example.com/somepage/1
# ...into this:
# http://www.example.com/somepage?id=1
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?/$1 [L]
</IfModule>

What's the best way to get rid of .php suffix in url strings so they look pretty? [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Remove .php extension with PHP
What's the best way to get rid of .php suffix in url strings so they look pretty?
Thank you in advance;-)
Use apache mod_rewrite (rewriting rules)
http://roshanbh.com.np/2008/02/hide-php-url-rewriting-htaccess.html
Make sure your apache installation has mod_rewrite enabled (will be in httpd.conf, or one of the files linked there, mods-enabled or such) and look into how routing works in cakePHP.
Couple of tips - the rewrite rules are found in the .htaccess files (make sure you don't have a unicode BOM if the server gives a 500 error) and if you do find you need those $_GET paramters, [qsappend] on your rewrite rule should pass them along. If you still get 500s the compilation errors on regexes can be found in apache's error log, invaluable for debugging.
Might be easier to do a simple project with mod_rewrite first, to learn how it works, as the combination of rewrite and routing in cake can get pretty complex pretty fast.
Options +MultiViews
in the Apache configuration.
Here is a gentle introduction into mod_rewrite.
The best way to do so (at least for me) is:
Use just one file to receive all request. In most of the cases it will be the index.php file.
Then, use mod_rewrite rules like this:
:
RewriteEngine On
RewriteBase /the_base_dir_of_your_app/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /the_base_dir_of_your_app/index.php [L]
Then, you can analize the URL using functions like basename($_SERVER['REQUEST_URI']); in order to decide what to do.
Use mod_rewrite - or start using ASP.NET MVC 2 :)
If you use a framework, like CakePHP (or any other) it will do it for you. For free. Right now.
.htaccess:
Permalinks
RewriteEngine on
Remove www
RewriteCond %{HTTP_HOST} ^www.yourdomain.com [NC]
RewriteRule (.*) http://yourdomain.com/$1 [R=301,L]
Links
RewriteRule ^faq$ /faq.php [L]
RewriteRule ^donations$ /donations.php [L]
RewriteRule ^contact$ /contact.php [L]
so they look pretty?
Beauty is in the eye of the beholder. It depends when you consider 'pretty'. A lot also depends on how much you want to get away from the conventions that make a working system possible and the constraints in terms of reconfiguring your site.
While others have mentioned using mod_rewrite, or URL parsing or other such approaches I'm not a fan of these - in addition to being very specific to the type of webserver the code is running on they also break the simple 1:1 mapping beween paths in URIs and paths on the webserver's filesystem.
You could just substitute '.php' with an extension of your choice...but that hardly meets my interpretation of 'pretty'.
The approach I take is to have every script (or at least every script with is intended to be entry point to generaeing a web page) is named as index.php and exists in its own uniquely named directory. The main reason for doing this is nothing to do with making the URL look nice but rather to make the codebase more manageable - I also have strict standards about the naming and placement of include files.
HTH
C.

Categories