Simple use of route prefixes within AuthComponent in a CakePHP App

In any regular website you have a restricted area for management, and a public webpage.
When writing a CakePHP app you would usually use the AuthComponent for authentication, and for allowing and denying actions. A boring task of using Auth is that you have to define in every controller that has public actions the allowed actions in that controller, it can be done by overriding the beforeFilter() method or by using any other technique, like looking for any defined variable with the allowed actions names and handle it in the AppController::beforeFilter(), or you can do it automatically! Yes, you can can assume a convention telling that every restricted action has a route prefix. So you won’t need to define any additional information on each controller.
The authorization logic for allowing users to reach a specified action is then set in the AppController::beforeFilter() by playing with the $this->params[‘prefix’] value.

A simple example is shown below:

We enable a single route prefix by editing app/config/core.php

	Configure::write('Routing.prefixes', array('admin'));

Then we edit our app/app_controller.php

class AppController extends Controller {

    public function beforeFilter () {
        if (empty($this->params['prefix'])) {
            $this->Auth->allow($this->action);
        } else {
            $this->layout = 'admin';
        }
    }

}

The example above checks for an non prefixed request (following our own conventions, it’ll be a public action), and if it is non prefixed just allow it, for example:

domain.com/posts/view/123

In other hand, if it is prefixed and there’s not a logged in user, it is not allowed, being denied by default.
So if a not logged user tries to request for:

domain.com/admin/posts/view/123

He is immediately redirected to the AuthComponent logoutRedirect url.

It’s just a very simple tip, i hope it helps someone :-D

Advertisements

Show SQL dump on redirect using CakePHP 1.3

Hi there!

An inconvenient i faced when i moved from CakePHP 1.2 to 1.3 is the fact of the debug SQL dump is now rendered as an element, this can be usefull if you want to customize or display it in any other place than in the bottom of the rendered output. But, in some situations, when you have an action without a view, those kind of actions usually redirect immediately after doing something, it means that the layout is never rendered, and as a consequence, the SQL dump too.

My solution is pretty simple and straight forward, i’ve just overrided the Controller::redirect() method in the AppController to detect if a debug was triggered (if any header was sent, it happens when you output something, in this case it’s sent by a debug() call), and if so, just render the sql_dump element, and stops.

The code is show below:

class AppController extends Controller {

    public function redirect ($url, $status = null, $exit = true) {
        if (headers_sent()) {
            $this->viewPath = 'elements';
            echo $this->render('sql_dump', false);
            if ($exit) {
                $this->_stop();
            }
        }
        parent::redirect($url, $status, $exit);
    }

}

git-svn error

I decided to start tracking with git an svn project where i’m involved, but without migrating it to everyone, so i decided to install git-svn, a Git-SVN bridge that let’s you work within a subversion project using a git repository.

I tried to import my project with git svn:

$ git svn clone -s user@hostname:/path/to/repo

but then i get the error:
E: ‘trunk’ is not a complete URL and a separate URL is not specified

Thinking for a while, i realized that i need to pass the url as i was doing a checkout with svn, so you should do..

$ git svn clone -s svn+ssh://user@hostname/path/to/repo

..instead.

Setting up Git with colors

git config --global color.branch auto
git config --global color.diff auto
git config --global color.interactive auto
git config --global color.status auto

SSHFS and multi-user access

In a situation described in a previous post, i needed to setup apache with PHP files for being hosted in another machine, for the effect i used SSHFS to mount a remote directory in my Document Root over SSH, it uses Fuse and only requires a SSH server running in the target machine. So i wrote an init script to mount that directory before apache starts using a RSA SSH key for the login. But when i tried i always get an HTTP 403 permission denied error, checked and double checked for permissions, and everything was right. Ok, the problem is described here, since SSHFS uses Fuse, fuse doesn’t allow other users than the one who mounted the remote directory to have access to it.

You have two options:

  1. Confiure /etc/fuse.conf setting the user_allow_other option
  2. Mount your remote directory as the user who’s gonna access it (if it will be only one user, like www-data), you can do it with the sudo -u option. man sudo for more info.

find(‘list’) and Containable

As you must know, when calling $this->Model->find(‘list’) passing a contain parameter, it won’t take effect, and you won’t be able to do something like:


$workers = $this->Worker->Person->find(
    'list',
    array(
        'fields' => array('Worker.id', 'Person.name')
        'contain' => array(
            'Worker',
            'PersonType' => array(
                'conditions' => array('PersonType.type' => 'Worker')
            )
        )
    )
);

a solution for this problem would be something like this:


$workers = $this->Worker->Person->find(
    'all',
    array(
        'fields' => array('Worker.id', 'Person.name')
        'contain' => array(
            'Worker',
            'PersonType' => array(
                'conditions' => array('PersonType.type' => 'Worker')
            )
        )
    )
);
$workers = Set::combine($workers, '{n}.Worker.id', '{n}.Person.id'')

Well.. it’s not bad at all, but we could get a better solution – we could create a custom find type for a find list with Containable support!
We’ll be following the Matt Curry’s custom find method published in it’s awesome CakePHP e-book.

So, at first you must download Matt Curry’s find plugin vendor’s folder, put it under your app’s plugin/find/ folder, you should create the find folder.
Then in your app’s app_model.php you should import the find_app_model.php vendor file, and your AppModel class would extends FindAppModel, this would include some initial setup done for custom find methods. Now you just add our __findListContainable() method to it, it defines our custom find list method.
And you will end up with an AppModel like this:

App::import('Vendor', 'Find.find_app_model');

class AppModel extends FindAppModel {

    public $actsAs = array('Containable');

    public function __findListContainable($options) {
        $default_fields = array("{$this->alias}.{$this->primaryKey}", "{$this->alias}.{$this->displayField}", null);
        if(!empty($options['fields'])) {
            $fields = $default_fields + $options['fields'];
            unset($options['fields']);
        } else {
            $fields = $default_fields;
        }
        $results = $this->find('all', $options);
        foreach($fields as $key => $field) {
            if(!empty($field)) {
                $fields[$key] = '{n}.'.$field;
            }
        }
        return Set::combine($results, $fields[0], $fields[1], $fields[2]);
    }

}

Ok, now you can do any find list with containable parameters with no problems like the Worker’s example above.

Have fun!

Ubuntu Lucid Lynx 10.4 LTS with PHP5.2 / CakePHP1.1, Ubuntu Lucid Lynx 10.4 LTS, and PHP5.3

Note: If you want to downgrade to PHP5.2 under Ubuntu Lucid 10.4 LTS just scroll down till the bottom of the post.

Hello! Last weekend I decided to upgrade my linux distro to the new ubuntu one, I was using a 2 years old ubuntu distro and after the launching of ubuntu 10.4 LTS with PHP 5.3 packages included, i thought it was a great chance for trying it and keep myself updated. But I forgot a little, but important, detail: I’m currently integrated in a project that consists in developing an huge information system based on CakePHP 1.1, it was the stable version of CakePHP when the development started, in that time CakePHP was in its 1.2RC2 release – it’s not of my buisness, but i find always myself wondering how cool it would be if that person had thought the development and maintenance would take some years, and the 1.2 would become stable.. 1.3.. and so on..
Anyway, let’s talk about what matters, i could not develop with CakePHP 1.1 under PHP 5.3, and i needed to make it work till Monday , i was left with 3 solutions:

  1. Fix the CakePHP 1.1 core for running under PHP 5.3
  2. Downgrade the PHP install for 5.2
  3. Setup a virtual machine as close as the deploying environment.

Well… in my mind the first one one was inconceivable, i dont have enough time to spent with what i’m not paid for in my spare times. About the second one…i didn’t want to downgrade, i wanted to make it only as fallback option. So i went ahead and started with the third solution.

So i downloaded and installed VirtualBox, downloaded a Debian Lenny small ISO image, created a new virtual machine with two virtual network adapters, the first one in the host-only mode, that means that the VM could not reach the outside network, only the hosting machine, that connection creates a loopback interface for the communicatio. The second adapter i setup with NAT mode, it allows you to reach the outside world through the hosting system giving the WM a virtual ip address. Why this network setup? Because we want to have access to the outside world, for software packages downloading, etc.. and we need to have access to our VM HTTP server, and through the loopback device ip address we can do it. During the debian install wizzard it asked me what kind of software did i want to install, i answered with an webserver direct answer! And it setup a system with apache. I installed PHP5 packages and it’s apache2 module more  the database one. I decided to leave the database and the document root filesystem in my physical system, since this app has some extremely heavy components with lots of queries and calculations in the database, so i configured my postgresql for accepting connections in my local virtual ip address, and configured my app for connecting to the virtual host machine ip address. Installed an SSH client in the VM, generated a DSA SSH key with ssh-keygen, and put it in my host machine authorized_keys with no command execution, port forwarding, X11 forwarding, and PTY allocation allowed. Setup an init script for mounting it using SSHFS in the document root, running it as www-data, edited the default apache’s VirtualHost and changed the DocumentRoot directive accordingly. Restarted all services and voilá! Opened my browser, typed it’s ip address and I had my wonderfull CakePHP 1.1 app running under ubuntu 10.4. I had my victory.

After some testing i realized that, as expected, it was a bit slow while handling a big bunchs of data. And I pondered to go through the third solution and removed all PHP5.3 packages from the system, and found this explaining a strategy to install Karmic packages in 10.4 to run PHP as CGI, I prefer PHP5.2 to run as an apache module, so everyting i did was this:


# remove all php packge
sudo aptitude purge `dpkg -l | grep php| awk '{print $2}' |tr "\n" " "`
sudo su
# use karmik for php pakage
echo -e "Package: php5\nPin: release a=karmic\nPin-Priority: 991\n"  >> /etc/apt/preferences.d/php
apt-cache search php5-|grep php5-|awk '{print "Package:", $1,"\nPin: release a=karmic\nPin-Priority: 991\n"}' >> /etc/apt/preferences.d/php
apt-cache search -n libapache2-mod-php5 |awk '{print "Package:", $1,"\nPin: release a=karmic\nPin-Priority: 991\n"}' >> /etc/apt/preferences.d/php
exit
# add karmik to source list
sed s/lucid/karmic/g /etc/apt/sources.list | sudo tee -a /etc/apt/sources.list.d/karmic.list
# update package database (use apt-get if aptitude crash)
sudo apt-get update
# install php
sudo apt-get install -t karmic php5-cli libapache2-mod-php5

But i won’t give up of PHP5.3 anyway ;-)

EDIT: Quoting a comment from Pablo

A fourth solution could be install an older xampp package, which is isolated from “system’s” php packages and libs. xampp-linux-1.7.1 has php 5.2.9