8

I'm trying to allow Clean-Urls, having MultiViews enabled.

All the pages I have, are in the root folder itself.

I am trying to achieve the following :

(current-status -> what I am trying to achieve)

 1. foo.com/services.php -> foo.com/services
 2. foo.com/services == foo.com/services/
 3. foo.com/services.php/second-level/ == foo.com/services/second-level

The services is not a folder, I explode $_SERVER['PATH_INFO'] and get the second-level path data.

I have already achieved the first one, but it fails when I enable MultiViews, using a .htaccess file and writing a rewrite.

Options +Indexes +FollowSymLinks -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.*) $1.php [L]

(Which would obviously fail, since it would change the request to services/second-level.php). I know I can write multiple rewrites in the .htaccess, and conditionally redirect.

But the strange fact is that on the live environment (shared hosting), it is working, without any .htaccess file in the root folder. Since it is a shared hosting, I cannot read the configuration file.

Any ideas on what configuration should I change (in apache.conf or *.conf) to achieve the above?

If it matters, I'm using Apache/2.2.22, and this problem started happening after the update.

Aaditi Sharma
  • 766
  • 2
  • 9
  • 20
  • I don't think you want this: `foo.com/services.php -> foo.com/services` but this: `foo.com/services -> foo.com/services.php`. It doesn't make much sense to show in the browser's address an "ugly" URL where the resource is shown `(foo.com/services.php)` while hiding the "pretty" one `foo.com/services`, except when there are very special reasons. ¿Are there? – Felipe Alameda A Jan 06 '13 at 20:10
  • @FelipeAlamedaA : I want Clean URL's itself. Just updated the question to make it clearer. – Aaditi Sharma Jan 09 '13 at 07:22

3 Answers3

12

I finally figured out how to solve it.

This works, removing the .htaccess file altogether, and changing the Virtual Directory to keep the following settings :

<VirtualHost *:80>
    ServerAdmin my-email-id
    ServerName foo.bar
    DocumentRoot /var/www/sites/foo/

    <Directory /var/www/sites/foo/>
        Options +FollowSymLinks +MultiViews +Indexes
        DirectoryIndex index.php
        AddType application/x-httpd-php .php
    </Directory>

</VirtualHost>

This helps me get all the pages to work, exactly as they were working on the server, without any of the Rewrite Conditions.

Aaditi Sharma
  • 766
  • 2
  • 9
  • 20
  • Using the MultiViews approach, I often see see error "no acceptable variant" in Apache's error log. Is this also the case for you? – crishoj May 02 '13 at 20:45
  • I was using "+MultiViews" with no luck. Adding "AddType application/x-httpd-php .php" made the trick for me. Thanks. – David Díaz Aug 01 '14 at 07:37
  • This approach is broken. See http://stackoverflow.com/q/16357933/1709587 for the problem it causes, and http://stackoverflow.com/a/24598848/1709587 for a breakdown of why and how to fix it (which explicitly references this answer). – Mark Amery Jan 07 '17 at 11:03
0

Clean URLs without .php extensions and without using MultiViews.

A flexible Web environment with virtual subdomain support using mod_userdir and mod_rewrite.

Allows following url layout

  • /var/www/sites/www/services.php
    • http://foo.bar/services.php/second-level/
    • http://foo.bar/services/second-level/
    • http://www.foo.bar/services/second-level/
    • http://127.0.0.1/services/second-level/
  • /var/www/sites/www/admin/login.php
    • http://foo.bar/admin/login.php/foo
    • http://foo.bar/admin/login/foo
    • http://www.foo.bar/admin/login/foo

Note with or without prepending www. is equal because www. is obsolete today... But now you can host virtual subdomains too simply by adding a folder in /var/www/sites/ (remember DNS)

  • /var/www/sites/images/imgpass.php
    • http://images.foo.bar/imgpass.php/photo.jpg
    • http://images.foo.bar/imgpass/photo.jpg
    • http://www.images.foo.bar/imgpass/photo.jpg
    • http://127.0.0.1/~images/imgpass/photo.jpg

...and so on but skips if /var/www/sites/images/imgpass itself exists.

I am using a multi-user environment where every user has its own webroot and subdomain.

/etc/apache2/sites-enabled/foo.bar.conf:

<VirtualHost *:80>
  ServerAdmin my-email-id
  ServerName foo.bar
  ServerAlias 127.0.0.1 *.foo.bar

  # The default web-root if no subdomain is given
  DocumentRoot /var/www/sites/www/

  UserDir /var/www/sites/*
  <Directory /var/www/sites/*>
            Order allow,deny
            Allow from all
            DirectoryIndex index.php index.html
            Options -MultiViews -Indexes

            # MultiViews workaround with 1 level subdir support
            RewriteEngine On

            RewriteCond %{REQUEST_FILENAME} !-d
            RewriteCond %{REQUEST_FILENAME} !-f
            RewriteCond %{REQUEST_FILENAME} ^(\/var\/www\/sites\/.+(\/[^\/]+){2}).*
            RewriteCond %1.php -f
            RewriteRule ^\/var\/www\/sites\/(.+)((?:\/[^\/]+){2})(.*) /~$1$2.php$3 [L]

            RewriteCond %{REQUEST_FILENAME} !-d
            RewriteCond %{REQUEST_FILENAME} !-f
            RewriteCond %{REQUEST_FILENAME} ^(\/var\/www\/sites\/.+(\/[^\/]+){1}).*
            RewriteCond %1.php -f
            RewriteRule ^\/var\/www\/sites\/(.+)((?:\/[^\/]+){1})(.*) /~$1$2.php$3 [L]
   </Directory>

   # Force all requests in background to UserDir compatible requests
   RewriteEngine on
   RewriteMap      lc                      int:tolower

   RewriteCond     %{REQUEST_FILENAME}     !^/~
   RewriteCond     %{HTTP_HOST}            ^(www\.)?(.+)\.foo\.bar$
   RewriteRule     /(.*)                   /~${lc:%2}/$1                   [PT,L]

</VirtualHost>

This code is not testet because my file system structure differs completely from the initial example. So I converted my configuration on the fly to fit to this example structure.

Note the configuration is incomplete. You need to tune it yourself for Your needs.

Sprinterfreak
  • 504
  • 4
  • 10
0

While MultiViews can be used for this, don't add an arbitrary MIME type to PHP files to get them to be served by MultiViews, like the accepted answer and many other sources on the internet suggest:

# Bad code - don't do this!
Options +MultiViews
AddType application/x-httpd-php .php

This hack, which I explain in detail at https://stackoverflow.com/a/24598848/1709587, appears to work, but is actually broken; it will fail whenever the server receives a request with an Accept header that does not include */*.

Instead, the clean solution is to use the MultiviewsMatch directive to tell Apache that it's valid to serve .php files regardless of the Accept and Accept-Language headers of the request:

# Good code - use this instead!
Options +MultiViews
<Files "*.php">
    MultiviewsMatch Any
</Files>
Community
  • 1
  • 1
Mark Amery
  • 143,130
  • 81
  • 406
  • 459