用.htaccess重写现有但破损的符号链接?

时间:2013-05-15 17:08:14

标签: .htaccess mod-rewrite symlink

我想使用在符号链接存在但已损坏的情况下执行的重写规则。

所以场景将是:

  1. 符号链接不存在:正常404/403错误。
  2. 符号链接存在但已损坏:调用generate-cache.php。
  3. 符号链接存在且正在运行:目标文件正常加载。
  4. 例如:

    ## Symlink does not exist.
    GET /links/cache/secret.jpg
    404 Not Found
    
    ## Symlink is broken.
    GET /links/cache/secret.jpg
      Links to /images/cache/secret.jpg
      Because it's broken, rewrites to: generate-cache.php?path=cache/secret.jpg
    200 OK
    
    ## Symlink works.
    GET /links/cache/secret.jpg
      Links to /images/cache/secret.jpg
    200 OK
    

    更新:我想避免使用PHP来执行这些检查,因为它会导致性能瓶颈。通过PHP输出文件(如果存在)会导致PHP锁定。此外,我没有选择使用多个PHP线程或安装其他apache模块。

1 个答案:

答案 0 :(得分:2)

我不知道在mod_rewrite中测试一个损坏的符号链接的方法(-l检查是否存在符号链接,但不会尝试跟踪它),这可能意味着你需要用PHP(或其他语言)编写某种回调函数。

另一种方法是重写所有请求,并在PHP中构建此逻辑:

  1. 如果文件存在于缓存目录中,请设置适当的标头并使用readfile()输出数据
  2. 如果符号链接存在(或者只是一个在“control”目录中具有正确名称的空文件;我假设您有一些其他进程创建符号链接,因此可以将其修改为touch文件,做适当的生成
  3. 如果符号链接/控制文件不存在,请发送404标题并立即退出
  4. 另一个稍微更高效的变体是让Apache直接提供缓存的图像(如果存在),并重写为PHP以执行第2步和第3步。这样的事情:

    RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
    RewriteRule /links/cache/(.*) generate-cache.php?path=$1
    

    在PHP中

    if ( ! file_exists('cache_control/' . $_GET['path'] )
    {
         header('HTTP/1.1 404 Not Found');
         exit;
    }
    else
    {
         // Control file exists, so this is an allowable file; carry on...
         generate_file_by_whatever_magic_you_have( 'links/cache/' . $_GET['path'] );
         header('Content-Type: image/jpeg'); // May need to support different types
         readfile( 'links/cache/' . $_GET['path'] );
         exit;
    }
    

    假设您可以用控制文件替换符号链接,并且名称直接匹配(即符号链接的目标可以从其名称“猜到”),您也可以将控制文件检查移动到mod_rewrite:

    # If the requested file doesn't exist (if it does, let Apache serve it)
    RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
    # Match the basic path format and capture image name into %1
    RewriteCond %{REQUEST_FILENAME} /links/cache/(.*)
    # Check if a cache control file exists with that image name
    RewriteCond %{DOCUMENT_ROOT}/cache_control/%1 -f
    # If so, serve via PHP; if not, no rewrite will happen, so Apache will return a 404
    RewriteRule /links/cache/(.*) generate-cache.php?path=$1