27

Bellow is my site directory structure:

htdocs/
    My-Project/
        public/
            index.php
            css/
            img/
            js/
        src/
            config.php
            templates/
            library/

I do not want any direct user access to any files inside the src directory. src contains my templating and backend logic scripts.

I want to set up my .htaccess so that when the user goes to my website (root folder My-Project), they are redirected to My-Project/public/index.php. I would like the URL to simply look like My-Project.com while on the index page.

Any help? I am hesitant to modify my .htaccess file as I see a lot of conflicting advice around here and on the net as to the best way to do this.

anubhava
  • 761,203
  • 64
  • 569
  • 643
tdc
  • 5,174
  • 12
  • 53
  • 102
  • Why the need for a public directory in the first place, incidentally? – Andrew Barber May 13 '14 at 15:43
  • If you're on shared hosting then the only way to do what you want would be through the .htaccess. If you have a VPS then you can point the server to that public folder using the hosting settings. – CheckeredMichael May 13 '14 at 15:44
  • @AndrewBarber: I suppose there isn't a requirement for it, I'm just trying to keep my front-end and logic code as separate as possible and this structure helps me stay organized. I'm open to recommendations though, I'm new to larger PHP projects :) – tdc May 13 '14 at 15:46
  • Well, it's usually expected that a site's root directory would be the 'public' part. But if you have code that you don't want accessed at all via requests, it should be out of the web directory entirely, as @CheckeredMichael notes. – Andrew Barber May 13 '14 at 15:47
  • @CheckeredMichael: yes shared hosting. I know I need to do it via `.htaccess` I'm just not sure which commands would accomplish both of the things I need. Would I need a .htaccess in the root to redirect to the /public/ folder, and then another inside /public/ to format the URL? – tdc May 13 '14 at 15:47
  • @AndrewBarber: I don't want users to be able to directly visit any of the `src` directories, but the scripts in `public` directory should be able to access them. – tdc May 13 '14 at 15:48
  • You could also do it via PHP, if you add a header to the index of `My-Project`. – ArtOfCode May 13 '14 at 15:51

6 Answers6

66

Place this code in /My-Project/.htaccess:

RewriteEngine On
RewriteBase /My-Project/

RewriteCond %{THE_REQUEST} /public/([^\s?]*) [NC]
RewriteRule ^ %1 [L,NE,R=302]

RewriteRule ^((?!public/).*)$ public/$1 [L,NC]
anubhava
  • 761,203
  • 64
  • 569
  • 643
  • This is partially working, everything loads except images which are returning 404's. this is because I'm using [retina images for PHP](http://retina-images.complexcompulsions.com/), which has me create a `.htaccess` in the `/public/` dir, it redirects image requests to retina-equivalents. Is there a way to make these two methods play nice together? – tdc May 13 '14 at 18:05
  • 1
    It can be done, can you post your .htaccess from `/My-Project/public/.htaccess`? – anubhava May 13 '14 at 18:21
  • 1
    @pathros: It is working and tested solution. You can post a new question with all the details to get your problem resolved. – anubhava Jul 22 '16 at 15:58
  • I get `Request exceeded the limit of 10 internal redirects due to probable configuration error.` [This](https://stackoverflow.com/a/16283670/9950378) worked for me. – Jean-Marc Zimmer Nov 03 '18 at 11:47
  • 2
    Note: If you're using XAMPP or similar, your `/htdocs/my-project/.htaccess` file should use `RewriteBase /my-project/` too! – Jimmy Adaro May 27 '19 at 18:31
11

Add the following to the first line of your .htaccess

DirectoryIndex public/index.php public/index.html
daxeh
  • 1,083
  • 8
  • 12
10

I made some changes to @anubhava's response to working on localhost and with friendly URLs.

Directory structure:

  • / (localhost root folder)
    • myapp/
      • public/
      • index.php
    • core/
      • some core files ...

myapp/.htaccess (myapp root folder)

RewriteEngine On
RewriteBase /myapp

RewriteCond %{THE_REQUEST} /public/([^\s?]*) [NC]
RewriteRule ^ %1 [L,NE,R=302]
RewriteRule ^(.*)$ public/index.php?$1 [L,QSA]

myapp/public/.htaccess

RewriteEngine On
RewriteBase /

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?$1 [L,QSA]

myapp/public/index.php

<?php
echo 'Hello<br>';
echo $_SERVER['QUERY_STRING'];

Some requests:

http://localhost/myapp/

Hello


http://localhost/myapp/post/new

Hello

post/new

SandroMarques
  • 6,070
  • 1
  • 41
  • 46
10

this works for me all the time. Create a .htaccess in your root directory outside of the public folder then add these 3 lines and boom problem solve.

RewriteEngine On
RewriteCond %{REQUEST_URI} !^public
RewriteRule ^(.*)$ public/$1 [L]
jerryurenaa
  • 3,863
  • 1
  • 27
  • 17
  • It works, but if I put public in the URL it also works, and since Google has indexed the URL with public. Do you know any way to redirect URLs with public to without public? I have tried to put this: `RewriteRule ^public/(.*)$ /$1 [R=301,L]` but it doesn't work. – jcarlosweb Sep 17 '20 at 09:50
  • Because we route everything to the /public you must before that code above specify the URL so it can then properly find the route. In your public folder create a new htaccess and add this code RewriteEngine on RewriteRule ^public/(.+)$ http://example.com/$2 [R=301,L] replace the url with your own url – jerryurenaa Sep 17 '20 at 14:35
1

I was looking for a same solution for my "pet project" deployed on a free web hosting Infinityfree.

The directory structure (before):

htdocs/
   ├─ public/
   └─ src/

None of the answers above separately didn't help me and caused 404 or 503 http errors or just showed me folders of a project.

SandroMarques' answer encouraged me to try add two .htaccess files. After multiple attempts, I found a solution that worked for me. I used anubhava's and SandroMarques' answers.

The directory structure (after):

htdocs/
   ├─ public/
   │   └─.htaccess //second file
   │
   ├─ src/
   └─.htaccess //first file

First .htaccess file:

RewriteEngine On
RewriteBase /

RewriteCond %{THE_REQUEST} /public/([^\s?]*) [NC]
RewriteRule ^ %1 [L,NE,R=302]

RewriteRule ^((?!public/).*)$ public/$1 [L,NC]

Second .htaccess file:

RewriteEngine On
RewriteBase /

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?$1 [L,QSA]

Maybe others will find this helpful.

Double-w-B
  • 54
  • 1
  • 4
0

ok so you can do this , with symfony 5, if you want to put a .htaccess to redirect the access to public/index.php file you have this:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^$ public/index.php [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ public/index.php [QSA,L]
and you can add this to redirect to https if you have a certificate for let's encrypt for example :
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L]