LicenseSyndicate This BlogPlanet PHPA Case of Mistaken Iterator - Sean Coates
Thursday, July 29. 2010 Open Source Your Career, my story - Stefan Koopmanschap Wednesday, July 28. 2010 July Slides - Brandon Savage Wednesday, July 28. 2010 Speaking at Dallas TechFest 2010 – Building a Web Service API - blog.phpdeveloper.org » PHP Tuesday, July 27. 2010 Beer Alchemy Integration - Sean Coates Tuesday, July 27. 2010 Aloha and the art of semantic web content - Henri Bergius Tuesday, July 27. 2010 Using HipHop for Static Analysis - Sebastian Bergmann Tuesday, July 27. 2010 Keynoting at PHPNW10 - Lorna Mitchell Tuesday, July 27. 2010 PHP for Android, PHP 6 canceled, APC in PHP 5.4 - Lately in PHP podcast episode 3 - PHP Classes Monday, July 26. 2010 PHP 5.3 at New York PHP this Tuesday - Daniel Krook Sunday, July 25. 2010 StatisticsLast entry: 2010-07-08 20:50
413 entries written
1552 comments have been made
|
Tuesday, April 29. 2008
An Example Zend Framework Blog ... Posted by Pádraic Brady
in PHP General, PHP Security, Zend Framework at
11:51
Comments (21) Trackback (1) An Example Zend Framework Blog Application - Part 4: Setting the Design Stage with Blueprint CSS Framework and Zend_Layout
One of the things I know with a certainty that sometimes depresses me is that my design skills are on the level of a 6 year old. In fact the 6 year old with crayons is likely superior in all respects
Previously: Part 3: A Simple Hello World Tutorial But, to be honest, it saves me a lot of time. I really don't like editing CSS when I can entice a monkey with vast bags of peanuts to do a better job later on. For the moment I just need a nice default design which looks okay. In this article we're going to take a stab at setting up a default blog style, using some filler content, and finally capturing the design with a Zend_View template to be consumed by Zend_Layout as a common HTML Layout for the entire future blog. Step 1: Adding Blueprint to the ProjectYou can download the Blueprint CSS framework from http://code.google.com/p/blueprintcss/. It is released under a dual licensing system using a Modified MIT License, or the GNU General Public License. Decompress the archive of the latest 0.7 release (as at time of writing) and return to our current project'spublic directory.Inside public create a new directory called css. Into this new directory, copy the decompressed blueprint directory and LICENSE file from the Blueprint distribution. We retain the license so future redistributions of the project (if any) include a copy for reference.Blueprint contains a default set of reasonable styling. This include the most fantastic of them all - when included correctly into any HTML document it sets all browsers to the same set of defaults. This completely negates the usual pain of Firefox, IE6, IE7 and Safari having sufficiently different styles internally that designs need a ton of small browser specific adjustments by hand. By hand is evil - Blueprint does it without interference. To complete this step, create an empty CSS file called style.css inside the /public/css directory. We'll include this in our HTML as a point for customising the Blueprint CSS and adding additional styling as needed.Step 2: Creating a Test HTML Document applying Blueprint CSSThe first step to any good design is using Photoshop or gimp to draw one up. I'm really bad at that however - so I stick with lots of filler text and write plain HTML from the start. Besides, it's a blog page - how complex can it be?We already have a "Hello, World" page from Part 3 of this article series - so let's stick with what we have and throw in a bunch of HTML for a potential main blog index page. We'll use lot's of words like "lorem ipsum" in keeping with a long history ("lorem ipsum" is the start of a long block of text used as filler text in printers since the 1500's - the full traditionally used text itself is over 2000 years old!) A quick word on using Blueprint CSS. Blueprint assumes you can't align divs (in this case not far from the truth Starting simple, open up the /application/views/scripts/index/index/phtml template used by our default Index controller and edit to contain the following:<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="language" content="en" /> <title><?php echo $this->escape($this->title) ?></title> <link rel="stylesheet" href="/css/blueprint/screen.css" type="text/css" media="screen, projection"> <link rel="stylesheet" href="/css/style.css" type="text/css" media="screen, projection"> <link rel="stylesheet" href="/css/blueprint/print.css" type="text/css" media="print"> <!--[if IE]><link rel="stylesheet" href="/css/blueprint/ie.css" type="text/css" media="screen, projection"><![endif]--> </head> <body> <div class="container"> <div class="block"> <div id="zfHeader" class="column span-24"> <h1>Lorem Ipsum</h1> </div> </div> <div class="block"> <div id="zfContent" class="column span-16"> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p> </div> <div id="zfExtraRight" class="column span-7"> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p> </div> </div> <div class="block"> <div id="zfFooter" class="span-24"> <p>Copyright © 2008 Pádraic Brady</p> </div> </div> </div> </body> </html> Go ahead and reopen http://zfblog/ in a browser. You'll quickly notice that with little effort, it looks oddly pretty and the main content and right column are aligned exactly even.In the HTML we did some very simple things. We have the standard 3 block solution - Header, Content, Footer. Both are contained in div's with assigned "span" width. Content is further divided into two columns with "span" widths - the total of which add to 1 less than the total of 24 spans. The reason for the missing span is simply to allow room for further styling which in varying browsers can have knock on effects - typically using the full span wodth across multiple column blocks ends up with a browser breaching the fixed 24 width and leaving a column dropped below the others. Let's add a few modifications to allow for a more realistic appearance of blog entries with a title and other assembled summary data. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="language" content="en" /> <title><?php echo $this->escape($this->title) ?></title> <link rel="stylesheet" href="/css/blueprint/screen.css" type="text/css" media="screen, projection"> <link rel="stylesheet" href="/css/style.css" type="text/css" media="screen, projection"> <link rel="stylesheet" href="/css/blueprint/print.css" type="text/css" media="print"> <!--[if IE]><link rel="stylesheet" href="/css/blueprint/ie.css" type="text/css" media="screen, projection"><![endif]--> </head> <body> <div class="container"> <div class="block"> <div id="zfHeader" class="column span-24"> <h1>Lorem Ipsum</h1> </div> </div> <div class="block"> <div id="zfContent" class="column span-16"> <h2>Excepteur Sint</h2> <p><?php echo gmdate('D, j M Y H:i:s T', time()) ?><br /> Posted by Pádraic Brady</p> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p> <hr /> <p>Tags: Lorem, Ipsum, Excepteur</p> <h2>Excepteur Sint</h2> <p><?php echo gmdate('D, j M Y H:i:s T', time()) ?><br /> Posted by Pádraic Brady</p> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p> <hr /> <p>Tags: Lorem, Ipsum, Excepteur</p> </div> <div id="zfExtraRight" class="column span-7"> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p> </div> </div> <div class="block"> <div id="zfFooter" class="span-24"> <p>Copyright © 2008 Pádraic Brady</p> </div> </div> </div> </body> </html> What we now have is pretty basic - but even in black and white it looks clean and quite blog-like. If you disable CSS for your browser, well, it still looks quite fine which is always a positive thing. Step 3: Splitting persistent markup into a Zend_Layout templateTraditionally, PHP templating has rarely addressed a common problem we have using templates. Somewhere in the design above (you can spot this easily) are elements common to almost every future page of our blog application. A stock solution is often to push these elements into separate templates, and include them as needed. This poses the problem of widespread references to these templates. What happens if we decide they only apply to half our site now, and need to replace them for 50% of all existing page specific templates? I call it PAIN. Others call it MIND-NUMBING.A simple tactic to avoid these symptoms is to segregate common elements in one single location, and make sure individual templates remain blissfully unaware of it's existence (then those 100 templates have nothing to edit if the central common template is replace for 50 of them!). In the Zend Framework this tactic was initially proposed over a year ago when attention was slowly turning towards the weak Zend_View side of the MVC equation. I proposed Zend_View Enhanced which include, among a lot of things, a Zend_View based solution to the common layout problem. Ralph Schindler proposed around the same time a Zend_Layout component for similar purposes. Eventually I lost on that score, and Zend_Layout was adopted. Such is life - at least the rest of Zend_View Enhanced with some modification was also adopted, making for a powerful templating solution taking full advantage of the PHP language (and not a limited subset obscured behind a secondary tag language). Examining our design above we can spot the common bits: header, footer and the righthand column. Zend_Layout uses a separate template - the Zend Framework manual is extremely obscure about how to actually get the Layout part working (hopefully fixed soon) but it's very simple. Create a new file in /application/views/layouts called common.phtml. What we'll do is copy in the above index.phtml template but delete the sections that are likely to change with different page views - namely the entries.<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="language" content="en" /> <title><?php echo $this->escape($this->title) ?></title> <link rel="stylesheet" href="/css/blueprint/screen.css" type="text/css" media="screen, projection"> <link rel="stylesheet" href="/css/style.css" type="text/css" media="screen, projection"> <link rel="stylesheet" href="/css/blueprint/print.css" type="text/css" media="print"> <!--[if IE]><link rel="stylesheet" href="/css/blueprint/ie.css" type="text/css" media="screen, projection"><![endif]--> </head> <body> <div class="container"> <div class="block"> <div id="zfHeader" class="column span-24"> <h1>Lorem Ipsum</h1> </div> </div> <div class="block"> <div id="zfContent" class="column span-16"> <?php echo $this->layout()->content ?> </div> <div id="zfExtraRight" class="column span-7"> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p> </div> </div> <div class="block"> <div id="zfFooter" class="span-24"> <p>Copyright © 2008 Pádraic Brady</p> </div> </div> </div> </body> </html> You'll notice I replaced the fake entries with a reference to a layout() function. Function calls on the template object instance generally are either called from the template object (an instance of Zend_View) or are references to a View Helper (a small class encapsulating reusable presentation logic - we'll hear a lot more about these later). In this case, it refers to the Zend_View_Helper_Layout class. This class instance has a public variable $content which contains all content rendered from all preceeding templates (bear in mind Layouts are rendered last - after Action specific templates).The process is simple. You visit a Controller and Action. That Action's template is rendered, and saved to the Layout View Helper. The Layout is rendered last, and the pre-rendered content inserted as the Layout template defines using a call to $this->layout()->content.With our Layout template prepared, let's remove all those common items from our Action specific template at /application/views/scripts/index/index.phtml:<h2>Excepteur Sint</h2> <p><?php echo gmdate('D, j M Y H:i:s T', time()) ?><br /> Posted by Pádraic Brady</p> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p> <hr /> <p>Tags: Lorem, Ipsum, Excepteur</p> <h2>Excepteur Sint</h2> <p><?php echo gmdate('D, j M Y H:i:s T', time()) ?><br /> Posted by Pádraic Brady</p> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p> <hr /> <p>Tags: Lorem, Ipsum, Excepteur</p> Now we're getting somewhere interesting. The revised template, only contains the content unique to that Controller/Action combination and it's output will be inserted into the common Layout we created - after we setup Zend_Layout! Step 4: Setting up Zend_Layout for operationGetting Zend_Layout working is again quite simple. We just need to make a few additions to our Bootstrap file. Specifically to thesetupView() static method.<?php require_once 'Zend/Loader.php'; class Bootstrap { public static $frontController = null; public static $root = ''; public static function run() { self::setupEnvironment(); self::prepare(); $response = self::$frontController->dispatch(); self::sendResponse($response); } public static function setupEnvironment() { error_reporting(E_ALL|E_STRICT); ini_set('display_errors', true); date_default_timezone_set('Europe/London'); self::$root = dirname(dirname(<u>_FILE_</u>)); // FILE constant should have two underscores // preceeding and following "FILE" } public static function prepare() { self::setupFrontController(); self::setupView(); } public static function setupFrontController() { Zend_Loader::registerAutoload(); self::$frontController = Zend_Controller_Front::getInstance(); self::$frontController->throwExceptions(true); self::$frontController->returnResponse(true); self::$frontController->setControllerDirectory( self::$root . '/application/controllers' ); } public static function setupView() { $view = new Zend_View; $view->setEncoding('UTF-8'); $viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer($view); Zend_Controller_Action_HelperBroker::addHelper($viewRenderer); Zend_Layout::startMvc( array( 'layoutPath' => self::$root . '/application/views/layouts', 'layout' => 'common' ) ); } public static function sendResponse(Zend_Controller_Response_Http $response) { $response->setHeader('Content-Type', 'text/html; charset=UTF-8', true); $response->sendResponse(); } } Since we're using paths a lot, I also added a $root static property rather than repeating dirname() everywhere!The new addition sets up Zend_Layout for use - it's automatically integrated into our application thereafter so there's no specific on/off switch outside the Boostrap we need worry about. We pass in a few starting options to customise Layouts. We set the path where Layouts can be found, and provide a default file name (minus the .phtml file extension) to use. One final step, because it's bugging me as I write this. Let's replace the Hello, World title in our IndexController ( /application/controllers/IndexController.php) with something more meaningful.class IndexController extends Zend_Controller_Action { public function indexAction() { $this->view->title = 'Maugrim\'s Marvelous Blog'; } } Go ahead and fire up a browser pointing to http://zfblog/.Conclusion This series, as you can tell, is all about taking small concrete steps. In this installment we've added a basic design, added the Blusprint CSS Framework to our toolbox, and set the pace for future templating by eradicating repetitive template code; moving it to a discrete layout template. I see it this as the conclusion of our setup tasks. In Part 3, we had a simple Hello World example. Now we have a skeletal blog design and a Layout moving. We're looking good! Next up: It's time to do away with the filler content and investigate a means of writing and saving real entries to the database. Once we have the most basic blog imaginable running, we can turn our attention to a new round of requirements like syntax highlighting (it will be a programming blog afterall) and perhaps a few design touchups to add a dash of colour. Note: The source code for this entry is available to browse, or checkout with subversion, from http://svn.astrumfutura.org/zfblog/tags/Part4. The full source code for the entire application (as it exists thus far) from http://svn.astrumfutura.org/zfblog. Continue to: Part 5: Creating Models with Zend_Db and adding an Administration Module Monday, April 28. 2008
An Example Zend Framework Blog ... Posted by Pádraic Brady
in PHP General, PHP Security, Zend Framework at
17:42
Comments (26) Trackback (1) An Example Zend Framework Blog Application - Part 3: A Simple Hello World Tutorial
It's almost obligatory when introducing a new programming topic, that the author present the simplest possible example. Usually this means getting a programming language or framework to print "Hello World" to the screen. I'm going to be no different. So much for originality...
Previously: Part 2: The MVC Application Architecture Step 1: Creating A New ApplicationBefore we jump into programming with the Zend Framework there are a few setup tasks. We need to install the Zend Framework, get a virtual domain running, and have a basic collection of directories and emtpy files created to hold our source code.You'll need to download the Zend Framework 1.5 (latest minor release) from http://framework.zend.com and put it somewhere on your include path. I try to minimise the number of include paths I end up having so I sometimes pick very odd places (like the PEAR directory which is usually already in the include_path) or another central library location like PEAR where I might have a dozen libraries all congregated. A common solution found on blogs and articles is to put the framework into a "library" directory within your application directory tree. Ordinarily I don't recommend this unless your application needs a specific version of the Zend Framework - centralising a Zend Framework location for multiple applications to access can make maintenance a bit easier. I've settled on using a virtual host mainly because it's easy to setup, and it helps avoid some of those annoying base path issues you get in your HTML when using mod_rewrite pretty urls - especially in development where, otherwise, the locahost document root becomes a mass of sub-directories upon sub-directories that end up causing base href issues so easily. Usually I open up the virtual-hosts.conf file from Apache's conf directory and add something like: NameVirtualHost ∗:80This should result in all HTTP queries for http://zfblog/ reaching the selected document root (which is the public directory for the project containing index.php, located in our subversion's working copy "trunk" directory). We'll create this directory structure a little later. We usually also need to reference localhost to ensure it's recognised as a host correctly - otherwise any localhost addresses you already have will suddenly divert to zfblog's document root myseriously For those of you on Windows XP or Vista, you also need to add the new virtual domain to your hosts file (usually at C:\WINNT\system32\drivers\etc\hosts). This is tricky in Vista - you will probably need to alter the file's permissions using an Administrator account to grant the local user additional Modify privileges. Make sure to reverse the privileges after! Edit it to look this: # Copyright (c) 1993-1999 Microsoft Corp.Restart your browser and with a little luck the browser will at least give us a directory listing (once you add the document root "public" directory as shown below). The least exciting part is the creation of a tree of directories to contain our source code. Wil Sinclair over at Zend is working on a Zend_Build component and this will one day hopefully eliminate too much of the repetition in creating these directories and default files. Until then let the monotony ensue (or keep a skeleton setup handy for copy and pasting Here's a snapshot of what the Hello World example looks like in the directory view from Eclipse: ![]() Copy this and create the same directory structure in a new directory called something like "zfblog". Putting it all in "trunk" is optional - I've using subversion here which is why that directory exists. If you haven't used Subversion before I highly recommend it - it's simple to learn and use. Let's examine each of these directories briefly. The "application" directory is where we place all the components of an application implementing the Model-View-Controller. Inside "application", "controllers", "models" and "views" represent respective locations of controller, model and view source code and templates. Inside "views" there is a subdivision between "filters", "helpers", "layouts" and "scripts". For now, remember we put all templates rendered by the View inside "scripts". In the screenshot, we see and index directory which will contain an "index.phtml" file, which is the view template for indexAction of an IndexController class. The others we'll meet later. The "modules" directory is also for controllers, models, and views, but in this case they are catagorised into multiple divisions of an application. If you think about it, an application can be broken into several parts, for example, the main application and an administration part. The administration section could be partitioned into the Admin Module so it's not intermixed with the main application. A Bootstrap.php file exists in the "application" directory which represents a class called "Bootstrap". It's purpose is to initialise the Zend Framework, adjust environment settings (for example, timezone and error_reporting level), and otherwise make application specific tweaks and additions before a HTTP request is processed. Most tutorials take an alternative view and put Bootstrap code into index.php. I strongly suggest you avoid this and use an actual class to organise the Bootstrap code - it makes it a lot easier to read if nothing else! The "config" directory simply holds the configuration data for the application, for example, database connection details. The "library" directory can hold a copy of the Zend Framework. Generally I avoid this since it's fairly easy to just add the Zend Framework to the PHP include_path, but it's still very useful if you want to change Zend Framework versions in use more flexibly. It's also simple to manage if you use it to add an svn::external reference to the Zend Framework subversion repository. The "public" directory holds all public files accessible by a request to the web server. This includes an index.php file, which handles all application requests by calling on the Bootstrap class, as well as any CSS, HTML, Javascript files, etc. A note on deployment practice: generally when deploying you'd want to move the "public" directory to your web server to be internet accessible, but keep the non-public directories somewhere below the web root. Since the public index.php ends up only making a simple reference to the Bootstrap file served by including it, this means most of the application files will not be accessible by internet users. It also means that the index.php file will end up deciding where the Bootstrap file is located - so it's the one public file that always needs to be edited by hand for deployment to change that location as needed. The "tests" directory usually holds any application specific unit, integration and acceptance tests. As I noted previously I'm deliberately taking a test-light approach to stay on topic (I have more than one testing/development article on Zend Devzone if interested in applying TDD or BDD). Main tests I expect to have are for application specific classes: any Model logic for example. At the end of this step you should have the directory structure in place containing some empty files as follows (create them now, and we'll fill them in later): /application/Bootstrap.phpStep 2: Implementing Our Bootstrap FileBootstrapping is when we setup the initial environment, configuration and Zend Framework initialisation for our application. It's not a difficult file to write, but it can grow ever larger and complex as your application gains features. To manage this I strongly suggest implementing it as a class with bitesize methods. Breaking it up does wonders for your sanity. For our Hello World skeleton application,/application/Boostrap.php contains:<?php require_once 'Zend/Loader.php'; class Bootstrap { public static $frontController = null; public static function run() { self::setupEnvironment(); self::prepare(); $response = self::$frontController->dispatch(); self::sendResponse($response); } public static function setupEnvironment() { error_reporting(E_ALL|E_STRICT); ini_set('display_errors', true); date_default_timezone_set('Europe/London'); } public static function prepare() { self::setupFrontController(); self::setupView(); } public static function setupFrontController() { Zend_Loader::registerAutoload(); self::$frontController = Zend_Controller_Front::getInstance(); self::$frontController->throwExceptions(true); self::$frontController->returnResponse(true); self::$frontController->setControllerDirectory( dirname(<u>_FILE_</u>) . '/controllers' ); } public static function setupView() { $view = new Zend_View; $view->setEncoding('UTF-8'); $viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer($view); Zend_Controller_Action_HelperBroker::addHelper($viewRenderer); } public static function sendResponse(Zend_Controller_Response_Http $response) { $response->setHeader('Content-Type', 'text/html; charset=UTF-8', true); $response->sendResponse(); } } Note: Due to some Serendipity bug in processing Geshi output, underline tags replace some underline characters such as for the PHP FILE constant which should have two underscrores proceeding and following "FILE". Sorry about that - S9Y has it's moments. The Bootstrap class has two main methods here: run() and prepare(). run() executes a full application request, whereas prepare() only sets up (but doesn't execute) the Front Controller. For now let's focus on run() and all the steps our Bootstrap takes when it's called. The prepare() method is something I use when applying TDD or BDD to developing controllers, since I then delegate controller execution to the testing framework. The first thing is to setup the local environment. So here we've set a timezone (as required by PHP5), enabled PHP's display_errors option, and set a fairly stiff error reporting level. If putting these basics into a class seems counter intuitive, you can simply extract them to the file head. Because I usually test extensively, I usually don't want these running during my tests and interfering with test results. Secondly we prepare the Front Controller. Zend_Controller_Front is an implementation of the Front Controller Design Pattern, which acts as a single point of entry into a Model-View-Controller architected application. I kid you not - every request which is not for an existing public file will go through it. In our case, since the Bootstrap is included into, and called by public/index.php, "index.php" is our single point of entry. Here, the prepare() stage involves setting up the Front Controller: - get an instance of Zend_Controller_Front - set it to throw all Exceptions (might want to disable this in production) - set it to return a Response object when dispatched - tell it where to find the default controllers The last step of prepare() makes some changes to the View. The reason I've done this is to show how to make an extremely common change - adding support for UTF-8 encoded output (such as my name!). Don't worry too much about the details now - the ViewRenderer Action Helper and the Helper Broker lets one add or modify Action Helpers and is well covered by Matthew Weier O'Phinney over on Zend Devzone - http://devzone.zend.com/article/3350-Action-Helpers-in-Zend-Framework. Now, what about /public/index.php?<?php // Update after deployment for location of non-public files $root = dirname(dirname(<u>_FILE_</u>)); // We're assuming the Zend Framework is already on the include_path set_include_path( $root . '/application' . PATH_SEPARATOR . $root . '/library' . PATH_SEPARATOR . get_include_path() ); require_once 'Bootstrap.php'; Bootstrap::run(); Simplicity itself! The index is our Front Controller's single point of entry into a Zend Framework application, and all it needs to do is determine a valid include_path for the application and then delegate all other tasks to the Bootstrap class's run() method. The final step is how to make all requests to "http://zfblog/" pass through index.php. This is solved for Apache web servers using it's Rewrite Module, which simply takes an incoming request URL, and rewrites it so it points to index.php. If you've never used Apache Rewrite before, you probably need to enable this module in http.conf before this works. Rewrite rules can be defined in Apache's http.conf file, or simply via a .htaccess file in "public" containing the rules: RewriteEngine onThe .htaccess file here first turns on Rewriting, and then specifies rules. The rules here map all requests to index.php, unless they relate to a file which exists on the server (i.e. it won't rewrite URLs to CSS, Javascript or image files). Step 4: Implementing The Index ControllerBefore we continue, a quick word on controller/view wiring. Some time back it was decided to make automated rendering the default mode of operation for the Zend Framework. This means Controller will rarely need manual intervention to render a View - instead an Action Helper called the ViewRenderer (which should sound familiar since it used it to add UTF-8 encoding in our Bootstrap!) is called upon. This helper locates a View matching the name of the current Controller and Action and automatically renders it. There are ways to disable this automated rendering as documented in the manual - which is often useful when you want to bypass Zend_View (e.g. maybe you're outputting finalised JSON or XML and no further templating or processing is needed).If a URL to a Zend Framework application does not contain a controller or action reference, then the Zend Framework uses the default "index" value. Since we only intend requesting to the root URL of "http://zfblog/", we'll need an Index Controller containing an Index Action. Let's create one! Add a file called "IndexController.php" in application/controllers containing:<?php class IndexController extends Zend_Controller_Action { public function indexAction() { $this->view->title = 'Hello, World!'; } } All controllers must extend Zend_Controller_Action, since it contains all later referenced internal methods and properties common to all Controllers. If you need to tweak the basic Controller to add new methods or properties you may do so using a subclass of Zend_Controller_Action and then making all application Controllers extend this subclass instead. Be very careful however in subclassing this way - it's useful for adding new properties to the class, but additional methods are often better added as discrete Action Helpers. Our new Action method ignores rendering; it's done automatically as discussed earlier. All we need to do is set View data we need. You can add almost anything to a View, since it just becomes a property in a View template. So feel free to add Objects and Arrays. If using Smarty or PHPTAL, this might be different. Above we've told the View that templates might refer to a variable "title" and given it a value of "Hello, World!". Once the Action method is done, the ViewRenderer will kick in and try to render a template located at "/path/to/application/views/scripts/index/index.phtml". And what use is a Controller, without a View to display? Step 5: Implementing The View For IndexController::indexAction()By default, the Zend Framework or more specifically the ViewRenderer Action Helper, will attempt to render a View template for all Controller Actions using a simple convention. For example, the template for IndexController::indexAction() should be located at "/index/index.phtml" within the "scripts" subdirectory of "views".The Zend_View component is responsible for rendering all View template, often with a little assistance (e.g. ViewRenderer or Zend_Layout) from the Controller. A Zend_View template is HTML (or some other output type) interspersed with PHP and it doesn't use a separate tag language such as what the Smarty template engine, for example, uses. Here's something to put into your index.phtml file for our first Zend Framework application: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="language" content="en" /> <title><?php echo $this->escape($this->title) ?></title> </head> <body> <p>Hello, World!</p> </body> </html> As you can see, it's almost pure HTML with a single PHP inclusion for the title text (which we set from our indexAction() method earlier!). To ensure security against Cross Site Scripting (XSS) we should escape all output from within the application, and Zend_View uses the PHP htmlspecialchars() function from it's Zend_View::escape() method. Another noteworthy mention is that, since we setup our View to use UTF-8 encoding, this encoding is also passed into htmlspecialchars(). If using escape() everywhere sounds bad - well, it is, and it isn't. It's a pain since it's something that would obviously benefit from automation - so not applying escaping is the exception by default. On the other hand it must be done at all times so if you ever see a variable being echoed that's not surrounded by the escape() method you should proceed with care. Step 6: Did it work?Go ahead and open up your browser. The base url of http://zfblog/ should now do it's thing and return a HTML document containing "Hello, World!".ConclusionGetting a simple example up and running has already provided a few insights. But don't let your guard down just yet. Like any battle plan, it will not survive first contact with the enemy (Maugrim's Marvellous Blog is so evilIt's a start. If you're lucky, it may be many starts since you can reuse a similar basic skeleton to skip all those setup tasks for other Zend Framework projects. Note: The source code for this entry is available to browse, or checkout with subversion, from http://svn.astrumfutura.org/zfblog/tags/Part3. The full source code for the entire application (as it exists thus far) from http://svn.astrumfutura.org/zfblog. Continue to: Part 4: Setting the Design Stage with Blueprint CSS Framework and Zend_Layout Thursday, April 24. 2008
Subversion for the Example Zend ... Posted by Pádraic Brady
in PHP General, PHP Security, Zend Framework at
19:40
Comments (0) Trackbacks (0) Subversion for the Example Zend Framework Blog Tutorial Series
You should all see a few commits commencing at the weekend. Probably all in one go since I largely have a standard skeleton I use already.
http://svn.astrumfutura.org/zfblog/ As mentioned previously, this is for live development so be patient for the next installments of the tutorial series if you update from the repository one day and find a bunch of unexplainable code
« previous page
(Page 1 of 3, totaling 7 entries)
next page »
Frontpage View as PDF: This month | Full blog |
CalendarQuicksearchCommentsPadraic Brady about HTML Sanitisation Benchmarking With Wibble (ZF Proposal) Wed, 28.07.2010 19:25 Documented being the operative word... HtmLawed's documentat ion makes it clear that it req uires developer input fo [...] Tyler about HTML Sanitisation Benchmarking With Wibble (ZF Proposal) Mon, 26.07.2010 19:04 HtmLawed has several documente d security issues and has neve r really had a comprehensive c heck of commonly known X [...] Padraic Brady about HTML Sanitisation Benchmarking With Wibble (ZF Proposal) Mon, 26.07.2010 11:28 I suggest reading the HtmLawed documentation paying attentio n to what it doesn't do by its elf. The docs did a grea [...] Padraic Brady about HTML Sanitisation Benchmarking With Wibble (ZF Proposal) Mon, 26.07.2010 11:09 Reason for the default is to o ffer a safe default. To keep s ome HTML, you need to define t he tags and attributes t [...] Mark van der Velden about HTML Sanitisation Benchmarking With Wibble (ZF Proposal) Sun, 25.07.2010 21:33 I do not understand the defaul t behaviour being "strip all H TML". In my experience the re ason for using libraries [...] Reinhardt about HTML Sanitisation Benchmarking With Wibble (ZF Proposal) Sat, 24.07.2010 08:52 I think htmLawed is perfectly fine. It is very configurable, and as one can see from the b enchmarks referred to he [...] Mikael Gramont about HTML Sanitisation Benchmarking With Wibble (ZF Proposal) Mon, 19.07.2010 07:25 That sounds great, I'll be hap py to look into it once you re lease it. Greg about HTML Sanitisation Benchmarking With Wibble (ZF Proposal) Sat, 17.07.2010 02:06 What specifically is wrong wit h HtmLawed ? I was considerin g using it. Carlos Aguado about HTML Sanitisation Benchmarking With Wibble (ZF Proposal) Mon, 12.07.2010 22:17 Hi Pádraic, This is extreme nly interesting! Once all that "in-depth sanity testing, cle anup and documentation" [...] Alex about HTML Sanitisation Benchmarking With Wibble (ZF Proposal) Mon, 12.07.2010 14:16 I am interested in demo too. When do you thin wibbler will be close to final state? Greg Freeman about HTML Sanitisation Benchmarking With Wibble (ZF Proposal) Sat, 10.07.2010 01:23 Great work Pádraic, interestin g name too, how did you come u p with it? Pádraic Brady about HTML Sanitisation Benchmarking With Wibble (ZF Proposal) Fri, 09.07.2010 14:30 These were initial benchmarks to check a specific target for speed. Another week or so and I'll check in a more ro [...] Bruce Weirdan about HTML Sanitisation Benchmarking With Wibble (ZF Proposal) Fri, 09.07.2010 14:04 And what about memory consumpt ion? DOM was a memory-hungry b east last time I checked. Pádraic Brady about HTML Sanitisation Benchmarking With Wibble (ZF Proposal) Fri, 09.07.2010 10:36 No demo yet - once Wibble get' s closer to a final state, I'l l get one up (and yes, I know it's a good idea to have [...] Gareth Heyes about HTML Sanitisation Benchmarking With Wibble (ZF Proposal) Fri, 09.07.2010 10:03 Demo anywhere? CategoriesTop ReferrersShow tagged entries application security article astrum futura asynchronous processing atom bdd behavior-driven development behaviour-driven development benchmark book deep end dependency injection design patterns devnetwork docbook documentation eve online games htmlpurifier inversion of control irish php user group irishisms maugrim microformat mock objects mockery model mutateme mutation testing mvc oauth openid openid and yadis pc gaming pear phing php php game development php games php general php security phpmock phpspec phpunit poka-yoke qgl quantum game library quantum star se rantings rss simpletest snarl solar empire surviving the deep end symfony tdd test spy tutorial unit testing xp programming xrd xrds xss yadis yaml zend framework zf proposal zfstde |


