Mod_rewrite Revisted

Mod_Rewrite Revisted

"The great thing about mod_rewrite is it gives you all the configurability and flexibility of Sendmail. The downside to mod_rewrite is that it gives you all the configurability and flexibility of Sendmail."

- Brian Behlendorf, Apache Group

One of the more powerful tricks of the .htaccess hacker is the ability to rewrite URLs. This enables us to do some mighty manipulations on our links; useful stuff like transforming very long URL's into short, cute URLs, transforming dynamic ?generated=page&URL's into /friendly/flat/links, redirect missing pages, preventing hot-linking, performing automatic language translation, and much, much more.

Make no mistake, mod_rewrite is complex. This isn't the subject for a quick bite-size tech-snack, probably not even a week-end crash-course, I've seen guys pull off some real cute stuff with mod_rewrite, but with kudos-hat tipped firmly towards that bastard operator from hell, Ralf S. Engelschall, author of the magic module itself, I have to admit that a great deal of it still seems so much voodoo to me.

The way that rules can work one minute and then seem not to the next, how browser and other in-between network caches interact with rules and testing rules is often baffling, maddening. When I feel the need to bend my mind completely out of shape, I mess around with mod_rewrite!

After all this, it does work, and while I'm not planning on taking that week-end crash-course any time soon, I have picked up a few wee tricks myself, messing around with webservers and web sites, this place..

The plan here is to just drop some neat stuff, examples, things that has proven useful, stuff that works on a variety of server setups; there are apache's all over my LAN, I keep coming across old .htaccess files stuffed with past rewriting experiments that either worked; and I add them to my list, or failed dismally; and I'm surprised that more often these days, I can see exactly why!

Nothing here is my own invention. Even the bits I figured out myself were already well documented, I just hadn't understood the documents, or couldn't find them. Sometimes, just looking at the same thing from a different angle can make all the difference, so perhaps this humble stab at URL Rewriting might be of some use. I'm writing it for me, of course. but I do get some credit for this..

# time to get dynamic, see..
rewriterule ^(.*)\.htm $1.php

beginning rewriting..

Whenever you use mod_rewrite (the part of apache that does all this magic), you need to do..

you only need to do this once per .htaccess file:
Options +FollowSymlinks
RewriteEngine on

Before any ReWrite rules. note: +FollowSymLinks must be enabled for any rules to work, this is a security requirement of the rewrite engine. Normally it's enabled in the root and you shouldn't have to add it, but it doesn't hurt to do so, and I'll insert it into all the examples on this page, just in case.

The next line simply switches on the rewrite engine for that folder. if this directive is in you main .htaccess file, then the ReWrite engine is theoretically enabled for your entire site, but it's wise to always add that line before you write any redirections, anywhere.

note: while some of the directives on this page may appear split onto two lines, in your .htaccess file, they must exist completely on one line. If you drag-select and copy the directives on this page, they should paste just fine into any text editor.

simple rewriting

Simply put, Apache scans all incoming URL requests, checks for matches in our .htaccess file and rewrites those matching URLs to whatever we specify. something like this..

all requests to whatever.htm will be sent to whatever.php:
Options +FollowSymlinks
RewriteEngine on
RewriteRule ^(.*)\.htm$ $1.php [nc]

Handy for anyone updating a site from static htm (you could use .html, or .htm(.*), .htm?, etc) to dynamic php pages; requests to the old pages are automatically rewritten to our new urls. no one notices a thing, visitors and search engines can access your content either way. leave the rule in; as an added bonus, this enables us to easily split php code and its included html structures into two separate files, a nice idea; makes editing and updating a breeze. The [nc] part at the end means "No Case", or "case-insensitive", but we'll get to the switches later.

Folks can link to whatever.htm or whatever.php, but they always get whatever.php in their browser, and this works even if whatever.htm doesn't exist! but I'm straying..

As it stands, it's a bit tricky; folks will still have whatever.htm in their browser address bar, and will still keep bookmarking your old .htm URL's. Search engines, too, will keep on indexing your links as .htm, some have even argued that serving up the same content from two different places could have you penalized by the search engines. This may or not bother you, but if it does, mod_rewrite can do some more magic..

this will do a "real" http redirection:
Options +FollowSymlinks
rewriteengine on
rewriterule ^(.+)\.htm$ http://corz.org/$1.php [r=301,nc]

This time we instruct mod_rewrite to send a proper HTTP "permanently moved" redirection, aka; "301". Now, instead of just redirecting on-the-fly, the user's browser is physically redirected to a new URL, and whatever.php appears in their browser's address bar, and search engines and other spidering entities will automatically update their links to the .php versions; everyone wins. and you can take your time with the updating, too.

not-so-simple rewriting

You may have noticed, the above examples use regular expression to match variables. what that simply means is.. match the part inside (.+) and use it to construct "$1" in the new URL. in other words, (.+) = $1 you could have multiple (.+) parts and for each, mod_rewrite automatically creates a matching $1, $2, $3, etc, in your target URL, something like..

a more complex rewrite rule:
Options +FollowSymlinks
RewriteEngine on
RewriteRule ^files/(.+)/(.+).zip download.php?section=$1&file=$2 [nc]

would allow you to present a link as..

http://mysite/files/games/hoopy.zip

and in the background have that translated to..

http://mysite/download.php?section=games&file=hoopy

which some script could process. you see, many search engines simply don't follow our ?generated=links, so if you create generating pages, this is useful. However, it's only the dumb search engines that can't handle these kinds of links; we have to ask ourselves.. do we really want to be listed by the dumb search engines? Google will handle a good few parameters in your URL without any problems, and the (hungry hungry) msn-bot stops at nothing to get that page, sometimes again and again and again…

I personally feel it's the search engines that should strive to keep up with modern web technologies, in other words; we shouldn't have to dumb-down for them. But that's just my opinion. Many users will prefer /files/games/hoopy.zip to /download.php?section=games&file=hoopy but I don't mind either way. As someone pointed out to me recently, presenting links as/standard/paths means you're less likely to get folks doing typos in typed URL's, so something like..

an even more complex rewrite rule:
Options +FollowSymlinks
RewriteEngine on
RewriteRule ^blog/([0-9]+)-([a-z]+) http://corz.org/blog/index.php?archive=$1-$2 [nc]

would be a neat trick, enabling anyone to access my blog archives by doing..

http://corz.org/blog/2003-nov

in their browser, and have it automagically transformed server-side into..

http://corz.org/blog/index.php?archive=2003-nov

which corzblog would understand. It's easy to see that with a little imagination, and a basic understanding of posix regular expression, you can perform some highly cool URL manipulations.

Here's the very basics of regexp (roughly from the apache mod_rewrite documentation)..

Text:
. Any single character
[chars] Character class: One of chars
[^chars] Character class: None of chars
text1|text2 Alternative: text1 or text2 (ie. "or")

Quantifiers:
? 0 or 1 of the preceding text
* 0 or N of the preceding text (hungry)
+ 1 or N of the preceding text

Grouping:
(text) Grouping of text
(either to set the borders of an alternative or
for making backreferences where the nth group can
be used on the target of a RewriteRule with $n)

Anchors:
^ Start of line anchor
$ End of line anchor

Escaping:
\char escape that particular char
(for instance to specify special characters.. ".[]()" etc.)

shortening URLs

One common use of mod_rewrite is to shorten URL's. shorter URL's are easier to remember and, of course, easier to type. an example..

beware the regular expression:
Options +FollowSymlinks
RewriteEngine On
RewriteRule ^grab(.*) /public/files/download/download.php$1

this rule would transform this user's URL..

http://mysite/grab?file=my.zip

server-side, into..

http://mysite/public/files/download/download.php?file=my.zip

which is a wee trick I use for my distro machine, among other things. everyone likes short URL's. and so will you; using this technique, you can move /public/files/download/ to anywhere else in your site, and all the old links still work fine. just alter your .htaccess file to reflect the new location. edit one line, done. nice. means even when stuff is way deep in your site you can have cool links like this.. /trueview/sample.php and this.

cooler access denied

In part one I demonstrated a drop-dead simple mechanism for denying access to particular files and folders. The trouble with this is the way our user gets a 403 "Access Denied" error, which is a bit like having a door slammed in your face. Fortunately, mod_rewrite comes to the rescue again and enables us to do less painful things. One method I often employ is to redirect the user to the parent folder..

they go "huh?.. ahhh!"
# send them up!
Options +FollowSymlinks
RewriteEngine on
RewriteRule ^(.*)$ ../ [nc]

It works great, though it can be a wee bit tricky with the URLs, and you may prefer to use a harder location, which avoids potential issues in indexed directories, where folks can get in a loop..

they go damn! Oh!
# send them exactly there!
Options +FollowSymlinks
RewriteEngine on
RewriteRule ^(.*)$ /comms/hardware/router/ [nc]

Sometimes you'll only want to deny access to most of the files in the directory, but allow access to maybe one or two files, or file types, easy..
deny with style!
# users can load only "special.zip", and the css and js files.
Options +FollowSymlinks
RewriteEngine On
rewritecond %{REQUEST_FILENAME} !^(.+)\.css$
rewritecond %{REQUEST_FILENAME} !^(.+)\.js$
rewritecond %{REQUEST_FILENAME} !special.zip$
RewriteRule ^(.+)$ /chat/ [nc]

Here we take the whole thing a stage further. Users can access .css (stylesheet) and javascript files without problem, and also the file called "special.zip", but requests for any other filetypes are immediately redirected back up to the main "/chat/" directory. You can add as many types as you need. You could also bundle the filetypes into one line using | (or) syntax, though individual lines are perhaps clearer.

prevent hot-linking

Believe it or not, there are some webmasters who, rather than coming up with their own content will steal yours. really! even worse, they won't even bother to copy to their own server to serve it up, they'll just link to your content! no, it's true, in fact, it used to be incredibly common. these days most people like to prevent this sort of thing, and .htaccess is one of the best ways to do it.

This is one of those directives where the mileage variables are at their limits, but something like this works fine for me..

how DARE they!
Options +FollowSymlinks
# no hot-linking
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www\.)?corz\.org/ [nc]
RewriteRule .*\.(gif|jpg|png)$ http://corz.org/img/hotlink.png [nc]

You may see the last line broken into two, but it's all one line (all the directives on this page are). let's have a wee look at what it does..

We begin by enabling the rewrite engine, as always.

The first RewriteCond line allows direct requests (not from other pages - an "empty referrer") to pass unmolested. The next line means; if the browser did send a referrer header, and the word "corz.org" is not in the domain part of it, then DO rewrite this request.

The all-important final RewriteRule line instructs mod_rewrite to rewrite all matched requests (anything without "corz.org" in its referrer) asking for gifs, jpegs, or pngs, to an alternative image. mine says "no hotlinking!". You can see it in action here. There are loads of ways you can write this rule. google for "hot-link protection" and get a whole heap. simple is best. you could send a wee message instead, or direct them to some evil script, or something.

lose the "www"

I'm often asked how I prevent the "www" part showing up at my site, so I guess I should add something about that. Briefly, if someone types http://www.corz.org/ into their browser (or uses the www part for any link at corz.org) it is redirected to the plain, rather neat, http://corz.org/ version. This is very simple to achieve, like this..

beware the regular expression:
Options +FollowSymlinks
RewriteEngine on
rewritecond %{http_host} ^www\.corz\.org [nc]
rewriterule ^(.*)$ http://corz.org/$1 [r=301,nc]

You don't need to be a genius to see what's going on here. There are other ways you could write this rule, but again, simple is best. Like most of the examples here, the above is pasted directly from my own main .htaccess file, so you can be sure it works perfectly.

automatic translation

If you don't read English, or some of your guests don't, here's a neat way to have the wonderful Google translator provide automatic on-the-fly translation for your site's pages. Something like this..

they simply add their country code to the end of the link, or you do..
Options +FollowSymlinks
RewriteEngine on
RewriteRule ^(.*)-fr$ http://www.google.com/translate_c?hl=fr&sl=en&u=http://corz.org/$1 [r,nc]
RewriteRule ^(.*)-de$ http://www.google.com/translate_c?hl=de&sl=en&u=http://corz.org/$1 [r,nc]
RewriteRule ^(.*)-es$ http://www.google.com/translate_c?hl=es&sl=en&u=http://corz.org/$1 [r,nc]
RewriteRule ^(.*)-it$ http://www.google.com/translate_c?hl=it&sl=en&u=http://corz.org/$1 [r,nc]
RewriteRule ^(.*)-pt$ http://www.google.com/translate_c?hl=pt&sl=en&u=http://corz.org/$1 [r,nc]

You can create your menu with its flags or whatever you like, and add the country code to end of the links.. Only certain areas of corz.org are covered by these rules, but they work well enough (though prefers users to ad the -fr manually. hmm).. Want to see this page in french?

Although it is very handy, and I've been using it here for a couple of years here at the org, for my international blog readers, all two of them, heh. Almost no one knows about it, mainly because I don't have any links . One day I'll probably do a wee toolbar with flags and what-not. Perhaps not. Trouble is, the Google translator stops translating after a certain amount of characters, though these same rules could easily be applied to other translators. And if you find a good one, one that will translate a really huge document on-the-fly, do let me know!

If you wanted to be really clever, you could even perform some some kind of IP block check and present the correct version automatically, but that is outside the scope of this document. note: this may be undesirable for pages where technical commands are given (like this page) because the commands will also be translated. "RewriteEngine dessus" will almost certainly get you a 500 error page!

httpd.conf

Remember, if you put these rules in the main server conf file (usually httpd.conf) rather than an .htaccess file, you'll need to use ^/... ... instead of ^... ... at the beginning of the RewriteRule line, in other words, add a slash.

inheritance..

If you are creating rules in sub-folders of your site, you need to read this.

You'll remember how rules in top folders apply to all the folders inside those folders too. we call this "inheritance". normally this just works. but if you start creating other rules inside subfolders you will, in effect, obliterate the rules already applying to that folder due to inheritance, or "decendancy", if you prefer. not all the rules, just the ones applying to that subfolder. a wee demonstration..

Let's say I have a rule in my main /.htaccess which redirected requests for files ending .htm to their .php equivalent, just like the example at the top of this very page. now, if for any reason I need to add some rewrite rules to my /osx/.htaccess file, the .htm >> .php redirection will no longer work for the /osx/ subfolder, I'll need to reinsert it, but with a crucial difference..

this works fine, site-wide, in my main .htaccess file
# main (top-level) .htaccess file..
# requests to file.htm goto file.php
Options +FollowSymlinks
rewriteengine on
rewriterule ^(.*)\.htm$ http://corz.org/$1.php [r=301,nc]

Here's my updated /osx/.htaccess file, with the .htm >> .php redirection rule reinserted..

but I'll need to reinsert the rules for it to work in this sub-folder
# /osx/.htaccess file..
Options +FollowSymlinks
rewriteengine on
rewriterule some rule that I need here
rewriterule some other rule I need here
rewriterule ^(.*)\.htm$ http://corz.org/osx/$1.php [r=301,nc]

Spot the difference in the subfolder rule, highlighted in red. you must add the current path to the new rule. now it works again, and all the osx/ subfolders will be covered by the new rule. if you remember this, you can go replicating rewrite rules all over the place.


troubleshooting tips..

rewrite logging..

When things aren't working out as you'd expect, the first thing you need to do is enable rewrite logging. I'll assume you are testing these mod_rewrite directives on your development mirror, or similar setup, and can access the main httpd.conf file. If not, why not? Testing mod_rewrite rules on your live domain is just a wee bit on the silly side, no? Anyway, here goes, put somewhere at the foot of your http.conf file..

Expect large log files..
#
# ONLY FOR TESTING REWRITE RULES!!!!!
#
RewriteLog "/tmp/rewrite.log"
#RewriteLogLevel 9
RewriteLogLevel 5

Set the file location and logging level to suit your own requirements. If your rule is causing your Apache to loop, load the page, immediately hit your browser's "STOP" button, and then restart Apache. All within a couple of seconds. Your rewrite log will be full of all your diagnostic information, and your server will carry on as before.

Setting a value of 1 gets you almost no information, setting the log level to 9 gets you GIGABYTES! So you must remember to comment out these rules and restart Apache when you are finished because, not only will rewrite logging create space-eating files, it will seriously impact your web server's performance.

RewriteLogLevel 5 is very useful, I find.

Fatal Redirection

If you start messing around with 301 redirects [r=301], aka. "Permanently Redirected", and your rule isn't working, you could give yourself some serious headaches..

Once the browser has been redirected permanently to the wrong address, if you then go on to alter the wonky rule, your browser will still be redirected to the old address (because it's a browser thing), and you may even go on to fix, and then break the rule all over again without ever knowing it. Changes to 301 redirects can take a long time to show up in your browser.

Solution: restart your browser, or use a different one.

Better Solution: Use [r] instead of [r=301] while you are testing . When you are 100% certain the rule does exactly as it's expected to, then switch it to [r=301] for your live site.


conclusion

In short, mod_rewrite allows you to send browsers from anywhere to anywhere. You can create rules based not simply on the requested URL, but also on such things as IP address, browser agent (send old browsers to different pages, for instance), and even the time of day; the possibilities are practically limitless.

The ins-and outs of mod_rewrite syntax are topic for a much longer document than this, and if you fancy experimenting with more advanced rewriting rules, I urge you to check out the apache documentation.

If you have apache installed on your system, there will likely be a copy of the apache manual, right here, and the excellent mod_rewriting guide, lives right here. do check out the URL Rewriting Engine notes for the juicy syntax bits. That's where I got the cute quote for the top of the page, too.
;o)
(or

mod_write trick to Convert http to https

mod_write trick to Convert http to https

Found this tip on an IBM website. If you want to convert all http requests to https requests (useful for secure-ish sites), use the following snippet in your .htaccess file:


RewriteEngine on
RewriteCond %{SERVER_PORT} =80
RewriteRule ^(.*) https://%{SERVER_NAME}%{REQUEST_URI}

PHP 5 Unable to Open HTTP Request Stream with fopen or fsockopen Functions

PHP 5 Unable to Open HTTP Request Stream with fopen or fsockopen Functions


With Apache/2.x.x or Apache/2.2.x webserver, with PHP5 as the scripting module, a HTTP communication error may occur within the PHP scripts that are parsing and running via the web server.

The errors that generated by PHP include:

PHP Warning: fopen(http://www.example.com): failed to open stream: HTTP request failed!
fsockopen(): unable to connect to …
file_get_contents(): failed to open stream: HTTP request failed!
PHP Warning: main(): Failed opening ‘http://www.example.com/index.html’ for inclusion …
PHP Warning: include(/usr/local/index.php): failed to open stream: No such file or directory in …

To resolve the problem, ensure that allow_url_fopen is enabled in PHP.INI configuration file. The line should look like this:

allow_url_fopen = On

Note: Depending on your system OS and configuration, the PHP.INI is located at various varied location, such as in Apache bin directory for Windows system or /usr/local/etc in FreeBSD Apache installation, if you don’t specify or point to PHP.INI in another directory.

If the error still happen and the PHP scripts still unable to connect to remote external servers and thus unable to download updates or retrieve files, check the user_agent setting in PHP.ini.

By default php.ini set the user_agent to “PHP” which signifies that it’s the script that try to access the web server. Some web servers will refuse and don’t allow script to access and receive the date from the server. So, by setting the user_agent to that of a web browser, PHP will let the web server know which kind of web browser will receive the date, and thus able to open the HTTP connection stream.

The user_agent can be set to any kind of browser strings, for example of Internet Explorer:

user_agent=”Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)”

Remote to Remote file transfer

Remote to Remote File Transfer Using Putty

I was looking for a Remote to remote file transfer for a long time as the time taken to download the whole thing using FTP and then upload the same to the server using our slow Broadbrand was taking lot a lot of time!

I found a Way!
the Steps are as follows!
  1. Login to putty of your Server (Remote2)
  2. Go to the path where you want the files to be uploaded!
  3. now write ftp ftp .XYZ.com
  4. use anonymous for id
    use your email address for password or whatever is the requirement for the Remote Site(Remote1)
  5. Now at the FTP prompt cd to the folder where the files are !
  6. Change settings by typing "prompt" and "ascii"
  7. Then simple command mget *.*
  8. And you are done
This Process is much faster and smoother !
Enjoy

Increasing Swap Space

Increasing Swap Space

Swap Basics

An older rule of thumb was to have a swap space at least the size of physical RAM, if not twice as large. However, you also need to consider growth. If you expect to increase your RAM in the future, you should consider that when you set how much space you are going to use for swap. RAM just slides into your system; increasing swap may require reinstalling the operating system, particularly if you have an older version of Linux.

So, how much do you assign to swap? Good question. In general, I still support the suggestion is twice as much as RAM. This is the "good reason" I mentioned for having more swap than physical RAM. Creating a large swap space is easier to do it now and waste the space than to reinstall later. Another good reason is when you have more than one user running graphical applications. In this case, then even setting swap to two times RAM is reasonable. If all the space is taken up on the primary hard disk, you can add a hard disk and use the swap command to add additional swap space.

The key factor is how many applications you will run and what kind of applications. You need to consider the behavior of the application. If you are doing work with some kind of graphics (i.e. graphic design, ray tracing, and so forth), then you might need to conside more swap. If you have a lot of users on your system, you might want more swap, as well.

Keep also in mind that accessing swap is slower than accessing RAM. You might want to consider adding more RAM. I have a co-worker who has 3 GB of RAM in his system as he does a lot of graphical work and it is an extreme burden on his system to be constantly swapping in and out. He never gets close to using all of his RAM, so he does not need a large swap space.

Versions of the Linux kernel prior to 2.4.10 "liked" to have at least twice as much swap as RAM. However, with the newer kernels, this is no longer true.

You also need to keep in mind that swapping takes up system resources. The time to access the hard disk is hundreds of times slower than the time to access RAM. Therefore, if speed is an important consideration, you should think about having enough RAM so you don't swap. The maximum size of your swap space depends on your hardware architecture and more recent kernels on the i386 can have swap partitions that are as large as 2Gb and you can have as many as 8 different swap partitions if you have kernel older than 2.4.10. Later versions support up to 32 swap spaces.

Note that I said swap spaces and not just swap device or swap partition. Linux allows you to create a swap file. Like any other file, a swap file exists on your filesystem and takes up space. The advantage is that you can add a swap file at any time, provide you have the space on the hard disk. You don't need to to repartition your hard disk or even reboot.

There are two different swap versions (or formats). Kernels prior 2.4 supports only version 0 swap spaces. Versions later than Linux 2.1.117 support version 0 and version swap. However, Linux 2.5 only supports version 1. Therefore you need to be careful when upgrading. The mkswap command can format in either format. See the mkswap for more details.

Another change with the 2.4.10 kernel is that the swap spaces can be up to 64 Gb in size. Note, however, that with some Linux distributions, the mkswap command can currently (Sep 2003) only create swap devices that are 2GB or smaller.

Managing Swap

In many cases, once the system is installed, you never have to think about swap again. However, when you start using your system more actively, add new software, and so on, you will probably find that you should at least take a look at your current swap usage.

Linux provides a number of tools to monitor swap. The easiest is the free command, which gives you a quick overview of the memory usage. You can also use the top which can provide an self-updating view of your system, including memory usage by process, users on the system, and so forth. Also the /proc/swaps and /proc/meminfo files contain information about memory usage on your system.

Linux also provides tools to manage your swap space. You can add and remove spaces as you need to, as well as turn them on and off, even while they are being used.

To create a file to be used a swap, you need to first create the file. This is most easily done with the dd command. To create a 65 Mb file, you might have this command (from the the mkswap man-page):

which displays:

65536+0 records in
65536+0 records out

Next you have to prepare the file for usage as swap space using the mkswap. The simplest form would be:

mkswap device size

Where "device" is either the name of a device node for a hard disk partition or the name of a file you want to use. The "size" option is only required when you create a swap file. However, it is actually superfluous and still maintained for backwards compatibility. The command you issue migt look like this:

Which displays:
Setting up swapspace version 1, size = 67104 kB

At this point we are ready to activate the swap space. If you are adding the swap space permanently, then you will need to include it in your /etc/fstab file. My default (initial) swap space looks like this:

/dev/hda5    swap    swap    pri=42   0 0

This basically says that the device /dev/hda5 is to be mounted onto the special mount point swap, is of type swap, has a priority of 42 and that the filesystem should not be dumped if the system crashes, nor should the filesystem be checked on system boot.

To automatically use the swap file we just created, we might add an entry that looks like this:

/data/swapfile.1 none swap pri=5,defaults 0 0

When your system boots, all swap devices will be added which are listed in the /etc/fstab, unless they have the "noauto" option (just like any normal filesystem). If I wanted to immediate add the swap space without having to reboot, I can run swapon -a, which will activate all swap spaces in the /etc/fstab file(again, unless they have the "noauto" option). If the swap space is already in use, the system will silently ignore it.

As you might guess, the priority of the swap space determines the order in which the swap space is used. The higher the priority the sooner it will be used. In this example, the primary swap space in its own parition has a priority of 42 and will be used before the swap file with a priority of 5.

We can also add swap space dynamically using the swapon command. After creating the swap space, you might activate it with this command:

To show what is currently beeing used as swap space we issue the command

This might show us:

Filename                        Type            Size    Used    Priority
/dev/hda5 partition 409616 200560 42
/data_c2/swapfile.1 file 65528 0 -1

Just as you can enable swap from the command line, you can also turn it off. This is done with the swapoff command and it might look like ths:

For more details see the swapoff man-page.

Play MP3 on Website!

2005-08-03: To play songs in a random order, we need to create a randomized playlist. Before you continue, I strongly recommend that you read How do I play a list of several MP3 songs on a web page? to understand the basics.

Now that you've read about playlists, you know that we need to create a .m3u file that lists the URLs of the songs we want to play. But how can we put those songs in a random order for every user? The answer: we'll use PHP. Using PHP code, we can easily open up a .m3u file, shuffle the songs with PHP's built-in shuffle function, and deliver the result to the web browser as a playlist. We'll use a very cool feature of PHP called PATH_INFO to avoid creating any temporary playlist files. See the technical notes at the end of this entry for details on how it all works.

PHP is a great choice for this job. But users who are required to use Perl/CGI or ASP programming for web development can still use the ideas presented here in their own code. And the PATH_INFO trick demonstrated here works just as well for Perl CGI programs. But if you are using a free web hosting service that doesn't allow any kind of server-side programming... well, it's time to start paying for hosting that includes PHP support. Hosting services that include PHP can be really, really cheap these days. Less than $10 a month in fact. So skip a pizza once in a while and get a real web host. When you pay for your PHP hosting, the host doesn't stuff your page with annoying ads or, even worse, "spyware" programs that will make your visitors very angry.
Follow these steps to play MP3 files in a random order on your web page:

1. Create a playlist file called playlist.m3u containing all of the songs you want, in any order. See How do I play a list of several MP3 songs on a web page? for complete instructions on how to make a playlist file.

2. Upload playlist.m3u to your web site. When you do, make a note of the file system path to playlist.m3u on the server. If your FTP program shows that the folder is /home/sites/yourname/www.example.com/examples/, then the path to playlist.m3u is /home/sites/yourname/www.example.com/examples/playlist.m3u. Note: this is NOT a URL. It is the place on the server's hard drive where the file lives. If you don't understand this, reread it until you do!

3. Create the file randomsongs.php, containing the following. There must be ABSOLUTELY NO BLANK LINES OR WHITE SPACES AT THE BEGINNING! Otherwise it will be too late for the script to output a playlist instead of an HTML page when that is appropriate.

$playlist = "/home/sites/myname/www.example.com/examples/playlist.m3u";
if ($_SERVER['PATH_INFO'] == "/playlist.m3u") {
# This a request for the actual playlist.
playlist();
} else {
# Fall through to end of script and display
# the player HTML.
}
function playlist() {
header("Content-type: audio/mpeg");

# Needed for PHP versions OLDER than 4.2.0 only.
# If your host still has PHP older than 4.2.0, shame on them.
# Find a better web host.
srand(make_seed());

# Fetch our list of songs from a file.
$songs = file($playlist);
shuffle($songs);
# Now output the URLs in random order.
foreach ($songs as $song) {
# Remove newline and any other leading and trailing
# whitespace from URL of song.
$song = trim($song);
echo "$song\n";
}
# Now exit before any HTML is produced.
exit(0);
}
# Needed only for very old versions of PHP,
# see srand call earlier.
function make_seed()
{
list($usec, $sec) = explode(' ', microtime());
return (float) $sec + ((float) $usec * 100000);
}
?>

MP3s Playing in Random Order


hidden="true"
autostart="true"
type="audio/mpeg"
loop="true">

4. At the top of randomsongs.php change the setting of the $playlist variable to match the file system path of your playlist file... which you wrote down in step two.

5. randomsongs.php assumes you will be placing your PHP page in a folder on your web site called /examples. If that's not right, change the src attribute of the embed element. DO NOT remove /playlist.m3u from the end of the URL. If you want to know why it's there, read the technical notes at the end of this entry.

5. Upload randomsongs.php to your web server.

6. Upload your .mp3 files if you have not already done so.

7. Access randomsongs.php with your web browser. In our example, the URL would be http://www.example.com/examples/randomsongs.php, but of course your URL will be different. Your songs will begin to play in a random order.

Insert the embed element anywhere inside the body element of your page. If you choose to make the player visible, place the embed element at an appropriate location within the page.

Congratulations, you're the proud owner of an HTML Shuffle. Much cheaper than the iPod Shuffle! (Just kidding, Apple.)

If your songs don't play:

1. Make sure you have successfully completed How do I play a list of several MP3 songs on a web page? first. Make sure you are successful with an ordinary playlist file before you move on to using randomsongs.php.

2. If you are using a very old version of PHP, or PHP compiled for CGI use instead of Apache module use, it's possible that $_SERVER['PATH_INFO'] doesn't work properly in your environment. With a little ingenuity, the script can be modified to create temporary .m3u files instead of outputting playlists directly to the browser.

Technical Notes

You could write a PHP page that creates a new .m3u file on the server for every visitor. Then your PHP code would output the HTML for a player that uses the src attribute of the element to point to that newly created file. But then you would have piles of temporary .m3u files lying around. And you would need more code to clean them up every so often. Yuck.

Fortunately, there's a simpler way.

PATH_INFO to the Rescue

When a user accesses, let's say, http://www.example.com/examples/mypage.php, the PHP code in mypage.php runs. That's not surprising to anyone.

But this might surprise you: when a user accesses http://www.example.com/examples/mypage.php/extrastuff, the user does not get an error. Instead, mypage.php still runs... and the "extra" part of the URL, /extrastuff, shows up in the PHP variable $_SERVER['PATH_INFO'].

How does this help us? We can use the src attribute of the embed element for our player to point right back to the PHP script... with /playlist.m3u tacked on to the end.

Before you blame our use of the MIME type audio/mpeg instead of audio/mpegurl for this pickiness about file extensions, you'd better read How do I play streaming audio on my web page? very carefully. In a nutshell, audio/mpegurl is the "right" way, but the fact is it doesn't work for lots of users.
That helps us in two ways:

First, even though they shouldn't do this and mime types should absolutely always tell browsers what to do, the fact is that many web browser/MP3 player combinations just won't accept a playlist unless the file appears to have a .m3u file extension. That means we need that /playlist.m3u at the end of the URL to make, for instance, Firefox for Windows happy.

Second, we can make this work for us by recognizing the /playlist.m3u part of the URL and generating the randomized playlist directly from PHP, writing it straight to the browser when the browser actually asks for it. No temporary files, no muss, and no fuss.

Remote Scripting with PHP

Remote Scripting with PHP

Remote scripting lets you pull data from a database and display it without loading a new Web page

When you sign for a Microsoft Passport account, at the registration page you are prompted to select your country and state, which are shown in a select box. When you select a country, the entire page first reloads and then shows you the corresponding states. This happens because when a country is selected, the form (containing the select boxes) is posted to a server-side script. The script connects to the database, fires a query to retrieve the states for the selected country and populates the 'state select box' with the state names. For the user, the reloading of the page is not a pleasant experience.

For a better user experience, you can use remote scripting. Using JSRS (JavaScript Remote Scripting), a JavaScript on a Web page can call a server-side script written in PHP, Perl, ASP, ASP .Net or JSP. So, you can set up the onChange event of a select box (the one for countries) to call a JavaScript function, which in turn communicates with a server-side script using JSRS. The server-side script will return the data (name of states) to the JavaScript, which will in turn populate the page with the data, all without reloading the page. To get a taste, we will now code the same countries-states example. For the server-side script, we will use PHP.

Setup
We assume that you have set up PHP and MySQL database on your machine. Next, create a database named rs in MySQL as:

mysqladmin –u root –p create rs

In the rs database, create two tables for the countries and states using the following SQL.

create table countries (id int auto_increment not null, name varchar(50), primary key(id));
create table states (id int auto_increment not null, name varchar(50), country_id int, primary key(id));

Here, the country_id is the foreign key. Populate both the tables with some values.
On our this month's CD, we have given out the JSRS library. Extract the file named jsrs23.zip present in the directory system/cdrom/src_code on the CD. Copy the files named jsrsClient.js and jsrsServer.php.inc to a directory on your Web server. Here, jsrsClient.js is the client side or JavaScript library and jsrsServer.php.inc is the server-side (PHP in our case) library.

The RS code
Next, write a PHP file (say, rstest.php), containing the two selected boxes for country and state. Name the select boxes as country and states, respectively. Populate the country select box with the country names and IDs (use them as the option's value) from the database. Include the client-side library by adding the following line between the tag pair.

Set the onChange event handler for the country select box to getStates( ). Within the getStates( ) function we will call the server-side script using a function (namely jsrsExecute) in the JSRS client-side library. The getStates( ) function (which should be present within the tag pair) looks as follows.

function getStates()
{
country=document.forms[0].country.options[document.forms[0].country.selectedIndex].value;
jsrsExecute( "get_states.php", listStates, "getStates" , country );
}

The parameters to the jsrsExecute function are as follows.
l Name of the PHP script
l Name of the JavaScript function to call when the server-side PHP script has returned results (the name of the states)
l Name of the PHP function to call within the PHP script, which is specified as the first parameter
l Parameters to pass to the PHP function specified as the third parameter

The get_states.php file will look as follows.
include("jsrsServer.php.inc");
jsrsDispatch( "getStates" );
function getStates($country)
{
$return_value="";
$dblink=mysql_connect("localhost","root","pcq");
mysql_select_db("rs",$dblink);
$query="select id,name from states where country_id=$country";
$query_result=mysql_query($query,$dblink);
while($row=mysql_fetch_array($query_result,MYSQL_ASSOC))
$return_value.=$row["name"]."~".$row["id"]."|";
return $return_value;
}
?>

The JSRS specific code has been marked in bold. The first line includes the server-side PHP library for JSRS and with the second line you declare the method to expose, to be called via JSRS. The syntax of jsrsDispatch( ) function is as follows.

jsrsDispatch( )

Note that getStates( ) PHP function returns the results in a form where each row is separated by a Pipe (|) and the states' IDs and names within each row are separated by a tilde (~).

What is left is coding the listStates function in rstest.php. The listStates function (again, preferably located between ) looks as follows.

function listStates(states)
{
jsrsExecute ("foo.php", callBack, "blankFunc");
document.forms[0].states.options.length=0;
options = states.split("|");
for( var i = 0; i < namevalue="options[i].split(">);
document.forms[0].states.options[i] = new Option(nameValue[0], nameValue[1]); }}

Note that in the first line we are calling the jsrsExecute( ) function again. This is just an ugly fix without which the browser will keep showing a loading status even after the states list has been populated. You should define a function named callBack with empty body as:

function callBack() {}

Besides PHP, JSRS supports numerous other server-side scripting languages, which include ASP, ASP .Net, JSP, Perl and Python. If you look at the extracted archive of JSRS, you will find server-side library files for ASP, Perl and Python. JSRS, however, supports only JavaScript (as the name indicates) at the client side. For more information on JSRS, go to www.ashleyit.com/rs/.

COUNTER