Mod Rewrite with Pagination - php

I wanna make this rather simple to ask so I can hope for a simple response. I'm somewhat new to mod rewriting (most I've done is a small cms using index.php?page=x and mod rewriting to that name). I have a shopping cart created by foreign people for my company before I started working here with little to no documentation and they are asking me to make the cart search engine friendly. I won't get too dirty with the details, just need to ask a question.
I have, say, results.php?name=friendly-url. I've edited my .htaccess so I can access these pages with a friendly url. It works perfectly.
RewriteRule ^([A-Za-z0-9-]+).html$ results.php?name=1
Now the cart has it written to paginate kinda awkwardly only because the $_GET variable is stupidly named. I'm trying to find out, without having to get really dirty and having to re-name files or re-route directories in the code, to make a simple friendly pagination.
The end result I'm looking for is something like starter-kits-01.html and starter-kits-02.html and so on. This is the mod rewrite I've been trying just to get something to work.
RewriteRule ^[A-Za-z-0-9-]+).html?p=([0-9]+)$ results.php?name=$1&pageNum_rsCWResults=$2
That, I believed, should allow me to render starter-kits.html?p=2. I'm getting no mod rewrite error, but it's messing up my $_GET variables. I can't do, say, /starter-kits/2/ without getting dirty and having to go through this messy code the foreign people made and change 500 lines of directories.
I've spent about 30 minutes on it, and I have 3 other projects going on today, so I'm going to move onto those while I wait for somebody a little more experienced with mod rewriting to give me a helping hand.
Much appreciated.

Just use:
RewriteRule ^([A-Za-z0-9-]+).html$ results.php?name=1 [QSA]
The QSA part tells it to forward any GET parameters on to the rewrite.
http://httpd.apache.org/docs/2.2/rewrite/flags.html#flag_qsa

The page rewriting you need to do should be done in PHP itself and only require a few lines in mod rewrite. I really recommend you download a copy of Drupal or WordPress to see how they do it. But basically here is how it should work.
You create a URL structure like this:
product-search/cat-toys
product-search/cat-toys/page-1 (should point to the same place as the previous URL)
product-search/cat-toys/page-2 (could also use "product-search/cat-toys/page/2)
You take your site and have everything relay through a central index.php file, mod rewrite takes care of this. You just use the URLs on your site and the PHP will take the params passed and parse it into the URL structure that then takes you to the results.
Essentially the URL path is passed to index.php to one parameter by mod rewrite.
Sample mod rewrite entry (from Drupal, very similar to Wordpress):
# Rewrite URLs of the form 'x' to the form 'index.php?q=x'.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]
Please check out these systems to get a better idea. WordPress is a much simpler, more straightforward system to go through.

Related

Using a backreference at the beginning of a pattern in an apache rewrite rule

I'm currently translating a website from english to spanish. I want to use a rewrite rule that can put the current language at the beginning of the url, just after the domain. Example:
current url without rewrite rules:
http://www.example.com/sample_subdirectory/?language=spanish
objective:
http://www.example.com/spanish/sample_subdirectory/
At the time of this writing, I have all my php files rewritten as if they were subdirectories (such as example.com/something.php to example.com/something/) so there's no problem there. My objective though is to see if there's a way to rewrite the url so that instead of displaying the language GET variable, it displays "/spanish/something/something_else/etc/"; The goal is to not have to do an individual rewrite rule for every url just for the spanish translations, but rather append that /spanish/ subdirectory towards the beginning of the url. I tried to figure out how to use the metacharacters but I don't think I was doing it right. Here's what I tried (I'm pretty sure this is done so wrong :/ )
RewriteCond %{QUERY_STRING} ^id=(spanish)$
RewriteRule ^/spanish/(.*)$ /$1?id=%1
I'm still kinda new at rewrite rules, I only know basic stuff, I'm definitely not a web server administrator so I wouldn't know how to implement what I'm going for. Hopefully it's possible to do this. Ironically, I could have probably finished typing simple rewrite rules instead of spending an hour trying to do this but oh well :P
Based on the example you give above, the following should do what you want:
RewriteCond %{QUERY_STRING} ^language=spanish$
RewriteRule ^/(.*)$ /spanish/%1?
The RewriteCond causes the RewriteRule to be run only when the query string is "language=spanish".
The RewriteRule saves the directory from the original URL and appends it to the directory "/spanish/". The ? at the end removes the query string.
Thanks to bobdye's insight, I realized I had to remove the condition altogether and tweak the RewriteRule to look like this:
RewriteRule ^/subdirectory/spanish/(.*)$ /subdirectory/$1?language=spanish
Note: /subdirectory is a folder inside a virtual server (localhost) that I have running on my laptop.
As you can see, I had to place the /spanish/ directory in the pattern and whatever subdirectory was under that I would use as a back reference to the actual link, then I would just append the GET variable language=spanish to the end of the link. I'll still need to test to make sure that this works for any number of subheadings under /spanish/ but this definitely solved my problem.

How to make multiple product or news sites without making tons of PHP files

i was thinking, regular site have just few subpages like:
-home
-about
-contact
And things like that, so in general you usually get below 10 .php files, but what if somebdy want to make CMS which generate new site for each news, right it is possible to make new php file for each of it but its unproductive.
I also find a way that i can just make something like "yourdomain.com/news/index.php?id=24" and just get data from mysql where ID = 24 but i need to display name of news in URL
So my question is how to make something like speciic URL for each news for example: www.yourdomain.com/news/name-of-new
without making tons of php files and with specific description, keyword for each of them
The best answer here is to adopt a MVC programming method with one entry point that you define. Let me show a very basic example that will not involve using a pre-made framework. Basically you will have one entry point (usually the index.php file) and then for the most basic example one folder with modules for each page.
You have to program the index.php so that according to a parameter it will load the correct page file. So far this is just what you suggested with the ?id=27 thingy.
Now let's make it a little piper. Create a .htaccess file next to your index.php one. A .htaccess file can define rules for your whole website. Here you need to make some rewrite rules.
A rewrite rule is basically something that will tell your website to act like if the user asked index.php?id=27 whereas he asked yourdomain.com/news
So type first this code to enable the rewrite rule engine
RewriteEngine On
RewriteBase /
Then make a simple rewrite rule like this one
RewriteRule ^/(.*)$ /index.php?page=$1 [L]
Please keep in mind that you must use relative links otherwise this so far implicit redirection will show up in the browser nav bar.
There is a plenty of way to make rewrite rules, check Htaccess rewrite rule on the internet to find one that suits to your architecture.
EDIT: for preventing your rewrite rule to run when the requested url is a file (like an image) use these directives before the rewrite rule line
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

GET variables not received from PHP redirect, is it a rewrite issue?

I'm working on a basic blog and trying to create a method to edit already-created entries. I know the code to render the entry in the edit view (admin page) works by manually passing the necessary GET variables in the url, e.g. "localhost/simple_blog/admin.php?page=blog&url=first-entry". This pulls all fields from the database without issue.
I have an .htaccess file performing rewrites, though:
RewriteEngine On
RewriteBase /simple_blog/
RewriteRule \.(gif|jpg|png|css|js|inc\.php)$ - [L]
RewriteRule ^admin/(\w+)(|/)$ admin.php?page=$1 [NC,L]
RewriteRule ^admin/(\w+)/([\w-]+) admin.php?page=$1&url=$2 [NC,L]
RewriteRule ^(\w+)/?$ index.php?page=$1
RewriteRule ^(\w+)/([\w-]+) index.php?page=$1&url=$2
The link to edit an entry is in the format "/simple_blog/admin/blog/first-entry", and hovering over the hyperlink on the page shows the reference to "localhost/simple_blog/admin/blog/first-entry" which is correct. Clicking the link and viewing the source on the page that loads shows that no values are being received from the previous page, though.
I'm just hoping someone with a bit more mod_rewrite and RegEx experience can look at this with me and maybe point something out that I'm missing, either that or confirm that the issue is not with my rewrite rules and is definitely elsewhere. I've triple-checked my functions, I receive no errors in Apache, and the access log merely shows that "first-entry" is being accessed by GET.
If this question is a dupe, PLEASE feel free to let me know and point me in the right direction. If you feel like you need more info/code examples, let me know that, too. :)
(Yes, I'm using "PHP for Absolute Beginners" by Jason Lengstorf; I'm in chapter 7 right now.)
EDIT: 1 Aug 2013
I've tested my rules on http://htaccess.madewithlove.be/ and it appears that almost any url I test it on only matches the final rule, thereby only sending "index.php" back my way. I've checked my syntax both using the "PHP for Absolute Beginners" book and external resources. Everything seems to check out. Anyone have any idea why it's doing this?
Here's a screenshot of the Rewrite test results.
Even though you've declared a RewriteBase, you can't exclude it from the pattern matching side of the Rules. A lot of the online testers don't support things like RewriteBase. Try this and see if it works.
RewriteEngine On
RewriteBase /simple_blog/
RewriteRule \.(gif|jpg|png|css|js|inc\.php)$ - [L]
RewriteRule ^simple_blog/admin/([\w-]+)/?$ admin.php?page=$1 [NC,L]
RewriteRule ^simple_blog/admin/([\w-]+)/([\w-]+) admin.php?page=$1&url=$2 [NC,L]
RewriteRule ^simple_blog/([\w-]+)/([\w-]+) index.php?page=$1&url=$2 [L]
RewriteRule ^simple_blog/([\w-]+)/?$ index.php?page=$1 [L]

mod_rewrite ignore variable if empty

Ok so i have a project that has product listing by categories,but also listing all products. I created a pagination for it,that works good. I set up mod_rewrite to work with paging on categories,but i cant manage to set it up for all products. The working one is www.domain.com/catalogue/catid/catname/pagenumber, and i also want to make www.domain.com/catalogue/pagenumber, but mod rewrite comes to problem here.
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]*)/?([^/]*)/?([^/]*)/?([^/]*)$ index.php?p=$1&cid=$2&cname=$3&page=$4 [L]
and when i try to call second link,he treats that page number as cid. So i want to set up mod rewrite to read what is needed,and ignore cid and cname in this case.
I'd like to give you an alternative for this one..
Instead of using regexes, which you seem to have a bit of a problem with still.. There's a much easier way.
If you redirect everything to index.php, no exceptions.
Then within index PHP, you can read the current url using $_SERVER['REQUEST_URI'], and it becomes very easy with explode('/', $url);' to do all this processing..
It's a much more natural way to do routing.
There is not an ultra reliable way to do this in mod_rewrite.
The most reliable method is check for this in PHP.
There are two main methods:
One as Evert mentions redirect all to the page in question and decipher the url from there, which is what most do
two, detect the amount of $_GET vars you receive and judge how the page should react to what it gets within the PHP.
What you ask is not very straight forward, nor very fast in regex so I would recommend slapping this clause onto PHP rather than trying to get regex to do it for you.
Why not use two rules, if you're sure you'll never get a link like catalogue/catid/pagenumber ?
RewriteRule ^([^/]*)/([^/]*)$ index.php?p=$1&page=$2 [L]
RewriteRule ^([^/]*)/([^/]*)/([^/]*)/([^/]*)$ index.php?p=$1&cid=$2&cname=$3&page=$4 [L]

How to beautiful query string URLs

I have an entire website built upon a link scheme of query strings (i.e. ?page=about or ?page=individual&i=johndoe). Of course, in retrospect we have decided to go with a different (beautified) scheme in order to be more SEO friendly (i.e. /about/ or /individual/johndoe/).
Is there a way to accomplish this change using mod_rewrite on an Apache .htaccess file without having to change all the links sitewide? For instance, if you click a link to ?page=about it would permanently redirect you to /about/.
The code I have tried will successfully display /about/ as ?page=about, however, there is no redirect involved. And to be honest, I've never done any work in mod_rewrite (and it's a bit intimidating), so I feel I'm going in the wrong direction. Nonetheless, here's the code I've been working with so far:
RewriteEngine On
RewriteRule ^([a-zA-Z0-9_]+)$ /$1/ [R]
RewriteRule ^([a-zA-Z0-9_]+)/$ /index.php?page=$1
RewriteRule ^([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)$ /$1/$2/ [R]
RewriteRule ^([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)/$ /index.php?page=$1&i=$2
RewriteRule ^([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)/$ /index.php?page=$1&id=$2
RewriteRule ^([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)/$ /index.php?page=$1&bctid=$2
RewriteRule ^([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)/$ /index.php?page=$1&bclid=$2
Any thoughts? I greatly appreciate any help.
First... The rewrite will only apply to rewriting requests. As a result your changes listed in your questions will now allow a page to be accessed in two ways:
/index.php?page=about
/about/
That means that unless you make changes throughout your site you will not really be making much of a change since everyone is pointing to the wrong URL.
I think instead you want to use mod_redirect, to redirect the user to the newer formed URL. I think you can then have that new url get mapped back to the version your site actually expects. I believe that this works, and doesn't cause a loop.
That being said i think there is some SEO ding since there is a redirect on all pages, and no one actually points to the nicer URLs directly. That might not give you the results you want. Another option would be to use those regex that you provide, and actually make the real code change in all your views. That might be easy or hard depending on how you are making your links.
Good luck.
Clarification
I read your questions as you want several different things:
you don't want to change anything huge in the way your site works but you want nice URLs (perhaps you are using a framework forces pages to be called like this). This means that you need to support both ugly and nice urls, which means you need mod_rewrite so that both versions work.
Your goal is to make better urls for search engines. That means that you should "encourage" users who use the ugly URLs to instead use the nice URLs. In that case you should probably clean up your old urls on your site. If not google will continue to crawl the ugly urls (since those will be the only ones it saw).
You can't clean up other peoples URLs so you should probably mod_redirect their links to ugly urls to your nice ones. That way google will find the nice urls nicely. (this is the part i'm not sure of. Will the mod_redirect and mod_rewrite cause a loop? I think not, but if it does then only #1 and #2 would be doable, and you'd just need to live with other people's sites pointing to your ugly urls
RewriteEngine On
RewriteRule ^([a-zA-Z0-9_]+)$ /$1/ [NC,R=301]
RewriteRule ^([a-zA-Z0-9_]+)/$ /index.php?page=$1
RewriteRule ^(artists)/([a-zA-Z0-9_]+)$ /artists/$2/ [NC,R=301]
RewriteRule ^(artists)/([a-zA-Z0-9_]+)/$ /index.php?page=individual&i=$2
RewriteRule ^(photos)/([a-zA-Z0-9_]+)$ /photos/$2/ [NC,R=301]
RewriteRule ^(photos)/([a-zA-Z0-9_]+)/$ /index.php?page=photogallery&person=$2
RewriteRule ^(post)/([a-zA-Z0-9_]+)$ /post/$2/ [NC,R=301]
RewriteRule ^(post)/([a-zA-Z0-9_]+)/$ /index.php?page=post&id=$2
RewriteRule ^(rss)/([a-zA-Z0-9_]+)$ /rss/$2/ [NC,R=301]
RewriteRule ^(rss)/([a-zA-Z0-9_]+)/$ /index.php?page=post&rss=$2
RewriteRule ^(search)/([a-zA-Z0-9_]+)$ /search/$2/ [NC,R=301]
RewriteRule ^(search)/([a-zA-Z0-9_]+)/$ /index.php?page=post&q=$2
RewriteRule ^(video)/([a-zA-Z0-9_]+)$ /video/$2/ [NC,R=301]
RewriteRule ^(video)/([a-zA-Z0-9_]+)/$ /index.php?page=videogallery&bctid=$2
RewriteRule ^(playlist)/([a-zA-Z0-9_]+)$ /playlist/$2/ [NC,R=301]
RewriteRule ^(playlist)/([a-zA-Z0-9_]+)/$ /index.php?page=videogallery&bclid=$2
Here's what I ended up using. Not sure if all those flags are necessary... but it works using the previous code. I still need to change all links sitewide (front-end and back-end), but I should also put in redirects for all the old links incase I miss one or in case other websites link to the old pages.
I mean the best way how do this is:
RewriteRule ^([a-zA-z0-9-]+)/?([a-zA-Z0-9/-]+)?$ index.php?page=$1&par=$2
and in PHP:
$page = $_GET["page"];
$parm = split("/",$_GET["par"]);
// first par
$parm[0];

Categories