Using htaccess to rewrite URL using an ID to a JPG filename - .htaccess

I currently have URLs like this:
/video/245008/245008_00000001.jpg
/video/245008/245008_00000002.jpg
etc.
I need htaccess to rewrite the above urls to be:
/video/245008/245008_1.jpg
/video/245008/245008_2.jpg
But only if the original 00000001.jpg, etc do not exist. Any suggestions?

Try adding these rules to the htaccess file in your document root (the one that has the video directory):
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} ^/video/([0-9]+)/\1_0+([1-9][0-9]*)\.jpg$
RewriteCond %{DOCUMENT_ROOT}/video/%1/%1_%2.jpg -f
RewriteRule ^ /video/%1/%1_%2.jpg [L]
The first condition checks that the current request points to a file that doesn't exist. The second condition checks that the request is for something in the video directory, 2 gorups of identical numbers, and underscore with at least one zero following it, then some more numbers. The third condition checks that the new URI points to a file that does exist.

Related

htaccess: rewrite URL to a file only if that file exists, but with regex captured groups

I have a CMS that I've built myself in PHP (Codeigniter framework). I was thinking why every time PHP has to process all code just that to respond with a page. So instead I will create the complete HTML pages and serve them when a user asks for them.
That is why I need to rewrite an URL to a specific file only if that file exists. For this, I need to use regex captured groups because I want to build this for all files in that folder and subfolders.
For example, I want to put a bunch of HTML pages on %{DOCUMENT_ROOT}/out and want to access them directly with rewrite rules.
For example, if the URL is like this:
htaaatps://www.dsaoidashd.com/services/development-of-desktop-applications
I want to look at the following location:
%{DOCUMENT_ROOT}/out/services
for
development-of-desktop-applications.html
and if it exists, I want to return it to the client browser without continuing.
And of course, if I have yet more levels like this:
htaaatps://www.dsaoidashd.com/services/development/of-desktop-applications
then I need to check this location:
%{DOCUMENT_ROOT}/out/services/development
for
of-desktop-applications.html
file and return it to the calling browser.
I tried
I know that I have to use RewriteCond to check if the file exists but how to pass it to the RewriteCond regex captured groups so I can check them based on the URL provided?
RewriteEngine on
RewriteCond %{DOCUMENT_ROOT}/out/$1.html -f
RewriteRule ^.*$ /$1.html [L]
Your RewriteCond is almost correct but you have to capture $1 in a group in RewriteRule and also your target needs to be out/$1.html.
You can use this rewrite rule in your site root .htaccess:
RewriteEngine On
# To internally forward /dir/file to /out/dir/file.html
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/out/$1.html -f
RewriteRule ^(.+?)/?$ out/$1.html [L]

How to write a htaccess rewrite rule where you can load a website inside a folder as it would be loaded from the root

I have the following folder structure
ROOT (loaded on domain.com)
+campaigns
|+campaign1
|-assets
|-index.php
|-campaign2
.htaccess
index.php
stuff.php
At the moment to access the website inside the folder campaign1 i would have to enter in the URL address bar: domain.com/campaigns/campaign1
What should i put in the .htaccess file so that when you put
domain.com/campaign1 the browser loads and shows everything from domain.com/campaigns/campaign1 but of course without visibly changing the URL in the address bar.
Thank you so much for your help.
You could do something like the following in the root .htaccess file using mod_rewrite. This is a general version if the "campaign" subdirectories are not known (or too many):
RewriteEngine On
# 1. Abort early if request already maps to a file or directory
RewriteRule ^campaigns/ - [L]
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# 2. Check if the first path-segment maps to a directory in "/campaigns` directory
# If so then internally rewrite the request to that subdirectory
RewriteCond %{DOCUMENT_ROOT}/campaigns/$1 -d
RewriteRule ^([^/]+)/ campaigns%{REQUEST_URI} [L]
Where $1 is a backreference to the captured subgroup in the RewriteRule pattern.
i would have to enter in the URL address bar: example.com/campaigns/campaign1
Since campaign1 is a directory you should be requesting campaign1/ (with a trailing slash) otherwise mod_dir is going to issue an external redirect to append the trailing slash.
when you put example.com/campaign1 the browser loads and shows everything from ...
Likewise, you should be requesting example.com/compaign1/ - with a trailing slash - and the above rule assumes that you are. It won't do anything if the trailing slash is omitted and you will get a 404. (If you are expecting third party requests where the trailing slash is omitted then you will need to manually issue a 301 redirect to append the trailing slash before the above rule.)
UPDATE:
What if i know the name of the campaign folder that goes into the campaigns folder? basically if i want to manually add the rule but campaign specific?
Yes, you can do this. In fact, if the number of campaigns you wish to rewrite in this way is limited then this may even be preferable since it avoids the filesystem check.
You may also be able to remove the second rule (second part of section#1 above) that prevents further processing should a file or directory be requested. ie. Remove the following:
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
So, instead of (or before) section#2 above you could do the following...
For a single campaign:
# 2. Rewrite campaign to "/campaigns" subdirectory
RewriteRule ^compaign1/ campaigns%{REQUEST_URI} [L]
For multiple campaigns:
# 2. Rewrite campaigns to "/campaigns" subdirectory
RewriteCond $1 =campaign1 [OR]
RewriteCond $1 =campaign2 [OR]
RewriteCond $1 =campaign3
RewriteRule ^([^/]+)/ campaigns%{REQUEST_URI} [L]
Note that it is specifically $1 =campaign1, the = is a prefix-operator on the CondPattern (2nd argument) itself. The = operator makes it an exact string match, not a regex.
Or, using a regex and alternation:
# 2. Rewrite campaigns to "/campaigns" subdirectory
RewriteCond $1 ^(campaign1|campaign2|campaign3)$
RewriteRule ^([^/]+)/ campaigns%{REQUEST_URI} [L]
(Although this could be combined into a single directive.)
UPDATE#2:
Add this before the internal rewrites to add a trailing slash at the end of the URL:
RewriteCond %{REQUEST_URI} !\.
RewriteRule !/$ %{REQUEST_URI}/ [R=301,L]
Note that all internal links must already linking to the URL with a trailing slash. This redirect is only for the benefit of search engines and third party links that might be referencing the non-canonical URL without a trailing slash.

How To check and remove if any subfolder exists in a Folder by Htaccess?

I have a file structure like this.
Folder
- .htaccess
- Subfolder
- Otherfolder
- file1.html
- file2.html
- filea.html
- fileb.html
I can have many folders at the place of 'otherfolder' and I don't want to add code for each subfolder of 'Subfolder'.
i want to remove all other subfolders names except folder.
I just want to get URL like - mywebsite.com/folder/file.html
Edit
currently I am using this code snippet in .htaccess
RewriteEngine On
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^subfolder/([^.]+)\.html$ /folder/$1 [L,R]
RewriteCond %{REQUEST_URI} !/folder/subfolder/
RewriteCond %{REQUEST_URI} !\.(css|js|jpg|gif|png|jpeg)$
RewriteRule ^(.+)/?$ /folder/subfolder/$1.html [L]
I can have many folders at the place of 'otherfolder' and I don't want to add code for each subfolder of 'Subfolder'.
This isn't possible in .htaccess alone. The problem is not in removing the subfolder from the URL (although this should already have been done in the internal link), the problem is internally rewriting the request back to the appropriate subfolder. There is no built-in mechanism to "search" for arbitrary files in .htaccess.
If you have a limited number of known subfolders then you can do this, but you need to add a rule (in the root .htaccess file) for every subfolder. However, this is not particularly efficient since you need to manually test for the existence of that file in each subfolder. You also have a potential problem of name collision. Obviously, if you effectively "flatten" the filesystem the file file1.html can only exist once on the filesystem, amongst all subfolders. If there is more than one file1.html then the first match wins.
In principle, you would need to do something like the following to rewrite a request for /folder/<file>.html back to /folder/subfolder/otherfolderN/<file>.html.
# Test "subfolder/otherfolder1"
RewriteCond %{DOCUMENT_ROOT}/folder/subfolder/otherfolder1/$0 -f
RewriteRule ^[^/.]\.html$ subfolder/otherfolder1/$0 [L]
# Test "subfolder/otherfolder2"
RewriteCond %{DOCUMENT_ROOT}/folder/subfolder/otherfolder2/$0 -f
RewriteRule ^[^/.]\.html$ subfolder/otherfolder2/$0 [L]
# Test "subfolder/otherfolder3"
RewriteCond %{DOCUMENT_ROOT}/folder/subfolder/otherfolder3/$0 -f
RewriteRule ^[^/.]\.html$ subfolder/otherfolder3/$0 [L]
The parent /folder/ could be abstracted out of the RewriteCond TestString if you wish, but the subfolder and otherfolderN would need to be hardcoded. (Although subfolder could be manually assigned to an environment variable to save repetition.)
Aside:
RewriteCond %{REQUEST_URI} !/folder/subfolder/
RewriteCond %{REQUEST_URI} !\.(css|js|jpg|gif|png|jpeg)$
RewriteRule ^(.+)/?$ /folder/subfolder/$1.html [L]
A "problem" with this code is that it rewrites the request regardless of whether the target file exists or not. This is OK if you are rewriting all requests to a single subfolder, but if you have multiple subfolders then you must check for the target file's existence before rewriting.
This also rewrites the request even if it already maps to an existing file. So any legitimate files in the /folder/ directory (eg. filea.html and fileb.html in your file structure) would not be accessible.
This also rewrites every file type (except for the few file extensions listed in the preceding condition). It would, for instance rewrite a request for foo/bar/file.webp to /folder/subfolder/foo/bar/file.webp.html. If you are only wanting to rewrite .html files then include this in the RewriteRule pattern and the preceding condition is not required.

How to rewrite directory for multiple level directories

This is my .htaccess
RewriteEngine On
# browser requests PHP
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /([^\ ]+)\.php
RewriteRule ^/?(.*)\.php$ /$1 [L,R=301]
# check to see if the request is for a PHP file:
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^/?(.*)$ /$1.php
RewriteCond %{REQUEST_URI} !^/(views|css|js|media|partials|php)
RewriteRule (.*) /views/$1
This is my project structure:
The idea is that all my HTML files are structured in the folder views, but I don't want my URL to be http://example.com/views/index but just http://example.com/index without the views-part.
This is working fine in the following case:
http://example.com/account/
But fails as soon as I try to access a file in the accounts-folder e.g: http://example.com/account/voeg-kind-toe
That results in a 404. Seems like this .htaccess solution only works for one-level directories.
Edit:
Interesting: If I place the bottom two lines on top (so placing the code to rewrite the view-part before the code to remove the php-extension); the php-extension works but the /views//part don't.
Create .htaccess like this
RewriteEngine on
RewriteCond %{HTTP_HOST} ^(www.)?example.com$
RewriteCond %{REQUEST_URI} !^/views/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /views/$1
RewriteCond %{HTTP_HOST} ^(www.)?example.com$
RewriteRule ^(/)?$ views/ [L]
As mentioned in my comment above, providing there are no other directives/conflicts then this should still "work" in a roundabout way. However, there is an issue with the following directive in the order you have placed it:
# check to see if the request is for a PHP file:
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^/?(.*)$ /$1.php
You aren't testing for files in the /views subdirectory. But also, REQUEST_FILENAME does not necessarily contain what (I think) you think it does. When you request /account/voeg-kind-toe (an entirely virtual URL path) then REQUEST_FILENAME contains /account (it actually contains an absolute filesystem path, but I've kept it brief). So, the above is testing whether /account.php exists, not /account/voeg-kind-toe.php, or even /views/account/voeg-kind-toe.php - which is presumably the intention.
So, on the first pass, the above condition fails, no rewrite occurs, and processing continues...
The second rule then rewrites the request for /account/voeg-kind-toe to /views/account/voeg-kind-toe. Providing there are no further mod_rewrite directives, the rewrite engine then starts over. This time, /views/account/voeg-kind-toe is the input.
On the second pass, REQUEST_FILENAME is /views/account/voeg-kind-toe (since /views/account is a physical directory) and the request is rewritten to /views/account/voeg-kind-toe.php (since the filesystem check should be successful). Providing you have no other directives then processing should now stop.
This is working fine in the following case: http://example.com/account/
/account/ is simply rewritten to /views/account/ by the last rule.
Edit: Interesting: If I place the bottom two lines on top (so placing the code to rewrite the view-part before the code to remove the php-extension); the php-extension works but the /views//part don't.
The same process as above occurs, EXCEPT this all occurs in a single pass and so is less dependent on other directives that might occur later in the file.
I'm not sure what you mean by "the /views//part don't"?
Assuming you only have .php files within the /views directory and all URLs are intended to target the /views subdirectory and you don't need to reference directories directly then you could do this is a single directive and rewrite everything that does not contain (what looks like) a file extension to /views/<whatever>.php.
For example:
RewriteRule !\.\w{2,4}$ /views%{REQUEST_URI}.php [L]
The L (last) flag is required if you have other mod_rewrite directives that follow - to prevent additional processing.
This does mean you can't rely on the directory index. ie. You need to request /index (as in your example), not simply / to serve /views/index.php.
(You still need your first rule that removes .php from the requested URL - although this is only strictly necessary if you are changing an existing URL structure, where you previously used .php on the URLs.)

htaccess file properly detects missing file from root directory but does not detect missing subdirectory

I have an .htaccess file that I'm using to catch when a requested image doesn't exist so I can make one. The file properly detects a missing image when requested from the directory the .htaccess file is in. But, if I request an image from a subdirectory that technically does not exist, .htaccess does not send me to my image handler. Can someone help me match any subdirectory that does not exist?
Here is my htaccess:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} .(jpg|jpeg|gif)$
RewriteRule ^(.*)$ missingimage.php?img=$1 [QSA,L]
That .htaccess file is placed in a folder called "uploads". So for example, my uploads folder also has oranges.jpg.
The following url will correctly pass the request to missingimage.php:
http://localhost/uploads/oranges_asdf.jpg
The following url will NOT correctly pass the request to missingimage.php, but instead returns a standard 404 from apache:
http://localhost/uploads/not_a_real_directory/oranges.jpg
How can I modify my htaccess to catch requests to directories that don't exist and still pass them to my image handler? Thank you.
REQUEST_FILENAME doesn't actually contain the full absolutely path if the request doesn't exist. My theory on this without actually digging into httpd core code would be that it's thinking we've come far enough to know that the request isn't actually there so let's stop looking.
i.e. if you request /uploads/fake/test.jpg it'll REQUEST_FILENAME contains /path/to/uploads/fake and won't actually continue to append /test.jpg on there, but does when you do /path/to/uploads/test.jpg because test.jpg is the termination of where it knows the request doesn't exist. Even if this isn't the reason why httpd stops the string there you have plenty of other variables that can help you.
This rewrite condition:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
is ridiculously popular right now for this trick of creating a dispatcher for MVC frameworks and does actually work, since /path/to/uplaods/fake is niether a file nor a directory and will send your request to your image dispatcher.
Here's the real fix for your extension matching condition... you need to get the REQUEST_URI because it will contain what the user actually requested (/uploads/fake/test.jpg) including the file extension and you can us it in your third RewriteCond to match the file extension. Since we're going to use that for the third rule, I cleaned up your first two to match.
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-d
RewriteCond %{REQUEST_URI} ^[A-Za-z0-9\/_-]+\/[A-Za-z0-9_-]+\.(jpg|jpeg|gif)$
RewriteRule ^(.*)$ missingimage.php?img=$1 [QSA,L]
I cleaned up your match on the file name as you were matching all sorts of bullshit with that leading period which is actually (when un-escaped) telling the preg match engine to match anything. So, backslash period will make preg match an actually period.
I also cleaned up the match on the first half to the request uri to include /alpha/num/directories_with/underscores-and-dashes/followed/by/alpha-num_filenames.jpg|jpeg|gif, feel free to remove that if you don't want it.

Resources