Test Yourself!

These ten questions run the length of the chapter, and each turns on behavior that catches working developers out. Every snippet is a complete file on the Ubuntu 225 setup of Installing Apache with mod_rewrite, mod_headers and mod_expires enabled, Options FollowSymLinks and AllowOverride All unless a question says otherwise, and DocumentRoot /var/www/example. show.php prints get: and the $_GET array as JSON; index.php prints front controller: and the requested path. Run nothing: write down the status, Location and body each request gets, and why. The answers, with the section each comes from, are in Appendix H.

Questions

Questions 1-3: which configuration applies?Apache config
# 1. The virtual host. What do /private/a.txt and /private/reports/q3.txt return?
<VirtualHost *:80>
  ServerName example.com
  DocumentRoot /var/www/example
  <Directory /var/www/example/private>
    Require all denied
  </Directory>
  <Location "/private/reports">
    Require all granted
  </Location>
</VirtualHost>
# 2. /var/www/example/.htaccess, then docs/.htaccess. new.html and current.html exist,
#    and docs/ has no index page. Status and X-Trail for /old.html, /docs/legacy.html,
#    /docs/old.html and /docs/?
Options -Indexes
Header append X-Trail "root"
RewriteEngine On
RewriteRule ^(.*)old\.html$ $1new.html [L]
# --- docs/.htaccess
Header append X-Trail "docs"
RewriteEngine On
RewriteRule ^legacy\.html$ current.html [L]
# 3. AllowOverride FileInfo only. Each line is the whole of a separate .htaccess.
#    Which ones leave / working, and what do the others log?
Header set X-Test "1"
ExpiresActive On
FallbackResource /index.php
Options -Indexes
php_value memory_limit 256M
Questions 4-6: what does mod_rewrite do?Apache config
# 4. /var/www/example/blog/.htaccess. Requests: /blog/about, /blog/post?id=5, /blog/old-post.
#    Which line after RewriteEngine On repairs the redirect?
RewriteEngine On
RewriteRule ^/about$ about.php [L]
RewriteRule ^post\?id=(\d+)$ show.php?id=$1 [L]
RewriteRule ^old-post$ new-post [R=301,L]
# 5. Requests: /a?y=2, /b?y=2, /tag/rock%20roll and /tag/c++
RewriteEngine On
RewriteRule ^a$ show.php?x=1 [L]
RewriteRule ^b$ show.php?x=1 [QSA,L]
RewriteRule ^tag/(.+)$ show.php?tag=$1 [L]
# 5b. These two lines are then appended. What happens to all four requests?
RewriteCond %{HTTP:X-Api-Version} -ge 2
RewriteRule ^api/(.*)$ show.php?v=2&r=$1 [B,L]
# 6. Meant to hide index.php. Requests: /index.php, /products/7, /css/site.css.
#    What one condition fixes the broken one?
RewriteEngine On
RewriteRule ^index\.php$ / [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [L]
Questions 7-9: redirects, protected files and headersApache config
# 7. Requests: /docs/v1/install?os=linux, /docs/v10 and /old-page
Redirect 301 /docs/v1 /docs/v2
Redirect 301 /old-page /new-page
RewriteEngine On
RewriteRule ^old-page$ show.php?from=rewrite [L]
# 8. .env, .git/config and config.php.bak (PHP source with a password) all exist.
#    What do /.env, /.git/config and /config.php.bak return?
<FilesMatch "^\.">
  Require all denied
</FilesMatch>
# 9. Requests: /, /missing and /old. Status, Location, and which of the two headers?
Header set X-Frame-Options "DENY"
Header always set X-Content-Type-Options "nosniff"
ErrorDocument 404 https://example.com/errors/404.html
Redirect 301 /old /new
Question 10: rules moved into the virtual hostApache config
# 10a. Copied unchanged from .htaccess into <VirtualHost>, with AllowOverride None, and
#     configtest says Syntax OK. Requests: /old-blog/2026/post.html and /css/site.css
RewriteEngine On
RewriteRule ^old-blog/(.*)$ /blog/$1 [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
# 10b. The same four lines, unchanged, inside the virtual host's directory section.
#      What do the two requests return now, and why?
<Directory /var/www/example>
  RewriteEngine On
  RewriteRule ^old-blog/(.*)$ /blog/$1 [R=301,L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteRule ^ index.php [L]
</Directory>