0

I have separate domains pointing to separate document roots on a dedicated box

I want to grant FTP access to a subfolder ftp-upload below this document root.

The proper FTP configuration is not part of this question

If a granted person uploads a file to document_root/ftp-upload, this file should be accessible via domain.com/file rather than domain.com/ftp-upload/file

The .htaccess file is in the document root

I've tried a few things but they don't seem to work.

<IfModule mod_rewrite.c>
    RewriteEngine on
    RewriteBase /
    ## check if the file exists in subfolder
    ##   ...and if found, stop and display it
    RewriteCond %{DOCUMENT_ROOT}/ftp-upload/$1 -f [OR]
    RewriteCond %{DOCUMENT_ROOT}/ftp-upload/$1 -d
    RewriteCond $1 !^$
    RewriteRule  (.*)  %{DOCUMENT_ROOT}/ftp-upload/$1 [L]

    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond $1 !^(index\.php|images|robots\.txt|css|assets|ftp-upload)
    RewriteRule ^(.*)$ index.php/$1 [L]
</IfModule>

I've also tried

RewriteCond  %{DOCUMENT_ROOT}/ftp-upload/${REQUEST_FILENAME} -f

and

RewriteCond %{DOCUMENT_ROOT}/ftp-upload%{REQUEST_URI} -f

It's a work in progress so this will not be the final solution, but this feature is being requested a lot. And I would rather not give them access to the document root if possible.

UPDATE: It looks like the thing DOES work, when it wants...

If I type in domain.com/test.txt (which exists in the ftp-upload directory only) the request goes to domain.com/index.php/test.txt and I am served the homepage

If I type in domain.com/ftp-upload/ I get a directory listing including test.txt

If I click on test.txt I get the file contents (which is "it works!"). If I then type in domain.com/test.txt I get the file contents displayed again...

My head exploded... any ideas?

SOLVED another way answers here did not work on my server.

The CMS I built now has another user group 'SEO Optimization' and an upload section. Under that section the user can select which of his assigned locations they want to upload the file to. The website index.php (controller/router) will serve the requested file if it exists in the upload folder. No .htaccess edits as my server was acting funky..

vortextangent
  • 561
  • 4
  • 16
  • I'm far from an .htaccess expert and can't say what to change in your given code, but you should have `RewriteEngine On` before any Rewrite* commands. It's only needed once. – akTed Jan 18 '13 at 20:16
  • Maybe I'm not fully aware of your needs. How will you access your index.php this way? **Why shall the 3rd party documents being located in document root?** Seems that you should change your applications design – hek2mgl Jan 18 '13 at 20:22
  • It's _very_ unlikely that your rewrite rules would really behave in the non-deterministic way you describe. It seems much more likely that you've forgotten to clear your browser cache after changing your rewrite rules, or possibly that there's a caching proxy between your browser and the server which for some reason has retained stale copies of some of the pages. Broken load balancing on your webhost could also trigger similar symptoms, if some of the servers end up out of sync with the others. Anyway, my first question would be, **can you reproduce the behavior you describe in the update?** – Ilmari Karonen Jan 22 '13 at 21:36
  • I've reproduced this behavior in Firefox, Internet Explorer, and Chrome (which i had to download and install before using). Also, on my Android device – vortextangent Jan 22 '13 at 21:40
  • As far as I know, there is no caching setup on any of the "addon" domains. I have one main domain that I setup caching with cloudflare (which does cause some headaches from time to time but I've gotten better at handling these). – vortextangent Jan 22 '13 at 21:55

5 Answers5

7

Facts as I understand them (please correct me if wrong)

  • you have seperate domains pointing to separate document roots
  • you want to grant FTP access to a subfolder ftp-upload below this document root.
  • the proper FTP configuration is not part of this question
  • if a granted person uploads a file to document_root/ftp-upload, this file should be accessible via domain.com/file rather than domain.com/ftp-upload/file
  • the .htaccess file is in the document root

For the above facts here's a working .htaccess file. Please note the folder name I used is ftp-upload, you've used several different versions in your question (ftp-upload, ftp_upload, ftpupload) make sure, this is consistent in your configuration

.htaccess in your domains document root folder

RewriteEngine On
RewriteBase /
RewriteCond %{DOCUMENT_ROOT}/ftp-upload%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}/ftp-upload%{REQUEST_URI} -d 
RewriteRule ^(.*)$  ftp-upload/$1       [L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond $1 !^(index\.php|images|robots\.txt|css|assets)
RewriteRule ^(.*)$  index.php/$1        [L]

What I do, is to check for the existence of the requested file in the subfolder /ftp-upload.

The tricky thing was that RewriteCond file -f requires a full path. That's why you would usually test against %{REQUEST_FILENAME}% If this condition is true (file exists) simply rewrite the request to ftp-upload/filename

This will also work for subfolders within ftp-folder e.g. folder ftp-folder/test/image.png will be accessible as /test/image.png

The second part is just your usual "if file does not exist, rewrite to /index.php"

EDIT

On a sidenote

OP stated "this doesn't work" - well, thank you for trying - I was close to delete my answer after this helpful comment, but after the work I put into this post and since I verified the suggested solution to be working perfectly, I decided to take a breath and give some debugging tips.

This said, if this does not work for you:

  • Make sure your "hidden" upload folder is actually called ftp-upload, also, Linux is case sensitive
  • Make sure your webserver is configured to read .htaccess files:

    • AllowOverride directive in your vhost configuration.
    • Usual value would be AllowOverride All
    • You can simply test this by adding something invalid (e.g. givemeanerror on) to your .htaccess and open the page in your webbrowser. If your .htaccess file is read, you will get a 500 Internal Server error message in your browser. If you don't have a test environment, you can do this in a test subfolder
  • The configuration I posted above should replace the entire content of your .htaccess file which is placed in your DOCUMENT_ROOT (NOT inside the ftp-upload folder), for debugging even remove the <IfModule> wrapper, which can be put back in once this is working

  • for testing, copy an image file into your ftp-upload folder, let's say test.png

  • if you still can't access http://yourdomain.com/test.png in a browser, I'd like to see the response headers for this request
  • if you don't know how to watch response headers go to http://www.webconfs.com/http-header-check.php, type in the URL http://yourdomain.com/test.png and copy the result

Hope this helps :)

Michel Feldheim
  • 17,625
  • 5
  • 60
  • 77
  • Which apache version are you using? Do you use apache after all? How did you test the result? Any errors? 'Doesn't work' is not enough info to continue :) (My proposition is tested and approved in apache 2.2.) – Michel Feldheim Jan 23 '13 at 14:55
  • Apache/2.2.22 (Unix) mod_ssl/2.2.22 OpenSSL/0.9.8m DAV/2 mod_bwlimited/1.4 – vortextangent Jan 23 '13 at 15:10
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/23248/discussion-between-vortextangent-and-michel-feldheim) – vortextangent Jan 23 '13 at 17:44
1

Please check this space I created base on your needs http://dev.wadakkir.org/test/

this is the structure of the previous space:

is that what you need ?

if so I could perform this behavior using the following .htaccess file

Options +Indexes
RewriteCond  %{REQUEST_URI} !^/test/subF/
RewriteRule ^(.*)$ /test/subF/$1

in your case it should be something like:

Options +Indexes
RewriteCond  %{REQUEST_URI} !^/ftp-upload/
RewriteRule ^(.*)$ /ftp-upload/$1

Hope it helps, if not I can still try again :)

UPDATE

As suggested in my previous comment, following is a fast written gateway to use, you can have a look at http://dev.wadakkir.org/test/ for the execution sample (I'll let it there for some time)

following are the source code I used:

index.php

<?php

require_once 'gateway.php';

echo "<h1>Hello World!</h1>";
?>
Existing file names are:
<ul>
    <li>01_Content_Of_Test_Folder.png</li>
    <li>02_Content_Of_SubF_Folder.png</li>
    <li>2ndTst.txt</li>
    <li>tst.txt</li>
</ul>

gateway.php

<?php

if( !empty($_GET['cf']) ){
$filename = "./subF/".$_GET['cf'];
if( is_file( $filename ) )
    dwldFunction($filename);
else{
    // TODO change this to what ever you want
    die("File not found ($filename)");
    }
    exit(1);
}


function dwldFunction( $fName ) {
// detect mime type
$mime = getMime( $fName );

header('Pragma: public');   
header('Expires: 0');       
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Cache-Control: private',false);
header('Content-Type: '. $mime );
header('Content-Disposition: attachment; filename="'.basename($fName).'"');
header("Content-Length: " . filesize($fName));
header('Connection: close');

readfile( $fName );
}

function getMime( $fName ) {
    $r = pathinfo($fName);
    $m ;
    //TODO: 
    // complete the following list or use
    //$finfo = finfo_open(FILEINFO_MIME_TYPE);
    //finfo_file($finfo, $fName);
    //finfo_close($finfo);
    // @: http://php.net/manual/en/function.finfo-file.php
    switch ( $r['extension'] ){
        case "pdf":
            $m = "application/pdf";
            break;
        case "txt":
            $m = "text/plain";
            break;
        case "png":
                $m = "image/png";
            break;
    }
    return $m;
}

and the .htaccess content is:

Options +Indexes

RewriteCond %{REQUEST_URI} !^/test/subF/
RewriteCond %{REQUEST_URI} !index.php
RewriteCond %{REQUEST_URI} !subF
RewriteRule ^(.*)$ /test/index.php?cf=$1

You can download the complete source code from this link

Abu Romaïssae
  • 3,841
  • 5
  • 37
  • 59
  • The problem with this is all requests will be forwarded to the subdirectory. index.php, which serves the rest of the site, will never be called. It looks like the problem is something with my server config, not the .htaccess rules. @Michel Feldheim's answer is the best right now... – vortextangent Jan 28 '13 at 19:04
  • what about a PHP solution ? did you though about it ? I can think about a creating a gateway – Abu Romaïssae Jan 28 '13 at 21:58
  • yea i'm designing and coding a php solution now, just wanted a quick fix in the mean time but I guess it's not going to happen. – vortextangent Jan 28 '13 at 22:05
  • I've a quick solution, almost ready to use in PHP if you are interested ! – Abu Romaïssae Jan 28 '13 at 22:12
  • easiest solution and quickest with lowest server overhead is a simple ln -s MF's is certainly an interesting solution but really isn't required – Dave Jan 29 '13 at 16:20
  • This is an interesting take, I ended up going a different route. – vortextangent Jan 29 '13 at 16:57
0

All these answers seem far too overly complex to me

Assuming we have a directory structure as follows

/home/user/www/ {web root} /home/user/ftpuploadfolder/ {ftp folder}

and you want that folder to appear via apache as /home/user/www/folder

why not just create a symlink? ln -s /home/user/ftpuploadfolder/ /home/user/www/publicfolder/

doing it this way you can have distinct permissions on the linked folder eg apache access only to public folder (not public read/write etc) and ftp access only to your ftpuploadfolder

Dave
  • 3,280
  • 2
  • 22
  • 40
0

I'd use an PHP file to read the wanted file (in the subfolder in this case), and then output it to the user. But, I think your solution can be found in the following answer:

https://stackoverflow.com/a/1851873/1794894

Community
  • 1
  • 1
Rvanlaak
  • 2,971
  • 20
  • 40
0
RewriteEngine on
RewriteBase /
RewriteCond %{HTTP_HOST} ^yourhost.com|^www.yourhost.com
RewriteCond %{REQUEST_URI} !^/new
RewriteRule ^(.*)$ new/$1 [L]

this mean

www.yourhost.com/new/

is actually

www.yourhost.com

Mertuarez
  • 901
  • 7
  • 24