eang
eang

Reputation: 1645

Apache URL rewriting not working

I'm trying to rewrite the static URLs on my shared webserver running apache2, in order to track the download counts of the files in the public_html/files/ subdirectory. I want to rewrite the urls like

http://example.com/files/foo.zip

into the url

http://example.com/files/download.php?file=foo.zip

The download.php script works fine if I type manually its URL in the browser.

The RewriteRule that I'm using is the following:

RewriteRule ^files/(.*)$ /files/download.php?file=$1 [L]

I tried two different ways:

  1. Insert the rule in the "root" public_html/.htaccess file. This results in a 500 error when I request example.com/files/foo.zip

    # public_html/.htaccess
    
    # Use PHP5.4 as default
    AddHandler application/x-httpd-php54 .php
    
    # BEGIN WordPress
    <IfModule mod_rewrite.c>
    RewriteEngine On
    # Default wordpress rules
    RewriteBase /
    RewriteRule ^index\.php$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.php [L]
    # My custom rule
    RewriteRule ^files/(.*)$ /files/download.php?file=$1 [L]
    </IfModule>
    
    # END WordPress
    
    Options -Indexes
    
  2. Insert the rule in a new public_html/files/.htaccess file. Now when I request example.com/files/foo.zip the download works, the rewrite doesn't, i.e. download.php is not called.

    # public_html/files/.htaccess 
    
    <IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteRule ^files/(.*)$ /files/download.php?file=$1 [L]
    </IfModule>
    

I'm having a hard time debugging this, because I'm on a shared server and I don't have a quick access to the apache error logs. What I'm doing wrong?

I should probably clarify that the url rewriting triggered by wordpress (with its permalinks) works fine.

UPDATE

This is files/download.php used for tracking downloads on my DB:

<?php
define('WP_USE_THEMES', false);
require('../wp-blog-header.php');

$filename = $_GET['file'];
$basepath = $_SERVER['DOCUMENT_ROOT']."/files/";
$realbase = realpath($basepath);

$actual_link = "http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
file_put_contents("request.log", $actual_link."\n\n", FILE_APPEND);

$inputpath = $basepath . $filename;
$realpath = realpath($inputpath);

if ($realpath === false || strpos($realpath, $realbase) !== 0) {
        echo "Directory traversal detected! <br/>";
        exit;
}

$fileinfo = pathinfo($realpath);
$filetypes = array("gz", "zip", "tgz");

$table = "downloads";           // table name
$pk = "filename";               // table primary key
$counter = "download_count";    // counter field


if (!in_array($fileinfo['extension'], $filetypes)) {
        echo "$inputpath - {$fileinfo['extension']} is an invalid download type.";
        exit;
}

if (file_exists($realpath)) {

        $count = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM {$table} WHERE {$pk} = '{$filename}';"));
        $query = "";

        if ($count == 1) {
                $query = "UPDATE {$table} SET {$counter} = {$counter} + 1 WHERE {$pk} = '{$filename}';";
        }

        else if ($count == 0) {
                $query = "INSERT INTO {$table} ({$pk}, {$counter}) VALUES ('{$filename}', 1);";
        }

        $wpdb->query($wpdb->prepare($query));

        $size = filesize($realpath);

        header("Content-Type: application/octet-stream");
        header("Content-Disposition: filename={$fileinfo['basename']}");
        header("Content-Length: {$size}");
        header("Cache-Control: private");
        header("Location: {$filename}");  

        readfile(basename($realpath));

}
else {
        echo "File $filename does not exist.";
}
exit;


?>

Upvotes: 0

Views: 546

Answers (2)

anubhava
anubhava

Reputation: 785146

Inside public_html/files/.htaccess you should have:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /files/

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ download.php?file=$1 [L,QSA]
</IfModule>

EDIT:

Try this in WP .htaccess:

# public_html/.htaccess

# Use PHP5.4 as default
AddHandler application/x-httpd-php54 .php
Options -Indexes -MultiViews

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
# Default wordpress rules
RewriteBase /
RewriteRule ^index\.php$ - [L]

# My custom rule
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^files/((?!download\.php).+)$ /files/download.php?file=$1 [L,QSA]   

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress

Upvotes: 1

Black Sheep
Black Sheep

Reputation: 6694

Try to put / here:

RewriteRule ^/files/(.*)$ /files/download.php?file=$1 [L]
             ^--here

Upvotes: 1

Related Questions