We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Project in a subdirectory

TL;DR: How to configure Phalcon if I don't want to run it under the root of the webserver?

I upgraded to version 4 and my websites stopped working. I have several websites running on the same host, as different instances of phalcon apps, under different directories. Let's say I want to create a new website:

$ cat /etc/issue
Ubuntu 18.04.3 LTS \n \l

$ cd /srv/www/html (this is the document root of https://172.18.0.90)
$ mkdir -p tools/foo/bar
$ cd tools/foo/bar
$ composer require phalcon/devtools
$ vendor/bin/phalcon -v

Phalcon DevTools (4.0.0)

Environment:
  OS: Linux my.host.name 4.4.0-101-generic #124-Ubuntu SMP Fri Nov 10 18:29:59 UTC 2017 x86_64
  PHP Version: 7.2.24-0ubuntu0.18.04.1
  PHP SAPI: cli
  PHP Bin: /usr/bin/php7.2
  PHP Extension Dir: /usr/lib/php/20170718
  PHP Bin Dir: /usr/bin
  Loaded PHP config: /etc/php/7.2/cli/php.ini
Versions:
  Phalcon DevTools Version: 4.0.0
  Phalcon Version: 4.0.0
  AdminLTE Version: 2.3.6

Now I create a new project:

$ vendor/bin/phalcon create-project example

When I go to https://172.18.0.90/tools/foo/bar/, I see:

Index of /tools/foo/bar
Name    Last modified   Size    Description
Parent Directory        -    
composer.json   2019-12-27 10:02    62   
composer.lock   2019-12-27 10:02    32K  
example/    2019-12-27 10:04    -    
vendor/ 2019-12-27 10:02    -    
Apache/2.4.29 (Ubuntu) Server at 172.18.0.90 Port 80

(Yes, indexing is enabled, just for debugging.) When I click into the 'example' directory, I see:

ToolsController handler class cannot be loaded
#0 [internal function]: Phalcon\Mvc\Dispatcher->throwDispatchException('ToolsController...', 2)
#1 [internal function]: Phalcon\Dispatcher\AbstractDispatcher->dispatch()
#2 /srv/www/html/tools/foo/bar/example/public/index.php(43): Phalcon\Mvc\Application->handle('/tools/foo/bar/...')
#3 {main}

So Phalcon is not aware that the root of the app is under tools/foo/bar/example. What is the proper way to configure this?

The 'baseUri' parameter must probably be set for the url service, but that doesn't affect the routing. Should I update .htrouter.php? Or add a RewriteBase to .htaccess? Or change the _url somehow? Or should I set something in the router service, like a prefix?

I'm trying to understand how the routing/dispatching works, how the controller/action is selected, and I've been reading over the zep files but it's a lot of code and I'm not sure if I am looking in the right place. So instead of reverting to trial & error I thought it might be better to ask here. Can someone point me in the right direction?

edited Dec '19

I found that one way is to add routes, like:

$router->add(
    '/tools/foo/bar/example/:controller/:action',
    [
        'controller' => 1,
        'action' => 2,
    ]
);

Another way is to update the $_SERVER['REQUEST_URI'] in index.php:

# Replace this...
echo $application->handle($_SERVER['REQUEST_URI'])->getContent();

# ...by this:
echo $application->handle(
    str_replace('/tools/foo/bar/example', $_SERVER['REQUEST_URI'])
)->getContent();

But both methods feel a bit like workarounds to me.

[edit] I like this way as well:

$application = new \Phalcon\Mvc\Application($di);
$uri = $_GET['_url'] ?? '';
$application->handle($uri)->send();

Is this the best way to solve this? Or is there still a more idiomatic way?

edited Dec '19

I hope It helps (for develop/testing purposes):

Looks like you're using apache.

Lets assume you created this folder at this address /home/your-username/webapps/ for create/test your projects and /home/your-username/webapps/www to put your projects online.

  • Add your username to apache group: sudo usermod -aG www-data your-username.
  • Check that you're in that group: groups your-username, maybe you must restart your session in your system.
  • Change owner of /home/your-username/webapps/www: sudo chown your-username:www-data -R /home/your-username/apps/www/.
  • Create a symbolic link from your www working folder to www apache folder (www apache folder can vary in your system): sudo ln -s /home/your-username/apps/www/ /var/www/html/apps.
  • Find and open apache configuration file (apache2.conf, httpd.conf, also can vary the name). You can require sudo permissions.
  • Enable rewrite module: sudo a2enmod rewrite
  • Search in apache config file something like this: <Directory "/var/www/html/"> (depends the system) and replace AllowOverride None by AllowOverride all.
  • Restart apache: sudo systemctl restart apache2
  • Start your new project in /home/your-username/webapps/my_test_project (whatever)
  • Create other symbolic link of public folder of your project in your personal www folder: sudo ln -s /home/your-username/webapps/my_test_project/THE_PUBLIC_FOLDER /home/your-username/apps/www/my_test_project.
  • Done!

Remember activate required php extensions to work with phalcon as well as permissions, and could be necessary put the full path in 'baseUri' => '/THE_FULL_ROUTE_OF_YOUR_PROJECT/' in your config.php.

In our example you can access to your projects from 127.0.0.1/apps/my_test_project

I appreciate your extensive answer, but I'm not looking for a way to host a project from my home directory. That works fine already, I enabled the userdir module in Apache for that purpose (# a2enmod userdir). Then you simply place your websites in /home/username/public_html, access them under https://172.18.0.90/~username/mywebsite and you don't need to worry about the directory rights either.

We are running all kinds of web tools, under different directories on the same Apache installation. So we may be using a tool under https://172.18.0.90/tool1, another under https://172.18.0.90/foo/tool2, and yet another under https://172.18.0.90/bar/baz/tool3.

Apache's document root is under /srv/www/html. So when I want to host a tool under for example: https://172.18.0.90/video/monitoring/heatmaps, then I should be able to go to /srv/www/html/video/monitoring and create a new Phalcon project called heatmaps:

$ cd /srv/www/html/video/monitoring
$ mkdir heatmaps
$ phalcon create-project heatmaps

Apache has read access (otherwise it wouldn't show a Phalcon error anyway, it would say 403 Forbidden or something like that).

When I now visit https://172.18.0.90/video/monitoring/heatmaps it says:

VideoController handler class cannot be loaded
#0 [internal function]: Phalcon\Mvc\Dispatcher->throwDispatchException('VideoController...', 2)
#1 [internal function]: Phalcon\Dispatcher\AbstractDispatcher->dispatch()
#2 /srv/www/html/video/monitoring/heatmaps/public/index.php(43): Phalcon\Mvc\Application->handle('/video/monitori...')
#3 {main}

What is happening is that the $_SERVER['REQUEST_ URI'] is /video/monitoring/heatmaps. This string is forwarded by router.php to the Phalcon router, which splits it up into parts and the first part 'video' is assumed to be the controller name. The second part 'monitoring' is assumed to be the action name. But of course this is not the intention. /video/monitoring/heatmaps is just the path to the website. Whatever comes after it should be used as the controller/action name. For example in /video/monitoring/heatmaps/region/show/1, "region" is the RegionController and "show" is the showAction().

In my second post I showed some solutions/workarounds but I'm just wondering if there's a more idiomatic way.

In fact in my example you can use practically any folder, and it's quite strange that when you create your projects in the apache folder it doesn't take the controllers correctly, you might have problems out there in the file permissions.

I initialize my projects in my user folder to avoid those problems.

Another option would be an automated script but that would depend more on apache than phalcon

edited Jan '20

What do your .htaccess files look like? I've never encountered this problem and I run tons of different apps in subdirectories. As far as I know, the .htaccess files should take care of passing the correct URL on to Phalcon.

In your index.php file, before $App->handle()->getContent(), output $_GET['url'] and see what that looks like. That should only contain the part of the url relative to your initial .htaccess file.

edited Jan '20

I have the same issue. I'm using Phalcon Framework (4.0.2) with Phalcon DevTools (4.0.1)

My top root directory is '/var/www/html' I created a subdirectory called 'phalcons/' then used devtools to create a project called proj1 by phalcon project proj1 simple --enable-webtools

so, the project should be in 'https://localhost/phalcons/proj1' but Phalcon thinks that 'phalcons' is a controller and 'proj1' is an action!!

I don't know why is that.

here is phalcons/proj1/.htaccess

<IfModule mod_rewrite.c>
        RewriteEngine on
        RewriteRule  ^$ public/    [L]
        RewriteRule  (.*) public/$1 [L]
</IfModule>

and here is phalcons/proj1/public/.htaccess

AddDefaultCharset UTF-8

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(.*)$ index.php?_url=/$1 [QSA,L]
</IfModule>

This is my phalcon environment: https://hub.docker.com/r/deadsoul/apache_phalcon

the only way I got it to work is by replacing echo $application->handle( $_SERVER['REQUEST_URI'] )->getContent(); with echo $application->handle( substr($_SERVER['REQUEST_URI'], strlen($config->application->baseUri)-1) )->getContent(); which is in public/index.php inspired by @gwijnja in his second comment.

is it because the devtools version is 4.0.1 and the framework is 4.0.2 ?