Detecting empty querystring with mod_rewrite - php

I have a strange problem, where to generate pages I am using my URL's as:
site/city/city-name/page-number
for that mod_rewrite is:
RewriteRule ^city/(.*)/(.*)$ tagcity.php?tag=$1&pnum=$2 [L]
But now the problem is if I delete the city-name and make it empty like "site/city//page-number" then it starts taking page-number as city-name.
Also can I have only one rewrite to serve pages with or without page numbers?
I know its a strange situation but unfortunatly some of my sites pages are indexed in Google as above.
How to detect that its empty so I can generate a 404 page?

Use a + instead:
RewriteRule ^city/(.+)/(.*)$ tagcity.php?tag=$1&pnum=$2 [L,QSA]
* means "0 or more repetitions", whereas + means "1 or more repetitions". Thus using a + requires that field to have at least something in it.
Also, you may want to make that [L,QSA] so that if there are any additional query parameters in the original URL, they'll be preserved. (QSA = Query String Append)
As requested in the comments, a rule with the ability to handle completely missing page number:
RewriteRule ^city/([^/]+)(?:/(.*))?$ tagcity.php?tag=$1&pnum=$2 [L,QSA]

Related

$_GET variable is not being set because of .htaccess file changes

I have been using '.htaccess' to rewrite how the page url should look so instead of:-
details.php?video=how+to+do+this&user=xxx
It should be more like this:-
/details/xxx/how+to+do+this
It's working and all, but here comes the issue; when I try to add a new $_GET category that wouldn't be useful all the time, that is the "page" get variable as not all video pages are going to have this variable. So when I add this variable nothing is set, it does show in the URL however.
/details/xxx/how+to+do+this?page=2
Here is the actual line of code that I used to rewrite one of the pages that's facing this issue.
RewriteRule ^user/(.*)/(.*)$ user.php?user=$1&view=$2
You can use:
RewriteRule ^user/(.*)/(.*)$ user.php?user=$1&view=$2 [NC,L,QSA]
QSA|qsappend When the replacement URI contains a query string, the default behavior of RewriteRule is to discard the existing query
string, and replace it with the newly generated one. Using the [QSA]
flag causes the query strings to be combined.
https://httpd.apache.org/docs/current/en/rewrite/flags.html

parameter passing by HTTP GET request other than as query parameters- slug/cleanurl/prettyurl

Note: The URL, code used here is only for demonstration purpose of my example.
I have seen that, For a HTTP GET request, if you want to pass a value for decision making, it is NOT passed through query String parameters for some good reasons.
Lets' say there's a thumbnail image showing a bookstore in houston location, say "ABC Bookstore"
The href attribute of that image is assumed as below
domain.com/texas/abcbookstore-houston
This is what is needed, and the page shows the book store details, instead of the URL being shown as domain.com/texas/details.php?id=1
Question:
Any ideas how the URL is analysed to fetch the key? One website when I looked at Network tab of Chrome, it showed
Request Headers
:authority:www.domain.com
:method:GET
:path:/texas/abcbookstore-houston
My thoughts:
I can extract the last word after parsing the complete URL, and I get 'abcbookstore-houston'
Code I tried:
$url = "domain.com/texas/abcbookstore-houston";
$path = parse_url($url, PHP_URL_PATH);
//echo $path;//// prints "/texas/abcbookstore-houston"
$parts = explode('/', rtrim($path, '/'));
$id_str = array_pop($parts);
echo $id_str; // prints abcbookstore-houston
My thinking is that we can have one more column in the main bookstore table called 'nameofid' and a query will fetch the 'id' whose 'nameofid' matches.
nameofid in this case is "abcbookstore-houston".
Summarized Question: Is this a correct approach? I have seen that in many of the websites, they no longer pass the query parameters even if that's a GET request, instead the URL looks clean like in this use-case.
As #charlietfl mentioned, I was actually looking at Clean URLs also called Pretty URLs
This is the actual book store details page
http://www.domain.com/texas/details.php?id=1
Basically this should be
http://www.domain.com/texas/details.php?id=abcbookstore-houston
I wanted this to be displayed in the address bar as
http://www.domain.com/texas/abcbookstore-houston
Finally, I found out the solution by making the below changes in .htaccess file
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(?:texas/)?([^/]+)/?$ details.php?id=$1 [NC,L,QSA]
The final command can be replaced by
RewriteRule ^texas/([^/]+)/?$ details.php?id=$1 [NC,L,QSA]
if 'texas' is mandatory and not optional.
So what is actually happening here is when I search for this URL http://www.domain.com/texas/abcbookstore-houston , the server is actually routing to http://www.domain.com/texas/details.php?id=abcbookstore-houston while we see only http://www.domain.com/texas/abcbookstore-houston in the address bar.
So inside details.php we can get the id using $_GET["id"] and continue our business logic.
Additional Notes:
If the objective was http://www.domain.com/abcbookstore-houston
then the RewriteRule would be
RewriteRule ^([^/]+)/?$ details.php?id=$1 [L,QSA]
Here's more explanation about the command used
RewriteEngine On turns the engine on.
RewriteCond %{REQUEST_FILENAME} !-f does not rewrite anything if the request filename exists, and is a file.
RewriteCond %{REQUEST_FILENAME} !-d does not rewrite anything if the request filename exists, and is a directory.
RewriteRule ^([^/]+)/?$ details.php?id=$1 [L,QSA] This is the actual rewrite rule. It takes anything after the domain name (anything other than forward slashes), and rewrites it to details.php, passing it as the id parameter.
RewriteRule ^texas/([^/]+)/?$ details.php?id=$1 [NC,L,QSA] This is the actual rewrite rule. It takes anything after {the domain name followed by the string 'texas'} (anything other than forward slashes), and rewrites it to details.php, passing it as the id parameter.
Note:
The technical term for word used in this use-case abcbookstore-houston is slug
https://en.wikipedia.org/wiki/Semantic_URL#Slug
A slug is the part of a URL which identifies a page using human-readable keywords.
To make the URL easier for users to type, special characters are often
removed or replaced as well. For instance, accented characters are
usually replaced by letters from the English alphabet; punctuation
marks are generally removed; and spaces (which have to be encoded as
%20 or +) are replaced by dashes (-) or underscores (_), which are
more aesthetically pleasing.

CodeIgniter Mod Rewrite Rules and the Controller

Learning PHP, I am playing around with mod_rewrite and CodeIgniter. I have configured my .htaccess file correctly with
RewriteEngine On
RewriteRule ^(resources)/(.*) $1/$2 [L]
RewriteRule ^(user_guide)/(.*) $1/$2 [L]
RewriteRule (.*) index.php?$1 [L]
I understand a bit of regex, and can appreciate what happens here. The rewrite rules are applied and the server than handles the final URL which in the above case- attaches index.php (the front controller) to the "pretty" URL. So far so good.
I now want a URL pattern :
/<person-name>/at/<place>
to get translated to :
/index.php/person/list?personName=$1&place=$2
And i handle the request at my list function in the person controller. I do not understand why the following doesn't work:
RewriteRule ^([a-z]+)/(at)/([a-z]+)$ index.php/person/list?personName=$1&place=$2 [L]
What am i doing wrong/where is my understanding flawed? I see that the placeholders are extracted correctly ($1 and $3), however, it throws a CodeIgniter 404.
Many thanks!
It's possible that the simplest fix will fix your issue. By wrapping "at" in parentheses, you're creating another matching group, which means that $2 will always be "at." That could be breaking everything. You want index.php?person/list?personName=$1&place=$3 But you may have noticed that issue and fixed it without fixing the problem, in which case, read on.
Check out How to make CodeIgniter accept "query string" URLs?. It seems to indicate that you can't mix and match the segment-based approach and the query string approach. Without seeing your controller code, I can't say for certain, but I'd start investigating there. You might also try:
RewriteRule ^([a-z]+)/(at)/([a-z]+)$ index.php?person/list/$1/$3 [L]
which would do the same thing the general-purpose CI redirect rule below does; send the URL off to index.php as a query string for processing. You've said you got it working with routes, so rather than passing a query string to your controller, you can expect person and place as two arguments. CI's handling of query strings leaves a lot to be desired, and I've never tried to MOD_REWRITE something including a query string into a query string.

Passing $_GET variables to virtual directories via .htaccess

I have the following .htaccess Rewrite rule below which works for converting virtual directories to parameters, for example:
www.example.com/usa/ny/nyc gets interpreted by PHP as www.example.com/index.php?path=usa/ny/nyc.
What I can't seem to figure out is how I would change my regex below to handle parameters of the virtual directories themselves. For example, I want:
www.example.com/usa/ny/nyc/?display=off&settings=none to be seen by PHP as www.example.com/index.php?path=usa/ny/nyc&param=display:off,settings:none.
What makes it extra tricky is that the parameters won't always be those two options I used in the example above, they will change dynamically. Any ideas or suggestions of how to go about accomplishing this?
RewriteRule ^/?([a-zA-Z_\-/]+)$ index.php?path=$1 [L]
Assuming you want to pass the query string unmodified, you can use the [QSA] (query string append) option like so:
RewriteRule /(.+)$ /index.php?path=$1 [L,QSA]
You can find the documentation for the QSA option here. From the docs:
With the [QSA] flag, a request for /pages/123?one=two will be mapped
to /page.php?page=123&one=two. Without the [QSA] flag, that same
request will be mapped to /page.php?page=123 - that is, the existing
query string will be discarded.
So, your PHP script will see all the parameters as standard _$_GET parameters, rather than needing to do any other modification.
If you would prefer to treat the result more like a typical path element, you can use the following:
RewriteRule /(.+)$ /index.php/$1 [L,QSA]
In the above case, your query string will still be appended, however you will need to handle the path explicitly using $_SERVER['PATH_INFO'].

.htaccess with php hidden parameters and language selection

I can't seem to get my .htaccess file to route the urls to my site correctly. I have a number of languages people can choose from wanting URL's like:
http://www.domain.com/en/
http://www.domain.com/en/contact
But I can't seem to get the page 'contact' working when writing a rule to get the 'en' variable.
RewriteRule /([^/]+)/([0-9]+)/ index.php?language=$1
I use that to grab the language code but how could I get the contact page to work?
EDIT:
Apparently I needed some QSA option but now the language get variable grabs contact as the variable with the en
RewriteRule ^(.*)$ index.php?language=$1 [QSA,L]
With this rule the site:
http://www.domain.com/en/contact
Returns:
en/contact
EDIT2
What I am trying to accomplish is the directory structure:
/
/contact
/about
Having these folders in the root but grabbing and ignoring the /en/ language variable. So I don't need a second variable for &page=contact, I need it to route into the directory folder.
Try combining your two expressions, although you need to modify the second group - [0-9]+ will only match numbers, not words like contact. Try this:
RewriteRule ^([^/]+)/([^/]+)/?$ index.php?language=$1 [QSA,L]
The QSA option allows a query string to be appended to the clean URL, perhaps something like this:
http://www.domain.com/en/contact?to=support&subject=Hello
In response to your comment, this expression should do the trick:
RewriteRule ^([^/]*)/([^/]+)/?$ $2/index.php?language=$1 [QSA,L]
In the rewritten rule, $2 holds contact, for example, and $1 holds en. The former is used as the directory, and the latter as an argument in the query string.

Categories