software

How to get a real-time stock quote using Google API

Ivo Kendra - Mon, 2009-01-05 23:39

After resolving the problem with authentication, I continued playing around with Google Finance API, using HTTP and XML. The API offers some nice functionality to retrieve user portfolio content, but it doesn’t take long to realize that there is no support for retrieving (real-time) stock quotes, probably for some good reason like licensing. But then, there is a way of getting real-time stock quotes on your Google Spreadsheet using the GoogleFinance() formula. Can this fact get us closer to retrieving real-time stock quotes using Google Data API?
(more…)

Categories: Agile, music, php, software

Happy new year!

Symfony - Mon, 2009-01-05 11:43

The symfony team would like to wish you a happy new year 2009.

2008 was a great year for symfony with the release of 28 minor versions (for 1.0, 1.1, and 1.2) and two major versions: 1.1 and 1.2.

We spent a lot of time updating the documentation, posting news and tutorials on the symfony blog (179 posts), and of course working on the Jobeet tutorial.

2008 was also the year of symfony plugins with more than 380 available plugins and 5300 registered users.

The symfony website traffic more than doubled in 2008. The fastest growing country for symfony has been India, followed closely by European countries: Russia, Ukraine, Romania, Poland, Hungaria, Spain, France, and United Kingdom.

As of today, the symfonians website references 1300 members and more than 420 symfony applications. It also has about 95 active job offers.

I hope 2009 will also be a great year for symfony.

Be trained by symfony experts - Jan 21 Paris - Feb 04 Montpellier - Feb 18 Paris - Mar 11 Nantes - Mar 18 Paris
Categories: php, software

Perception and reality in the land of OpenID

FactoryCity - Mon, 2009-01-05 00:11

A couple related posts caught my attention recently about OpenID. As I’m now a board member of the OpenID Foundation, I feel some responsibility for helping to inform folks about OpenID: what it is, how it’s used, why I believe that it has so much potential — and at same time, address what it isn’t, won’t or can’t be, and what the scope of the OpenID solution stack is.

The first is a post by Nick O’Neill from the Social Times blog: “OpenID Organizes the Organizers While Facebook and Google Start Letting Users Login“. It was posted on December 29th.

He begins his criticism with a slight error:

Over the weekend the OpenID Foundation announced that they are having its first election of community board members.

In fact, over that particular weekend, the OIDF announced the results of its election, not the kick off.

But his broader sentiment deserves a response:

[...while] Facebook and Google have launched their own identity services that enable users to instantly log in to any site with third-party accounts[, ... the] group seems to still be in the process of organizing though. … I think the group is over planning and under executing.

Josh Catone from SitePoint picked up his point, suggesting that “OpenID Needs to Start Getting Real“. He writes:

What the OpenID Foundation needs to do is start “getting real.” Getting real is a business philosophy from 37signals, a successful web application software company based in Chicago. Though there’s a lot more to their idea, one of the main themes essentially boils down to this: stop screwing around with all the stuff that doesn’t matter and just wastes time (like politics and meetings), and start doing the stuff that needs to get done (like building your app). Don’t worry about the details until people are already using what you’re selling.

I agree with O’Neill that so far the OpenID Foundation seems to be spending too much time on organizational stuff, and not enough time on actually doing what needs to get done. In a chapter of their book “Getting Real,” 37signals talks about how meetings can kill productivity. “Every minute you avoid spending in a meeting is a minute you can get real work done instead,” they write. From my admittedly outsider’s vantage point, it appears that the people behind OpenID are getting too caught up in the organizational stuff, getting too lost in the details, and not spending enough time on execution.

My perspective, of course, is that of an outsider. I’m not privy to what’s going on behind closed doors, so to speak. So my perception of what’s really going on could be off. But at this point in the game, public perception is what it’s all about.

And therein lies the heart of the problem. Perception is reality in the land of OpenID and will shape the thinking of developers, users and those who make up the OpenID and user-centered identity communities unless we initiate a campaign to earnestly counter those perceptions.

Nevermind that for OpenID to succeed, it must be developed with the involvement of many different groups, each with slightly different ideas, objectives and release cycles. Unlike Facebook Connect, OpenID is essentially consensus technology. To advance, it must secure and maintain the buy-in and adoption of many parties on every forward step. But let’s ignore that for a moment, because that’s an issue for us to overcome.

Jim Louderback (veteran of PC Mag) recounted his miserable experience trying to sign in to Disqus with his OpenID in a post titled “I can haz OpenID?“. Apparently, he can not, since he abandoned his comment and resorted to posting it to Twitter instead. The problem apparently had to do with Clickpass, but that’s besides the point, as the experience left a serious impression (emphasis mine):

And that gets me back to OpenID. I love the idea of having one set of identification credentials that I can use around the web. If it all works right, it’ll be awesome, birds will sing and the swallows will return to wherever they’ve disappeared from. But it won’t all work right, not all the time. We’re talking software here, and the internet, and the egos of childish web developers. Occasional (or more often) fail is guaranteed.

It’s even worse than I feared. A few days after my Disqus debacle I was talking with a developer friend of mine who was bemoaning the sorry state of OpenID implementations. It seems that all the big sites have their own flavors, and the OpenID foundation just doesn’t have enough clout to force a single standard across the web.

That’s a bad state of affairs. It guarantees more fail - and also guarantees epic finger-pointing. Who will lose? The users, first, who won’t be nearly as patient nor accommodating as I am. But in the end the whole glorious promise of OpenID will be left in tatters, and we’ll be back to our walled-gardens of identification. And that’s just too bad - because an open, interoperable identity system is actually one of the best ideas I’ve heard in a long time. Too bad no one can get their act together to actually build it right.

And these are the stories that will be told and retold because it’s not the successes that are heralded — it’s the epic failures. As much as I like to rag on Twitter about OAuth, their service is a million times better than it was six months ago during the Summer of the Fail. Twitter ops deserve a lot of credit for making hard decisions about which features should be cut in order to scale the service.

But when it works, people don’t shower Twitter with praise. It’s expected. It’s only when there are problems that people raise their voices — and it’s no different with OpenID. Unfortunately it’s this cacophony of complaints that ends up shaping the negative perceptions of OpenID.

So, when the Japanese chapter of the OpenID Foundation releases figures that show significant and gaining consumer awareness of OpenID in Japan that contradict the outdated and statistically insignificant findings (PDF) that Yahoo presented last year (on which so much criticism was heaped), few seem to notice.

Progress in Japan alone isn’t enough of course. But it does suggest that there is more to the story of OpenID’s overall progress and success in the marketplace. It also suggests that OpenID has yet to succumb to Facebook Connect or that it ever will (or that that’s even the right question).

Still, what all this says to me is that the OpenID Foundation and the community at large have its work cut out for itself.

As more people begin to believe in the promise of OpenID, more people will commit themselves to the success of OpenID, taking ownership of the idea, and promoting it their friends and family (as they did with Firefox). Our opportunity is to make good on the hope that people have for OpenID and effectively channel it to challenge the bruised perception that defines OpenID today. If we succeed, changing perceptions truly will change reality.

Categories: online, software

A week of symfony #105 (29 december 2008 -> 4 january 2009)

Symfony - Sun, 2009-01-04 23:43

This week marked the end of a great year for symfony, full of good news, events, new documentation and lots of symfony releases. Surely 2009 will be even better. In addition, Jobeet tutorial still attracted lot of attention during this week with several fixes and improvements.

Development highlights

  • r14378: [1.1, 1.2] [sfPropelPlugin] updated propel behavior inclusion logic to use only core classes
  • r14385: [1.0] fixed i18N and open_basedir restriction problem
  • r14421: [1.2] updated sfProjectFreezeTask help text to be more verbose
  • Updated dwhittle branch
  • ...and many other changes

Development digest: 108 changesets, 26 defects created, 10 defects closed, 7 enhancements created, 17 documentation defects created, 11 documentation defects closed and 6 documentation edits.

Book and documentation

Plugins

  • New plugins
    • tsTitlePlugin: creates nice title tag with delimiter from default view.yml
    • symfonyUnderControlPlugin: aims at integration the lime unit testing framework with the phpUnderControl/CruiseControl Continuous Integration system. It will allow you to have lime output xUnit XML files that can be parsed by phpUnderControl/CruiseControl to be displayed in it's web interface.
    • sfJqueryWidgetsPlugin: adds two jQuery widgets to the list of available widgets bundled in the framework (drop down list that fires an Ajax request upon DOM event and sortable list that fires an Ajax request upon change).
    • sfClearBoxWindowPlugin: a wraper of ClearBox that allows to view images in playing mode for your site.
    • pkAdminQuickCreatePlugin: symfony's admin generator can provide pulldowns to select these, but what if they don't already exist? pkAdminQuickCreatePlugin makes it easy to implement "quick create" buttons.
    • sfAdvMemcachePlugin: allows easy use memcache to store cache or session.
  • Updated plugins
    • pkImageConverterPlugin: initial checkin
    • sfDoctrineAdminGeneratorWithShowPlugin: fixed some bugs
    • sfAdvancedAdminGeneratorPlugin: changed help for hints, fixed a javascript bug, hint and help are now separated, stylesheet fixed
    • sfAssetsLibraryPlugin: fixed PHP functions is_dir and is_writable to use full paths for accurate results, modified lib/helper/sfAssetHelper auto_wrap_text so it works, added Cancel button to sidebar_search and number of results to searchSuccess
    • sfEzcWorkflowPlugin: fixed typo
    • bhLDAPAuthPlugin: case insensitive group matching for authz, merged in 1.0 branch recent fixes from 1.1 branch
    • sfApplyPlugin: documentation issues
    • sfEasyDebugPlugin: fixed a typo in the documentation, fixed a issue with ::assert(), fixed display in ::assert(), fixed bug in logging
    • sfPropelActAsPolymorphicBehaviorPlugin: fixed undefined variable in symfony 1.0
    • sfTaskExtraPlugin: updated generate:plugin task so it can be run on an empty plugin directory, added sfProjectConfiguration::enablePluginDevelopment() method for whitelisting those plugins the addon tasks should act on
    • sfSmartyPlugin: updated compiler process and optimized parsing methods, updated documentation, updated use helper method to accept comma delimited string list of helpers, updated helper compilation method for cleaner compiled templates
    • sfImageTransformPlugin: updated the README and package.xml ready for the release of 0.2.0
    • sfFormExtraPlugin: fixed blacklist validator changing the case of value in a case-insensitive context
    • swToolboxPlugin: added sendMail method to the controller, added swWidgetFormDoctrineSelectNestedSetPosition widget
    • sfDatagridPlugin: released 1.0.4 version, fixed the symfony cc notice, fixed the action bar rendering problem with ie
    • sfPropelSqlDiffPlugin: added Propel 1.3 compatibility, created 1.2 branch, code cleanup, added package.xml, fixed README, fixed bug in propel:build-all-diff task

Some new symfony powered websites

They talked about us

Be trained by symfony experts - Jan 21 Paris - Feb 04 Montpellier - Feb 18 Paris - Mar 11 Nantes - Mar 18 Paris
Categories: php, software

Twitter and the Password Anti-Pattern

FactoryCity - Sat, 2009-01-03 03:30

I’ve written about the password anti-pattern before, and have, with regards to Twitter, advocated for the adoption of some form of delegated authentication solution for some while.

It’s not as if Twitter or lead developer Alex Payne aren’t aware of the need for such a solution (in fact, it’s not only been publicly recognized (and is Issue #2 in their API issue queue), but the solution will be available as part of a “beta” program shortly). The problem is that it’s taken so long for Twitter’s “password anti-pattern” problem to get the proper attention that it deserves (Twitter acknowledged that they were moving to OAuth last August) that unsuspecting Twitter users have now exposed themselves (i.e. Twitter credentials) to the kind of threat we knew was there all along.

This isn’t the first time either, and it probably won’t be the last, at least until Twitter changes the way third party services access user accounts.

Rather than focus on Twply (which others have done, and whose evidence still lingers), I thought I’d talk about why this is an important problem, what solutions are available, why Twitter hasn’t adopted them and then look at what should happen here.

Why the password anti-pattern matters

I can’t link directly to it, but comment #8 on Fred Oliveira’s post captures one clear reason why the password anti-pattern increasingly matters more:

Regardless of the perceived value of the service, when it comes to reputation online, little else matters than one’s accumulated social and data capital. Some people store their data capital (essentially original content coupled with residue from their social capital) with LinkedIn; others, Facebook or MySpace. Still others use their own blogs or rely on a medly of services like Twitter, FriendFeed, or Flickr.

To some degree, experimentation with third party services can elevate one’s status, drive commerce, or provide a recommendation filter for friends. So handing over the keys to the vault that stores your data capital should be a big deal.

The more frequently we do this, the more routine it becomes, the more we become desensitized to the inherent risks in this behavior. And so we take it for granted that we must cough up a username and password in order to try out that new shiny service, given the countless times previously where nothing bad happened. And then you get Twply. Or Quechup.

Now, phishing works in a similar way, but is distinctive in an important respect:

In the case of phishing, it’s kind of like a faux valet that stands outside a well-regarded restaurant waiting for unsuspecting victims to hand over the keys to their Benz (where that restaurant is your email account). Once a phisher gets a nibble, they position themselves as a known authority (i.e. your bank), preying on the naivete and disorientation of their victim. No where better is there than the web for such schemes, where the true value of account credentials are abstract and technical.

The difference between run-of-the-mill phishing and password anti-pattern cases is intent. Most third parties implement the anti-pattern out of necessity, in order to provide an enhanced service. The vast majority don’t do it to be malicious or because they intend to abuse their customers — quite the contrary! However, by accepting and storing customer credentials, these third parties are putting themselves in a potentially untenable situation: servers get hacked, data leaks and sometimes companies — along with their assets — are sold off with untold consequences for the integrity — or safety — of the original customer data.

Given the ends (providing cross-site functionality (importing address books, posting to blogs or Twitter, etc)), you could argue that the means are incidental or justified. But we can — and have an obligation to — do better.

Solutions for the password anti-pattern

Given the prevalence of this problem, several solutions have emerged, most notably OAuth.

OAuth is actually an extraction of a number of protocols that came before. In the place of a username and password, it substitutes a consumer key (like a username for an application) and a token, and adds a cryptographic signature to make sure that no one tampers with the “request envelope” while in transit.

Interestingly, OAuth emerged from a shortcoming with OpenID. Since OpenID authentication works without passwords, we needed a way for OpenID to be used with APIs and in desktop applications. Therefore, we needed a way to delegate authentication back to an original source, and then receive authorization to act on behalf of the user, all without ever needing their user credentials. Of course this problem wasn’t unique to OpenID, and so we developed it to be agnostic about how authentication is performed (that is, with or without OpenID).

Since its release just over a year ago, OAuth has replaced both Yahoo and Google’s custom delegated authentication protocols, and has become a central component of OpenSocial. More recently, Eran Hammer, the specification’s editor and lead author, brought OAuth to the IETF in order to advance the community-driven protocol to the next level of internet infrastructure. But it’s not the only solution to this problem.

FriendFeed implements what they call a Remote Key in place of a user’s password:

What’s a remote key?

A remote key is a kind of password that you can give to third-party applications and websites to let them interact with FriendFeed on your behalf. There are limits to what can be done using a remote key, which means it’s a lot safer than giving a site your FriendFeed password.

This idea was suggested to Twitter in November.

While there are benefits to this model — especially in terms of simplicity — it requires a user to remember two secrets: their password and their remote key. It also means that all third-party applications act at the same level of authority, since services can’t distinguish one application from another. For a service like FriendFeed, where most of the interactions seem to happen on-site, this model makes sense. For a service like Twitter, whose primary traffic comes from external sites and applications, it does not.

And then there’s the “security through obscurity” solution that provides access to data with single or limited use URLs that are usually so long and cryptic as to be virtually unguessable. This is the solution that Basecamp offers its OpenID users and that Flickr uses for its guest pass service.

Twitter and OAuth

Anything besides the standard username and password combo will arguably add complexity and confusion to the user experience of web apps and mashups (both for users and developers). Alex Payne made this point loud and clear:

Still, sooner than later, something is going to need to be done. And Twply is only the tip of the iceberg. As people continue to accrue social and data capital, we’re going to need to offer them better options for securing their accounts while providing them flexible and usable access. The sooner we start training people on the new model, the better off we’ll all be.

But Alex has additional gripes about OAuth:

The downside is that OAuth suffers from many of the frustrating user experience issues and phishing scenarios that OpenID does. The workflow of opening an application, being bounced to your browser, having to login to twitter.com, approving the application, and then bouncing back is going to be lost on many novice users, or used as a means to phish them. Hopefully in time users will be educated, particularly as OAuth becomes the standard way to do API authentication.

Another downside is that OAuth is a hassle for developers. BasicAuth couldn’t be simpler (heck, it’s got “basic” in the name). OAuth requires a new set of tools. Those tools are currently semi-mature, but again, with time I’m confident they’ll improve. In the meantime, OAuth will greatly increase the barrier to entry for the Twitter API, something I’m not thrilled about.

These are actually very good points.

At the same time, there’s a balance to be found between accepting the status quo (thereby promoting it) versus creating the solution. Alex has repeatedly referred to the work of the Twitter User Experience team as slowing down their adoption of OAuth, but it seems to me that there’s been an open opportunity to engage with the OAuth and OpenID communities to address these issues, especially as they are at the core of why Google has yet to become an OpenID relying party. These problems are not unique to Twitter and are issues that the entire community needs to address. As much as I’m a pain in the ass about OAuth support in Twitter, I am also willing to jump in and help develop solutions — but thus far, Twitter has been absent from the channels where solutions are being generated.

Everyone’s got their priorities and Twitter has come a long way in the past several months in terms of performance and stability. But in 2009, I want to defeat the password anti-pattern once and for all! Starting with Twitter would be a significant strategic achievement and I know that Twitter is game, it’s just matter of getting it done and making it happen.

So, Alex, where do we begin? What can we do to help?

Categories: online, software

Moving to Blogger

It’s final. Three years ago, I moved from Sun hosted Roller to self-hosted WordPress. But I am done with it. WordPress may have loads of features - I only care about some of them, and I want to get rid of my server at LunarPages.com.

Blogger seems to be quite ok. And more importantly, it allows you to have your blog hosted at your own domain, which is one of the reasons I started considering it in the first place.

In a way, to me, it marks the end of an era. Instead of buying computational power, I ‘buy’ the services (note that I don’t actually pay for it). I aim to buy computational power only if I need it, through cloud computing services, which is getting fairly simple these days.

The location of my blog will also move, so if you feel like updating links, this would be a good time. The new location is http://blog.flotsam.nl/. Flotsam.nl is a domain I acquired last year. My new email address is [my first name]@flotsam.nl.

Categories: JSP/Java, software

Troubleshooting 401 with GoogleLogin Authorization header

Ivo Kendra - Mon, 2008-12-29 14:54

I was writing a small script to retrieve some data from Google Finance using the relevant Google Data API. I’m writing a stand-alone, desktop application and have therefore used the ClientLogin username and password authentication. The login worked fine, I was receiving HTTP status 200 and the appropriate response with the authentication token. Yet any subsequent attempt to use the Data API (to insance to retrieve the portfolio data) failed with HTTP 401 Token Invalid error.
(more…)

Categories: Agile, music, php, software

A week of symfony #104 (22->28 december 2008)

Symfony - Sun, 2008-12-28 23:04

Despite holidays, symfony continues fixing bugs and improving its performance. Moreover, this week ended the wildly successful Jobeet tutorial. Lastly, 7 new plugins were introduced and more than 16 plugins were updated.

Development highlights

  • r14246: [1.2] fixed Unable to use my own form formatter
  • r14248: [1.1] fixed form generation for PHP 5.1.2
  • r14253, r14256: [1.2] [sfDoctrinePlugin] fixed camel case columns for admin generators
  • r14255: [1.2] [sfDoctrinePlugin] fixed help message for insert-sql task
  • r14258: [1.2] [sfDoctrinePlugin] fixed filtering on numeric columns in admin generator
  • r14259, r14261: [1.1, 1.2] fixed issue with sfWidgetFormTime not being able to preselect single digit inputs correctly
  • r14264: [1.2] fixed DateFormHelper not correctly resolving single digits with leading zero (eg '01')
  • r14265, r14266, r14267: [1.0, 1.1, 1.2] minor improvement in search_in performance of sfFinder when not searching symlinks
  • r14286: [1.2] [sfDoctrinePlugin] fixed task so env is passed to the insert-sql task
  • r14287: [1.2] [sfDoctrinePlugin] added coverage for sfDoctrineRoute and Doctrine admin generators.
  • r14288: [1.2] improved sfFileCache for most common cases by factor 3
  • r14289: [1.2] [sfPropelPlugin] fixes deletion of files in sfFormPropel missing an DIRECTORY_SEPARATOR
  • Updated dwhittle branch: fixed test count in sfFormTest
  • ...and many other changes

Development digest: 117 changesets, 40 defects created, 27 defects closed, 6 enhancements created, 6 enhancements closed, 16 documentation defects created, 5 documentation defects closed and 10 documentation edits.

Book and documentation

Wiki

  • New Job Postings:
    • Symfony/ExtJs developer - full-time based in Chambéry, France - Job Specification - Contact: christine.dietz [at] vanoise [dot] com

Plugins

  • New plugins
    • sfFabulousPlugin: allows AJAX form validation, works with the new sfForm (sf 1.1 & 1.2), easy and quick integration (thanks to helpers)
    • pkImageConverterPlugin: easy and efficient image conversion using the netpbm utilities
    • sfPluginsTestPlugin: tests if a plugin structure seems to be correct. This is very useful if you have many external plugins that are updated frequently through SVN; sometimes the repositories move and you get an invalid structure (for example, the author starts to use branches)
    • tbDuplicateKeyPlugin: an extension to the Symfony admin generator: converts duplicate key errors reported by MySQL into user-friendly Symfony validation errors
    • Upcoming plugins: sfOpenInviterPlugin, sfWailyPlugin and dinSlotPlugin
  • Updated plugins
    • sfPropelActAsPolymorphicBehaviorPlugin: added automatic mixin of custom methods when using symfony >= 1.1, fixed regression
    • sfTaskExtraPlugin: added name of class to top of generated test stub
    • sfPropelActAsTaggableBehaviorPlugin: added filter classes, added plugin's configuration file + new tests, updated the documentation, released 0.9 version
    • sfPropelAuditPlugin: updated documentation
    • sfXSLTViewPlugin: added symfony 1.2 compatablity
    • sfDoctrineGuardPlugin: fixed redirect after login
    • bhLDAPAuthPlugin: work around adLDAP PHP_NOTICE in some cases
    • sfExtendedFileValidatorPlugin: added sf 1.2 compatibility
    • sfRequestPlugin: initial checkin, fixed typo in removeError function, 1.0.1 version released
    • sfGuardHttpAuthPlugin: added more documentation
    • limexPlugin: initial import, improved build file, exluded build/config files/dirs from SVN
    • sfSmartyPlugin: streamlined and optimized sfSmarty renderFile and loadHelper methods, updated sfSmartyView to allow rendering of .php files via sfPHPView automatically (thanks to sfHamlView), copied sfPartialView to sfSmartyPartialView to fix caching problems (ie sfHamlView), updated link_to_app helper method for correct behaviour between environments, updated sfSmarty to assign_by_ref all values from the view, updated sfSmarty to correctly select the renderer for the layout
    • sfApplyPlugin: updated documentation
    • eCropPlugin: added a new method (cropLargestPossibleArea()) to crop the largest possible area acording to a width / height ratio (just like the cropLargestSquareArea() method, but not only for square anymore), refactored cropLargestSquareArea() so it uses cropLargestPossibleArea() internally
    • sfAssetsLibraryPlugin: added check for success of Root Node creation, give success or error message
    • sfImageTransformPlugin: fixed copy bug, added Overlay transform, added new generic type of transforms which are independant of image library, merging in mime-detection branch into trunk (plugin now supports mime detection libraries Fileinfo (PECL) and MIME_Type (PEAR))

Some new symfony powered websites

  • Handwritten Thank You Cards: Printed and handwritten thank you card service. We will write/print, postage, and send out thank you cards for all occasions including weddings, graduations, businesses, baby showers, and birthdays.

They talked about us

Be trained by symfony experts - Jan 21 Paris - Feb 04 Montpellier - Feb 18 Paris - Mar 11 Nantes - Mar 18 Paris
Categories: php, software

How to get a Singleton right

Stubblog - Sun, 2008-12-28 14:13
Books, tutorials and other design pattern featuring articles often tend to present the Singleton Design Pattern as the first one. This is for two reasons:

  • The Singleton is a very easy to understand design pattern, even for developers new to design patterns or relatively new to the object oriented world.

  • The Singleton solves a problem that 99% of these developers have, namely to provide a global access point to some class they make use of everywhere in their application.



However, the Singleton design pattern is fundamentally flawed. This is nothing new and is discussed amongst developers since some years now (just search for "evil singleton"). The Singleton violates several rules of good object oriented design. Code using the Singleton class depends on that class. It is not usable without this class, which in turn makes the client code hard to test. The client code is not programmed against an interface but against a concrete class, though promoting tight coupling between the client and the Singleton, instead of the desired loose coupling. Additionally, classes implementing the Singleton pattern itself are hard to test. Singleton just replaces a global variable and hides it in a class - the global state stays in your application. So, when everybody agrees that global state is bad and that its appearance as Singleton implementations does not make the code any better, why is the Singleton design pattern so often used then?
Continue reading "How to get a Singleton right"
Categories: php, software

The results of the OpenID Board election are in!

FactoryCity - Sat, 2008-12-27 22:00

I received an SMS from Michael Richardson this morning (around 8am here in Hawaii) congratulating me on my election to the board of the OpenID Foundation. It seems fitting that I should receive first word from him, since, as the Karl Rove of my campaign, he came up with the “kind of a big deal” slogan from Anchorman.

Anyway, I’m thrilled about the outcome of the election and am looking forward to working with Snorri Giorgetti, Nat Sakimura, David Recordon, (each of whom received two year terms along with me) and Eric Sachs, Scott Kveton, and Brian Kissel (who received one year terms).

I’m also pleased that 80% of the 217 foundation members voted in the first-ever OpenID election. We’ve obviously got a lot of work ahead of us, but I’m very confident that we’ll make great strides in 2009.

Categories: online, software

Responding to criticisms about OpenID: convenience, security and personal agency

FactoryCity - Sat, 2008-12-27 08:50

a href=”http://www.flickr.com/photos/factoryjoe/3111987220/” title=”Twitter / Chris Drackett: @factoryjoe openID should … by factoryjoe, on Flickr”img src=”http://farm4.static.flickr.com/3001/3111987220_bdd75e1938.jpg” width=”500″ height=”206″ alt=”Twitter / Chris Drackett: @factoryjoe openID should be dead… its over-rated.” class=”figure figure-a”//a

a href=”http://shelfworthy.com”citeChris Dracket/cite/a responded to one of my tweets the other day, saying that “OpenID should be dead… it’s way over-rated”. I’ve of course heard a href=”http://factoryjoe.com/blog/2008/10/28/openid-usability-is-not-an-oxymoron/”plenty of criticisms/a of OpenID, but hadn’t really heard that it was “overrated” (which implies that people have a higher opinion of OpenID than it merits).

Intrigued, I replied, asking him to elaborate, which he did via email: blockquoteI don’t know if overrated is the right word.. but I just don’t see OpenID ever catching on.. I think the main reason is that its too complex / scary of an idea for the normal user to understand and accept.

In my opinion the only way to make OpenID seem safe (for people who are worried about privacy online) is if the user has full control over the OpenID provider. While this is possible for people like you and me, my mom is never going to get to this point, and if she wants to use OpenID she is going to have to trust her sensitive data to AOL, MS, Google, etc. I think that people see giving this much “power” to a single provider as scary.

Lastly I think that OpenID is too complex to properly explain to someone and get them to use it. People understand usernames and passwords right away, and even OAuth, but OpenID in itself I think is too hard to grasp. I dunno, just a quick opinion.. I think there is a reason that we don’t have a single key on our key rings that opens our house, car, office and mailbox, not that that is a perfect/accurate analogy, but its close to how some people I’ve talked to think OpenID works./blockquote

Rather than respond privately, I asked whether it’d be okay if I posted his follow-up and replied on my blog. He obliged.

To summarize my interpretation of his points: strongOpenID is too complex and scary, potentially too insecure, and too confined to the hands of a few companies./strong

The summary of my rebuttals:

ul
liOpenID will become a a href=”#convenience”strongnecessary convenience/strong/a in cloud computing./li
liOpenID can be a href=”#security”strongincrementally secured/strong/a and, combined with OAuth, helps to defeat the password-anti-pattern./li
liOpenID is about more than just accounts and fewer passwords mdash; it’s a building block for online identity, and therefore a href=”#agency”strongpersonal agency for web citizens/strong/a./li
/ul

hr /

h3 id=”convenience”Convenience/h3

OpenID should not be judged by today’s technological environment alone, but rather should be considered in the context of the migration to “cloud computing”, where people no longer access files on their local harddrive, but increasingly need to access data stored by web services.

All early technologies face criticism based on current trends and dominant behaviors, and OpenID is no different. At one time, people didn’t grok sending email between different services (in fact, you couldn’t). At one time, people didn’t grok IMing their AOL buddies using Google Talk (in fact, you couldn’t). At one time, you had one computer and your browser stored all of your passwords on the client-side (this is basically where we are today) and at one time, people accessed their photos, videos, and documents locally on their desktop (as is still the case for most people).

Cloud computing represents a shift in how people access and share data. Already, people rely less and less on physical media to store data and more and more on internet-based web services.

As a consequence, people will need a mechanism for referencing their data and services as convenient as the codec:\/code prompt. An OpenID, therefore, should become the referent people use to indicate where their data is “stored”.

An OpenID is not just about identification and blog comments; nor is it about reducing the number of passwords you have (that’s a by-product of user-centered design). Consider:

ul
liif I ask you where your photos are, you could say Flickr, and then prove it, because a href=”http://blog.flickr.net/en/2008/01/31/flickr-and-openid/”Flickr supports OpenID/a./li
liif I ask you where friends are, you might say MySpace, and then prove it, because a href=”http://developer.myspace.com/Community/blogs/devteam/archive/2008/07/24/openid-coming-to-a-myspace-profile-near-you.aspx” title=”OpenID, Coming to A MySpace Profile Near You”MySpace will support OpenID/a./li
liif you host your own blog or website, you will be able to provide your address and then prove it, because you are a href=”http://wordpress.org/extend/plugins/openid/”OpenID-enabled/a./li
/ul
The long-term benefit of OpenID is being able to refer to all the facets of your online identity and data sources with one handy — emideally memorable/em — web-friendly emidentifier/em. Rather than relying on my email addresses alone to identify myself, I would use my OpenIDs, and link to all the things that represent me online: from my resume to my photos to my current projects to my friends, web services and so on.

The big picture of cloud computing points to OpenIDs simplifying how people access, share and connect data to people and services.

hr /

h3 id=”security”Security/h3

I’ve heard many people complain that if your OpenID gets hacked, then you’re screwed. It’s like putting all your eggs in one basket, they claim.

But that’s really no different than if your email account gets hacked. Since your email address is used to reset your password, any or all of your accounts could have their passwords reset and changed; worse, the password emand/em the account email address could be changed, locking you out completely.

At minimum, OpenID is no worse than the status quo.

At best, combined with OAuth, third-parties never need your account password, defeating the a href=”http://adactio.com/journal/1357″password anti-pattern/a and providing a href=”http://factoryjoe.com/blog/2007/12/19/public-nuisance-1-importing-your-contacts”a more secure way to share your data/a.

Furthermore, because securing your OpenID is outside of the purview of the spec, you can choose an OpenID provider (or set up your own) with a level of security that fits your needs. So while many OpenID providers currently stick with the traditional username and password combo, others offer more sophisticated approaches, from client-side certificates and hardware keys to biometrics and image-based password shields (as in the case of my employer, a href=”http://vidoop.com”Vidoop/a).

One added benefit of OpenID is the ability to audit and manage access to your account, just as you do with a credit card account. This means that you have a record of every time someone (hopefully you!) signs in to one of your accounts with your OpenID, as well as how frequently sign-ins occur, from which IP addresses and on what devices. From a security perspective, this is a major advantage over basic usernames and passwords, as collecting this information from each service provider would prove inconvenient and time-consuming, if even possible.

Given this benefit, it’s worth considering that identity technologies
a href=”http://www.forbes.com/technology/2008/12/11/smart-cards-obama-tech-enter-cx_sm_1212smartcards.html” title=”Forbes: Obama: Think Smart Cards”are being pushed on the government/a. If you’re worried about putting all your eggs in one basket, would you think differently if the government owned that basket?

OpenID won’t force anyone to change their current behavior, certainly not right away. But wouldn’t it be better to have the option to choose an alternative way to secure your accounts if you wanted it? OpenID starts with the status quo and, coupled with OAuth, provides an opportunity to make things better.

We’re not going to make online computing more secure overnight, but it seems like a prudent place to start.

hr /

h3 id=”agency”Personal agency for web citizens/h3

Looking over the landscape of existing social software applications, I see very few (if any) that could not be enhanced by OpenID support.

OpenID is a cornerstone technology of the emerging social web, and adds value anywhere users have profiles, accounts or need access to remote data.

Historically, we’ve seen similar attempts at providing a universal login account. Microsoft even got the name right with “Passport”, but screwed up the network model. Any identity system, if it’s going to succeed on the open web, needs to be designed with user choice at its core, in order to facilitate marketplace competition. A single-origin federated identity network will always fail on the internet (as citea href=”http://josephsmarr.com/”Joseph Smarr/a/cite and citea href=”http://therealmccrea.com”John McCrea/a/cite a href=”http://www.webmonkey.com/blog/OpenID_Q_A:_Plaxo_s_Joseph_Smarr_and_John_McCrea”like to say/a of Facebook Connect: a href=”http://therealmccrea.com/2008/07/16/my-prediction-for-2008-a-mid-year-check-in/”qWe’ve seen this movie before/q/a).

As such, selecting an identity provider should not be relegated to a default choice. Where you come from (what I call emprovenance/em) has meaning.

For example, if you connect to a service using your Facebook account, the relying party can presume that the a href=”http://developers.facebook.com/news.php?blog=1story=108″profile information/a that Facebook supplies a href=”http://www.insidefacebook.com/2008/12/10/facebook-connect-making-blog-comments-more-authentic/”will be authentic/a, since Facebook works hard to ferret out fake accounts from its network (unlike MySpace). Similarly, signing in with a Google Account provides a verified email address.

Just like the issuing country of your passport may say something about you to the immigration official reviewing your documents, the OpenID provider that you use may also say something about you to the relying party that you’re signing in to. It is therefore critical that people make an informed choice about who provides (and protects) their identity online, and that the enabling technologies are built with the option for individuals to vouch for themselves.

In the network model where anyone can host their own independent OpenID (just like anyone can set up their own email server), competition may thrive. Where competition thrives, an ecosystem may arise, developed under the rubric of market dynamics and Darwinian survivalism. And in this model, the individual is at the center, rather than the services he or she uses.

This the citizen-centric model of the web, and a href=”http://blogs.law.harvard.edu/vrm/2008/11/20/vrm-is-personal/” title=”Doc Searls: VRM is personal”each of us are sovereign citizens of the web/a. Since I define and host my own identity, I do not need to worry about services like a href=”http://blog.pownce.com/2008/12/01/goodbye-pownce-hello-six-apart/”Pownce being sold/a or a href=”http://iwantsandy.com”I Want Sandy/a users a href=”http://www.valuesofn.com/blog/2008/11/fork-in-road.html”left wanting/a. I have choice, a href=”http://factoryjoe.com/blog/2007/11/26/data-banks-data-brokers-and-citizen-bargaining-power/”I have bargaining power/a, and I have emagency/em, and this is critical to the viability of the social web emat scale/em.

hr /

h3 id=”conclusion”Final words/h3
OpenID is not overrated, it’s just early. We’re just getting started with writing the rules of social software on the web, and we’ve got a lot of bad habits to correct.

As cloud computing goes mainstream (evidenced in part by the a href=”http://gigaom.com/2008/12/26/for-amazon-netbooks-are-a-smash-hit/”growing popularity of Netbooks this holiday season!/a), we’re going to need a consumer-facing technology and brand like OpenID to help unify this new, more virtualized world, in order to make it universally accessible.

Fortunately, as we stack more and more technologies and services on our OpenIDs, we can independently innovate the security layer, developing increasingly sophisticated solutions as necessary to make sure that only the emright/em people have access to our accounts and our data.

It is with with these changes that we must evaluate OpenID — not as a technology for 2008’s problems — but as a formative building block for 2009 and the future of the social web.

Categories: online, software

Jobeet - Day 24: Another Look at symfony

Symfony - Wed, 2008-12-24 08:00

Today is the last stop of our trip to the wonderful world of symfony. During these twenty-three days, you learned symfony by example: from the design patterns used by the framework, to the powerful built-in features. You are not a symfony master yet, but you have all the needed knowledge to start building your symfony applications with confidence.

As we wrap up the Jobeet tutorial, let's have another look at the framework. Forget Jobeet for an hour, and recall all the features you learned during the last three weeks.

What is symfony?

The symfony framework is a set of cohesive but decoupled sub-frameworks, that forms a full-stack MVC framework (Model, View, Controller).

Before coding head first, take some time to read the symfony history and philosophy. Then, check the framework prerequisites and use the check_configuration.php script to validate your configuration.

Eventually, install symfony. After some time you will also want to upgrade to the latest version of the framework.

The framework also provides tools to ease deployment.

The Model

The Model part of symfony can be done with the help of the Propel ORM. Based on the database description, it generates classes for objects, forms, and filters. Propel also generates the SQL statements used to create the tables in the database.

The database configuration can be done with a task or by editing a configuration file. Beside its configuration, it is also possible to inject initial data, thanks to fixture files. You can even make these files dynamic.

Propel objects can also be easily internationalized.

The View

By default, the View layer of the MVC architecture uses plain PHP files as templates.

Templates can use helpers for recurrent tasks like creating a URL or a link.

A template can be decorated by a layout to abstract the header and footer of pages. To make views even more reusable, you can define slots, partials, and components.

To speed up things, you can use the cache sub-framework to cache a whole page, just the action, or even just partials or components. You can also remove the cache manually.

The Controller

The Controller part is managed by front controllers and actions.

Tasks can be used to create simple modules, CRUD modules, or even to generate fullly working admin modules for model classes.

Admin modules allows you to built a fully functional application without coding anything.

To abstract the technical implementation of a website, symfony uses a routing sub-framework that generates pretty URLs. To make implementing web services even easier, symfony supports formats out of the box. You can also create your own formats.

An action can be forwarded to another one, or redirected.

Configuration

The symfony framework makes it easy to have different configuration settings for different environments. An environment is a set of settings that allows different behaviors on the development or production servers. You can also create new environments.

The symfony configuration files can be defined at different levels and most of them are environment aware:

The configuration files mostly uses the YAML format.

Instead of using the default directory structure and organize your application files by layers, you can also organize them by feature, and bundle them in a plugin. Speaking of the default directory structure, you can also customize it according to your needs.

Debugging

From logging to the web debug toolbar, and meaningful exceptions, symfony provides a lot of useful tools to help the developer debug problems faster.

Main symfony Objects

The symfony frameworks provides quite a few core objects that abstract recurrent needs in web projects: the request, the response, the user, the logging, the routing, and the view cache manager.

These core objects are managed by the sfContext object, and they are configured via the factories.

The user manages user authentication, authorization, flashes, and attributes to be serialized in the session.

Security

The symfony framework has built-in protections against XSS and CSRF. These settings can be configured from the command line, or by editing a configuration file.

The form framework also provides built-in security features.

Forms

As managing forms is one of the most tedious task for a web developer, symfony provides a form sub-framework. The form framework comes bundled with a lot of widgets and validators. One of the strength of the form sub-framework is that templates are very easily customizables.

If you use Propel, the form framework also makes it easy to generate forms and filters based on your models.

Internationalization and Localization

Internationalization and localization are supported by symfony, thanks to the ICU standard. The user culture determines the language and the country of the user. It can be defined by the user itself, or embedded in the URL.

Tests

The lime library, used for unit tests, provides a lot of testing methods. The Propel objects can also be tested from a dedicated database and with dedicated fixtures.

Unit tests can be run one at a time or all together.

Functional tests are written with the sfFunctionalTest class, which uses a browser simulator and allows symfony core objects introspection through Testers. Testers exist for the request object, the response object, the user object, the current form object, the cache layer and the Propel objects.

You can also use debugging tools for the response and forms.

As for the unit tests, functional tests can be run one by one or all together.

You can also run all tests together.

Plugins

The symfony framework only provides the foundation for your web applications and relies on plugins to add more features. In this tutorial, we have talked about sfGuardPlugin, sfFormExtraPlugin, and sfTaskExtraPlugin.

A plugin must be activated after installation.

Plugins are the best way to contribute back to the symfony project.

Tasks

The symfony CLI provides a lot of tasks, and the most useful have been discussed in this tutorial:

You can also create your own tasks.

Acknowledgements

Writing a tutorial like Jobeet is both exciting and exhausting. You spend hour after hour trying to figure out how to convey your message, how to explain concepts, and how to provide simple but meaningful and reusable examples.

Writing such a big tutorial is just impossible to do without people around supporting you along the process. For Jobeet, I (Fabien Potencier) had the chance to benefit from top notch reviewers. They are all part of the symfony adventure and I want to thank them all for the time they spent on the Jobeet project.

Kris Wallsmith, our community manager and soon-to-be-announced symfony 1.3 release manager, took the time to proof-read my far-from-perfect English prose. As this tutorial was published on a day-to-day basis, and because I live in France, and he in the US, he got up very early every single morning this month, including weekends, to read and fix each tutorial.

Stefan Koopmanschap, one of the most active symfony evangelist, took the responsibility to run the Subversion repository. Thanks to his work, you can view the code and start reading the tutorial for any day.

Fabian Lange, the symfony 1.2 release manager, and the symfony "guy", read the book with a Windows perspective and tried to be our newbie reader. On a side note, he recently bought a Mac so we need someone else to take on the "Windows guy" responsibility.

Jonathan Wage, the Doctrine lead developer, took the time to create a Doctrine edition of the tutorial. Thanks to his great efforts, you can choose between Propel or Doctrine as your main ORM for symfony, and still enjoy the same tutorial.

Pascal Borelli, an online barfly on the symfony french IRC channel, and the most friendly symfony community member, read the tutorial chapter after chapter at speed light. His continuous support and his kind words kept me in good mood to write this tutorial from start to finish.

See you soon

Before you leave, I would like to talk about one last thing about symfony. The framework has a lot of great features and a lot of free documentation. But, one of the most valuable asset an Open-Source can have is its community. And symfony has one of the most amazing and active community around. If you start using symfony for your projects, consider joining the symfony community:

Joyeux Noël !

Be trained by symfony experts - Jan 21 Paris - Feb 04 Montpellier - Feb 18 Paris - Mar 11 Nantes - Mar 18 Paris
Categories: php, software

Symfony 1.2: upload a file inside an embedded form

Stereo Development Blog - Wed, 2008-12-24 03:09

Symfony 1.1 introduced the ability to embed forms inside other forms. Symfony 1.2 enhanced this feature greatly by providing the ability to automatically save any related objects found within these nested forms (see this blog post). Another new feature introduced in 1.2. is the ability to automatically handle file uploads in forms. Basically if you have a propel object with a file field, and define this field in your form validation schema as an sfValidatorFile, symfony takes care of removing any old field, saving the new one, and updating the column in the object to reflect the new file name. Pretty sweet. (You can read more about this feature in What’s New in 1.2.)

Everything is nearly perfect, except one problem: File fields in embedded forms are *not* processed automatically. It took me a long time to track down the issue, but it was a good opportunity for me to explore some of the new sfForm framework and really get under the under to understand how it all works.

When you call save() on a form, here is a summary of the methods called:

$form->save() | $form->doSave() // updates the object, and then saves the object | $form->updateObject() | $form->processValues() // sets $values | $form->processUploadedFile($field); | $form->getValue($field) | $form->saveFile($field) | $form->object->fromArray($values, BasePeer::TYPE_FIELDNAME); | $form->object->save()

When processValues() encounters a field that has a validator of the class sfValidatorFile, it calls processUploadedFile(). Let’s take a look at this method:

/** * Saves the uploaded file for the given field. * * @param string $field The field name * @param string $filename The file name of the file to save * * @return string The filename used to save the file */ protected function processUploadedFile($field, $filename = null) { if (!$this->validatorSchema[$field] instanceof sfValidatorFile) { throw new LogicException(sprintf('You cannot save the current file for field "%s" as the field is not a file.', $field)); }   if ($this->getValue($field.'_delete')) { $this->removeFile($field);   return ''; }   if (!$this->getValue($field)) { $column = call_user_func(array(constant(get_class($this->object).'::PEER'), 'translateFieldName'), $field, BasePeer::TYPE_FIELDNAME, BasePeer::TYPE_PHPNAME); $getter = 'get'.$column;   return $this->object->$getter(); }   // we need the base directory if (!$this->validatorSchema[$field]->getOption('path')) { return $this->getValue($field); }   $this->removeFile($field);   return $this->saveFile($field, $filename); }

The problem is, when an embedded form is processed, it never gets bound to its [cleaned] values present in the parent form. So, any calls to getValue() from the embedded form comes back empty. That renders the processUploadedFile() useless when called from an embedded form.

The best fix I could find for this is to override the parent form’s bind() method so that it would in turn assign cleaned values and set the isBound status of its nested forms.

public function bind(array $taintedValues = null, array $taintedFiles = null) { $ret = parent::bind($taintedValues, $taintedFiles); foreach ($this->embeddedForms as $name => $form) { $this->embeddedForms[$name]->isBound = true; $this->embeddedForms[$name]->values = $this->values[$name]; }   return $ret; }

Once this new method is in place in the parent form’s class, the file was being processed as intended. I’m not sure if this was just an oversight or is a bug or what, but I’m sure other symfony developers will encounter this issue just as I have. If you have a better solution, please share it with us!!

Categories: general tech, php, software

Jobeet - Day 23: The Deployment

Symfony - Tue, 2008-12-23 14:30
Previously on Jobeet

With the configuration of the cache system yesterday, the Jobeet website is ready to be deployed on the production servers.

During twenty-two days, we have developed Jobeet on a development machine, and for most of you, it probably means your local machine; except if you develop on the production server directly, which is of course a very bad idea. Now, it is time to move the website to the production servers.

Today, we will see what need to be done before going to production, what kind of deploying strategies you can use, and also the tools you need for a successful deployment.

Preparing the Production Server

Before deploying the project to production, we need to be sure the production server is well-configured. You can re-read day 1, where we explained how to configure the web server.

In this section, we assume that you have already installed the web server, the database server, and PHP 5.2.4 or later.

If you don't have an SSH access to the web server, skip the part where you need to have access to the command line.

Server Configuration

First, you need to check that PHP is installed with all the needed extensions and is correctly configured. As for day 1, we will use the check_configuration.php script provided with symfony. As we won't install symfony on the production server, download the file directly from the symfony website:

http://trac.symfony-project.org/browser/branches/1.2/data/bin/check_configuration.php?format=raw

Copy the file to the web root directory and run it from your browser and from the command line:

$ php check_configuration.php

Fix any fatal error the script finds and repeat the process until everything works fine in both environments.

PHP Accelerator

For the production server, you probably want the best performance possible. Installing a PHP accelerator will give you the best improvement for your money.

From Wikipedia: A PHP accelerator work by caching the compiled bytecode of PHP scripts to avoid the overhead of parsing and compiling source code on each request.

APC is one of the most popular one, and it is quite simple to install it:

$ pecl install APC

Depending on your Operating System, you will also be able to install it with the OS native package manager.

Take some time to learn how to configure APC.

The symfony Libraries Embedding symfony

One of the great strength of symfony is that a project is self-contained. All the files needed for the project to work are under the main root project directory. And you can move around the project in another directory without changing anything in the project itself as symfony only uses relative paths. It means that the directory on the production servers does not have to be the same as the one on your development machine.

The only absolute path that can possibly be found is in the config/ProjectConfiguration.class.php file; but we took care of it during day 1. Check that it actually contains a relative path to the symfony core autoloader:

// config/ProjectConfiguration.class.php require_once dirname(__FILE__).'/../lib/vendor/symfony/lib/autoload/sfCoreAutoload.class.php';   Upgrading symfony

Even if everything is self-contained in a single directory, upgrading symfony to a newer release is nonetheless insanely easy.

You will want to upgrade symfony to the latest minor release from time to time, as we constantly fix bugs and possibly security issues. The good news is that all symfony versions are maintained for at least a year and during the maintenance period, we never ever add new features, even the smallest one. So, it is always fast, safe, and secure to upgrade from one minor release to another.

Upgrading symfony is as simple as changing the content of the lib/vendor/symfony/ directory. If you have installed symfony with the archive, remove the current files and replace them with the newest ones.

If you use Subversion for your project, you can also link your project to the latest symfony 1.2 tag:

$ svn propedit svn:externals lib/vendor/ # symfony http://svn.symfony-project.com/tags/RELEASE_1_2_1/

Upgrading symfony is then as simple as changing the tag to the latest symfony version.

You can also use the 1.2 branch to have fixes in real-time:

$ svn propedit svn:externals lib/vendor/ # symfony http://svn.symfony-project.com/branches/1.2/

Now, each time you do an svn up, you will have the latest symfony 1.2 version.

When upgrading to a new version, you are advised to always clear the cache, especially in the production environment:

$ php symfony cc

If you also have an FTP access to the production server, you can simulate a symfony cc by simply removing all the files and directories under the cache/ directory.

You can even test a new symfony version without replacing the existing one. If you just want to test a new release, and want to be able to rollback easily, install symfony in another directory (lib/vendor/symfony_test for instance), change the path in the ProjectConfiguration class, clear the cache, and you are done. Rollbacking is as simple as removing the directory, and change back the path in ProjectConfiguration.

Tweaking the Configuration Database Configuration

Most of the time, the production database has different credentials than the local one. Thanks to the symfony environments, it is quite simple to have a different configuration for the production database:

$ php symfony configure:database "mysql:host=localhost;dbname=prod_dbname" prod_user prod_pass

You can also edit the databases.yml configuration file directly.

Assets

As Jobeet uses plugins that embed assets, symfony created relative symbolic links in the web/ directory. The plugin:publish-assets task regenerates or create them if you install plugins without the plugin:install task:

$ php symfony plugin:publish-assets Customizing Error Pages

Before going to production, it is better to customize default symfony pages, like the "Page Not Found" page, or the default exception page.

We have already configured the error page for the YAML format during day 16, by creating an error.yaml.php and an exception.yaml.php files in the config/error/ directory. The error.yaml.php file is used by symfony when in the prod environment, whereas exception.yaml.php is used in the dev environment.

So, to customize the default exception page for the HTML format, create two files: config/error/error.html.php and config/error/exception.html.php.

The 404 page (page not found) can be customized by changing the error_404_module and error_404_action settings:

# apps/frontend/config/settings.yml all: .actions: error_404_module: default error_404_action: error404   Customizing the Directory Structure

To better structure and standardize your code, symfony has a default directory structure with pre-defined names. But sometimes, you don't have the choice but to change the structure because of some external constraints.

Configuring the directory names can be done in the config/ProjectConfiguration.class.php class.

The Web Root Directory

On some web hosts, you cannot change the web root directory name. Let's say that on your web host, it is named public_html/ instead of web/:

// config/ProjectConfiguration.class.php class ProjectConfiguration extends sfProjectConfiguration { public function setup() { $this->setWebDir($this->getRootDir().'/public_html'); } }  

The setWebDir() method takes the absolute path of the web root directory. If you also move this directory elsewhere, don't forget to edit the controller scripts to check that the path to the ProjectConfiguration file is still valid:

require_once(dirname(__FILE__).'/../config/ProjectConfiguration.class.php');   The Cache and Log Directory

The symfony framework only write in two directories: cache/ and log/. For security reasons, some web host do not set write permissions in the main directory. If this is the case, you can move these directories elsewhere on the filesystem:

// config/ProjectConfiguration.class.php class ProjectConfiguration extends sfProjectConfiguration { public function setup() { $this->setCacheDir('/tmp/symfony_cache'); $this->setLogDir('/tmp/symfony_logs'); } }  

As for the setWebDir() method, setCacheDir() and setLogDir() takes an absolute path to the cache and log directories respectively.

The Factories

During the Jobeet tutorial, we talked about symfony core objects like sfUser, sfRequest, sfResponse, sfI18N, sfRouting, and so on. These objects are automatically created, configured, and managed by the symfony framework. They are always accessible from the sfContext object, and like many things in the framework, they are configurable via a configuration file: factories.yml. This file is configurable by environment.

When the sfContext initializes the core factories, it reads the factories.yml file for the class names (class) and the parameters (param) to pass to the constructor:

response: class: sfWebResponse param: send_http_headers: false  

In the previous snippet, to create the response factory, symfony instantiates a sfWebResponse object and pass the send_http_headers option as an parameter.

Begin able to customize the factories means that you can use a custom class for symfony core objects instead of the default one. You can also change the default behavior of these classes by changing the parameters send to them.

Let's see some classic customizations you might want to do.

Cookie Name

To handle the user session, symfony uses a cookie. This cookie has a default name of symfony, which can be changed in factories.yml. Under the all key, add the following configuration to change the cookie name to jobeet:

# apps/frontend/config/factories.yml storage: class: sfSessionStorage param: session_name: jobeet   Session Storage

The default session storage class is sfSessionStorage. It uses the filesystem to store the session information. If you have several web servers, you would want to store the sessions in a central place, like a database table:

# apps/frontend/config/factories.yml storage: class: sfPDOSessionStorage param: session_name: jobeet db_table: session database: propel db_id_col: id db_data_col: data db_time_col: time   Session Timeout

By default, the user session timeout if 1800 seconds. This can be changed by editing the user entry:

# apps/frontend/config/factories.yml user: class: myUser param: timeout: 1800   Logging

By default, there is no logging in the prod environment because the logger class name is sfNoLogger:

# apps/frontend/config/factories.yml prod: logger: class: sfNoLogger param: level: err loggers: ~  

You can for instance enable logging on the filesystem by changing the logger class name to sfFileLogger:

# apps/frontend/config/factories.yml logger: class: sfFileLogger param: level: error file: %SF_LOG_DIR%/%SF_APP%_%SF_ENVIRONMENT%.log  

In the factories.yml configuration file, %XXX% strings are replaced with their corresponding value from the sfConfig object. So, %SF_APP% in a configuration file is equivalent to sfConfig::get('sf_app') in PHP code. This notation can also be used in the app.yml configuration file. It is very useful when you need to reference a path in a configuration file without hardcoding the path (SF_ROOT_DIR, SF_WEB_DIR, ...).

Deploying What to deploy?

When deploying the Jobeet website to the production server, we need to be careful not to deploy unneeded files, or override files uploaded by our users, like the company logos.

In a symfony project, there are three directories to exclude from the transfer: cache/, log/, and web/uploads/. Everything else can be transfered as is.

But for security reasons, you also don't want to transfer the "non-production" front controllers, like the frontend_dev.php and frontend_cache.php scripts.

Deploying Strategies

In this section, we will assume that you have full control over the production server(s). If you can only access the server with a FTP account, the only deployment solution possible is to transfer all files every time you deploy.

The simplest way to deploy your website is to use the built-in project:deploy task. It uses SSH and rsync to connect and transfer the files from a server to another one.

The servers are to be configured in the config/properties.ini configuration file:

# config/properties.ini [production] host=www.symfony-project.com port=22 user=jobeet dir=/var/www/jobeet/ type=rsync pass=  

To deploy to the newly configured production server, use the project:deploy task:

$ php symfony project:deploy production

If you run this command, symfony will only simulate the transfer. To actually deploy the website, add the --go option:

$ php symfony project:deploy production --go

Even if you can provide the SSH password in the properties.ini file, it is better to configure your server with a SSH key to allow password-less connections.

By default, symfony won't transfer the directories we have talked about in the previous section, nor it will transfer the dev front controller script. That's because the project:deploy task exclude files and directories are configured in the config/rsync_exclude.txt file:

# config/rsync_exclude.txt .svn /web/uploads/* /cache/* /log/* /web/*_dev.php

For Jobeet, we need to add the frontend_cache.php file:

# config/rsync_exclude.txt .svn /web/uploads/* /cache/* /log/* /web/*_dev.php /web/frontend_cache.php

You can also create a config/rsync_include.txt file to force some files or directories to be transfered.

Even if the project:deploy task is very flexible, you might want to customize it even further. As deploying can be very different based on your server configuration and topology , don't hesitate to extend the default task.

Each time you deploy a website to production, don't forget to at least clear the configuration cache on the production server:

$ php symfony cc --type=config

If you have changed some routes, you will also need to clear the routing cache:

$ php symfony cc --type=routing

Clearing the cache selectively allows to keep some parts of cache like the template one.

See you Tomorrow

The deployment of a project is the very last step of a symfony development life-cycle. It does not mean that you are done. This is quite the contrary. A website is something that has a life by itself. You will probably have to fix bugs and you will also want to add new features over time. But thanks to the symfony structure, and the tools at your disposal, upgrading your website is going to be simple, fast, and safe.

Tomorrow is already the last day of the Jobeet tutorial. It will be time to stand back a little, and have a look at what you learned during the twenty-three days of Jobeet.

Don't miss the last installment of Jobeet.

Be trained by symfony experts - Jan 21 Paris - Feb 04 Montpellier - Feb 18 Paris - Mar 11 Nantes - Mar 18 Paris
Categories: php, software

Jobeet - Day 22: The Cache

Symfony - Mon, 2008-12-22 16:20
Previously on Jobeet

Today's tutorial starts the last week of Jobeet. We will talk about a very interesting topic: caching.

The symfony framework has many built-in cache strategies. For instance, the YAML configuration files are first converted to PHP and then cached on the filesystem. We have also seen that the modules generated by the admin generator are cached for better performance.

Today, we will talk about another cache: the HTML cache. To improve your website performance, you can cache whole HTML pages or just parts of them.

Creating a new Environment

By default, the template cache feature of symfony is enabled in the settings.yml configuration file for the prod environme