30

I think I am pretty close. I have the htaccess redirecting to the website (frontend/web) and the /admin path (backend/web). The site appears fine, CSS files loading, etc.

If you go to: http://localhost/yii2app/ - it loads the homepage, and doesn't redirect in the address bar, but the page shows frontend/web in all the URLs.

if you go to: http://localhost/yii2app/admin - it loads the backend login page, however it immediately redirects to /backend/web/site/login in the address bar (ugly).

Problem: The frontend/backend paths are showing in the URLs (address bar, and links on the page).

What I need: I want the whole site to operate without showing frontend/backend links. The project's root should pull (invisibly) from the frontend/web without showing it.. So http://localhost/yii2app/ runs my whole frontend, and http://localhost/yii2app/admin/ runs my whole backend.

Why? I feel this setup would be pretty solid and elegant when live on a server. I want to be able to push my project folder live to a site and it work just fine without having to have hacks to handle local vs server.

.htaccess file in /yii2app dir:

Options -Indexes
RewriteEngine on

<IfModule mod_rewrite.c>
    RewriteCond %{REQUEST_URI} !^/backend/web/(assets|css)/
    RewriteCond %{REQUEST_URI} admin
    RewriteRule .* backend/web/index.php [L]

    RewriteCond %{REQUEST_URI} !^/(frontend|backend)/web/(assets|css)/
    RewriteCond %{REQUEST_URI} !admin
    RewriteRule .* frontend/web/index.php [L]
</IfModule>

Now in frontend and backend web directories, they both have the same .htaccess:

RewriteEngine on

# if a directory or a file exists, use the request directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

# otherwise forward the request to index.php
RewriteRule . index.php

I do not want to see /frontend/web or /backend/web ever :)

I tried to play with the RewriteRule in the root's htaccess to add /admin to the URL, but it kept telling me /admin does not exist. I KNOW it does not exist, and I don't want it to exist. I want it to be a relative path.. ie: /admin == /backend/web.

Worded another way. I way everything in the project's root (http://localhost/yii2app/) to load frontend/web, but without showing it. Also, http://localhost/yii2app/admin to load backend/web and just showing http://localhost/yii2app/admin. Obviously they would have their respective controller/action attached to them. So admin could look like http://localhost/yii2app/admin/site/login

NOTE: I have not played with any of the files. This is a stock yii2 advanced setup, using composer, and following the docs. The only thing I have played with so far are the htaccess files mentioned.

Thank you!

Sohel Ahmed Mesaniya
  • 3,013
  • 1
  • 19
  • 29
Wade
  • 3,509
  • 2
  • 26
  • 45
  • or... you can learn how to set up virtual hosts on your computer and be done with hacky things like this. Why are you creating a problem and then trying to find a silly solution to it? Google virtual hosts and whatever OS you have and learn to do it the proper way – Mihai P. Jan 23 '15 at 23:16
  • I already know about vhosts, though I don't feel I should have to create a virtual host to solve this problem for a Yii2 test bin. – Wade Jan 24 '15 at 01:53
  • 2
    You don't have to be rude about it. If your too bothered to answer, or help, then don't post and move on. Why would I want 100 virtual hosts setup for every single thing I run, or test... – Wade Jan 25 '15 at 03:57
  • You can define the DocumentRoot of your virtual host for your domain with web directory (/path to directory/backend/web), so it opens web directory by entering the domain without showing it. You don't necessarily need to add htaccess rules. – TheDevWay Nov 05 '17 at 09:55

7 Answers7

33

Try this with .htaccess Method-

Step 1

Create .htaccess file in root folder, i.e advanced/.htaccess and write below code.

Options +FollowSymlinks
RewriteEngine On

# deal with admin first
RewriteCond %{REQUEST_URI} ^/(admin) <------
RewriteRule ^admin/assets/(.*)$ backend/web/assets/$1 [L]
RewriteRule ^admin/css/(.*)$ backend/web/css/$1 [L]

RewriteCond %{REQUEST_URI} !^/backend/web/(assets|css)/  <------
RewriteCond %{REQUEST_URI} ^/(admin)  <------
RewriteRule ^.*$ backend/web/index.php [L]


RewriteCond %{REQUEST_URI} ^/(assets|css)  <------
RewriteRule ^assets/(.*)$ frontend/web/assets/$1 [L]
RewriteRule ^css/(.*)$ frontend/web/css/$1 [L]
RewriteRule ^js/(.*)$ frontend/web/js/$1 [L] 
RewriteRule ^images/(.*)$ frontend/web/images/$1 [L]

RewriteCond %{REQUEST_URI} !^/(frontend|backend)/web/(assets|css)/  <------
RewriteCond %{REQUEST_URI} !index.php
RewriteCond %{REQUEST_FILENAME} !-f [OR]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.*$ frontend/web/index.php

Note : if you are trying in local server then replace ^/ with ^/project_name/ where you see arrow sign. Remove those arrow sign <------ after setup is done.

Step 2

Now create a components/Request.php file in common directory and write below code in this file.

namespace common\components;


class Request extends \yii\web\Request {
    public $web;
    public $adminUrl;

    public function getBaseUrl(){
        return str_replace($this->web, "", parent::getBaseUrl()) . $this->adminUrl;
    }


    /*
        If you don't have this function, the admin site will 404 if you leave off 
        the trailing slash.

        E.g.:

        Wouldn't work:
        site.com/admin

        Would work:
        site.com/admin/

        Using this function, both will work.
    */
    public function resolvePathInfo(){
        if($this->getUrl() === $this->adminUrl){
            return "";
        }else{
            return parent::resolvePathInfo();
        }
    }
}

Step 3

Installing component. Write below code in frontend/config/main.php and backend/config/main.php files respectively.

//frontend, under components array
'request'=>[
    'class' => 'common\components\Request',
    'web'=> '/frontend/web'
],
'urlManager' => [
        'enablePrettyUrl' => true,
        'showScriptName' => false,
],

// backend, under components array
'request'=>[
    'class' => 'common\components\Request',
    'web'=> '/backend/web',
    'adminUrl' => '/admin'
],
'urlManager' => [
        'enablePrettyUrl' => true,
        'showScriptName' => false,
],

Step 4 (Optional, if doesn't work till step three)

create .htaccess file in web directory

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

Note: make sure you have enabled your mod rewrite in apache

Thats it! You can try your project with
www.project.com/admin, www.project.com

in local server
localhost/project_name/admin, localhost/project_name

mohit
  • 1,661
  • 1
  • 12
  • 23
  • 1
    I used this answer but I got problem when installing the system in a windows server.. How to convert the `.htaccess` to `web.config` – beginner May 15 '15 at 06:45
  • this worked for me, but I have another project now where I don't have a frontend, only a backend, how can I rewrite this so '/' goes to backend web? (and I can't just use the basic template) – Ruben May 17 '15 at 11:32
  • i am working on advance version of yii2 and i want to rewrite this **/frontend/home/jobs** to **/jobs/**. i tried your answer but after this i got exception error and invalid file directory. so how can i do this – devajay Jun 18 '15 at 04:29
  • create an htaccess file in frontend web directory and write this code in it `RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ /index.php?/$1 [L]` Make sure you have enabled mod-rewrite. – mohit Jun 22 '15 at 06:32
  • what issues you are getting? – mohit Jul 01 '15 at 12:00
  • Mohit i uploaded to subdomain, How can i access admin. – Ilyas karim Aug 01 '16 at 13:22
  • Subdomain.domain.com/admin – mohit Aug 01 '16 at 17:36
  • I've used the you steps is working but their is problem when I write a rules in like 'home'=>'site/index' menu URL not changed (http://localhost/application/site/index) – Kailas Dec 27 '16 at 05:01
  • @kailas `'urlManager' => [ 'enablePrettyUrl' => true, 'enableStrictParsing' => true, 'showScriptName' => false, 'rules' => [ '' => 'site/', ], // ... ]` – mohit Dec 27 '16 at 10:22
  • @mohit thanks. working fine. can you update the answer by adding rules. in it. It'll we helpful others – Kailas Dec 27 '16 at 10:43
  • Performed the above steps its giving me this error: Setting read-only property: yii\web\Application::request – Sadia Feb 16 '17 at 09:42
  • is it possible to add one more frontend and named it to be site.com/front2/ – Vinod C Mar 13 '17 at 06:01
  • 1
    Thank you a lot, but you forgot javascripts and images inside the first .htaccess: RewriteRule ^js/(.*)$ frontend/web/js/$1 [L] RewriteRule ^images/(.*)$ frontend/web/images/$1 [L] – Gabriele Carbonai Jun 22 '17 at 11:31
  • I discovered with chrome is redirect to frontend/web, I think there is some mistake in the first .htaccess, how can be resolve it? – Gabriele Carbonai Oct 03 '17 at 11:31
26

If your only goal is to achieve not ever seeing /frontend/web or /backend/web, even without using .htaccess rules, you could go for the following:

Why not just pull out the contents of the web folders and place them in the root? Just adjust the path referring to the framework and config files in the entry scripts index.php.

Your dir structure would look like:

- yii2app/
    - frontend/
    - backend/
    - common/
    - .. other folders..
    - admin/
        - assets/
        - css/
        - index.php
    - assets/
    - css/
    - index.php

Your yii2app/index.php would then look like:

defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');

require(__DIR__ . '/vendor/autoload.php');
require(__DIR__ . '/vendor/yiisoft/yii2/Yii.php');
require(__DIR__ . '/common/config/bootstrap.php');
require(__DIR__ . '/frontend/config/bootstrap.php');

$config = yii\helpers\ArrayHelper::merge(
    require(__DIR__ . '/common/config/main.php'),
    require(__DIR__ . '/common/config/main-local.php'),
    require(__DIR__ . '/frontend/config/main.php'),
    require(__DIR__ . '/frontend/config/main-local.php')
);

$application = new yii\web\Application($config);
$application->run();

and your yii2app/admin/index.php would look like:

defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');

require(__DIR__ . '/../vendor/autoload.php');
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
require(__DIR__ . '/../common/config/bootstrap.php');
require(__DIR__ . '/../backend/config/bootstrap.php');

$config = yii\helpers\ArrayHelper::merge(
    require(__DIR__ . '/../common/config/main.php'),
    require(__DIR__ . '/../common/config/main-local.php'),
    require(__DIR__ . '/../backend/config/main.php'),
    require(__DIR__ . '/../backend/config/main-local.php')
);

$application = new yii\web\Application($config);
$application->run();

EDIT: your entry scripts could look different to mine, but you should get the idea of changing the paths to find the framework files with these examples.

deacs
  • 4,089
  • 2
  • 24
  • 36
  • Moving the dirs was a thought. I was looking for the htaccess method to keep everything exactly the way it came after running composer. I didn't know what adverse affects moving those dirs around would have to running composer in the future. I figured htaccess would allow me to keep the structure exactly how it came out of the box. – Wade Jan 24 '15 at 01:57
  • You can use composer just fine when updating and the app will work as you expect too. So there is basicly no downside so this approach imho. – deacs Jan 24 '15 at 08:25
  • Thanks bro. It helped me a lot. Just what I wanted. Just add the htaccess code for basic template in both admin and root directory and it works like a charm – shivgre Mar 23 '16 at 09:46
  • @beginner Then you are doing something wrong. This method will always work with yii2 regardless of version – deacs Jan 11 '17 at 08:11
  • Yeah I did something wrong. The above also works even in the basic template. – beginner Jan 11 '17 at 08:14
3

Like @deacs said just move the files from frontend/web to yii2app (root folder) and create a folder in yii2app "admin" and move files from backend/web to yii2app/admin and then create .htaccess files in both admin and yii2app with following code :

Options +FollowSymLinks
IndexIgnore */*

RewriteEngine on

# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

# otherwise forward it to index.php
RewriteRule . index.php

Then add/modify the urlManager component in config file main.php in both frontend/config/main.php and backend/config/main.php with following code :

    'urlManager' => [
        'enablePrettyUrl' => true,
        'showScriptName' => false,
        'enableStrictParsing' => false,
        'rules' => [
        ],
    ],

Then change the index.php in yii2app with following code :

<?php
defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');

require(__DIR__ . '/vendor/autoload.php');
require(__DIR__ . '/vendor/yiisoft/yii2/Yii.php');
require(__DIR__ . '/common/config/bootstrap.php');
require(__DIR__ . '/frontend/config/bootstrap.php');

$config = yii\helpers\ArrayHelper::merge(
    require(__DIR__ . '/common/config/main.php'),
    require(__DIR__ . '/common/config/main-local.php'),
    require(__DIR__ . '/frontend/config/main.php'),
    require(__DIR__ . '/frontend/config/main-local.php')
);

$application = new yii\web\Application($config);
$application->run();

Also change the index.php in yii2app/admin with following code :

<?php
defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');

require(__DIR__ . '/../vendor/autoload.php');
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
require(__DIR__ . '/../common/config/bootstrap.php');
require(__DIR__ . '/../backend/config/bootstrap.php');

$config = yii\helpers\ArrayHelper::merge(
    require(__DIR__ . '/../common/config/main.php'),
    require(__DIR__ . '/../common/config/main-local.php'),
    require(__DIR__ . '/../backend/config/main.php'),
    require(__DIR__ . '/../backend/config/main-local.php')
);

$application = new yii\web\Application($config);
$application->run();

Thats all you need to complete the SEO friendly URLs in yii2. I was struggling myself and then I got help from @deacs answer and I though maybe this will help someone.

shivgre
  • 1,073
  • 1
  • 12
  • 29
1

After 2 days searching for best solutions I make it this way (host on shared hosting). I make subdomain admin.xxxxx.com and point it to document root /public_html/xxxxxx/backend/web
Because shared hosting don't allow you to put custom document root for you main domain, I use this solution :

Change the primary domain name on your account, then add the old primary domain as an addon domain. This way, you can pick the root folder you want for the primary domain/new addon domain. (The new primary domain will now point to public_html.)

Then point (now my addon domain) to right document root for frontend /public_html/xxxxxx/frontend/web

Sohel Ahmed Mesaniya
  • 3,013
  • 1
  • 19
  • 29
despotbg
  • 429
  • 4
  • 10
0

I followed "deacs" answer and got following error

Invalid Configuration – yii\base\InvalidConfigException
The directory does not exist: D:/wamp/www/yii2app/assets

then i created "assets" folder in "yii2app" and it works

----------Second method------------------------

Without moving files you can follow following link

https://github.com/yiisoft/yii2-app-advanced/blob/master/docs/guide/start-installation.md

----------Third method-----------------------------

http://www.yiiframework.com/doc-2.0/guide-tutorial-shared-hosting.html

Aamir Sarwar
  • 271
  • 2
  • 9
0

So far the easiest and the most flexible solution for me are symlinks. You can put project anywhere and only create symlinks to directories forced by your hosting. For example, put project in ~/domains/example.com/project and create symlinks to public_html directory.

cd ~/domains/example.com
# remove old public_html directory
mv public_html old_public_html
# create symlink for fronted
ln -s ./project/frontend/web public_html
# create symlink for backend in /admin subdirectory
ln -s ./project/backend/web public_html/admin

And there you have http://example.com/ with frontend and http://example.com/admin/ with backend.

If you need backend in separate domain (admin.example.com):

ln -s ~/domains/example.com/project/backend/web ~/domains/admin.example.com/public_html

Pros

  1. No twisted rewrite rules that almost nobody understand.
  2. You don't have whole project in public directory, so some misconfiguration of webserver and/or PHP will no public your code and config files.
  3. You can adapt the project to any structure required by hosting.
  4. If you use relative symlinks, you can keep it under version control and create single webroot with all apps as subdirectories.

Cons

  1. If you have a hosting with some restricted open_basedir settings without any control over it, you may unable to do use it.
rob006
  • 18,710
  • 5
  • 41
  • 58
0

put .htaccess in web dir

code

RewriteEngine on

# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

# otherwise forward it to index.php
RewriteRule . index.php