The best way to do this is a 2 step approach. Obviously - since we are dealing with serving physical files off of your server then we have to ensure that we put in place good security in order to prevent people abusing the system and your server.
Firstly, if you want to have your files secure you will need to specify a directory outside of the webroot where the files will be stored. This allows you to not need a .htaccess file to protect the directory and means that people cannot just guess the filenames via semi-random urls. All you need to check is that php has read access (and write access if you are going to be handline uploads) to this directory. Put this directory into a variable and use that variable everywhere, then you can change the location of the directory as you like. You may also need to check that other users dont have access to this directory so other people on your server cant get access to it.
Now - to serve the files (without the need for a .htaccess file) you will have to have a script into which you pass the file you require as an argument in the query string (or just as the complete query string). Therefore, access to files will be like this....
http://blah.com/index.php?fish.zip
In your index.php file you can then decide whether to serve the file to them or not.
In order to decide whether to serve the file you will need to follow a set of steps...
1, are they authenticated or do you need to get a username/passsword combo off them. if they are authenticated go to the next step - otherwise show them a login form.
2, Ensure that the filename passed to you does not access any files outside of the directory you want them to access. This will involve getting rid of any ../ combinations (trying to move up a directory) and any absolute paths (/etc/blah.conf).
3, If the following step was ok then we can go about giving them the file. The easiest way is to use something like readfile to dump to the browser without having to do any other work. You will also want to write out some file headers so the browser knows the file type coming to it (there are other threads on this board which deal with this in more detail) but - you may just want to set them all to application/octet-stream so that the browser downloads them all instead of trying to open them.
Just one last point to note is that you should never let the user know the location of the directory on your server or any information regarding the directory structre, dont allow absolute paths to be passed in the query string, just make sure all file requests are served relative to the directory you want them to have access to.
Anyhow - hope this helps you out.... let us know how it goes.