.htaccess:从公共目录提供静态文件,而没有URL中的公共文件,否则重写为index.php

时间:2018-10-29 11:56:21

标签: php apache .htaccess mod-rewrite

以下是我的网站目录结构:

htdocs/
    My-Project/
        .htaccess
        public/
            css/
            img/
                img.jpg
            js/
        index.php
        ...(other stuff)

我想使用.htaccess文件检查请求的路径是否为public /目录中的文件(类似于从express.static中的目录中提供静态文件)。如果是,则提供服务,否则将请求转发到/index.php。

基本上,我的问题可以分为以下子问题:

SubProblem1:仅提供公共目录中的文件,否则路由到index.php
SubProblem2:从公共目录提供这些文件,而不需要URL中的“公共”

因此,/My-Project/img/img.jpg应该重写为/My-Project/public/img/img.jpg,而/My-Project/notexisting.file/My-Project/test应该重写为/My-Project/index.php

到目前为止,这是我的主意:

    RewriteEngine On

    #Block 1
    #Condition: File exists in public directory
    RewriteCond %{DOCUMENT_ROOT}/My-Project/public/$1 -f
    RewriteRule ^(.*)$ public/$1 [L]

    #Block 2
    #Condition: File doesn't exist in public directory
    RewriteCond %{DOCUMENT_ROOT}/My-Project/public/$1 !-f
    RewriteRule ^(.*)$ index.php [L,QSA]

Block 1独立时->解决了SubProblem2,但是一旦添加了Block 2来解决SubProblem1,则每个请求都将重写为index.php。为什么会这样呢? 为什么第二个RewriteCond无法正常工作?

2 个答案:

答案 0 :(得分:0)

这是我使用的:

#include <stdio.h>
#include <stdlib.h>

#define LENGTH 5

enum Types {
    CHAR,
    INT,
    FLOAT
};

typedef struct {
    void *data;
    int type;
} Type;

#define FMT_CHAR "%c"
#define FMT_INT "%d"
#define FMT_FLOAT "%f"

#define MAX_FORMATTED_LEN 100 // TODO: adjust this: put the maximum length of a printed float or int

char *fmt_type(char *buffer, Type *t);

#define FMT_TYPE(t) fmt_type((char [MAX_FORMATTED_LEN+1]){""}, t)


char *fmt_type(char *buffer, Type *t) {
    switch(t->type) {
        case CHAR:
            sprintf(buffer, FMT_CHAR, *((char *)t->data));
            break;
        case INT:
            sprintf(buffer, FMT_INT, *((int *)t->data));
            break;
        case FLOAT:
            sprintf(buffer, FMT_FLOAT, *((float *)t->data));
            break;
        default:
            printf("Wrong type: %d. Panicking.", t->type);
            exit(-1);
    }
    return buffer;
}



int main()
{
    int i0 = 3, i1 = 421;
    float f0 = 2.5;
    char c0 = 'H', c1 = 'a';

    Type a = { &i0, INT };

    Type b = { &f0, FLOAT };

    Type c = { &c0, CHAR };

    Type d = { &i1, INT };

    Type e = { &c1, CHAR };

    Type *array[LENGTH] = { &a, &b, &c, &d, &e }; 

    //printf("Random entry: %s\n", FMT_TYPE(array[rand() % LENGTH]));

    // the following is just for testing:
    int i = 0;
    for (i = 0; i < LENGTH; i++) {
        printf("entry: %s\n", FMT_TYPE(array[i]));
    }
}
  

如果需要,请更新我的apache虚拟主机配置:

RewriteEngine On

# The following rule tells Apache that if the requested filename
# exists, simply serve it.

RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]


# The following rewrites all other queries to index.php. The 
# condition ensures that if you are using Apache aliases to do
# mass virtual hosting, the base path will be prepended to 
# allow proper resolution of the index.php file; it will work
# in non-aliased environments as well, providing a safe, one-size 
# fits all solution.

RewriteCond %{REQUEST_URI}::$1 ^(/.+)(.+)::\2$
RewriteRule ^(.*) - [E=BASE:%1]
RewriteRule ^(.*)$ %{ENV:BASE}index.php [NC,L]

然后在<VirtualHost *:80> ServerName awesome.scot ServerAlias localhost DocumentRoot /var/www/html/public <Directory "/var/www/html"> DirectoryIndex index.php FallbackResource /index.php Options -Indexes +FollowSymLinks AllowOverride FileInfo All Require all granted </Directory> ProxyPassMatch ^/(.*\.php)$ fcgi://php:9000/var/www/html/public/$1 </VirtualHost> 中,我添加了/etc/hosts,所以现在我使用127.0.0.1 awesome.scot在浏览器中访问我的网站

请注意vhost conf中的两个文件夹,一个是站点根目录,一个是公共目录。

如果您尚未打开虚拟主机,请尝试一下!取消注释apache conf中的vhosts行,然后进入额外的文件夹并配置您的vhost,然后重新启动!

答案 1 :(得分:0)

第二个RewriteCond不能按我预期的那样工作,因为一旦Block1重写了请求,Block2中的$ 1就不会包含与Block1中相同的信息。

示例

想象一下,我们有URI /My-Project/img/img.jpg
Block1 中,$1将是img/img.jpg。因为此文件存在,所以将满足RewriteCondition,并且新URI将为My-Project/public/img/img.jpg
现在是 Block2 :由于重写了URI,此处将$1定义为public/img/img.jpg。因此,RewriteCondition将检查URL MyProject/public/public/img/img.jpg下是否存在任何现有文件。当然不是。因此,无论以前是否进行过重写,始终都会满足RewriteCondition,并且每个请求都将被重写为index.php。

解决方案

RewriteEngine On

RewriteCond %{DOCUMENT_ROOT}/My-Project/public/$1 -f
RewriteRule ^(.*)$ public/$1 [L]

RewriteCond %{THE_REQUEST} \s/My-Project/public/ [NC,OR]
RewriteCond $1 !^public/
RewriteRule ^(.*)$ index.php [L]