Why I wouldn’t use Symfony for a new project

Symfony is pretty good for a PHP framework — it's probably still one of the better ones. While Symfony is open source, its development clearly isn't open.

Nowadays, it is mainly unmaintained. Well, it's maintained by Sensio, which is very closed towards outsiders, and doesn't apply fixes for versions below 1.3 even when patches are handed ready to them. Which means for instance that the official 1.0 doesn't work with PHP 5.3 even though the fixes are available and straightforward.

I will pass on the worrisome attitude towards security of the most used plugin as I've talked about it extensively already. Constant reminders don't even work.

There is much more activity towards Symfony2, which might explain the lack of updates to the 1.x branches. Symfony2 introduces more decoupling, which should avoid many bugs reported but ignored by the development team, probably because they are boring to fix and require very deep knowledge in Symfony's architecture — I would have tried to fix them myself if I had the time and motivation; I'm afraid I usually take the easy route and work around them.

But how does Symfony2 looks for a developer? What I've seen is fairly standard and boring, and sometimes looks like sad attempts of reimplementing Python features in PHP. Why not use Python then?

Doctrine2 is even worse — it's the same broken, undocumented API. Propel 1.5, with a minimum set of changes, became much more powerful and easy to use for a developer. At least there's hope on this side.

Overall, it seems the Symfony lead developers don't take much input from the community (like the decision to follow Zend conventions), and focus on making something fun to write, instead of fun to use. I have the choice between an undermaintened version and a future version which will break compatibility without giving me much advantages; moreover some of the stuff that was shown in conferences isn't event implemented yet. I'm not used to see that in the free software word.

Time to switch?

Share:
  • del.icio.us
  • Twitter
  • Reddit
  • Digg
  • Facebook
  • Google Bookmarks
  • DZone
  • LinkedIn
  • Wikio
  • Identi.ca
Posted in PHP, Symfony | Tagged , , , , | Comments closed

Reducing the gap between Symfony and non-PHP frameworks

Something that always annoyed me is how tedious it is to install a Symfony project on a machine. Since I frequently need to intervene quickly on a project for work, and I was getting a brand-new machine, I really didn't want to create an apache vhost (let alone install Apache: it's painfully slow and its configuration is obscure and hard to debug), edit my /etc/hosts file, etc. for each project.

Moreover, developers are not system administrators and should not have to do complicated setups, especially when it turns out to be badly set up, and problems are "resolved" by "chmod 777" or "chmod 666" (which is indeed evil), a very sad but true practice promoted even by the developers of Symfony since there is a symfony fix-perms command that basically does that. It should have been named symfony break-perms or symfony please-make-things-insecure-i-want-to-go-back-to-windows or never been made.

On most non-PHP frameworks, there is a small embedded webserver that you can run on-demand. No configuration needed. Moreover, no special rights needed: a simple user can start it.

Since there was no such webserver written in PHP that was able to run Symfony properly, I chose to auto-configure lighttpd with a simple tool called symfttpd. The genconf tool was born.

However, I encountered another issue I didn't think of before: for each project, I had to create symbolic links to the Symfony source code (another practice of the Symfony community, and there is no proper alternative in the PHP world). Hence, I created mksymlinks. For the developer, it is very simple to use: configure once on the machine, once per project, and that's it.

genconf only generates a configuration, which is still very practical for a system administrator; moreover it is flexible and well-tested. But it still required the develop to configure something, and there still was the rights problem.

Hence I created spawn which handles starting and stopping the webserver, just like non-PHP frameworks do. As a nice addition, it keeps server and PHP logs in the logfolder of the project.

symfttpd has even more uses; one I didn't think of at first was that it can automate the installation of a project on a continuous integration platform, and can start a webserver for functional testing (both are used daily at work).

One of the most important aspects of symfttpd is that all tools are independent: you can use only mksymlinks or genconf (though spawn more or less requires the use of both, it isn't set in stone). A system administrator will find use in mksymlinks and genconf, and a developer more in mksymlinks and spawn.

You'll find extensive documentation on the project page; what will follow is a quick tutorial for developers.

Install the necessary packages:

 
# Debian/Ubuntu
aptitude install php5-cgi php5-cli lighttpd
 
# Gentoo
emerge php # with USE="cli cgi"
emerge lighttpd # with USE="fastcgi"
 
# Macports
port install php5 +fastcgi && port install lighttpd
 
# Windows
Nice try.
 

Get the symfttpd source code:

 
cd && git clone git://github.com/laurentb/symfttpd.git
 

There are also archives you can download here if you want to avoid git or bleeding-edge changes.

Basic configuration:

 
# notice the dot before symfftpd.conf.php
$EDITOR ~/.symfftpd.conf.php
 

Enter something like that:

 
<?php
$options['sf_path']['1.0'] = '/home/myuser/symfony/1.0';
$options['sf_path']['1.4'] = '/home/myuser/symfony/1.4';
 

Of course, you have to have to adapt it to the Symfony versions you have installed and where you put them.

Configure the project:
If the project is using Symfony 1.4 in the lib/vendor/symfony, you don't need to do anything. In case it is different, or to be on the safe side, create the file config/symfttpd.conf.php in your project. After, add the file to your project's version control repository. If you're lucky, someone already did it for you.

 
cd ~/myproject
# this time, no dot
$EDITOR config/symfttpd.conf.php
 
 
<?php
$options['want'] = '1.3'; // The version of Symfony used by your project
$options['lib_symlink'] = 'lib/vendor/symfony'; // lib/vendor/symfony will lead to the "lib" directory of Symfony
 
 
~/symfttpd/mksymlinks
 

You're done.
It will create symbolic links for plugins too, even if the version of Symfony (1.0 for instance) doesn't handle them!

To start the server:

 
~/symfttpd/spawn
 

It will then tell you how to access it. It's time to stop fighting with old, unpredictable software like Apache and start developing again!

What's coming in future releases:

  • Colors
  • Interactive configuration
  • Server/PHP logs displayed in the terminal
  • Handling "sample" files
  • Custom configuration support on various places

Contributors are welcome.

Share:
  • del.icio.us
  • Twitter
  • Reddit
  • Digg
  • Facebook
  • Google Bookmarks
  • DZone
  • LinkedIn
  • Wikio
  • Identi.ca
Posted in PHP, Symfony, Sysadmin | Tagged , , , , , | 2 Comments

And I thought sfDoctrineGuardPlugin was bad…

Update: You can safely ignore this angry rant as the issues have been fixed.

I am speechless. While doAuthPlugin looks interesting (especially because it uses inheritance and not some silly secondary Profile table), on the topic of security it is worse than sfDoctrineGuardPlugin.

Let's have a quick look at doAuthTools.

  public static function rememberHash(User $user) {
    return md5($user->getId().'-'.$user->getUsername().substr($user->getPassword(),0,5));
  }

There's the use of md5, which doesn't doesn't resist long to rainbow tables attacks nowadays, but the worst is what is used. No random data at all, no salt.
The user id is most of the time public, the username almost always is, and for absolutely no reason only the first five characters of the password are used.

 
  public static function activationCode(User $user) {
    return md5($user->getCreatedAt().time().$user->getUsername().substr($user->getUsername(),0,5));
  }

created_at is easy to guess, time() is easy to guess and the rest is public. Again, what's with the use of substr()? I would also guess the author wanted to use the password and not the username.

 
  public static function generatePassword() {
    return substr(md5(rand(1000,9999).time()),0,8);
  }
 

Now this is just sad. Sure, even with the use of a-f0-9 there is still 16^8 possible passwords, but why not spend a little time and try to use all the available letters? It also means that if you know the user id and username, you know you only have 16^5 rememberHashes to brute-force, which is easily doable.

We've already seen that using rand() is bad, but restricting it is even worse. Why on earth? To sum up, the password is constructed from a poor random algorithm with under 9000 possible values, and an easily predictable timestamp.

Frightening.

Share:
  • del.icio.us
  • Twitter
  • Reddit
  • Digg
  • Facebook
  • Google Bookmarks
  • DZone
  • LinkedIn
  • Wikio
  • Identi.ca
Posted in PHP, Symfony | Tagged , , , , | 3 Comments
Bear