rewrite urls , not all urls works - .htaccess

I have blog and I want to rewrite the link
site.com/blog -> for the blog index blog_posts.php
site.com/blog/{post-slug} -> for the single_post.php?post-slug={post-slug}
site.com/blog/topic/{topic} -> for the filtered_posts.php?topic={topic}
my problem is when I access to a post or a topic its access to site.com/blog blog_posts.php
I think because when access to blog_posts.php and write after it any think like kbjsflgjdouihaiufhslkdf access to blog_posts.php
my try
RewriteRule ^blog/([0-9a-zA-Zأ-ي-]+)/ single_post.php?post-slug=$1 [NC,L]
RewriteRule ^blog/ blog_posts.php [NC,L]
RewriteRule ^blog/topic/([0-9a-zA-Zأ-ي-]+)/ filtered_posts.php?topic=$1 [NC,L]
and if there are any thing that tech all about the .htaccess please gimme a link

RewriteRule ^blog/([0-9a-zA-Zأ-ي-]+)/ single_post.php?post-slug=$1 [NC,L]
RewriteRule ^blog/ blog_posts.php [NC,L]
RewriteRule ^blog/topic/([0-9a-zA-Zأ-ي-]+)/ filtered_posts.php?topic=$1 [NC,L]
You need to change the order of the directives and/or make the regex more specific. Order is important - the most specific regex need to be first.
For instance, your first rule ^blog/([0-9a-zA-Zأ-ي-]+)/ will naturally match any URL of the form /blog/topic/<something>, so the request is rewritten to single_post.php and the 3rd rule is never processed.
And your 2nd rule (^blog/), matches anything else that simply starts /blog, so again, the 3rd rule would never be processed.
Your example URLs, eg /blog/{post-slug} do not include a slash suffix, however, the directives you have written look as if you are trying to match one? Although you are not using any end-of-string anchor on the regex, so you are probably matching too much. For instance, the regex ^blog/([0-9a-zA-Zأ-ي-]+)/ will match a URL of the form /blog/{post-slug}/1234/something/etc which is probably not the intention (if it is the intention then it's still a fault as you potentially have a duplicate content issue).
I'm assuming your URLs are as per your example - no trailing slash.
I also queried (in comments) whether /blog a physical directory on the filesystem? If it is then your first example URL, ie. /blog is not canonical since mod_dir will implicitly trigger a 301 redirect to append the trailing slash. I'm assuming this is a physical directory and the canonical URL is actually /blog/, not /blog.
Try the following instead:
RewriteRule ^blog/topic/([0-9a-zA-Zأ-ي-]+)$ filtered_posts.php?topic=$1 [L]
RewriteRule ^blog/([0-9a-zA-Zأ-ي-]+)$ single_post.php?post-slug=$1 [L]
RewriteRule ^blog/$ blog_posts.php [L]
I also remove the NC (nocase) flag. You are already checking for both lowercase and uppercase letters in the regex, but if you are also allowing uppercase letters in other parts of the URL then you potentially have a duplicate content (non-canonical) URL issue that would need to be resolved.
Reference:
https://httpd.apache.org/docs/current/rewrite/intro.html
https://httpd.apache.org/docs/current/mod/mod_rewrite.html

Related

.htaccess 301 redirect from old RewriteRule to new

I have a problem with making a 301 redirection. I was using "flat" link system on website with RewriteRule:
domain.com/rubric-news
domain.com/article-815/news-title
RewriteRule ^rubric-([^*]*) news.php?kat=$1
RewriteRule ^article-([^*]*)/([^*]*)-([^*]*) article.php?id=$1&kat=$2&title=$3
Today I started to build better internal links system for SEO so now RewriteRules looks like this:
domain.com/news
domain.com/news/title-815
RewriteRule ^([a-z0-9]+)$ news.php?kat=$1 [L]
RewriteRule ^([^*]*)/([^*]*)-([^*]*) article.php?id=$3&kat=$1&title=$2 [L,NC,QSA]
now I should make 301 redirection from old links to the new ones and I don't know how to make it. Can anyone help me?))
The redirect directives would follow exactly the same principles as you have already used for the rewrites. (Although there are potential issues with the rewrites/regex you are currently using - see below).
Try it like this before your existing rewrites:
# Redirect "/rubric-<news>" to "/<news>"
RewriteRule ^rubric-([a-z0-9]+)$ /$1 [R=301,L]
# Redirect "/article-<815>/<news>-<title>" to "/<news>/<title>-<815>"
RewriteRule ^article-(\d+)/(\w+)-(\w+)$ /$2/$3-$1 [R=301,L]
I have assumed your "id" parameter is all numeric (as per your example). (Although your existing directives do not enforce this.)
Any query string will be be passed through by default (you do not need the QSA flag here).
You should test first with 302 (temporary) redirects to avoid potential caching issues. Clear your browser cache before testing.
Aside:
RewriteRule ^([^*]*)/([^*]*)-([^*]*) article.php?id=$3&kat=$1&title=$2 [L,NC,QSA]
The regex [^*]* matches anything that is not an asterisk (*) 0 or more times. You should be matching anything that is not a slash 1 or more times, ie. [^/]+. And you are missing the end-of-string anchor on the end of the regex (as you have on the preceding rule). With the very generic regex you are currently using (ie. [^*]*) this does not strictly matter, however, it is potentially ambiguous, ...
Your regex should be more restrictive (similar to the preceding rule). If your id consists of digits only then match only digits. If the title is only alphanumeric then match only letters and numbers, not everything. Currentrly it "looks like" the news and title parameters could contain hyphens, but that would introduce an ambiguity.
The NC flag is naturally superfluous here.
Consider something like this instead:
RewriteRule ^(\w+)/(\w+)-(\d+)$ article.php?id=$3&kat=$1&title=$2 [L,NC,QSA]
If your title can contain hyphens then change the regex accordingly. eg. ^(\w+)/([\w-]+)-(\d+)$

Mirror a file in htaccess

I'm trying to work on making a new site and I want to be able to mirror a site. Below is an example:
User visits: https://example.com/items/{some child folder}
User sees this file mirrored: https://example.com/items/listing.php
I want user to be able to see that file, but, when doing so, it don't want it to redirect. Any ideas?
UPDATE
I found a solution to the above problem. However, I need another question fixed. How would I stop the file listing.php in the /products folder from following the redirect?
RewriteEngine On
RewriteRule ^products/(.*) index.php?name=$1 [NC,L]
How would I stop the file listing.php in the /products folder from following the redirect?
RewriteRule ^products/(.*) index.php?name=$1 [NC,L]
Be more specific in the regex. If your products don't contain dots in the URL-path then exclude dots in the regex. For example:
RewriteRule ^products/([^./]+)$ index.php?name=$1 [L]
The above assumes your product URLs are of the form /products/<something>. Where <something> cannot consist of dots or slashes (so naturally excludes listing.php) and must consist of "something", ie. not empty.
Unless you specifically need the NC flag then this potentially opens you up to duplicate content.
If you want to be explicit then include a condition (RewriteCond directive):
RewriteCond %{REQUEST_URI} !^/products/listing\.php$
RewriteRule ^products/([^/]+)$ index.php?name=$1 [L]
The REQUEST_URI server variable contains the root-relative URL-path, starting with a slash. The ! prefix on the CondPattern negates the regex.
Or, use a negative lookahead in the RewriteRule pattern, without using a condition. For example:
RewriteRule ^products/(?!listing\.php)([^/]+)$ index.php?name=$1 [L]
Reference:
https://httpd.apache.org/docs/current/rewrite/intro.html
https://httpd.apache.org/docs/current/mod/mod_rewrite.html

Redirect /blog/article to /articles/article in .htaccess

As the title says, I want to redirect from my old blog URL to the new one. Here is what I tried:
RewriteRule ^/blog/(.*)$ /articles/$1 [R=301,NC,L]
I really thought that this would work but it turns out that I am missing something. If you could help out that would be great.
The URL-path that is matched by the RewriteRule pattern in a per-directory context (ie. in .htaccess) never starts with a slash because the directory-prefix (that ends with a slash) is first removed. In order words, the regex ^/blog/(.*)$ will never match.
You would need something like the following instead:
RewriteRule ^blog/(.*) /articles/$1 [R=301,NC,L]
Note the absence of the slash at the start of the pattern. This contrasts when mod_rewrite is used in a server (or virtualhost) context, then the slash prefix is required.

URL rewrite more precise match, not URLs that just start with the same string

Let's say I have phpbb3 forums software and I want to prettify some URLs. I put this in my htaccess:
RewriteRule ^cake viewforum.php?f=5&%{QUERY_STRING} [L]
which works for domain.tld/cake and domain.tld/cake/ but it also catches domain.tld/cake-recipes and domain.tld/cake-recipes/ for instance, and so rewrites them.
How can I write this so that it only matches that exact URL, not URLs that begin with that string?
You need to add $ in order to delimit your rule pattern.
RewriteRule ^cake/?$ viewforum.php?f=5 [L,QSA]
The above rule will now only match domain.tld/cake or domain.tld/cake/.
Also, you can avoid using %{QUERY_STRING} by adding QSA flag (which does the same, but in a more elegant way)

Mod rewrite to redirect except on a certain page

Trying to write a rewrite rule in my htaccess so that any request to /en/shop/index.html or /fr/shop/index.html stays on the server, but if the user goes to any other page it redirects to a different server. Here's what I've got so far and it doesn't work.
RewriteRule ^(.*)/shop/(.*) [L]
RewriteRule ^(.*)$ http://www.newwebsite.com/$1 [R=301]
Add a dash to tell the first RewriteRule that you want the matches to be passed through unchanged:
RewriteRule ^.*/shop(/.*)?$ - [L]
I also removed the first set of parentheses since you're not using the results of the match so there's no need to store the matched patterns. I assumed you might need to match /shop without a trailing slash so that's why the (/.*)? section is there.

Resources